TLS. Kamailio. Asterisk. Настройка
Схема которую планировали реализовать:
Client1 —<TLS>— Kamailio —<UDP>— Asterisk —<UDP>— Kamailio —<TLS>— <Client2>
Что почитать перед тем как настраивать, это сразу несколько позиций, они обязательно вам пригодятся, ибо быстро сделать даже такую простую схему без понимания принципа не получится. А может и получится, но останутся дыры.
- Документация TLS модуля для Камалио 4.4 – прекрасно описывается как создать сертификат без получения и т.д.
- ssldump -Nn покажет обмен внутри протокола ssl кто кому какие сертификаты посылает
- howto kamailio and tls
Теперь непосредственно, то как работает TLS в двух словах.
- создать центра сертификации – CA
- подписать им сертификат для Камалио
- скопировать в подписанный сертификат приватный ключь, этот на всякий случай
- создать сертификат для sip-клиента
- скопировать приватный ключ в сертификат т.к. некоторые сип клиенты не имеют возможность для указания отдельно приватного ключа в настройках
- вынести конфигурацию tls в отдельный файл
- далее прописать в calist.pem сертификат CA. Это нужно чтобы камалио получив сертификат от клиента проверил его CA в своем списке и если СА в доверенных, то одобрить сертификат (при этом неважно откуда звонит клиент и какой домен (CN) указан в сертификате
- Повесить камалио на lts : listen:tls:ip_address:5061
- подключить к своему клиенту сертификат.
- клиент будет проверять сертификат поэтому, в виндоус нужно добавить в доверенные центры сертификации ваш сертификат CA, который вы создавали в самом начале.
- в сертификате Камалио обязательно должен быть указан CN соответствующий домену Камалио, либо его IP адресу если домена как такогово нет.
- В настройках камалио нужно оставить только verify_certificate = yes, require_certificate = no. Если поставить оба значения, то у меня ситуация выглядела так: Во время звонка при передаче ACK сообщения sip-клиент создавал новое соединение TLS и оно было отказывалось работать, потому, что не совпадали CN ожидаемые sip-клиентом и указанные в сертификате. Не стал разбираться дальше почему так происходит.
Настройка на данном этапе завершена, сертификат проверяется, т.е. использовать левый сертификат не получится.
15.06.2017Восстановление базы MySQL из бинарных логов
Восстановление базы MySQL из бинарных логов
Простая статься на хабре, помогает быстренько восстановить утерянные insert в таблицы.
Восстановление базы данных из ib_logfile0
10.06.2017SIPP Тестирование Asterisk
Решил провести тестирование Астериска на предмет максимального количества звонков.
Сразу скажу, у меня Астериск 1.4 и я просто посылаю на эхотест его, примеры эхотеста в астериска в sip.conf есть.
Чтобы провести тестирование нагрузки нам понадобится sipp
- yum install sipp
- копируем в локальный каталог сценарий с uac_pcap.xml из документации sipp
- копируем pcap файлы для астериск в каталог pcap текущей папки
- подбираем нужные параметры для sipp и должно работать
Здесь я опишу только 4 пункт:
в моем случае конфигурация рабочая выглядит так:
sipp -sf uac_pcap.xml -r 1 -mi 111.111.111.111 -i 111.111.111.111 -s 1005 222.222.222.222 -trace_msg -rtp_echo -d 5000
где
111.111.111.111 – внешний интерфейс вашей машины
222.222.222.222 – адрес астериска
1005 – номер для эхотеста
-d 5000 – пауза в 5 секунд (опционально)
и все погнали, в моей конфигурации сети, без особых проблем астериск успевает обслужить 50 вызовов в секунду и примерно 500 одновременных соединений, потом начинаются ретрансмиты сообщений.
Memcached и ограничение соединений к нему
Столкнулся с тем, что клиенты получают ошибку вызванную тем что скрипты на сайте не могу подключиться к memcached
докопался до вот чего:
Огромное количество соединений к localhost остаются в состоянии time_wait в документации по memcached прекрасно сказано, что нужно проверить для увеличении производительности, а вот здесь был конкретный совет по поводу подвисших соединений:
Details of how to tune these variables are outside the scope of this document, but google for “Linux TCP network tuning TIME_WAIT” (or whatever OS you have) will usually give you good results. Look for the variables below and understand their meaning before tuning.
!THESE ARE EXAMPLES, NOT RECOMMENDED VALUES!
net.ipv4.ip_local_port_range = 16384 65534
net.ipv4.tcp_max_tw_buckets = 262144
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
Я внес в систему только параметр net.ipv4.ip_local_port_range
сделав его в два раза больше и дело пошло. Полезной оказалась статься про мониторинг memcached в частности утилита memcache-top и команда netstat которая показала кол-во еще ожидающих закрытия соединений.
Автозапуск Debian 6 и Centos 6.8
Запуск программ при старте Debian:
Добавление скрипта в автозагрузку:
1
|
# update-rc.d имя_в_initd defaults
|
Удаление скрипта из автозагрузки:
1
|
# update-rc.d -f имя_в_initd remove
|
1
|
chkconfig ––levels 234 демон on
|
О себе и реквизиты
Я рос хорошим мальчиком. Давным давно, работая в службе технической поддержки в небольшом интернет-провайдере, случилось так, что у моего коллеги не получилось настроить voip телефонию в компании и за дело взялся я. Это самая моя любимая работа разбираться в том, в чем я не разбираюсь. Если у меня появляется азарт в этом, то всё – ныряю с головой.
Так я начал работать с интернет-телефонией.
Нет нужды описывать мой жизненный путь, оно как правило ни к чему, только повздыхать да покритиковать стороннему наблюдателю – от чего я вас, дорогие друзья, избавлю.
Но, немного расскажу про специфику… Во-первых, я не знаю почему, но мне в телефонии больше всего нравится разбираться и оптимизировать, чем создавать что-то большое и с нуля. Так получилось, что большая часть моей работы пока я был наемным рабочим состояла в том, чтобы разбираться с проблемами сети и телефонии. Поэтому, когда приходят клиенты не с тем, чтобы собрать что-то новое, а разобраться в проблемах или что-то оптимизировать – я прыгаю в это дело с радостью.
И вот я уже не хочу тратить много времени на статью про себя, просто скажу работаю на компанию ООО “ЮКСИ”.
Реквизиты:
ООО «ЮКСИ»
sip: 74952284411@did.yooxy.ru
Юр. Адрес: 454021, ул Молодогвардейцев д.58 оф.1
Почтовый адрес: 454902, ул. Гостевая 3, оф. 002
ОГРН 1127447003386
ИНН/КПП 7447206406/744701001
Директор Еремин Павел Сергеевич, действует на основании Устава.
Расчетный счет № 40702810590000016075
в ОАО «ЧЕЛЯБИНВЕСТБАНК»
БИК 047501779 ИНН 7421000200 КПП 745301001
Кор/счет 30101810400000000779
Куда я попал?
Добро пожаловать в обновленную версию записной книжки voip-инженера.
Давно начал вести записи по поводу решений разных задач области ip-телефонии. И несмотря на то, что задача это достаточно занудна, лично для меня конечно, часто ей пользовался. Моя работа связана как правила с разными задачами, от программирования до развертывания нескольких серверов для телефонии.
Что можно здесь найти, в первую очередь конечно меня, как консультанта, но и заметки по решениям разных задач. Вот список рубрик в которых приходилось решать те или иные задачи и решения которых, находятся на старом адресе http://opensips-blog.yooxy.ru
- Asterisk
- SQL запросы
- Unix вопросы
- Безопасность
- Городские номера
- Готовые решения
- Идеи
- Проблемы в коде
- Проблемы при настройке
- Спорт
- Гитара
Ограничение вызовов для exten
Ограничение одновременных вызовов в Астериске . Смысл прост: Ищем каналы по выражению “116-” а потом считаем кол-во элементов в массиве.
3.02.2016same => n,GotoIf($[“${FIELDQTY(CHANNELS(${CALLERID(num)}-), )}” > “1”]?busy-custom,s,1)
Asterisk. Annoucement. Dialplan. ChannelRedirect. Elastix. Part 2.
В предыдущей заметке описал решение с когда пользователь вручную набирает номер и воспроизводит, во время разговора, заранее записанное приветствие.
В этой заметке, мы несколько изменим решение, т.к. оказывается оно еще должно работать с роботом AMI которым пользователи активно пользуются.
Итак, для начала скрипт АМИ, которым осуществляется вызов:
Action: Login
Username: admin
Secret: werkjnfgopw
Action: Originate
ActionID: 12345
Channel: Local/117@tapi
Context: agent-custom
Exten: 12122396200
Priority: 1
Ранее смысл решения основывался на том, чтобы сохранить внутренний номер телефона, привязать к нему имя правильного канала (то куда позвонили) и собственно воспроизвести в этот канал файлик с названием “extension_x”.
Для реализации у нас в файле extension_custom.conf:
Этот контекст ловит определенный номер формата #*00x и записывает приветствие в файлик “extension_x”. Тут все просто.
[custom-record] ; Context for recording voice messages
exten => _#*00X,1,Noop(${EXTEN})
same => n,Set(CHANNEL(language)=ru)
same => “”n,Set(MONITOR_FILENAME=${DIR}${CALLERID(num)}_${EXTEN:4})
same”” => n,Playback(beep)
same => n,Answer
same => n,Record(${MONITOR_FILENAME}:wav)
same => n,Playback(vm-msgsaved)
same => n,Playback(${MONITOR_FILENAME})
same => n,Playback(vm-goodbye)
этот макрос выполняется когда мы совершаем вызов вручную в функцию Dial встроен код ‘M^(testsub)’ делалось это прям через веб инфтерфейс Эластикса.
[macro-testsub]
exten => s,1,NoOp(${CHANNEL})
exten => s,n,NoOp(${MYVAR})
exten => s,n,Set(DB(br/${MYVAR})=${CHANNEL})
exten => s,n,NoOp(${DB(br/${MYVAR})})
Этот контекст должен вызываться когда с ext приходит команда ##X что означает, что ext хочет воспроизвести приветствие.
[transfer-context]
exten => “” _##X,1,NoOp(${DB(br/${CALLERID(num)})})
exten”” => “”_##X,2,Set(DB(from_ext/last_ext)=${CALLERID(num)})
exten”” => “”_##X,3,ChannelRedirect(${DB(br/${CALLERID(num)})},play-context,${EXTEN},1)
exten”” => _##X,4,Playback(${DIR}${CALLERID(num)}_${EXTEN:-1}) ;
exten => _##X,5,Hangup()
А Это вспомогательный контекст, в него мы перескакием, когда собственно случается событие приоритета 3 в transfer-context. До сих пор не понятно, почему нельзя передать переменную через channelredirect – приходит ее сохранять в DB затем извлекать…
[play-context]
exten => _##X,1,noop(${DB(from_ext/last_ext)})
exten => _##X,2,Playback(${DIR}${DB(from_ext/last_ext)}_${EXTEN:-1}) ;
exten => _##X,3,Set(DB(from_ext/last_ext)=”0″)
exten => _##X,4,Hangup()
Итак, при вызове функции AMI Originate как я описал выше, вызывается два пользователя: внутренний 116 например и внешний внутренний вызывается в контексте [tapi]
[tapi]
exten => 116,1,Answer
exten => 116,n,SIPAddHeader(Alert-Info: Ring Answer)
exten => 116,n,NoOp(Context: agent)
exten => 116,n,Dial(SIP/116)
exten => 116,n,hangup
а затем вызывается контекст [agent-custom]: Это все делает тот AMI скрипт. В подчеркнутых строчках сохранение переменной какой внутренний номер позвонил и вызов макроса dialer-dial, который…
exten => _1XXXXXXXXXX,1,Answer
exten => _1XXXXXXXXXX,n,NoOp(Context: agent)
exten => _1XXXXXXXXXX,n,noop(CALLERID: “””${CALLERID(all)})
exten””” => _1XXXXXXXXXX,n,NoOp(EXTEN: ${EXTEN})
exten => _1XXXXXXXXXX,n,noop(SIP_to: ${SIP_HEADER(TO)})
exten => _1XXXXXXXXXX,n,noop(SIP_from: ${SIP_HEADER(FROM)})
exten => _1XXXXXXXXXX,n,Set(__FROM_EXT=${CHANNEL(name)})
exten => _1XXXXXXXXXX,n,Dial(SIP/t1/991${EXTEN},60,r^M(dialer-dial))
exten => _1XXXXXXXXXX,n,noop(DIALSTATUS= ${DIALSTATUS})
exten => _1XXXXXXXXXX,n,gotoif($[“${DIALSTATUS}”= “BUSY”]?busy-custom,s,1)
exten => _1XXXXXXXXXX,n,gotoif($[“${DIALSTATUS}”= “CONGESTION”]?congestion-custom,s,1)
exten => _1XXXXXXXXXX,n,gotoif($[“${DIALSTATUS}”= “CHANUNAVAIL”]?congestion-custom,s,1)
exten => _1XXXXXXXXXX,n,gotoif($[“${DIALSTATUS}”= “NOANSWER”]?congestion-custom,s,1)
exten => _1XXXXXXXXXX,n,hangup
который… сохранит для нас связку внутреннего номера и канала который мы вызываем в базу Астериска.
26.12.2015[macro-dialer-dial]
exten => s,1,NoOp(${FROM_EXT:6:3})
exten => s,n,Set(MYVAR_A=${FROM_EXT:6:3})
exten => s,n,Set(DB(br/${MYVAR_A})=${CHANNEL})
Asterisk. Annoucement. Dialplan. ChannelRedirect. Elastix.
Менеджеры услышав сигнал автоответчика обычно кладут трубку, либо оставляют свои координаты. При большом количестве звонков таких ситуаций может возмникать приличное кол-во.
Задача: Записать заранее приветствие в нескольких вариантах, и затем воспроизводить его абонентку по нажатию на кнопки быстрого набора.
Проблема: Быстрый набор – это просто очередной INVITE с заранее запрограммированным кодом, поэтому, для астериска это выглядит как поступление нового звонка.
Решение: Я решил эту задачу как для DTMF так и для использования speed-dial.
Ключ к решению: Основная проблема это заставить астериск воспроизводить заранее записанное приветствие нужному абоненту, если просто внести в dialplan запись вида ##1, где номер приветствия то астериск его проиграет тому кто прислал вызов, а нам нужно воспроизвести его абоненту, да еще и в терминологии Asterisk в другой канал.
Коротенько: Записывать приветствия мы будем формата XXXX_N.wav , XXXX- номер эксентшина который записывает приветствие, а N – это номер самого приветствия, таким образом мы можем записывать несколько приветствий для одного экстеншина.
[custom-record] ; Context for recording voice messages
exten => _#*00X,1,Noop(${EXTEN})
same => n,Set(CHANNEL(language)=ru)
same => “”n,Set(MONITOR_FILENAME=${DIR}${CALLERID(num)}_${EXTEN:4})
same”” => n,Playback(beep)
same => n,Answer
same => n,Record(${MONITOR_FILENAME}:wav)
same => n,Playback(vm-msgsaved)
same => n,Playback(${MONITOR_FILENAME})
same => n,Playback(vm-goodbye)
Воспроизведение: При звонке мы сохраняем данные кто звонил и имя канала куда позвонили : ${CALLEDRID(num)} – ${CHANNEL}, Делать это нужно в время команды Dial поэтому используется pre_dial_handler, для Эластикс это просто Опции в разделе General Setting. Tt – дает возмоножсть пользоваться DTMF, а ^M(testsub) выполняет макрос testsub.
[macro-testsub]
exten => s,1,NoOp(${CHANNEL})
exten => s,n,NoOp(${MYVAR})
exten => s,n,Set(DB(br/${MYVAR})=${CHANNEL})
exten => s,n,NoOp(${DB(br/${MYVAR})})
Чтобы запомнить переменную кто звонил мы добавляем строчку “exten => s,n,Set(__MYVAR=${CALLERID(number)})” в macro-user-callerid и отправляем этот макрос в файл extensions_override_elastix Это означает, что Эластикс будет читать его их этого файла, чтобы не случилось в конфигурации. __ – означает что эта переменная будем передана вновь создаваемому каналу командой Dial.
И теперь при получении кода ##N от пользователя мы просто смотрим есть такая переменная в DB Астериска, если есть, то переводим сохраненный ранее канал в место где начинается воспроизведение.
[transfer-context]
exten => “”_##X,1,NoOp(${DB(br/${CALLERID(num)})})
exten”” => “”_##X,2,ChannelRedirect(${DB(br/${CALLERID(num)})},transfer-context,${EXTEN},3)
exten”” => _##X,3,Playback(${DIR}${MYVAR}_${EXTEN:-1}) ;
exten => _##X,4,Hangup()
Таким образом никаких скриптов, все гибко, красиво, изящно.
Бай.
PS: http://asteriskfaqs.org/2010/09/09/asterisk-users/set-channel-variable-from-within-other-channel.html
PS: https://wiki.asterisk.org/wiki/display/AST/Function_DB
| Posted in Без рубрики | No Comments »