Рубрики
Kamailio FreeSWITCH

Kamailio часть 12. Работа в облаке через один сетевой интерфейс, SIP сигнализация через TCP

В этой статье мы рассмотрим очень популярный кейс (Kamailio в AWS, GCE, Hetzner и любом другом облаке), когда Kamailio находится в приватной сети с одним сетевым интерфейсом, при этом, со стороны провайдера облачных услуг, на маршрутизаторе настроен NAT. Также рассмотрим настройку SIP сигнализации через TCP и поддержку Proxy Protocol

Kamailio через NAT на одном сетевом интерфейсе. Теория и пратика. Возможные варианты в Cloud

Во всех предыдущих статья рассматривалось, как настроить Kamailio с двумя сетевыми интерфейсами, где на первом интерфейсе настроен публичный (белый) IP адрес напрямую в ВМ, второй сетевой интерфейс — настроен приватный (серый, согласно rfc1918) адрес. В данном случае все довольно просто и понятно. Первый интерфейс — для взаимодействия с внешними (белыми) IP адресами (клиентами, транками через интернет…), второй же — для взаимодействия с media серверами (FreeSWITCH, Asterisk или другой Softswitch 5 класса) или приватными SIP trunk

Kamailio перед NAT, NAT в EC2/ВМ

Но эта парадигма не работает в облаках. Дело в том, что в AWS (Elastic IP), GCE и в остальных облаках, как правило, внешний IP адрес не добавляется напрямую в ВМ (AWS EC2, GCE Compute), а выполняется трансляция сетевых адресов (NAT). Схематично это выглядит следующим образом:

Kamailio behind NAT AWS GCE
Kamailio перед NAT в облаках (например AWS)

Kamailio через AWS NLB/GCE Cloud Load Balancer/Hetzner Load Balancer

При этом возможен другой сценарий, когда Kamailio стоит перед балансировщиком нагрузки, в AWS это называется Network Load Balancer, в Hetzner — Load Balancer, в Google Cloud — Cloud Load Balancer. Схематично это выглядит следующим образом:

Load Balancer (на примере AWS NLB) перед Kamailio

В данном случае, это делается для возможности горизонтального масштабирования самого Kamailio, но клиент при этом обращается не напрямую в Kamailio, а через балансировщик нагрузки, который проверяет доступность Kamailio нод, а также распределяет нагрузку в зависимости от выбранного алгоритма

Настройка Kamailio для работы в облаке с одним сетевым (приватным) интерфейсом

Т.к SIP протокол чувствителен к прохождению NAT и нужно корректно настроить это самое прохождение NAT (Kamailio часть 2. Прохождение NAT в SIP протоколе, разбор прохождения NAT в Kamailio), в ином случае SIP сигнализация будет работать некорректно (например, не будет доходить ACK в первой транзакции, как это рассматривалось в 3 части цикла статей).

Мне известно два варианта для корректного проставления публичных и приватных IP адресов:
1) Один сетевой интерфейс, но слушающий разные порты

Один сетевой интерфейс на разных портах

2) Два сетевых интерфейса

Два сетевых интерфейса на одинаковом портах, но с разными приватными IP адресами

В этой статье рассматривается первый вариант, когда у нас есть только один сетевой интерфейс, но работающий на разных портах

В самом верху конфигурационного файла приведем listen к следующему виду:

listen=udp:LOCAL_IP:5060 advertise PUBLIC_IP:5060 name "public_socket"
listen=udp:LOCAL_IP:5070 name "private_socket"
listen=tls:LOCAL_IP:7777 advertise PUBLIC_IP:7777 name "public_webrtc_socket"
alias=tls:yourdomain.com:7777
alias=udp:yourdomain.com:5060

Где LOCAL_IP — приватный IP адрес сетевого интерфейса сервера
advertise — сообщает, что в Record-Route и Via заголовках необходимо указать другой IP адрес
PUBLIC_IP — публичный IP адрес (напр. Elastic IP или IP адрес балансировщика)
yourdomain.com — ваш домен (для работы TLS)


ВАЖНО
Не забудьте открыть необходимые порты в ACL/Firewall в случае простого NAT (напр. Elastic IP)
При использовании балансировщика необходимо сделать проброс портов с балансировщика на сервер с Kamailio


Далее воспользуемся модулем corex.so, с помощью set_send_socket_name(sname) есть возможность принудительно указывать, с помощью какого сокета (указывается имя сокета, из строки listen берется name) необходимо выполнить обработку запроса.

