суббота, 24 января 2015 г.

Centos, ndpi и imq. Обновлено 3.06.2015.

Сборка ядра для Centos с патчами IMQ и nDPI. 

Еще один мануал сборки ядра с Ndpi и imq. Теперь для Centos 7. Проверялся только под x64! Мануал максимально подробный, на уровне "копировать-вставить".

Переходим в домашний каталог и создаем необходимые директории
 cd ~/ 
 mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
 echo '%_topdir %(echo $HOME)/rpmbuild' > ~/.rpmmacros 

Устанавливаем необходимые пакеты
 yum install rpm-build redhat-rpm-config asciidoc hmaccalc nano perl-ExtUtils-Embed pesign xmlto
 yum groupinstall "Development Tools"
 yum install audit-libs-devel binutils-devel elfutils-devel elfutils-libelf-devel zlib-devel
 yum install newt-devel numactl-devel pciutils-devel python-devel zlib-devel
 yum install ncurses-devel qt-devel bc libnetfilter_conntrack-devel  libnfnetlink-devel libpcap-devel net-tools wget libselinux-devel

Получаем исходники последнего ядра (на момент написания это 3.10.0-123.20.1) и патч  подправленный (с офф сайта патч выдавал режекты) IMQ.
 rpm -i http://vault.centos.org/7.0.1406/updates/Source/SPackages/kernel-3.10.0-123.20.1.el7.src.rpm 
 cd ~/rpmbuild/SPECS
 rpmbuild -bp --target=$(uname -m) kernel.spec
 cd ~/rpmbuild/SOURCES/ && wget https://www.dropbox.com/s/jay95g9tqbnhu29/linux-3.10-imq.diff

Переходим в каталог и копируем  конфиг
 cd ~/rpmbuild/BUILD/kernel-*/linux-*/
 /bin/cp configs/kernel-3.10.0-x86_64.config .config   

Подправим spec файл
 cd ~/rpmbuild/SPECS/  
 /bin/cp kernel.spec kernel.spec.back
 sed -i -e '5 s/^/%define buildid .IMQ\n/;' kernel.spec  
 sed -i -e '/Patch999999/i\Patch999998: linux-3.10-imq.diff' kernel.spec
 sed -i -e '/ApplyOptionalPatch linux-kernel-test.patch/i\ApplyOptionalPatch linux-3.10-imq.diff' kernel.spec

Накладываем патч IMQ и включаем модуль
 cd ~/rpmbuild/BUILD/kernel-*/linux-*/
 patch -p1 < ../../../SOURCES/linux-3.10-imq.diff
 make menuconfig

Device Drivers; Network Device Support;
[M] IMQ (intermediate queueing device) support

Networking Supportt; Networking Options; Network Packet Filtering Framework (Netfilter); Core Netfilter Configuration → "IMQ" Target Support

Подправим файл конфига
 sed -i -e '1 s/^/# x86_64\n/;' .config  

Копируем наши конфиги
 /bin/cp ./.config ../../../SOURCES/kernel-3.10.0-x86_64.config  
 /bin/cp ./.config ../../../SOURCES/kernel-3.10.0-x86_64-debug.config  

Ну и сборка
 cd ~/rpmbuild/SPECS/   
 rpmbuild -bb --without kabichk  --without debug --without debuginfo --target=`uname -m` kernel.spec  

После устанавливаем наше ядро.
 rpm -ivh --force ../RPMS/x86_64/kernel-*.rpm 
Перезагружаемся и проверяем
 reboot  
 modprobe xt_IMQ  
 lsmod | grep IMQ  

Если все нормально то увидим приблизительно следующее
 xt_IMQ         12532 0  

Теперь iptables.
 cd ~/ && rpm -ivh http://vault.centos.org/7.0.1406/os/Source/SPackages/iptables-1.4.21-13.el7.src.rpm 
 cd ~/rpmbuild/SPECS
 rpmbuild -bp  iptables.spec 
 cd ~/rpmbuild/SOURCES/ && wget https://www.dropbox.com/s/x2pvnznhq3z4jnt/imq-iptables-1.4.13.diff
 cd ~/rpmbuild/SPECS/

Подправим iptables.spec
 sed -i -e '/Patch1/a\Patch2: imq-iptables-1.4.13.diff' iptables.spec
 sed -i -e '/%patch1 -p1/a\%patch2 -p1 -b imq-iptables-1.4.13' iptables.spec

Теперь можем собрать и установить
 rpmbuild -bb iptables.spec  
 rpm -Uvh  ../RPMS/x86_64/iptables-*.rpm   

Далее xtables
 cd ~/  
 wget https://www.dropbox.com/s/l16zkc8gbubf9ae/xtables-addons-2.6.tar.xz  
 tar -xvf xtables-addons-2.6.tar.xz  
 cd xtables-addons-2.6  
 ./configure  
 make 
 make install 

Следующий шаг nDpi. Использоваться будет версия nDpi без патча ядра. Недостатком этого является отсутствие возможности использовать xt_connlabel. Если кому-то будет интересно, выложу дополнение по сборке с патчем.
 cd ~/  
 wget http://devel.aanet.ru/ndpi/nDPI-1.5.1.20150513.tar.gz  
 tar -xvzf nDPI-1.5.1.20150513.tar.gz && cd ./nDPI-1.5.1.20150513/ && ./autogen.sh && cd ./ndpi-netfilter/
 sed -i -e 's/net, __ndpi_free_flow, n)/net, __ndpi_free_flow, n, 0 ,0)/' src/main.c
 make
 make install  
 make modules_install  
 modprobe xt_ndpi    

