IAX2

К своему стыду гоняю голос между серверами по SIP. А в некоторых местах каналы совсем узкие (512/256k). А там и данные и голос, QoS конечно спасает, но может все-таки попробовать диковинный протокол IAX2? — Попробовать)

IAX2(The Inter-Asterisk eXchange protocol, version 2) это собственный VOIP протокол Asteriska. При использовании протокола SIP для передачи трафика RTP (голоса) используются порты, отличные от тех, что работают с методами обмена сигналами. Например, Asterisk получает сигналы SIP через порт 5060, а трафик RTP (голос) проходит через порты от 10000 до 20000 по умолчанию. IAX-протокол отличается тем, что и обмен сигналами, и трафик медиа-данных выполняется через один порт: 4569. Следствие такого подхода – протокол IAX лучше подходит для топологий с использованием NAT.

Конфигурационный файл iax.conf
[general]
bindport=4569 Порт на котором будем слушать (по умолчанию 4569).
bindaddr=192.168.0.1 Адрес на котором будем слушать(по умолчанию все)
iaxcompact=yes Ставить yes если планируете использовать layered switches или другие сценарии которые могут вносить задержку в просмотр диалплана — увеличите производительность. Заставляет * плодить независимые потоки когда получает IAX DPREQ (Dialplan Request) вместо блокировки во время ожидания ответа.
nochecksums=no; Отключает проверку контрольной сумы UDP(во фре только no!)
delayreject=yes Для повышения уровня безопасности(устойчивость против брутфорс атак) будет вносить задержку при отправке отказа аутентификации для REGREQ или AUTHREP.(задержка при отсылке сообщения в отказе аутентификации)
amaflags=default можно задать глобальный AMA флаг для IAX звонков. может быть: ‘default’, ‘omit’, ‘billing’, или ‘documentation’. Эти флаги используются в CDR.
adsi=no включает поддержку Analog Display Services Interface на оборудовании пользователей.
srvlookup=yes проводить ли SRV проверку при исходящих вызовах.
accountcode=lss0101 задаем учетку по умолчанию для CDR в дополнение к указанию на каждого пользователя
language=en язык по умолчанию(когда используем например голосовые сообщения)
mohinterpret=default какой класс музыки во время ожидания должен воспроизводиться по этому каналу, если он не задан с помощью Set(CHANNEL(musicclass)=whatever). Если установить в «passthrough» для оповещения вместо локального воспроизведения музыки во время ожидания всегда будет передаваться сообщение ожидания. Опция может быть задана как глобально так и для конкретного пользователя.
mohsuggest=default MOH которую ты предлагаешь услышать второй стороне.
bandwidth=low | medium | high контролирует какие кодеки следует использовать. Может принимать значение low, medium, high
disallow=all Какие кодеки запрещено использовать.
allow=g729 Какие кодеки разрешено использовать.
Кодеки которые мы можем использовать в этих опциях:
g723.1 g729 h263 sinear gsm alaw adpcm g726 h261 lpc10 speex ilbc ulaw
jitterbuffer=yes вкл jitterbuffer, используется только для Входящего Аудио.
forcejitterbuffer=yes|no принудительное использование джитбуфера, только если клиент совсем не справляется с этой задачей.
maxjitterbuffer максимальный размер джитбуффера.
resyncthreshold когда jitterbuffer замечает значительные изменения в задержке, которая продолжается в течение нескольких кадров, производится ресинхронизация, предполагается, что изменение задержки было вызвано путаницей временных меток. Порог для улавливания изменения задержки = джиттер X 2 + это значение. RESYNCING может быть отключена путем установки этого параметра в значение -1.
maxjitterinterps Максимальное количество пустых кадров вставки, которое должен возвратить подряд буфер, компенсирующий задержки. Поскольку некоторые клиенты не передают кадры CNG/DTX для обозначения паузы в разговоре, буфер, компенсирующий задержки, будет воспринимать такое количество пустых кадров как начало паузы. Это предотвращает появление искажений при длительной паузе.
jittertargetextra значение в мс на сколько новый джитбуфер увеличит свой размер. По умолчанию 40, те без модификации джитбуффер установит свое значение = размеру джиттера + 40мс. Увеличение этого значения помогает в сетях с низкой задержкой, но в которых иногда бывают пики нагрузки.
minregexpire = 60 в секундах минимальный интервал для истечения срока действия регистрации
maxregexpire = 60 в секундах максимальный интервал для истечения срока действия регистрации
encryption = yes включает шифрование, по умолчанию откл.
forceencryption = yes канал не будет установлен если обе стороны не поддерживают шифрование
trunkmaxsize = 128000 параметр регулирующий максимальное кол-во каналов в IAX2 транке.
Эта опция определяет максимальную полезную нагрузку в байтах в IAX2 транке за заданное время. Рассмотрим это на примере. Если мах к-во вызовов=800, и каждый звонок передается 20ms кадрами используя ulaw ((8000hz / 1000ms) * 20ms * 1 byte per sample = 160 bytes в фрейме), максимальная нагрузка в байтах (160 bytes в фрейме) * (800 звонков) = 128000 bytes. Как только этот предел достигнут, звонки могут прерываться, голос может пропадать. В зависимости от кодека и количества каналов, может потребоваться увеличить это значение, но в большинстве случаев его достаточно.
trunkmtu = 1240
с увеличением трафика в транке может ухудшаться качество голоса изза фрагментации UDP датаграм.этот параметр устанавливает MTU для IAX2 UDP транка. по умолчанию 1240 байт, если полезная нагрузка превышает 1240 байт для всех 20ms, то сообщение бдет разбито на несколько 1240 byte сообщений(фрагментированно). 0 — фрагментацию будет проводить операционка.
trunkfreq как часто сообщения будут передаваться в транке(по умолчанию 20мс).Это означает что через транк будет отосланы все данные полученные за последние 20мс. Увеличивая время между отправками мы увеличиваем и полезную нагрузку сообщения. Обратите внимание в зависимости от trunkmtu, сообщения могут отсылаться более часто чем здесь задано. Например Если размер сообщения вырос до trunkmtu менее чем за 20ms то сообщение отсылается немедленно. Допустимые значения 10-1000ms
trunktimestamps=yes
Определяет, должна ли Asterisk посылать временные метки для каждого отдельного подкадра, входящего в состав магистрального кадра (trunk frame). При передаче этих временных меток немного увеличивается требуемая полоса пропускания (менее чем на 1 Кбит/с/звонок), но они гарантируют что фрейм нормально доберется от одного сервера к другому)
iaxthreadcount = 10 к-во iax helper потоков для обработки I/O.
iaxmaxthreadcount = 100 к-во дополнительных динамических потоков, которые могут наплодиться для обработки I/O
register => [email protected]:5656 как и в SIP позволяет подкл сервачок с динамическим IP
Выражение регистрации register = используется для регистрации вашего сервера Asterisk на удаленном сервере. Это позволяет удаленному концу соединения знать ваше местонахождение на случай, если вы сконфигурированы с динамическим IP-адресом. Заметьте, что выражения register используются, только если вы сконфигурированы на удаленном конце как равноправный участник сети и когда host=dynamic.
subscribe_network_change_event = yes если используется res_stun_monitor, то позволяет определить изменился ли внешний адрес.
authdebug=no вкл/откл автодебаг аутентификации
tos=ef Class of service параметры QoS для Ethernet фрейма
cos=5 Type of service параметры QoS в поле заголовка IP пакета.
regcontext=iaxregistrations
Задавая контекст, Asterisk будет динамически создавать и уничтожать NoOp с приоритетом 1, для пира который регается или разрегивается. Эта опция используется в сочетании с regexten, определяющей, какой добавочный номер должен быть выполнен. Если параметр regexten не задан, в качестве добавочного номера используется имя равноправного участника.
более одного regexten может быть задано с помощью’&’. также могут использоваться шаблоны.
autokill=yes. Она используется для того, чтобы предотвратить задержку в системе, когда участник сети не отвечает (ACK) на пакет NEW (запрос на установление нового соединения) в течение 2000 мс. Вместо значения yes здесь можно задать время (в миллисекундах) ожидания ACK на пакет NEW. Управлять опцией autokill (автоуничтожение) для
каждого отдельного равноправного участника сети можно, определяя параметр qualify (качество) для тех участников, о возможном недостаточном качестве используемых сетевых соединений которых известно заранее.
codecpriority=caller Сервера договариваются о кодеках. Варианты
caller-предпочтение отдается кодеку звонящего,
host-предпочтение отдается кодеку локального компа(принимающего),
disabled — полностью отключить договоронености о кодеках.
reqonly — Предпочтения кодеков игнорируются, и вызовы принимаются, только если запрашиваемый кодек доступен
allowfwdownload=yes обновление прошивки на клиентах.. лучше не трогать и оставить выкл.
rtcachefriends=yes Asterisk будет кэшировать соединения типа friend, регистрирующиеся в режиме реального времени, точно так же, как если бы они поступали из iax.conf.
rtsavesysname=yes сохранять имя системы в реалтайм базе во время регистрации.
rtupdate=yes Asterisk обновит при регистрации IP-адрес, порт вызова и срок действия регистрации пира.
rtautoclear=yes Этот параметр определяет, должна ли Asterisk автоматически завершать действие регистрации соединений типа friend, созданных «на лету», по тому же графику, как если бы они были зарегистрированы обычным способом. Если задано значение yes, по истечении срока действия регистрации friend исчезнет из конфигурации до следующей регистрации. Если задано целое значение, регистрация будет действительна в течение этого количества секунд, а не обычного срока действия регистрации. Варианты: yes no количествосекунд.
rtignoreregexpire=yes Если yes и срок регистрации пира, зарегистрировавшегося в режиме реального времени, истек (на основании срока действия регистрации), Asterisk продолжит использовать IP-адрес и порт, хранящиеся в базе данных.
parkinglot=edvina слот парковки для IAX пользователей, также может быть задан в features.conf

