Рубрики
Kamailio

Kamailio часть 2. Прохождение NAT в SIP протоколе, разбор прохождения NAT в Kamailio

В этой статье мы научимся проходить NAT в SIP с использование SIP сервера Kamailio.

Проблема прохождения NAT связана изначально с самим протоколом SIP (Для решения этой проблемы в Kamailio используется модуль nathelper)
При разработке SIP протокола предполагалось, что скоро все перейдут на IPv6, где не будет проблем с недостающими «белыми» или «публичными» адресами. Но на момент написания этой статье, до сих пор не все провайдеры поддерживают IPv6 адресацию, хотя уже многие облачные провайдеры перешли на IPv6 маршрутизацию. Но проблема с прохождение NAT все так же остро стоит и сейчас. В этой статье мы рассмотрим методы прохождения NAT’а в телефонии и реализуем это на Kamailio.

Теория прохождения NAT в SIP протоколе с разбором примеров

Для того, чтобы понять, что такое NAT, следует руководствоваться RFC 1918. В этом RFC приводится список приватных подсетей, которые не маршрутизируются в интернете. Ниже приведен этот список:

Приватные(«серые») подсети

10.0.0.0 — 10.255.255.255 (10/8 prefix)
172.16.0.0 — 172.31.255.255 (172.16/12 prefix)
192.168.0.0 — 192.168.255.255 (192.168/16 prefix)

Соответственно когда пользователь хочет совершить вызов или зарегистрироваться на SIP сервере, в SIP сообщении мы часто увидим IP адрес из приведенных выше подсетей. Т.к эти подсети не участвуют в маршрутизации в интернете, и их может быть бесчисленное множество в локальных сетях каждой организации, мы получим недозвон, обрыв связи спусти 30-32сек и.т.д. Проблема усугубляется тем, что в SIP протоколе де-факто в качестве стандарта используется UDP датаграммы, а как известно UDP не устанавливает сессию перед началом передачи, как это делает TCP.

Из этого следует, что нам необходимо при запросе от пользователя на регистрацию/звонок определить, находится ли пользователь за NAT’ом. В большинстве случаев ответ будет да, за исключением разве что WebRTC клиентов, которые сами решают вопрос прохождения NAT’а (об этом ниже).

Соответственно, есть два подхода по прохождению NAT’а:

1. Client-side NAT, т.е прохождением NAT’а занимается сам пользователь. Это его работа сообщить «белый» или публичный IP адрес нашему SIP серверу. Для этого используется, например STUN сервер (сообщает нашему SIP серверу публичный IP пользователя, после чего работает связь идет напрямую с пользователем), TURN сервер (работает как прокси, вся сигнализация/голос идет через TURN сервер), ICE (Последовательно проверяет возможность достучаться к STUN серверу, если STUN сервер не обнаружен, пробует достучаться до TURN серверов, по моему опыту используется реже всего).
2. Server-side NAT, т.е узнать публичный IP адрес пользователя входит в обязанности нашего SIP сервера, клиенту знать об этом ничего не нужно. Это наиболее предпочтительный вариант т.к в таком случае пользователь может даже не знать, что такое NAT.

Обычно архитектура телефонии предоставляет собой следующие варианты:
1) У SIP сервера есть 2 (или более) сетевых интерфейса. На одном из интерфейсов напрямую заведен публичный («белый») IP адрес. Схематично это выглядит следующим образом:

SIP NAT in Kamailio example public IP

Т.е из схемы видно, что у пользователя (пользовательская сеть) есть свой маршрутизатор для выхода в интернет. У этого маршрутизатора есть некий публичный («белый») IP адрес 2.2.2.2, а внутри сети используются приватные адреса 192.168.0.0/24. SIP сервер же смотрит напрямую в мир с IP адреса 1.1.1.1.

2) Сам SIP сервер находится за NAT, так называемый «симметричный NAT». Схематично это выглядит так:

SIP NAT for Kamailio example symmetric nat

С этой схемой чаще всего сталкиваются те, кто использует публичное облако (Amazon, Google Cloud…). Или же это сознательное решение, чтобы централизованное управлять доступностью серверов в мир с помощью сетевого оборудования. В подавляющем большинстве случаев делается обычный проброс портов с роутера 1.1.1.1 на сервер 172.19.0.2. Обычно открываются порты для SIP/SIPS 5060/5061, и порты для RTP (диапазон указывается в зависимости от используемого Media сервера, например 10000-40000). Обычно, все будет хорошо работать как с прямой парковой публичного IP на SIP сервере, так и с пробросом портов через NAT.

Практическое руководство по прохождению NAT в Kamailio с примерами реализации

На моем сервере реализована первая схема, т.е у SIP сервера на виртуальной машине есть два сетевых интерфейса:

network interfaces on example server
eth0: сетевой интерфейс с публичным IP адресом: 78.**.241.199
eth1: сетевой интерфейс с приватным IP адресом 172.19.0.2

Давайте посмотрим, не изменяя конфигурационный файл из предыдущей (SIP регистрация Kamailio часть 1) статьи, какой запрос на регистрацию сейчас к нам приходит и какой IP адрес запоминает Kamailio для зарегистрированного пользователя.

При отправке запроса на регистрацию из пользовательской сети с IP 192.168.0.103, SIP Server (kamailio) увидит следующее SIP сообщение:

2021/02/10 12:24:31.424157 185.165.***.5*:1210 -> 78.**.241.199:5060
REGISTER sip:ipcalls24.com;transport=UDP SIP/2.0
Via: SIP/2.0/UDP 192.168.0.103:5060;branch=z9hG4bK-524287-1---9744b615cd80de9b;rport
Max-Forwards: 70
Contact: <sip:1111@192.168.0.103:5060;rinstance=19dadbf6a0cea50b;transport=UDP>
To: <sip:[email protected];transport=UDP>
From: <sip:[email protected];transport=UDP>;tag=ff72e816
Call-ID: vAHsCDcqu_eE2ZJZ71fv3Q..
CSeq: 1 REGISTER
Expires: 70
Allow: INVITE, ACK, CANCEL, BYE, NOTIFY, REFER, MESSAGE, OPTIONS, INFO, SUBSCRIBE
Supported: replaces, norefersub, extended-refer, timer, outbound, path, X-cisco-serviceuri
User-Agent: Z 5.4.9 rv2.10.11.7
Allow-Events: presence, kpml, talk
Content-Length: 0

Теперь давайте посмотрим какой IP адрес пользователя Kamailio записал себе в оперативную память

Как проверить зарегистрирован ли номер

Для этого в Kamailio есть две возможности. Это можно сделать с помощью команды kamctl или kacmd.
Kamcmd позволяет выполнять RPC команды в Kamailio как на локальном хосте, так и на удаленном. Для kamcmd необходимо добавить модуль «ctl.so»
Kamctl может использовать kamcmd, но больше предназначен для работы с базой данных, выполнение команд происходит через именнованный pipe(fifo). Для kamctl необходимо загрузить модуль jsonrpcs.so.
Загрузка модулей происходит по аналогии с другими модулями, в конфиге /etc/kamailio/kamailio.cfg:

loadmodule «ctl.so»
loadmodule «jsonrpcs.so»

Для этого выполним команду:

kamcmd ul.lookup location [email protected]

Где kamcmd — вызов RPC команды, ul.lookup — ключ, location — название таблицы в которой хотим найти пользователя, [email protected] — имя аккаунта+домен

Результат выполнения команды будет следующий:

результат выполнения команды kamcmd для просмотра регистрации

Или же получим JSON массив с данными об зарегистрированном аккаунте через kamctl

kamctl ul show 1111

Где kamctl — вызов команды, ul show — ключи для вывода информации, 1111 — имя аккаунта

Результат выполнения будет аналогичен вызову команды kamcmd, но представлен в JSON массиве:

вывод результата команды kamctl в формате JSON об зарегистрированном пользователе

Address Of Record (AOR) берется из поля FROM/TO, SIP сервер запоминает пользователя при успешной регистрации (запоминает AoR + заголовок Contact URI) и будет думать, что он находится в одной локальной сети с пользователем и что ему назначен IP 192.168.0.103, что не соответствует действительности. При попытке дозвона до номера 1111, Kamailio посмотрит в первую очередь зарегистрирован ли пользователь, и если пользователь найден и он зарегистрирован, то входящий вызов на 1111 будет отправлен на IP адрес содержащийся в поле Contact, а как мы помним, там указан приватный IP адрес и поэтому вызов по факту никуда не дойдет.

Для решения этой проблемы и реализации Server-Side архитектуры прохождения NAT’а нам необходимо узнать публичный IP адрес пользователя при регистрации и записать его в оперативную память Kamailio, в поле Contact. Это делается с помощью ранее упомянутого модуля nathelper. Для этого в первую очередь загрузим сам модуль ко всем остальным модулям, а также загрузим модуль siputils (будет использоваться для работы с SIP сообщениями):

loadmodule "nathelper.so"
loadmodule "siputils.so"

После чего необходимо в главном маршруте, request_route выполнять проверку на NAT. Для этого мы создадим пользовательский маршрут с гворящим именем «NAT».

route[NAT] {
        if (nat_uac_test("19")) {
                if (is_method("REGISTER")) {
                        set_contact_alias();
                } else {
                        if(is_first_hop()) {
                                set_contact_alias();
                        }
                }
        }
        return;
}

Давайте более подробно разберем, что значит этот маршрут. В первую очередь мы выполняем проверку на NAT с помощью функции nat_uac_test. Цифры 19 — это сумма всех флагов, которые вызываются. В данном случае цифры 19 значит использование следующих флагов: 16,2,1. Это означает, что мы флагом 1 проверяем поле Contact по RFC1918 и RFC6598, т.е проверяем содержит ли поле Contact приватный IP адрес
Флагом 2 мы проверяем заголовок Via на соответствие source IP и если не указан порт, используем порт по умолчанию — 5060.
Флагом 16 проверяется, отличается ли source порт от того, что указано в заголовке Via, если не указан порт — используется порт по умолчанию 5060.

Далее уже знакомая конструкция, с помощью которой мы проверяем действительно ли это SIP сообщение регистрации и если да — мы добавляем публичный IP адрес как alias вызовом функции set_contact_alias(). Например так будет выглядеть поле Contact в опертивной памяти Kamailio после вызова set_contact_alias:

nathelper alias добавление в заголовок SIP Contact

Видно, что добавилось поле alias, который содержит публичный IP адрес User Agent’а (185.***.163.51) и его порт (1210 в данном случае)

Оставшиеся функции, если запрос не REGISTER мы рассмотрим в следующей статье, когда будем совершать первые вызовы.

Теперь необходимо добавить вызов функции для каждого поступающего сообщения в request_route

request_route {
        route(NAT);
        if (is_method("REGISTER")) {
                route(AUTH);
        }
}

Итоговый конфигурационный файл /etc/kamailio/kamailio.cfg будет выглядеть так:

#!define DBURL "postgres://kamailio:secret_password@localhost:5433/kamailio"


loadmodule "pv.so"
loadmodule "ctl.so"
loadmodule "jsonrpcs.so"
loadmodule "tm.so"
loadmodule "textops.so"
loadmodule "sl.so"
loadmodule "usrloc.so"
loadmodule "registrar.so"
loadmodule "auth.so"
loadmodule "db_postgres.so"
loadmodule "auth_db.so"
loadmodule "siputils.so"
loadmodule "nathelper.so"

#############[Подключение к БД]###########
modparam("auth_db", "db_url", DBURL); # указываем URL для подключения, берем его из ранее созданной директивы DBURL

request_route {
        if (is_method("INVITE") || is_method("REGISTER")) {
                route(NAT);
        }

        if (is_method("REGISTER")) {
                route(AUTH);
        }
}

route[AUTH] {
                if (!auth_check("$fd", "subscriber", "1")) {
                        force_rport();
                        auth_challenge("$fd", "1");
                        exit;
                }
                force_rport();
                if (is_method("REGISTER")) {
                        save("location");
                        exit;
                } else {
                        return;
                }
}

route[NAT] {
        if (nat_uac_test("19")) {
                if (is_method("REGISTER")) {
                        set_contact_alias();
                } else {
                        if(is_first_hop()) {
                                set_contact_alias();
                        }
                }
        }
        return;
}

Заключение

В этой статье мы научились проходить NAT для регистрации, познакомились сжато с теорией NAT’а и взаимодействие с SIP протоколом. И на практике было показано, как работать с модулем nathelper в Kamailio.
В следующей статье мы совершим первый вызов между пользовательскими телефонными агентами.

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

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

6 ответов к “Kamailio часть 2. Прохождение NAT в SIP протоколе, разбор прохождения NAT в Kamailio”

Модуль то вы загрузили loadmodule «siputils.so»
loadmodule «nathelper.so» но не показали что вы его включили !!!
Статья точно не для новичка !! Я буду периодически писать вам что у вас не так но такое ощущение что вы не все описываете или это просто перевод одной из

Это авторские статьи, а не перевод. При загрузки модулей siputils и nathelper, мы используем функции, которые предоставляют эти модули. У модулей нет понятия включить/выключить. Модули можно только инициализировать и при необходимости (а такой необходимости в nathelper/siputils нет) прописать параметры через modparam. Более того, я скопировал полностью конфигурационный файл, который приведен в самом конце статьи и все прекрасно заработало без неизвестных включений модулей.

Подскажите почему часть по нат не по классическому из документации ?
А именно это место:
if (is_method(«REGISTER»)) {
set_contact_alias();
} else {
Везде где я открываю примеры из этот участок выглядит как:

if (is_method(«REGISTER»)) {
fix_nated_register();
} else {
у вас же оба раза строчка
set_contact_alias();

Добрый день!
Сделано по официальной документации kamailio. Если открыть дефолтный kamailio.cfg, который находится в /etc/kamailio/kamailio.cfg, то нигде не будет использоваться fix_nated_contact, но будет использоваться set_contact_alias/handle_ruri_alias. Это более новые функции, которые заменили собой использование fix_nated_contact.

Странно, у меня выхлоп несколько иной.
# kamctl ul show 0018
{
«jsonrpc»: «2.0»,
«error»: {
«code»: 500,
«message»: «AOR not found in location table»
},
«id»: 383324
}

или
# kamcmd ul.lookup location [email protected]
error: 500 — AOR not found in location table

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

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