Проверяем с помощью lsmod | grep xt_ndpi. Если все нормально то в выводе увидите xt_ndpi
Протоколы с которыми можно работать.
 iptables -m ndpi -h  

Как и в прошлый раз привожу ссылку на тему, с которой все началось. За патчи говорим спасибо

Полноценное тестирование не проводил. Максимум что я проверил - поднятие интерфейсов IMQ, перенаправление трафика с интерфейсов на IMQ и  1-2 правила nDpi с маркировкой. Поэтому если что-то работает не так просьба отписаться.

UPD. В новых патчах добавлен target Ndpi. Теперь можно упростить маркировки трафика или его классификацию. Например:
iptables -t mangle -A POSTROUTING -m ndpi --http -j MARK --set-mark 3  
iptables -t mangle -A POSTROUTING -m ndpi --http -j RETURN
Теперь можно записать как:
 iptables --t mangle -A POSTROUTING -m ndpi --proto bittorrent -j NDPI --value 3 --set-mark --ret  
А классификацию:
 iptables -t mangle -A POSTROUTING -m ndpi --bittorrent -j CLASSIFY --set-class 1:5  
 iptables -t mangle -A POSTROUTING -m ndpi --bittorrent -j RETURN  
Можно записать как:
 iptables -t mangle -A POSTROUTING -m ndpi --proto bittorrent -j NDPI --value 0X10005 --set-clsf --ret  

UPD2. Обновлено.  Цитата Vel

Большие изменения в BT: добавлен парсер сообщений (dht) и хеш для хранения ip:port получаемых парсером
По-умолчанию хеш отключен! Чтобы его включить нужно указать его размер 1-32 (параметр bt_hash_size). Число элементо хеша будет равно N*1024.
Кроме это можно указать время хранения данных в хеше 900-3600 секунд (параметр bt_hash_timeout)
Число хранимых элементов в хеше и другую информацию о хеше можно посмотреть в /proc/net/xt_ndpi/info
При тестировании на сети /24 с 300Мбитным трафиком число элементов было 0.8-1.2 миллиона элементов!
Каждый элемент - 24 байта!
Хэш включается командой  modprobe xt_ndpi bt_hash_size= bt_hash_timeout= подставив нужные значения  для bt_hash_size и bt_hash_timeout (Естественно если модуль уже был загружен до этого, то его надо выгрузить).

P.S.  Уважаемые копипастеры. Будьте добры указывать первоисточники. Хотя бы ссылку на тему https://www.linux.org.ru/forum/general/9685281

четверг, 8 января 2015 г.

Уведовление занятости абонента при включенном Call Waiting в Asterisk.

     Наверное многие знают о существовании опции Call Waiting в Asterisk.  Функция конечно хорошая, но не без недостатка. Если абонент, кому звонят, понимает, что на второй линии другой абонент, на которого он в случае чего может переключиться, то звонящий же не узнает, разговаривает сейчас  абонент на другом конце или просто не отвечает на звонок. И, казалось бы, хорошая опция  этим недостатком может убить  все плюсы. По крайней мере в нашем офисе сотрудники часто были недовольны друг другом, думая что  на их звонки не отвечают.

     В конце концов  мне это надоело и решил искать решение. Нашел его достаточно быстро. Оказалось что я не один, кому не очень понравилась работа это функции. Решение нашел тут.

     Если  коротко, то в extensions_custom.conf надо добавить
  [from-internal-custom]  
 include => macro-dialout-one-predial-hook  
 [macro-dialout-one-predial-hook]   
  exten => s,1,Noop(DEVICE STATE - ${DEVICE_STATE(${DSTRING})})   
  exten => s,n,ExecIf($["${DEVICE_STATE(${DSTRING})}" = "INUSE"]?Playback(abonent_zanyat))   
  exten => s,n,ExecIf($["${DEVICE_STATE(${DSTRING})}" = "INUSE"]?Set(D_OPTIONS=Ttm))   
  exten => s,n,ExecIf($["${DEVICE_STATE(${DSTRING})}" = "RINGINUSE"]?Playback(abonent_zanyat))   
  exten => s,n,ExecIf($["${DEVICE_STATE(${DSTRING})}" = "RINGINUSE"]?Set(D_OPTIONS=Ttm))   
где abonent_zanyat название проигрываемого файла. Кстати саму начитку заказывать  у сторонних фирм не хотелось (уж больно много просят за пару слов), так что на помощь пришли онлайн синтезаторы речи. В частности этот. Текст был следующий: "В настоящий момент абонент разговаривает. Вы можете дождаться ответа или перезвонить позже." Сохранить файл можно с помощью инструментов разработки  браузера. При выборе голоса Milena получилось очень даже натурально. Был даже удивлен что не сразу и заметно, что это речь синтезатора (особенно если это услышать в трубке телефона).

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

     Сотрудники теперь довольны =)

UPD. Если у вас версия freepbx не самая свежая (например freepbx 2.11) то в файле ..admin/modules/core/functions.inc.php находим строку
 $ext->add($mcontext,$exten,'godial', new ext_dial('${DSTRING}', '${ARG1},${D_OPTIONS}'));  
и меняем на
 $ext->add($mcontext,$exten,'godial', new ext_execif('$["${QAGENT}"=""]', 'Macro', 'CHECK_DEVICE_STATE,')); 
 $ext->add($mcontext,$exten,'', new ext_dial('${DSTRING}', '${ARG1},${D_OPTIONS}'));  

В extensions_custom.conf в свою очередь контекс именуем не macro-dialout-one-predial-hook, а macro-CHECK_DEVICE_STATE