Asterisk PJSIP: Решение проблем с NAT через media_use_received_transport
Топология SIP за NAT и проблема SDP
Проблема односторонней слышимости (One-Way Audio) или полного отсутствия звука при установленном вызове (отсчет секунд идет) — самая частая головная боль в VoIP. В протоколе SIP управляющий трафик (сигнализация, порт 5060) и медиатрафик (RTP голос, порты 10000-20000) разделены. В момент поднятия трубки устройства обмениваются пакетами SDP (Session Description Protocol), в которых указывают, на какой IP и порт им слать аудио. Если телефон находится за NAT (домашний роутер), он вставляет в SDP свой локальный IP (например, 192.168.1.15). Asterisk пытается отправить голос на этот 'серый' IP в интернет, и пакеты теряются. Бизнес-риски: клиенты не слышат операторов колл-центра, срывы важных переговоров.
Анализ пакета SDP (Причина проблемы)
| Параметр в теле пакета SIP (SDP) | Что он означает | Поведение за NAT |
|---|---|---|
c=IN IP4 192.168.1.15 | Connection Information (Куда слать медиа) | Указывает серый IP. Сервер отправляет голос «в никуда». |
m=audio 11244 RTP/AVP... | Media Port (Порт для приема RTP) | Указывает локальный порт телефона. |
Применение механизма Symmetric RTP в PJSIP
Сценарий 1: Включение media_use_received_transport
В современном стеке PJSIP параметр rtp_symmetric и media_use_received_transport спасают ситуацию, заставляя Asterisk игнорировать серые IP-адреса внутри SDP-пакета (SDP Connection Address) и отправлять аудиопоток обратно на тот публичный IP и порт NAT-роутера, с которого физически прилетели первые медиа-пакеты.
Фрагмент файла pjsip.conf (Настройка Endpoint)
[100]
type=endpoint
context=from-internal
disallow=all
allow=alaw,ulaw
aors=100
--- Блок решения проблем с NAT ---
rtp_symmetric=yes ; Отвечать на RTP туда, откуда они пришли (Symmetric RTP)
force_rport=yes ; Игнорировать SIP Via заголовок, отвечать на публичный IP (Сигнализация)
rewrite_contact=yes ; Перезаписывать Contact URI (Сигнализация)
media_use_received_transport=yes ; Отправлять RTP через тот же транспорт (IP/Порт), что и сигнализация, пока не получен первый RTP пакет от клиента (Важно для WebRTC)
direct_media=no ; Запретить телефонам общаться напрямую (Asterisk всегда гоняет голос через себя)Сценарий 2: Глобальная настройка транспорта (Local Net)
Чтобы Asterisk сам не отправлял провайдеру свой внутренний IP-адрес (если сам сервер стоит за NAT), необходимо глобально настроить секцию [transport].
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0:5060
local_net=192.168.1.0/24 ; Наша локальная сеть
external_media_address=8.8.8.8 ; ВНЕШНИЙ публичный IP-адрес роутера (для SDP)
external_signaling_address=8.8.8.8 ; ВНЕШНИЙ публичный IP (для SIP)Типовые ошибки администраторов
- Пропуск direct_media=no: По умолчанию сервер может попытаться соединить два телефона напрямую. Если они в разных подсетях или за NAT, звука не будет. Голос всегда должен идти через АТС (PBX-Proxy).
- Использование SIP ALG на роутере: Бытовые роутеры (MikroTik, TP-Link, Keenetic) имеют функцию SIP ALG (SIP Helper), которая пытается налету менять IP в SDP пакетах. Чаще всего она ломает пакеты, портя хеши MD5. SIP ALG необходимо отключать на маршрутизаторах!
Траблшутинг RTP-трафика за сложными NAT (Double NAT) — ювелирная работа. Инженеры ITSTM проведут анализ дампов (tcpdump/sngrep), настроят STUN/TURN серверы и обеспечат кристально чистый голос в вашей корпоративной сети.
Частые вопросы (FAQ)
В чем отличие rtp_symmetric от media_use_received_transport?
rtp_symmetric заставляет Asterisk ждать первый RTP-пакет от клиента и слать ответ на его IP/Порт (Comedia). Однако, если клиент молчит или это WebRTC (ICE-кандидаты), Asterisk не знает, куда слать. Параметр media_use_received_transport заставляет использовать транспортный IP/Порт из сигнализации (SIP) в качестве предварительного адреса для RTP.
Работает ли это для chan_sip?
В устаревшем драйвере chan_sip аналогом комбинации этих параметров (force_rport, rewrite_contact, rtp_symmetric) является одна настройка: nat=yes (или nat=force_rport,comedia).
Звук есть, но обрывается ровно через 30 секунд. Почему?
Это классический признак потери ACK-пакета или разрыва сессии по Session-Timers из-за NAT. Телефон не получает подтверждения на 200 OK. Убедитесь, что rewrite_contact=yes включен.
Как проверить с помощью tcpdump, куда летит голос?
Выполните на сервере Asterisk: tcpdump -nqt -s 0 -A -i eth0 port 5060 or udp range 10000-20000. В трафике ищите IP-адреса назначения. Если вы видите, что пакет летит на 'серый' IP абонента (10.x.x.x) в публичный интернет — настройки NAT не применились.