Следующие две опции используются для отключения проверки calltoken в целях совместимости с IAX2 клиентами, которые пока не поддерживают его.
requirecalltoken=no
Проверка calltoken может быть установлена как опция для одного адреса IP или диапазон IP-адресов с помощью «calltokenoptional» только в [general].
calltokenoptional=209.16.236.73/255.255.255.0

maxcallnumbers=512 Ограничивает к-во одновременных звонков к определенному IP. как только лимит достигнут, новые звонки не устанавливаются, пока не освободится свободный слот. в большинстве случаев значения по умолчанию достаточно. Работает только для динамических пиров которые прошли регистрацию.

maxcallnumbers_nonvalidated=8192 используется для задания к-ва звонков для соединений у которых отключен calltoken. В отличии от ‘maxcallnumbers’ этот лимит действует на все соединения без проверки call token

Раздел [callnumberlimits]
Ограничивает к-во одновременных звонков с заданного IP(или подсети). Более приоритетно чем ‘maxcallnumbers’, но может быть перезаписано используя ‘maxcallnumbers’ в свойствах пира. Лимит действует для каждого индивидуального адреса в диапазоне, а не на весь диапазон в целом.
[callnumberlimits]
10.1.1.0/255.255.255.0 = 24
10.1.2.0/255.255.255.0 = 32

shrinkcallerid=yes удаляет ‘(‘, ‘ ‘, ‘)’, ‘.’, ‘-‘ из CallerID. Пример пришло callerid 555.5555, с помощью этой опции станет 5555555. По умолчанию включено.

Секция описания пиров
type тип учетки user-только входящие, peer — только исходящие, friend-вх и исх звонки.
context Контекст для входящих звонков для этого пользователя
secret=пароль Пароль для этого пользователя
disallow запрещает использование этих кодеков
allow разрешает использование этих кодеков
setvar = Можем задать некоторую переменную.
dbsecret / Хранить пароль в БД (astdb).
callerid Caller ID для этого пользователя
deny IP с которых запрещено подключатся
permit IP с которых разрешено подключатся
host ip_addr или dynamic Указываем статический IP, аc ассоциируемый с этим аккаунтом, или использовать динамический.
mask=255.255.255.0 Маска подсети для хоста
defaultip=192.168.0.1 IP который будет использоваться ДО регистрации
accountcode=string Код учета для биллинга
qualify=yes Проверяет доступность пира, по умолч 2000мс
mailbox [email protected] Ящик голосовой почты
trunk=yes Вкл/откл транкинг IAX2 для этого контекста.
transfer может быть присвоено значение yes, no или mediaonly. Если задано yes, Asterisk, если может, будет выполнять переадресацию вызова с целью сократить путь пакета между двумя конечными точками. (Очевидно, что это не будет возможным, если Asterisk придется выполнять перекодировку или преобразование между протоколами или если состояние сети не обеспечивает возможности соединения двух конечных точек напрямую.) Если задано значение no, Asterisk не будет пытаться переадресовать вызов. Если задано значение mediaonly, Asterisk будет пытаться переадресовывать медиапоток так, чтобы он проходил непосредственно между двумя конечными точками, но обмен служебными сигналами (сообщения установления и разрыва соединения) по-прежнему будет проходить через Asterisk. Это полезно, потому что гарантирует правильность записей параметров вызовов даже несмотря на то, что переносимые данные больше не проходят через сервер Asterisk.
peercontext string Контекст по умолчанию для звонков пиров.
regexten extension Какой доб номер должен быть добавлен в диалплан.
jitterbuffer Вкл/откл джитбуффер индивидуально для каждого пользователя.
immediate=yes немедленно переходить к номеру s при получении вызова.
qualifyfreqok определяют частоту проверки возможности установления соединения с удаленным участником, когда он находится в состоянии OK
qualifyfreqnotok определяют частоту проверки возможности установления соединения с удаленным участником, когда он находится в состоянии не OK
qualifysmoothing=no Если он активирован, Asterisk будет брать среднее из двух последних значений времени подтверждения возможности соединения. Это помогает не допустить появления равноправных участников, отмеченных как LAGGED (с запаздыванием), особенно в сети с потерями.
sendani В сети PSTN с SS7 для идентификации вызывающего абонента используется автоматическое определение номера (Automatic Number Identification, ANI). Пользователю предоставляется Caller ID (ID звонящего). Caller ID формируется из ANI, поэтому их легко спутать. Блокировка Caller ID приводит к установлению флага конфиденциальности для ANI, но базовой сети все равно известен источник вызова. ANI используется уже некоторое время. Его первоначальным назначением было доставка на входящую станцию номера абонента, выполняющего междугородный звонок, для которого выставляется счет. В отличие от Caller ID, ANI не требует SS7, поскольку может передаваться с помощью DTMF. Также ANI не может быть заблокирован.
auth определяет, какой метод аутентификации используется в канале: plaintext, md5 или rsa.
Параметр plaintext в IAX обеспечивает очень низкий уровень защиты. Хотя он разрешает соединение с каналом только при условии введения правильного пароля, но тот факт, что пароль хранится в файле iax.conf как простой текст и передается и принимается в таком же незашифрованном виде, делает этот метод аутентификации очень ненадежным.
md5 обеспечивает большую безопасность сетевого соединения, однако по-прежнему в файле iax.conf на обоих концах соединения должен быть задан текстовый secret. Вот как происходит аутентификация в данном случае: сервер А запрашивает соединение с сервером В, который, в свою очередь, отвечает запросом на авторизацию, включающим сгенерированный случайным образом номер. Сервер А генерирует хеш MD5, используя значение, заданное в поле secret файла iax.conf, и случайный номер, полученный от сервера В. Этот хеш возвращается в ответе на запрос на авторизацию, и сервер В сравнивает его с локально сгенерированным хешем. Если хеши совпадают, предоставляется разрешение на доступ.
rsa обеспечивает самый высокий уровень безопасности. Чтобы использовать RSA-аутентификацию, каждый конец соединения, с помощью сценария astgenkey, должен создать пару ключей — открытый и закрытый. После этого открытый ключ передается на дальний конец. Каждый конец соединения в свое описание канала должен включить открытый ключ противоположного конца, используя для этого параметры inkeys и outkey. RSA-ключи хранятся в папке /usr/local/share/asterisk/keys/(Для FreeBSD). Открытым ключам присваиваются имена имя.рub; закрытым ключам — имя.key. Закрытые ключи должны быть зашифрованы по алгоритму 3DES.
inkeys=сервер_один:сервер_два
Опция inkeys может использоваться для аутентификации пользователя с помощью RSA-ключа. Чтобы связать с описанием канала типа user более одного RSA-ключа, имена ключей записываются через двоеточие (:). Для подтверждения допустимости соединения может использоваться любой из заданных ключей. Inkey — это открытый ключ, который вы раздаете своим пользователям.
outkey=закрытый_ключ может использоваться для аутентификации канала peer с помощью RSA-ключа. Для исходящей аутентификации может использоваться только один RSA-ключ. Outkey не распространяется; это ваш закрытый ключ.

Теперь добавим примерчиков:
General не будет изменяться за исключением шифрования!

[general]
bindport=4569
bindaddr=0.0.0.0
iaxcompat=no
nochecksums=no
delayreject=yes
amaflags=default
adsi=no
srvlookup=no
language=ru
mohinterpret=default
mohsuggest=default
bandwidth=low
disallow=all
allow=g729
jitterbuffer=yes
encryption=yes
forceencryption=yes
subscribe_network_change_event = no
authdebug=yes
tos=ef
cos=5
autokill=yes
shrinkcallerid=yes    

1. Самый легкий пример тупо направляем трафик из сервера А в сервер Б.
Главный сервер iax.conf:

[region1]
type=friend
host=10.109.39.39
qualify=2000
context=remote

extensions.conf

exten => _875XXX,1,NoOp(IAX2)
same => n, Dial(IAX2/region1/${EXTEN})

Сервер на удаленной площадке:

[Main]
type=friend
host=10.109.68.68
qualify=2000
context=remote

extensions.conf

exten => _888XXX,1,NoOp(IAX2)
same => n, Dial(IAX2/Main/${EXTEN})

2. Немного усложним задачу включим аутентификацию и шифрование:
На центральном сервере iax.conf:

encryption = yes
forceencryption = yes
[Main]
type=friend
auth=md5
host=10.109.39.39
qualify=2000
context=remote
username=region1
secret=pass
trunk=yes
<pre>
На удаленном:
<pre>
[region1]
type=friend
auth=md5
host=10.109.39.100
qualify=2000
context=remote
username=Main
secret=pass1
trunk=yes

3. Разнесем отдельно peer и user
region1

[region1]
type=user
auth=md5
secret=outmain_pass
context=incoming
trunk=yes

[Main]
type=peer
auth=md5
host=10.109.68.68
qualify=2000
context=remote
username=Main
secret=inmain_pass
trunk=yes

Main

;incoming call
[Main]
type=user
auth=md5
secret=inmain_pass
context=incoming
trunk=yes

[region1]
type=peer
auth=md5
host=10.109.39.39
qualify=2000
context=remote
username=region1
secret=outmain_pass
trunk=yes

4. Используя приватный и публичный ключи
region1

[region1]
type=friend
auth=rsa
inkeys=region1
host=10.109.39.100
qualify=2000
context=remote
trunk=yes

Main

[Main]
type=friend
auth=rsa
inkeys=Main
host=10.109.68.40
qualify=2000
context=remote
trunk=yes

!!!По поводу шифрования: encryption=yes
Поддерживается только AES128
После включения этой опции в выводе команды ‘iax2 show peers’ слева от поля «статус» появится «(E)», что должно означать, будто шифрование включено. Включение encryption гарантировано означает лишь отображение этих символов, и больше ничего.

Для того чтобы шифрование действительно использовалось, необходимо использовать метод авторизации md5. Думаю вполне понятно, почему при использовании метода plaintext использовать шифрование попросту бессмысленно (как, вы ещё используете plaintext авторизацию? зря, очень зря). Самое же удивительное что шифрование не будет работать с rsa-авторизацией.

Для конечного пользователя это означает, что опция encryption=yes реально использоваться будет только если другая сторона его поддерживает _и_ используется md5 авторизация. В любом другом случае Asterisk в iax2 show peers будет бодро рапортовать об используемом шифровании, которое использоваться не будет.
Если включить опцию forceencryption=yes, то транк не установится если одна из сторон не поддерживает шифрование.

APP1. как генерировать ключи
astgenkey -n ;не требовать пароля
Жмакаем Enter
вводим название ключа(на Main Main, на region1 region1)
В этой же папке получаем два ключа(на Главном):
Main.key — приватный ключ
Main.pub — публичный ключ
В этой же папке получаем два ключа(на удаленном):
region1.key — приватный ключ
region1.pub — публичный ключ

Складируем эти ключи:
Main.key — перемещаем в /usr/local/share/asterisk/keys локального астериска и больше никуда (ну если только бекап сделать)
Main.pub — перемещаем в /usr/local/share/asterisk/keys локального астериска и в эти же папки всех других АТС, с которыми мы будем связываться.
Аналогично для удаленной АТС

Обмениваемся pub ключами складываем в те же папки
к сожалению на лету инициализировать ключи не получилось
поэтому нужно ребутить всю атску

asterisk -rvvvv
core stop now
asterisk -i
asterisk -rvvvv
keys show

UPD26_04_13: Если вдруг в конфиге поменяли параметр, а он не поменялся(((, то перезагрузка модуля нам не поможет нужно:

module unload chan_iax2.so
module load chan_iax2.so

Учтите делать это желательно на пустом канале, а то Вас не поймут))

Предложения, пожелания или нашли ошибку — не стесняемся пишем в комментах)

Комментарии: