Рубрики
Kamailio

Kamailio часть 1. Правильная SIP Регистрация в Kamailio, создание внутренних SIP номером

В этой статье мы подключим базу данных, вкраце рассмотрим теорию обработки SIP регистрации и авторизации, реализуем ее на практике в Kamailio

Это продолжение части 0, сегодня мы начнем реализовывать схему из вводной части в Kamailio.

Подключение базы данных PostgreSQL для работы с Kamailio

В этой статье мы не будем рассматривать установка и настройку самой базы данных. Замечу только, что у меня на сервере установлена база данных Postgres версии 11 с который мы и будем работать. Для подключения базы данных необходимо установить пакет с драйвером. Для этого необходимо выполнить:

yum install -y kamailio-postgresql

После установки драйвера, необходимо указать данные для подключения базы данных в файле /etc/kamailio/kamctlrc.

SIP_DOMAIN=ipcalls24.com #Ваш домен
DBENGINE=PGSQL #Используемый драйвер, может быть PGSQL для Postgres, MYSQL соответственно для драйвера MYSQL
DBHOST=localhost # IP или DNS адрес базы данных к которой будем подключаться
DBPORT=5433 # Порт для подключения, по умолчанию 5432 в Postgres, 3306 для MySQL
DBNAME=kamailio # Название создаваемой базы данных
DBRWUSER="kamailio" # Имя пользователя с правами на запись и чтение
DBRWPW="*********" # Пароль для пользователя
DBROUSER="kamailioro" # Имя пользователя с правами только на чтение
DBROPW="*********" # Пароль для пользователя
DBROOTUSER="postgres" # Корневой пользователь с правами на создание баз данных/таблиц. В PostgreSQL по умолчанию пользователь postgres, в MySQL - root
DBROOTPW="*********" # Пароль для корневого пользователя

После чего из под пользователя с sudo правами необходимо выполнить инициализацию базы данных с помощью команды kamdbctl и два раза ответить да(y):

kamdbctl create

INFO: creating database kamailio ...
INFO: Core Kamailio tables succesfully created.
Install presence related tables? (y/n): y
INFO: creating presence tables into kamailio ...
INFO: Presence tables succesfully created.
Install tables for imc cpl siptrace domainpolicy carrierroute
                drouting userblacklist htable purple uac pipelimit mtree sca moh
                rtpproxy rtpengine secfilter? (y/n): y
INFO: creating extra tables into kamailio ...
INFO: Extra tables succesfully created.

На этом инициализация базы данных закончена. В конфигурационном файле /etc/kamailio/kamailio.cfg необходимо указать директиву #!define следующего вида:

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

Где DBURL — название директивы, postgres — используемый драйвер для подключения, kamailio — имя пользователя для подключения, secret_password — пароль пользователя, localhost — IP или DNS имя базы данных для подключения, 5433 — порт для подключения, kamailio — название базы данных к которой подключаемся.

Файл конфигурации будет выглядеть следующем образом:

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

loadmodule "db_postgres.so" # подключаем ранее установленный пакет kamailio-postgresql

request_route {
        exit;
}

На этом подключение к базе данных завершено.

Теория обработка запросов SIP регистрации с примерами

Теория работы с запросами SIP REGISTER описана в RFC 3261. Сама регистрация выглядит следующим образом:

Kamailio REGISTER trace

Т.е из этой трассировки видно следующее:
1) Пользователь отправляет запрос REGISTER на SIP сервер (в нашем случае в роли SIP сервера выступает Kamailio) следующего вида:

2021/02/07 13:42:33.936074 185.165.***.5*:7014 -> 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---a8c525c096737c3f;rport
Max-Forwards: 70
Contact: <sip:[email protected]:5060;rinstance=93a63da919047bbf;transport=UDP>
To: <sip:[email protected];transport=UDP>
From: <sip:[email protected];transport=UDP>;tag=9753211e
Call-ID: 1w7vRiDmp-rpqKe3jhvxaQ..
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

SIP сервер проверяет SIP сообщение на наличие поля «Authorization» и в случае, если не находит его отправляет телефонному агенту пользователя запрос на аутентификацию (401 Unauthorized).