Изменим следующие блоки в route[DIALOG]:

route[DIALOG] {
        if (has_totag()) {
                if (loose_route()) {
                        handle_ruri_alias();
                        route(RELAY);
                }
        }
        if (is_method("ACK")) {
                if ( t_check_trans() ) {
                        route(RELAY);
                        exit;
                } else {
                        exit;
                }
        }

        if (!ds_is_from_list("1", "2") && !ds_is_from_list("2")) {
                setflag(tswitch);
                set_send_socket_name("private_socket");
........................................................
        } else {
                setflag(fswitch);
                set_send_socket_name("public_socket");
........................................................

Изменение FreeSWITCH dialplan

Также необходимо изменить диалплан для медиа серверов. Сам dialplan настраивался в статье 7

Изменим local_call с sofia/softswitch/${destination_number}@sip.ipcalls24.com на:

<action application="bridge" data="{sip_invite_domain=${sip_from_host}}sofia/softswitch/${destination_number}@yourdomainORipaddr:5070"/>

Теперь сделаем тестовый вызов и посмотрим трассировку через sngrep

Leg-A

И Leg-B:

Leg-B

По трассировке видно, что абонент А отправил SIP INVITE на публичный порт (адрес регистрации) — 5060. Далее, этот вызов пришел на Kamailio, который отправил вызов на media сервера (в нашем случае FreeSWITCH) с source port 5070 на destination port 5090 (настройка через dispatcher рассматривалась ранее)

SIP сигнализация через TCP + Proxy Protocol

В некоторых случаях необходимо обеспечить возможность совершать вызовы не только через UDP, но и через TCP протокол (например, балансировщик не поддерживает UDP). Есть несколько моментов, на которые необходимо обратить внимание

Настройка TCP портов в Kamailio

По аналогии с UDP необходимо настроить прослушивание портов для TCP

В конфигурационный файл, к другим listen директивам добавляем:

listen=tcp:LOCAL_IP:5060 advertise PUBLIC_IP:5060 name "public_tcp_socket"
listen=tcp:LOCAL_IP:5070 name "private_tcp_socket"

Также необходимо изменить параметры, которые идут после listen на следующие:

mhomed=1
tcp_accept_no_cl=yes
tcp_reuse_port=yes 
tcp_connection_lifetime=3605
enable_tls=yes

По умолчанию, tcp_connection_lifetime равняется 120 секунд, т.е TCP сессия оборвется через 120 секунд. Некоторые SIP клиенты (софтфоны) умеют делать keepalive самостоятельно, чтобы продлевать время жизни TCP сессии. На это полагаться я бы не советовал, ввиду того, что абоненты могут подключаться с разных аппаратных и софтовых клиентов. Поэтому настройкой tcp_connection_lifetime принудительно задается время жизни сессии в один час.

Настройка tcp_reuse_port разрешает kamailio переиспользовать открытые TCP порты

Теперь, попробовав зарегистрироваться на сервере через софтфон, будет видна следующая ситуация:

Доступные протоколы для регистрации SIP TCP/SIP UDP

Как видно, теперь у нас доступно 3 протокола для регистрации и возможности совершения звонков. Доступен UDP, TCP и TLS (который мы настраивали в статье Kamailio часть 10. Реализация WebRTC в Kamailio с рассмотрением примеров)

Proxy Protocol в Kamailio

Proxy Protocol применяется в тех случаях, когда SIP сервер находится за балансировщиком нагрузки (напр. AWS NLB, HAproxy, Hetzner Load Balancer…). Клиент фактически устанавливает TCP сессию не с SIP балансировщиком, а с балансировщиком нагрузки, который стоит перед ним. Балансировщик нагрузки создает TCP соединение с upstream (в нашем случае — Kamailio) и в качестве исходного IP адреса и/или порта указывает свои собственные, а не настоящего абонента. Для того, чтобы это исправить необходимо включить поддержу Proxy Protocol как на балансировщике, так и на SIP сервере. Proxy Protocol позволяет передать в заголовке PROXY реальный IP адрес клиента, а также используемые порты.

Load Balancer Proxy Protocol

После того, как вы включили Proxy Protocol на вашем балансировщике, необходимо добавить параметр, который включает Proxy Protocol в Kamailio. Ко всем остальным TCP параметрам добавляется:

mhomed=1
tcp_accept_haproxy=yes
tcp_accept_no_cl=yes
tcp_reuse_port=yes
tcp_connection_lifetime=3605
enable_tls=yes

Параметр tcp_accept_haproxy позволяет обрабатывать SIP запросы с PROXY заголовками.

Посмотрим на SIP REGISTER, который пришел через балансировщик нагрузки:

2023/02/03 14:09:17.087555 10.10.8.2:52920 -> 10.*.*.**4:5060
REGISTER sip:ipcalls24.com SIP/2.0
Via: SIP/2.0/TCP 192.168.1.128:43751;branch=z9hG4bK-524287-1---3f660f74b108932e;rport;alias
Max-Forwards: 70
Contact: <sip:[email protected]:43751;rinstance=075ace6eb3d6bece;transport=TCP>
To: "1001"<sip:[email protected]>
From: "1001"<sip:[email protected]>;tag=bc29d013
Call-ID: Y9goKh1s_XWGFDuSYw87xA..
CSeq: 1 REGISTER
Expires: 600
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, SUBSCRIBE, UPDATE, INFO, MESSAGE
Supported: path, replaces, timer, norefersub
User-Agent: SessionTalk 6.0
Content-Length: 0

Видно, что изменился только исходный IP адрес (адрес балансировщика нагрузки), остаьная часть SIP REGISTER приходит без изменений (как было до появление балансировщика)

Настройка RTPengine с одним сетевым интерфейсом

После того, как была настроена корректная SIP сигнализация, также необходимо внести изменения в конфигурационный файл rtpengine (изначальная статья по установке, Kamailio часть 4. Обработка RTP потоков через sipwise RTPengine, взаимодействие SIP протокола с RTP), чтобы в SDP заголовках проставлялся корректный IP (приватный или публичный, в зависимости от плеча)

Внесем в конфигурационный файл rtpengine.conf (или любой другой, указанный в systemd демоне) изменения

[rtpengine]

table = 0

listen-ng = LOCAL_IP:2223

interface = internal/LOCAL_IP;external/LOCAL_IP!PUBLIC_IP

timeout = 60
silent-timeout = 3600
tos = 184

port-min = 10000
port-max = 40000

Обратив внимание на строку interface, мы видим изменения в правой части, в external. Восклицательный знак (!) обозначает тот же смысл, что и advertise. Т.е при отправке SIP сообщения с SDP во внешнюю сеть, будет изменен сам IP адрес на внешний

И убедимся, что в rtpengine_manage корректно проставлены флаги internal и external:

route[RELAY] {
...........................................................
if (has_body("application/sdp") && isflagset(tswitch)) {
                rtpengine_manage("ICE=remove replace-origin UDP/RTP external internal");
        } else {
                if (pcre_match("$dP", "(?i)wss|ws")) {
                        rtpengine_manage("replace-origin ICE=force SDES=off UDP/TLS/RTP/SAVPF codec-mask=all codec-transcode=PCMA,PCMU internal external");
                } else {
                        rtpengine_manage("ICE=remove replace-origin internal external");
                }
        }
...........................................................

Заключение

В этой статье мы рассмотрели, как работать в облачных решениях. Какие концепции существуют и как обходить ограничения по NAT. Также рассмотренна TCP сигнализация и параметры регулируемые со стороны Kamailio. В заключении, добавили настройку Proxy Protocol.

Если есть желание сделать пожертвование, то это можно сделать кликнув по ссылке или же нажав на кнопку. Спасибо за поддержку !)

Для зарубежных платежных систем/карт

5 ответов к “Kamailio часть 12. Работа в облаке через один сетевой интерфейс, SIP сигнализация через TCP”

Не дошел до сюда но вычитал на других ресурсах про advertise
Белый ip — прроброс 5060 и 10000-2000 на внутренний 192.168.1.33 это кама плюс диспетчер ретранслирует на астер в этой же сети 192.168.1.40. На астере транк с провайдером- прекрасно работает вся эта схема -.

Я так и не смог с камы зарегатся у провайдера , автор мог бы создать на задарме тестовый номер и все это показать —
и побольше схем бы — например 1 kamailio регается у провайдера ,2 kamailio регаються пользователи это для скрытия топологии а на астерах диалплан может так …..

так что пока так но продолжаем изучать и тестировать )))

У Задармы realm (etc.tario.ru) отличается от домена. Если правильно прописать, то всё работает.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *