Complete DDS training workflow and delivery package
This commit is contained in:
parent
68dd83c7c2
commit
4c4b91064f
229 changed files with 11969 additions and 1024 deletions
2
sip/.dockerignore
Normal file
2
sip/.dockerignore
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*.log
|
||||
*.wav
|
||||
22
sip/Dockerfile
Normal file
22
sip/Dockerfile
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
FROM ubuntu:22.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends asterisk ca-certificates gettext-base openssl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY pjsip.conf.template /opt/lct-sip/pjsip.conf.template
|
||||
COPY extensions.conf /etc/asterisk/extensions.conf
|
||||
COPY http.conf /etc/asterisk/http.conf
|
||||
COPY modules.conf /etc/asterisk/modules.conf
|
||||
COPY rtp.conf /etc/asterisk/rtp.conf
|
||||
COPY entrypoint.sh /usr/local/bin/lct-sip-entrypoint
|
||||
RUN chmod +x /usr/local/bin/lct-sip-entrypoint \
|
||||
&& mkdir -p /recordings /var/lib/lct-sip /tls \
|
||||
&& chown -R asterisk:asterisk /recordings /var/lib/lct-sip
|
||||
|
||||
EXPOSE 5060/udp 5060/tcp 5061/tcp 8088/tcp 10000-10099/udp
|
||||
HEALTHCHECK --interval=10s --timeout=3s --retries=6 --start-period=15s \
|
||||
CMD asterisk -rx "core show uptime" >/dev/null 2>&1 || exit 1
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/lct-sip-entrypoint"]
|
||||
50
sip/entrypoint.sh
Normal file
50
sip/entrypoint.sh
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
credentials=/var/lib/lct-sip/credentials.env
|
||||
mkdir -p /var/lib/lct-sip /recordings /tls
|
||||
umask 077
|
||||
|
||||
override_6001=${SIP_6001_PASSWORD:-}
|
||||
override_6002=${SIP_6002_PASSWORD:-}
|
||||
override_6003=${SIP_6003_PASSWORD:-}
|
||||
override_6101=${SIP_6101_PASSWORD:-}
|
||||
override_6102=${SIP_6102_PASSWORD:-}
|
||||
if [ -s "$credentials" ]; then
|
||||
# Файл содержит только сгенерированные hex-значения без shell-конструкций.
|
||||
. "$credentials"
|
||||
fi
|
||||
SIP_6001_PASSWORD=${override_6001:-${SIP_6001_PASSWORD:-$(openssl rand -hex 16)}}
|
||||
SIP_6002_PASSWORD=${override_6002:-${SIP_6002_PASSWORD:-$(openssl rand -hex 16)}}
|
||||
SIP_6003_PASSWORD=${override_6003:-${SIP_6003_PASSWORD:-$(openssl rand -hex 16)}}
|
||||
SIP_6101_PASSWORD=${override_6101:-${SIP_6101_PASSWORD:-$(openssl rand -hex 16)}}
|
||||
SIP_6102_PASSWORD=${override_6102:-${SIP_6102_PASSWORD:-$(openssl rand -hex 16)}}
|
||||
SIP_EXTERNAL_MEDIA_ADDRESS=${SIP_EXTERNAL_MEDIA_ADDRESS:-127.0.0.1}
|
||||
cat > "$credentials" <<EOF
|
||||
SIP_6001_PASSWORD=$SIP_6001_PASSWORD
|
||||
SIP_6002_PASSWORD=$SIP_6002_PASSWORD
|
||||
SIP_6003_PASSWORD=$SIP_6003_PASSWORD
|
||||
SIP_6101_PASSWORD=$SIP_6101_PASSWORD
|
||||
SIP_6102_PASSWORD=$SIP_6102_PASSWORD
|
||||
EOF
|
||||
chmod 600 "$credentials"
|
||||
|
||||
export SIP_6001_PASSWORD SIP_6002_PASSWORD SIP_6003_PASSWORD SIP_6101_PASSWORD SIP_6102_PASSWORD SIP_EXTERNAL_MEDIA_ADDRESS
|
||||
envsubst '${SIP_6001_PASSWORD} ${SIP_6002_PASSWORD} ${SIP_6003_PASSWORD} ${SIP_6101_PASSWORD} ${SIP_6102_PASSWORD} ${SIP_EXTERNAL_MEDIA_ADDRESS}' \
|
||||
< /opt/lct-sip/pjsip.conf.template > /etc/asterisk/pjsip.conf
|
||||
chmod 640 /etc/asterisk/pjsip.conf
|
||||
chown root:asterisk /etc/asterisk/pjsip.conf
|
||||
|
||||
if [ ! -s /tls/sip.crt ] || [ ! -s /tls/sip.key ]; then
|
||||
openssl req -x509 -nodes -newkey rsa:3072 -sha256 -days 365 \
|
||||
-keyout /tls/sip.key -out /tls/sip.crt \
|
||||
-subj '/CN=localhost/O=LCT local SIP training stand' \
|
||||
-addext 'subjectAltName=DNS:localhost,IP:127.0.0.1' \
|
||||
-addext 'extendedKeyUsage=serverAuth' 2>/dev/null
|
||||
fi
|
||||
chmod 640 /tls/sip.key
|
||||
chmod 644 /tls/sip.crt
|
||||
chown root:asterisk /tls/sip.key /tls/sip.crt
|
||||
chown -R asterisk:asterisk /recordings /var/lib/lct-sip
|
||||
|
||||
exec asterisk -f -U asterisk -G asterisk -vvv
|
||||
28
sip/extensions.conf
Normal file
28
sip/extensions.conf
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
[general]
|
||||
static=yes
|
||||
writeprotect=yes
|
||||
clearglobalvars=no
|
||||
|
||||
[lct-training]
|
||||
; 6001 — ДДС, 6002 — старший группы, 6003 — преподаватель.
|
||||
exten => _600[1-3],1,NoOp(LCT training call ${CALLERID(num)} -> ${EXTEN})
|
||||
same => n,Set(RECORDING_FILE=${STRFTIME(${EPOCH},UTC,%Y%m%d-%H%M%S)}-${CALLERID(num)}-${EXTEN}-${UNIQUEID})
|
||||
same => n,MixMonitor(/recordings/${RECORDING_FILE}.wav,b)
|
||||
same => n,Dial(PJSIP/${EXTEN},30)
|
||||
same => n,StopMixMonitor()
|
||||
same => n,Hangup()
|
||||
|
||||
; 6101/6102 — браузерные WebRTC-абоненты. Тот же учебный контекст и запись,
|
||||
; но отдельные endpoints не ломают обычные UDP/TCP-софтфоны 6001–6003.
|
||||
exten => _610[1-2],1,NoOp(LCT WebRTC training call ${CALLERID(num)} -> ${EXTEN})
|
||||
same => n,Set(RECORDING_FILE=${STRFTIME(${EPOCH},UTC,%Y%m%d-%H%M%S)}-${CALLERID(num)}-${EXTEN}-${UNIQUEID})
|
||||
same => n,MixMonitor(/recordings/${RECORDING_FILE}.wav,b)
|
||||
same => n,Dial(PJSIP/${EXTEN},30)
|
||||
same => n,StopMixMonitor()
|
||||
same => n,Hangup()
|
||||
|
||||
; Эхо-номер нужен для проверки полного SIP/RTP-пути без второго устройства.
|
||||
exten => 7000,1,NoOp(LCT SIP echo test)
|
||||
same => n,Answer()
|
||||
same => n,Echo()
|
||||
same => n,Hangup()
|
||||
8
sip/http.conf
Normal file
8
sip/http.conf
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[general]
|
||||
enabled=yes
|
||||
bindaddr=0.0.0.0
|
||||
bindport=8088
|
||||
tlsenable=no
|
||||
|
||||
; Порт доступен только локально/Docker-сети. Браузер приходит по WSS через
|
||||
; Nginx; прямой HTTP нужен лишь для health/smoke на localhost.
|
||||
7
sip/modules.conf
Normal file
7
sip/modules.conf
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
[modules]
|
||||
autoload=yes
|
||||
|
||||
; Ubuntu всё ещё поставляет legacy chan_sip, который первым захватывает
|
||||
; WebSocket subprotocol `sip`. Все endpoints стенда описаны в PJSIP.
|
||||
noload => chan_sip.so
|
||||
load => res_pjsip_transport_websocket.so
|
||||
156
sip/pjsip.conf.template
Normal file
156
sip/pjsip.conf.template
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
[global]
|
||||
type=global
|
||||
user_agent=LCT-112-Training-SIP
|
||||
endpoint_identifier_order=auth_username,username,ip,anonymous
|
||||
|
||||
[transport-udp]
|
||||
type=transport
|
||||
protocol=udp
|
||||
bind=0.0.0.0:5060
|
||||
|
||||
[transport-tcp]
|
||||
type=transport
|
||||
protocol=tcp
|
||||
bind=0.0.0.0:5060
|
||||
|
||||
[transport-tls]
|
||||
type=transport
|
||||
protocol=tls
|
||||
bind=0.0.0.0:5061
|
||||
cert_file=/tls/sip.crt
|
||||
priv_key_file=/tls/sip.key
|
||||
method=tlsv1_2
|
||||
verify_client=no
|
||||
verify_server=no
|
||||
allow_reload=yes
|
||||
|
||||
; TLS для браузера завершает тот же Nginx, что обслуживает АРМ. До Asterisk
|
||||
; SIP signaling идёт WebSocket внутри изолированной Docker-сети.
|
||||
[transport-ws]
|
||||
type=transport
|
||||
protocol=ws
|
||||
bind=0.0.0.0
|
||||
external_media_address=${SIP_EXTERNAL_MEDIA_ADDRESS}
|
||||
|
||||
[training-endpoint](!)
|
||||
type=endpoint
|
||||
context=lct-training
|
||||
disallow=all
|
||||
allow=ulaw
|
||||
allow=alaw
|
||||
direct_media=no
|
||||
rtp_symmetric=yes
|
||||
force_rport=yes
|
||||
rewrite_contact=yes
|
||||
ice_support=yes
|
||||
timers=yes
|
||||
dtmf_mode=rfc4733
|
||||
language=ru
|
||||
|
||||
[6001](training-endpoint)
|
||||
auth=6001-auth
|
||||
aors=6001
|
||||
callerid=Диспетчер ДДС <6001>
|
||||
|
||||
[6001-auth]
|
||||
type=auth
|
||||
auth_type=userpass
|
||||
username=6001
|
||||
password=${SIP_6001_PASSWORD}
|
||||
|
||||
[6001]
|
||||
type=aor
|
||||
max_contacts=3
|
||||
remove_existing=yes
|
||||
qualify_frequency=30
|
||||
|
||||
[6002](training-endpoint)
|
||||
auth=6002-auth
|
||||
aors=6002
|
||||
callerid=Старший группы <6002>
|
||||
|
||||
[6002-auth]
|
||||
type=auth
|
||||
auth_type=userpass
|
||||
username=6002
|
||||
password=${SIP_6002_PASSWORD}
|
||||
|
||||
[6002]
|
||||
type=aor
|
||||
max_contacts=3
|
||||
remove_existing=yes
|
||||
qualify_frequency=30
|
||||
|
||||
[6003](training-endpoint)
|
||||
auth=6003-auth
|
||||
aors=6003
|
||||
callerid=Преподаватель <6003>
|
||||
|
||||
[6003-auth]
|
||||
type=auth
|
||||
auth_type=userpass
|
||||
username=6003
|
||||
password=${SIP_6003_PASSWORD}
|
||||
|
||||
[6003]
|
||||
type=aor
|
||||
max_contacts=3
|
||||
remove_existing=yes
|
||||
qualify_frequency=30
|
||||
|
||||
[webrtc-endpoint](!)
|
||||
type=endpoint
|
||||
context=lct-training
|
||||
disallow=all
|
||||
allow=ulaw
|
||||
allow=alaw
|
||||
direct_media=no
|
||||
webrtc=yes
|
||||
use_avpf=yes
|
||||
media_encryption=dtls
|
||||
dtls_auto_generate_cert=yes
|
||||
dtls_verify=fingerprint
|
||||
dtls_setup=actpass
|
||||
ice_support=yes
|
||||
media_use_received_transport=yes
|
||||
rtcp_mux=yes
|
||||
rtp_symmetric=yes
|
||||
force_rport=yes
|
||||
rewrite_contact=yes
|
||||
timers=yes
|
||||
dtmf_mode=rfc4733
|
||||
language=ru
|
||||
|
||||
[6101](webrtc-endpoint)
|
||||
auth=6101-auth
|
||||
aors=6101
|
||||
callerid=Веб ДДС <6101>
|
||||
|
||||
[6101-auth]
|
||||
type=auth
|
||||
auth_type=userpass
|
||||
username=6101
|
||||
password=${SIP_6101_PASSWORD}
|
||||
|
||||
[6101]
|
||||
type=aor
|
||||
max_contacts=2
|
||||
remove_existing=yes
|
||||
qualify_frequency=30
|
||||
|
||||
[6102](webrtc-endpoint)
|
||||
auth=6102-auth
|
||||
aors=6102
|
||||
callerid=Веб старший группы <6102>
|
||||
|
||||
[6102-auth]
|
||||
type=auth
|
||||
auth_type=userpass
|
||||
username=6102
|
||||
password=${SIP_6102_PASSWORD}
|
||||
|
||||
[6102]
|
||||
type=aor
|
||||
max_contacts=2
|
||||
remove_existing=yes
|
||||
qualify_frequency=30
|
||||
5
sip/rtp.conf
Normal file
5
sip/rtp.conf
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
[general]
|
||||
rtpstart=10000
|
||||
rtpend=10099
|
||||
strictrtp=yes
|
||||
icesupport=yes
|
||||
Loading…
Reference in a new issue