2021/02/07 13:42:33.936448 78.**.241.199:5060 -> 185.165.***.5*:7014
SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 192.168.0.103:5060;branch=z9hG4bK-524287-1---a8c525c096737c3f;rport=7014;received=185.165.***.5*
To: <sip:[email protected];transport=UDP>;tag=e0d499bb1b78bcb08c87e527cc2e4090.e11a79c9
From: <sip:[email protected];transport=UDP>;tag=9753211e
Call-ID: 1w7vRiDmp-rpqKe3jhvxaQ..
CSeq: 1 REGISTER
WWW-Authenticate: Digest realm="ipcalls24.com", nonce="YB/hZWAf4DncAbF2L2CUDyTdoHRvBdno", qop="auth"
Server: IPCALLS24
Content-Length: 0

Пользовательский агент (напр. софтфон Zoiper, MicroSIP или же физическая трубка) получая такое сообщение должен отправить зашифрованные логин/пароль/realm(домен) в новом запросе REGISTER в строку Authorization:

2021/02/07 13:42:33.997725 185.165.***.5*:7014 -> 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---90c1eb9eeb5f82d3;rport
Max-Forwards: 70
Contact: <sip:[email protected]:5060;rinstance=93a63da919047bbf;transport=UDP>
To: <sip:[email protected];transport=UDP>
From: <sip:[email protected];transport=UDP>;tag=9753211e
Call-ID: 1w7vRiDmp-rpqKe3jhvxaQ..
CSeq: 2 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
Authorization: Digest username="1111",realm="ipcalls24.com",nonce="YB/hZWAf4DncAbF2L2CUDyTdoHRvBdno",uri="sip:ipcalls24.com;transport=UDP",response="b695531add54b51e3e4af8ae2f76ba8d",cnonce="815d6db03cb5323f453ef713d2491122",nc=00000001,qop=auth,algorithm=MD5
Allow-Events: presence, kpml, talk
Content-Length: 0

И в случае, если логин/пароль корректны, SIP сервер отправляет подтверждение 200 OK:

2021/02/07 13:42:34.063125 78.**.241.199:5060 -> 185.165.***.5*:7014
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.0.103:5060;branch=z9hG4bK-524287-1---b4a02461fd257b9f;rport=7014;received=185.165.***.5*
To: <sip:[email protected];transport=UDP>;tag=e0d499bb1b78bcb08c87e527cc2e4090.e11a79c9
From: <sip:[email protected];transport=UDP>;tag=9753211e
Call-ID: 1w7vRiDmp-rpqKe3jhvxaQ..
CSeq: 3 REGISTER
Server: IPCALLS24
Content-Length: 0

С этого момента User Agent(UA) пользователя считается зарегистрированным и хранится в оперативной памяти/базе данных (в зависимости от настроек).

Исходя из примера выше нам необходимо реализовать следующий алгоритм:

алгоритм обработки SIP регистрации

Практика обработки запросов SIP REGISTER с примерами

  1. Необходимо добавить следующие модули:
  • pv.so # для доступа к псевдопеременным, список всех псевдомеременных можно посмотреть здесь
  • textops.so # для работы с SIP заголовками
  • sl.so # зависимость для registrar модуля
  • usrloc.so # зависимость для registrar модуля
  • registrar.so # для обработки запросов регистрации. По умолчанию все сохраненные регистрация хранятся в оперативной памяти, но можно настроить хранения и в базе данных с помощью модуля USRLOC
  • auth.so # модуль используемый для аутентификации
  • db_postgres.so # модуль драйвера базы данных
  • auth_db.so # модуль который позволяет при запросах аутентификации работать с базой данных

Ниже приведен конфиг /etc/kamailio/kamailio.cfg

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

loadmodule "pv.so"
loadmodule "textops.so"
loadmodule "sl.so"
loadmodule "usrloc.so"
loadmodule "registrar.so"
loadmodule "auth.so"
loadmodule "db_postgres.so"
loadmodule "auth_db.so"

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

request_route {
        exit;
}

2. Необходимо проверить с какого IP адреса пришел запрос. В случае если IP адрес «белый» т.е публичный, нам ничего не нужно делать. Если же IP адрес «серый» т.е приватный (список приватных подсетей определен в RFC 1918), нам необходимо узнать публичный IP, с которого пришел запрос. В этой статье мы не будем углубляться в проблему прохождения NAT, это материал для следующей статьи. Упомяну только, что для прохождения NAT’a в Kamailio есть модуль nathelper который мы и будем использовать в будущем.
Сейчас мы допускаем, что работаем только с приватными адресами и все пользователи находятся в нашей подсети. Поэтому конфигурационный файл будет выглядить следующим образом (прикладываю только request_route, без модулей и параметров модулей):

request_route {
        if (is_method("REGISTER")) { # проверяем какое SIP сообщение пришло с помощью модуля textops, функции is_method. 
                route(AUTH); # Если пришел запрос на регистрацию - отправляем в пользовательский маршрут  AUTH.
        }
}

По комментариям должно быть все понятно, что мы делаем. Теперь, нам необходимо создать пользовательский маршрут с именем AUTH (имя задается пользователем. Т.е если мы укажем в request_route вызов маршрута AUTH2 и создадим его, все будет так же работать как и с именем маршрута AUTH)

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

Давайте более подробно рассмотрим что за маршрут мы создали.

1) Функция auth_check из модуля auth_db принимает 3 значения:
authc_check(realm, table, flags).
realm — домен, в нашем случае у нас создан только 1 домен ipcalls24.com. Этот домен мы получаем из псевдопеременной $fd из запроса регистрации, из заголовка From. Это можно наглядно увидеть из ранее приведенного запроса регистрации. Ниже приведена строка из которой берется домен:

From: <sip:1111@ipcalls24.com;transport=UDP>;tag=9753211e

Псевдопеременная выделена $fd выделенна курсивом.
table — название таблицы в базе данных в которой хранятся созданные SIP аккаунты. По умолчанию таблица называется «subscriber» и находится в ранее созданной базе данных «kamailio»
flags — значение цифры 1 в флаге означает, что будут проверятся соответствие полей From, To в запросе регистрации для запросов REGISTER.

Функция auth_check из модуля auth_db проверяет наличие поля Authorization (помните теорию?) и корректность realm, логина и пароля. В случае, если функция возвращает одну из ошибок, то начинает выполнятся тело условия (происходит вызов функции auth_challenge). Все коды ошибок приведены в официальной документации модуля и доступны по ссылке. Так же стоит упомянуть, что функция auth_check работает как для запросов REGISTER, так и для остальных запросов. Приведенное выше описание работы распространяется на запрос REGISTER, остальные варианты будут расмотренны позднее.

2) Т.к в заголовке Via указан не порт источника, а обычно указан порт 5060 или любой другой в зависимости от настроек телефонного агента пользователя, функцией force_rport мы отправляет ответы на тот же порт, с которого пришел запрос, а не который указан в заголовке Via

2) Функция auth_challenge из модуля auth принимает 2 значения:
auth_challenge(realm, flags)
realm — домен, принцип работы такой же как и в функии auth_check
flags — все доступные флаги приведены в официальной документации и доступны по ссылке. В приведенном примере мы используем qop=auth (флаг 1). Чтобы понимать, что это значит можно прочитать об этом в википедии.

Функция auth_challenge отправляет ответ 401 Unauthorized (также было описано в теории и алгоритме приведенном выше). После чего обязательно вызвать прерывание, чтобы сообщение не пошло дальше по маршруту. Это делается с помощью exit.

3) Как только User Agent отправит корретное поле Authorization с верным логином/паролем/realm’ом, происходит вызов функции save(«location») из модуля registrar. Вызов этой функции записывает поле Contact в оперативную память Kamailio. Все сохраненные Contact URI/AoR можно посмотреть с помощью вызовов команд kamcmd и/или kamctl (при подключении модуля ctl.so и jsonrpc.so соответственно).

Итоговый конфигурационный файл будет выглядеть следующим образом:

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


loadmodule "pv.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"

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

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

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

Заключение

В этой статье мы реализовали возможность регистрации SIP аккаунтов. Для добавления нового SIP аккаунта можно сделать запись напрямую в базу данных kamailio, в таблицу subscriber или же вызвать команду:

kamctl add [email protected] 11111111

Где 1111 — создаваемый номер, ipcalls24.com — домен к которому относится этот номер, 11111111 — пароль для этого SIP аккаунта.

Теперь можете попробовать зарегистрироваться, например с помощью Zoiper или MicroSIP.

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

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

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

11 ответов к “Kamailio часть 1. Правильная SIP Регистрация в Kamailio, создание внутренних SIP номером”

Автор Ты пишешь всё просто супер ,
хотелось бы уточнить там где написанно:

(realm — домен, в нашем случае у нас создан только 1 домен ipcalls24.com. )

1)Это запись уже в базе данных присутствует или нет ?
2) для наглядности не мешало бы с начало GUI (Siremis) впихнуть , чтоб можно было там смотреть и понятнее было бы
3) Как вариант следующую статью про установку и использование Siremis ?

Привет!
Да, эта запись появляется после создания локального абонента через
kamctl add [email protected] 11111111 (как пример)
Как раз при создании абонента, в базе данных, в таблице subscriber мы указываем домен абонента через @, т.е ipcalls24.com. Вот как раз это и есть realm.
Уточню, что Kamailio может быть как с одним доменом (типично для одной организации), так и мультидоменным (multi tenant в англоязычной литературе), именно поэтому используется $fd (т.е берем значение realm из запроса абонента), но также можно и захардкодить один единственный realm, например так:
if (!auth_check(«ipcalls24.com», «subscriber», «1»)) {
Но по моему мнению, правильным решением является использование псевдопеременной $fd

По поводу GUI, не подскажу, но не уверен, что получится реализовать сложные схемы обработки вызова через любое GUI. Поэтому пока только текстовый вид 🙂

Попробывал закинуть донат, так как система иностранная , не пропустили платёж

Mar 21 01:46:28 debiandc kamailio[15100]: WARNING: [core/socket_info.c:1480]: fix_hostname(): could not rev. resolve 10.20.7.104

modparam(«auth_db», «db_url», DBURL); Вставляю это
root@debiandc:~# systemctl restart kamailio
Job for kamailio.service failed because the control process exited with error code.
See «systemctl status kamailio.service» and «journalctl -xe» for details.
root@debiandc:~# systemctl status kamailio
● kamailio.service — Kamailio (OpenSER) — the Open Source SIP Server
Loaded: loaded (/lib/systemd/system/kamailio.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Wed 2022-04-13 01:11:02 EDT; 4s ago
Docs: man:kamailio(8)
Process: 15455 ExecStart=/usr/sbin/kamailio -P /run/kamailio/kamailio.pid -f $CFGFILE -m $SHM_MEMORY -M $PKG_MEMORY (code=exited, status=255/EXCEPTION)
CPU: 21ms

Apr 13 01:11:02 debiandc systemd[1]: kamailio.service: Control process exited, code=exited, status=255/EXCEPTION
Apr 13 01:11:02 debiandc systemd[1]: kamailio.service: Failed with result ‘exit-code’.
Apr 13 01:11:02 debiandc systemd[1]: Failed to start Kamailio (OpenSER) — the Open Source SIP Server.
Apr 13 01:11:02 debiandc systemd[1]: kamailio.service: Scheduled restart job, restart counter is at 5.
Apr 13 01:11:02 debiandc systemd[1]: Stopped Kamailio (OpenSER) — the Open Source SIP Server.
Apr 13 01:11:02 debiandc systemd[1]: kamailio.service: Start request repeated too quickly.
Apr 13 01:11:02 debiandc systemd[1]: kamailio.service: Failed with result ‘exit-code’.
Apr 13 01:11:02 debiandc systemd[1]: Failed to start Kamailio (OpenSER) — the Open Source SIP Server.
root@debiandc:~#

Вы пишите «Address of Record, берется из поля Contact» — не знаю, как конкретно в Kamailio, но в RFC это не так. AoR — это публичный адрес User Agent, он не привязан к конкретному IP адресу устройства. АoR у одного пользователя всегда один и тот же. В отличии от Contact URI, который хоть и выглядит похожим образом, но может быть разным в зависимости от того, с какого устройства или из какого места зарегистрировался пользователь (User Agent). При регистрации AoR находится в полях TO и FROM, а в поле CONTACT как раз раходится Contact URI.
В вашей следующей статье приводится вывод комнады kamctl ul show и там довольно наглядно показывается, что AoR может содержать больше чем один Contact. Хотя личном мне удивительно почему AoR обозначен просто как «1111» потому как полный формат AoR это всё-таки user@domain

Перечитал RFC, действительно когда писал по памяти ошибся. Спасибо за замечание, статью поправил.
По поводу полного формата AoR user@domain, будет отображаться в полном виде при включенной мультидоменности, сейчас не отображается т.к есть единственный домен.

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

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