ISP`s IT Аутсорсинг
Быстрый переход: Главная блога Главная сайта Форум
Если Вы чего то недопоняли или не нашли - задайте
вопрос на нашем форуме и мы попробуем Вам помочь.
Subnets.ru Регистрация IP и Автономных систем mega-net.ru

Архивные статьи в категории ‘Программинг’

Добро пожаловать в блог! Надеемся, что Вы еще вернетесь.

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

Задача звучала просто: необходимо установить LG (Looking Glass) для отображения информации с BGP роутера FreeBSD с установленной quagga.

Что такое LG ?

Looking Glass позволяет выполнить на BGP роутере команды и отобразить результат их выполнения в web-интерфейсе:

  • show ip bgp
  • show ip bgp neighbors advertised-routes
  • show ip bgp summary
  • ping
  • traceroute

Для получения данных с роутера LG может использовать протоколы:  SSH, telnet или rsh.

Мы пользуемся telnet`ом.

LG мы всегда использовали один. Это разработка Cougar официальный сайт www.version6.net.

LG screenshot

Данный LG написан на языке программирования PERL и является CGI скриптом. Для соединения использует PERL модуль  Net::Telnet (/usr/ports/net/p5-Net-Telnet)

Последняя версия LG, доступная на это момент, датируется 25.11.2004 года и имеет номер 1.9.

Скачать исходный код можно на официальном сайте http://www.version6.net/lg/lg-1.9.tar.bz2 или с нашего сайта http://subnets.ru/files/lg-1.9.tar.bz2.

Ранее мы использовали этот LG для получения инфы с Juniper, а тут понадобилось получить с quagga (демон bgpd).

Установили LG, зашли в web-интерфейс LG и ….. и нифига. По нажатию на кнопку «Submit» LG просто долго «думает» (подвисает), а затем выдает страницу с запрошенной командой и пустым результатом.

Пара слов об установке.

В README автор достаточно четко описал что надо делать, повторяться мы не будем, но позволим себе добавить кусок конфига для HTTP сервера apache:

<VirtualHost XXX.XXX.XXX.XXX:80>
    ServerAdmin mymail@mydomain.ru
    DocumentRoot /usr/local/www/lg
    ServerName lg.subnets.ru

    ScriptAlias / /usr/local/www/lg/cgi/lg.cgi

    ErrorLog /var/log/http/lg_error.log
    CustomLog /var/log/http/lg_access.log common

    <Directory "/usr/local/www/lg">
        Options -Indexes FollowSymLinks MultiViews
        AllowOverride All
    </Directory>
</VirtualHost>

Сначала подумали, что мы напортачили в конфиге, но после перечитывания мануала и разнообразных вариантов конфига стало понятно, что дело не в нем.

Остро встал вопрос о debug`е действий LG, но разработчик не предусмотрел такой возможности 🙁  В логах появляется лишь строчка с запросом и ничего больше….

Пришлось лезть в исходки. В результате изысканий стало понятно, что проблема возникает уже после установки telnet соединения  между LG и quagga (демоном bgpd).

Это удалось понять используя более детальное логирование действий LG и просмотра вывода tcpdump:

tcpdump -Xni lo0 port 2605

Слушали ифейс lo0 (loopback) т.к. LG и quagga находтся на одном сервере и bgpd запущен командой:

/usr/local/sbin/bgpd -d -A 127.0.0.1

Возникает она потому что скрипт не может заматчить «command prompt», иными словами строку приглашения.

Что делать ? Разбираться с этим дальше уже нет времени, т.к. на выяснение проблемы уже убили кучу времени.

Тут я вспомнил про порт p5-Net-Telnet-Cisco (/usr/ports/net-mgmt/p5-Telnet-Cisco).  Примеры  использовании этого порта я показывал в статье Backup конфига Cisco на FTP.

Решил по быстрому попробовать такой вариант подключения по telnet к quagga. Сказано — сделано. Установил  порт p5-Net-Telnet-Cisco, поправил исходный код lg.cgi и все заработало.

Думаю что мы не единственные кто сталкивался/столкнулся/столкнется :))) с этой проблемой, надеюсь эта статья вам поможет.

Модифицированный нами код можно скачать тут: http://subnets.ru/files/lg-1.9.1.tar.gz
В архиве присутствуют файлы:

  • lg-1.9_ORIGINAL.tar.gz — это оригинальный архив от автора LG
  • lg.cgi.diff — это DIFF файл между оригинальной версией и модифицированной

Уточню, что код модифировался только в части отвечающий за подключение по telnet`у к quagga, остальной код остался без изменений.

Списки Looking Glass в Инете:

З.Ы. При копировании статьи ссылка на источник ОБЯЗАТЕЛЬНА ! Пожалуйста, уважайте чужой труд.

Авторы: Панфилов Алексей (lehis (at) subnets.ru) и Николаев Дмитрий (virus (at) subnets.ru)

Ничего не понялТак себе...Не плохоДовольно интересноОтлично ! То что нужно ! (голосов: 1, среднее: 5,00 из 5)
Загрузка...
Отправить на почту Отправить на почту

Нам недавно пришлось реализовывать «кабельный тестер» на PHP. В Инете нашлась статья, спасибо автору большое, которую я и приведу, прежде чем переходить к кодингу:

В коммутаторы DES-3526 и DES-3550 (возможно DES-3028 и DES-3052) встроен кабельный тестер который позволяет определять (уточнить точность измерений) длину кабеля.

Использование из CLI

Комманда не требует админских полномочий (повторяющиеся строки удалены):

DES3526:user#cable_diag ports 1-24
Command: cable_diag ports 1-24

Perform Cable Diagnostics ...

 Port   Type    Link Status            Test Result           Cable Length (M)
 ----  ------  -------------  -----------------------------  ----------------
  1     FE      Link Down      OK                             -
  2     FE      Link Down      No Cable                       -
...
  10    FE      Link Down      Pair1 Open      at 22  M       -
                               Pair2 Open      at 22  M
  11    FE      Link Down      Pair1 Open      at 25  M       -
                               Pair2 Open      at 25  M
  12    FE      Link Down      Pair1 Open      at 88  M       -
                               Pair2 Open      at 88  M
  14    FE      Link Up        OK                             40
  15    FE      Link Down      Pair1 Open      at 18  M       -
                               Pair2 Open      at 18  M
  16    FE      Link Up        OK                             69
  18    FE      Link Down      Pair1 Open      at 4   M       -
                               Pair2 Open      at 4   M
  19    FE      Link Up        OK                             34
  20    FE      Link Down      OK                             -
  21    FE      Link Up        OK                             40
  22    FE      Link Down      Pair1 Open      at 29  M       -
                               Pair2 Open      at 29  M
  24    FE      Link Down      Pair1 Open      at 22  M       -
                               Pair2 Open      at 22  M

Возможные значения:

  • Pair Open — обрыв на растоянии ХХ метров
  • Link Up, длинна ХХ метров
  • Link Down, OK — нельзя измерить длинну кабеля (но нагрузка есть)
  • Link Down, No Cable — нет кабеля

Описание OID-ов:

1.3.6.1.4.1.171.12.58.1.1.1.2 -
swEtherCableDiagPortType OBJECT-TYPE
  SYNTAX INTEGER {
    fastEthernet(0),
    gigaEthernet(1),
    other(2)
  }

# snmpwalk -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.2
SNMPv2-SMI::enterprises.171.12.58.1.1.1.2.1 = INTEGER: 0

SNMPv2-SMI::enterprises.171.12.58.1.1.1.2.25 = INTEGER: 1

SNMPv2-SMI::enterprises.171.12.58.1.1.1.2.26 = INTEGER: 1
Имеем, порты 1-24 поддерживают нужный функционал. Проверить состояние линков:

1.3.6.1.4.1.171.12.58.1.1.1.3 -
swEtherCableDiagLinkStatus OBJECT-TYPE
  SYNTAX INTEGER {
    link-down(0),
    link-up(1),
    other(2)
  }

# snmpwalk -v2c -c public 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.3

SNMPv2-SMI::enterprises.171.12.58.1.1.1.3.1 = INTEGER: 0

Все OID с результатом имеют валидные значения только после выполнения теста. Далее — OIDы для состояния пар:

  • 1.3.6.1.4.1.171.12.58.1.1.1.4 — cтатус первой пары
  • 1.3.6.1.4.1.171.12.58.1.1.1.5 — cтатус второй пары
  • 1.3.6.1.4.1.171.12.58.1.1.1.6 — cтатус третьей пары
  • 1.3.6.1.4.1.171.12.58.1.1.1.7 — cтатус четвертой пары

Возможные значения:

  • ok(0)
  • open(1)
  • short(2)
  • open-short(3)
  • crosstalk(4)
  • unknown(5)
  • count(6)
  • no-cable(7)
  • other(8)

И, соответственно, длины пар: 1.3.6.1.4.1.171.12.58.1.1.1.8 — длинна первой пары 1.3.6.1.4.1.171.12.58.1.1.1.11 — длинна четвертой пары OID, предназначенный для запуска теста:

1.3.6.1.4.1.171.12.58.1.1.1.12

Это единственный OID предназначенный как для чтения так и для записи.

  • action(1)
  • processing(2)
  • other(3)

Тестирование

Работа с кабельным тестером в целом совершенно стандартна (что есть несомненный плюс)

Общий подход:

  • Запустить тест (запись нужного значения в соответвующий OID
  • Дождаться завершения (проверить стением OID со статусом)
  • Считать интересующие значения.

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

Линк есть, работающий абонент:

DES3526:user#cable_diag ports 21
Command: cable_diag ports 21

 Perform Cable Diagnostics ...

 Port   Type    Link Status            Test Result           Cable Length (M)
 ----  ------  -------------  -----------------------------  ----------------
  21    FE      Link Up        OK                             40

Запустить тест:

# snmpset -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.12.21 i 1

SNMPv2-SMI::enterprises.171.12.58.1.1.1.12.21 = INTEGER: 1

Проверить что он завершился (cтатус != 2):

# snmpget -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.12.21

SNMPv2-SMI::enterprises.171.12.58.1.1.1.12.21 = INTEGER: 3

Проверить состояние линка (1 — есть линк)

# snmpget -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.3.21

SNMPv2-SMI::enterprises.171.12.58.1.1.1.3.21 = INTEGER: 1

Проверить состояние 1-й пары (0 — ОК)

# snmpget -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.4.21

SNMPv2-SMI::enterprises.171.12.58.1.1.1.4.21 = INTEGER: 0

Проверить состояние 2-й пары (0 — ОК)

# snmpget -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.5.21

SNMPv2-SMI::enterprises.171.12.58.1.1.1.5.21 = INTEGER: 0

Проверить состояние 3-й пары (8 — Нет кабеля, что естественно для 100-мбитного порта)

# snmpget -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.6.21

SNMPv2-SMI::enterprises.171.12.58.1.1.1.6.21 = INTEGER: 8

Проверить состояние 4-й пары (8 — Нет кабеля, что естественно для 100-мбитного порта)

# snmpget -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.7.21

SNMPv2-SMI::enterprises.171.12.58.1.1.1.7.21 = INTEGER: 8

Определить длинну 1-й пары (40 метров) # snmpget -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.8.21

SNMPv2-SMI::enterprises.171.12.58.1.1.1.9.21 = INTEGER: 40

Определить длинну 2-й пары (40 метров, что логично, т.к. пары одинаковые)

# snmpget -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.9.21

SNMPv2-SMI::enterprises.171.12.58.1.1.1.9.21 = INTEGER: 40

Определить длинну 3-й пары (0 метров, фактически — не используется, не включена)

# snmpget -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.10.21

SNMPv2-SMI::enterprises.171.12.58.1.1.1.10.21 = INTEGER: 0

Определить длинну 4-й пары (0 метров, фактически — не используется, не включена)

# snmpget -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.11.21

SNMPv2-SMI::enterprises.171.12.58.1.1.1.11.21 = INTEGER: 0

Кабель не подключен:

DES3526:user#cable_diag ports 2
Command: cable_diag ports 2
 Perform Cable Diagnostics ...

 Port   Type    Link Status            Test Result           Cable Length (M)
 ----  ------  -------------  -----------------------------  ----------------
  2     FE      Link Down      No Cable                       -

Запустить тест, убедиться что при запросе ответе — «нет кабеля» (8)

# snmpset -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.12.2 i 1

SNMPv2-SMI::enterprises.171.12.58.1.1.1.12.2 = INTEGER: 1

# snmpget -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.4.2

SNMPv2-SMI::enterprises.171.12.58.1.1.1.6.2 = INTEGER: 8

Кабель есть, отключен

Подключаю 2-х метровый патч-корд к коммутатору (второй конец висит в воздухе):

DES3526:user#cable_diag ports 2
Command: cable_diag ports 2

 Perform Cable Diagnostics ...

 Port   Type    Link Status            Test Result           Cable Length (M)
 ----  ------  -------------  -----------------------------  ----------------
  2     FE      Link Down      Pair1 Open      at 3   M       -
                               Pair2 Open      at 2   M

# snmpset -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.12.2 i 1

SNMPv2-SMI::enterprises.171.12.58.1.1.1.12.2 = INTEGER: 1

Кабель имеет статус open:

# snmpget -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.4.2

SNMPv2-SMI::enterprises.171.12.58.1.1.1.4.2 = INTEGER: 1

«Обрыв» (в реальности — просто конец кабеля) на расстоянии 3 метра по одной и 2 метра по другой паре.

# snmpget -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.8.2

SNMPv2-SMI::enterprises.171.12.58.1.1.1.8.2 = INTEGER: 3

# snmpget -v2c -c private 172.16.34.3 1.3.6.1.4.1.171.12.58.1.1.1.9.2

SNMPv2-SMI::enterprises.171.12.58.1.1.1.9.2 = INTEGER: 2

Насколько я могу судить, точности измерения вполне достаточня (плюс-минус метр).

Короткое на нескольких парах Сделал тестовый кабель с «коротким» на первой и третьей парах. Коммутатор показал правильные результаты для используемых пар:

DES3526:user#cable_diag ports 3
Command: cable_diag ports 3

 Perform Cable Diagnostics ...

 Port   Type    Link Status            Test Result           Cable Length (M)
 ----  ------  -------------  -----------------------------  ----------------
  3     FE      Link Down      Pair1 Short     at 3   M       -
                               Pair2 Open      at 3   M

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

Ссылка на оригинал статьи: http://wiki.sirmax.noname.com.ua/index.php/Dlink_Cable_Tester

Спасибо автору за труд, ну а мы перейдем к реализации этого безобразия на PHP.

PHP

Приведу простой пример, как все это может выглядеть на PHP.

Так как код в блоге выглядит не айс, то выкладываю файликом: http://subnets.ru/saved/dlink_cable_tester.php.txt

В моем рабочем варианте я ессно использую MySQL и все данные о свичах, OID`ах и значениях беру из БД.

З.Ы. При копировании статьи ссылка на источник ОБЯЗАТЕЛЬНА !

Автор: Николаев Дмитрий (virus (at) subnets.ru)

Ничего не понялТак себе...Не плохоДовольно интересноОтлично ! То что нужно ! (голосов: 4, среднее: 5,00 из 5)
Загрузка...
Отправить на почту Отправить на почту

От админа:

Гугля по Инету наткнулся на толковую статью, решил скопировать в блог, дабы сохранить.

ipfw это удобный и гибкий пакетный фильтр, но без внешних средств решение он может принимать только на основе данных в заголовке пакета (ip и udp/tcp). Иногда этого недостаточно и нужно учитывать содержимое пакета. Например у меня возникло желание зафильтровать DNS-запросы MX-записей, которые в большом количестве делают зараженные спамерскими троянами клиентские компьютеры, чем вызывают повышенную загрузку DNS-сервера. В случае если клиентские компьютеры за NAT, почтовых серверов на них быть не должно, и MX-записи им спрашивать не нужно. Правильно ли так делать это отдельный вопрос, здесь будет рассмотрен только технический аспект — как это сделать.

Для решения данной задачи есть как минимум три варианта:
Из ipfw через divert-сокет отправлять пакеты процессу работающему в userspace, который будет слушать divert-сокет и фильтровать приходящие на него пакеты. Главный минус такого варианта — большие накладные расходы и как следствие низкая производительность. Другой минус — этот демон еще нужно написать. Хотя не исключено, что кто то уже написал демон слушающий divert и фильтрующий пакеты через bpf.
ng_bpf — узел Netgraph использующий bpf для фильтрации пакетов
ng_bpf можно подключить непосредственно к ng_ether.
пакеты в ng_bpf можно отправлять из ipfw через ng_ipfw, при выполнении определенного правила через.

Я выбрал последний вариант (ng_ipfw+ng_bpf), несмотря на то, что он несколько сложнее (ниже напишу почему), чем ng_ether+ng_bpf. Во-первых связка ng_ipfw+ng_bpf теоретически должна работать немного быстрее (тесты не проводил), а во вторых из ipfw удобно рулить тем какие пакеты отправлять на дальнейшую обработку в bpf, а какие нет.

bpf

Для начала нужно определиться по какому bpf-выражению будем фильтровать пакеты. Исходная задача звучала так: DNS-запросы (бит QR установлен в 1). Тип запроса — MX. Со вторым сложнее — в одном пакете может быть запрос на несколько записей разных типов, а сами запросы имеют переменную длину, и начинаются со строки заканчивающейся на 0 длина которой не указана в полях. Парсить такой запрос полностью в bpf очень неудобно. Впрочем это и не нужно — запросы посылаемые спамботами содержать запрос только на одну запись типа MX и можно просто заглянуть в конец пакета — там будут поля Type (MX — 0x000f)и Class (IN — 0×0001). Если это проверять, то под правило будут подпадать любые пакеты у которых в конце запрос на MX-запись.

При составлении выражения удобно пользоваться описанием формата пакетов с сайта networksorcery.com 1).

udp[10] & 0×80 = 0 - проверяем, что 1-й бит, байта со смещением 102) выставлен в 1, т. е. то, что это запрос, а не ответ.
udp[udp[4:2]-4 : 4] = 0x000f0001 - последние 4 байта UDP пакета 0x000f0001. udp[4:2] это длинна UDP пакета в байтах (вместе с заголовком).

В результате получается выражение:

udp dst port 53 and udp[10] & 0x80 = 0 and udp[udp[4:2]-4 : 4] = 0x000f0001

Но для ng_bpf нужно не выражение, а bpf-программа — набор низкоуровневых инструкций, которые нужно выполнить для проверки пакета. Чем то напоминает упрощенный и усеченный ассемблер.

В какие инструкции нужно преобразовать выражение зависит от того, что подается на вход bpf-фильтра — IP пакеты (начиная с заголовка IP-пакета без каких либо дополнительных заголовков), ethernet-фреймы (т. е. заголовок канального уровня и далее IP пакет) или пакет какого либо другого канального уровня.

В случае если ng_bpf подключен к ng_ether на его вход подаются ethernet фреймы, и для получения bpf-кода можно воспользоваться способом описанным в man ng_bpf — tcpdump -ddd и последующее приведении в формат который нужен для netgraph с помощью awk.

В случае подключения ng_bpf к ng_ipfw на вход подаются IP пакеты и такой способ не подойдет — в начале будет пара команд проверяющих поле в заголовке ethernet-фрейма которого в нашем случае нету, а в последующих командах будет использовано смещение на 14 байт больше чем нужно.

Поэтому есть два способа — составить программу руками заглядывая в man bpf и /usr/include/net/bpf.h (за основу можно взять вывод tcpdump -ddd, но с нуля написать не сложнее чем вручную дизассемблировать вывод tcpdump -ddd, изменить и потом снова перевести это в bpf-код). Это процесс сильно напоминает программирование на ассемблере с последующим переводом этого в машинные коды.

Или можно написать небольшую программку для компиляции выражения в bpf-код проверки IP пакетов (в libpcap это тип DLT_RAW, т. е. “сырой” IP пакет без каких либо дополнительных заголовков).

Cначала я составил bpf-код вручную, потом решил, что такой способ хорошо только в учебных целях, поскольку отнимает много времени и для повседневной работы не годится.

Потом написал маленькую программку которая это делает используя libpcap:

/*
 * to compile type:
 * gcc -lpcap bpf_comp.c -o bpf_comp
 */

#include <err.h>
#include <pcap.h>
#include <stdio.h>
#include <sysexits.h>

int main(int argc, char *argv[])

{
        struct bpf_program bp;
        unsigned int i;

        if (argc != 2)
                errx(EX_USAGE, "Usage %s 'filter expression'", argv[0]);

        if(pcap_compile_nopcap(65535, DLT_RAW, &bp, argv[1], 1, 0)) {
                errx(EX_USAGE, "filter syntax error");
        }

        printf("bpf_prog_len=%d bpf_prog=[ ", bp.bf_len);

        for (i = 0; i < bp.bf_len; i ++) {
                printf("{ code=%d jt=%d jf=%d k=%d } ",
                        bp.bf_insns[i].code, bp.bf_insns[i].jt, bp.bf_insns[i].jf, bp.bf_insns[i].k);
        }

        printf("]\n");

        exit(0);
}

Для тестирования этой программы можно посмотреть bpf-программу для фильтрации udp пакетов:

:~> ./bpf_comp udp
bpf_prog_len=5 bpf_prog=[ { code=0 jt=0 jf=0 k=0 } { code=48 jt=0 jf=0 k=9 } { code=21 jt=0 jf=1 k=17 } { code=6 jt=0 jf=0 k=65535 } { code=6 jt=0 jf=0 k=0 } ]

Если у Вас получится программа, не 5 команд (bpf_prog_len=5), а 7, значит libpcap собран с поддержкой IPv6 которая пока реализована не очень хорошо. В результате для DLT_RAW создается фильтрующий код, который кроме интересующих нас пакетов может поймать и лишние (это происходит в libpcap до версии 0.9.5 включительно, а в 0.9.6 это должно быть исправлено, но в любом случае если в сети используется только IPv4, то лучше собирать libpcap без поддержки IPv6, чтобы bpf-программа была короче и быстрее). Поэтому если у вас получилось 7 команд для udp, рекомендую пересобрать без поддержки IPv6:

echo 'NO_INET6=true' >> /etc/make.conf
cd /usr/src/lib/libpcap/
make clean
make
make install

Для интересующего нас выражения получается такая bpf-программа:

:~> ./bpf_comp 'udp dst port 53 and udp[10] & 0x80 = 0 and udp[udp[4:2]-4 : 4] = 0x000f0001'
bpf_prog_len=18 bpf_prog=[ { code=0 jt=0 jf=0 k=0 } { code=48 jt=0 jf=0 k=9 } { code=21 jt=0 jf=14 k=17 } { code=40 jt=0 jf=0 k=6 } { code=69 jt=12 jf=0 k=8191 } { code=177 jt=0 jf=0 k=0 } { code=72 jt=0 jf=0 k=2 } { code=21 jt=0 jf=9 k=53 } { code=80 jt=0 jf=0 k=10 } { code=69 jt=7 jf=0 k=128 } { code=72 jt=0 jf=0 k=4 } { code=20 jt=0 jf=0 k=4 } { code=12 jt=0 jf=0 k=0 } { code=7 jt=0 jf=0 k=0 } { code=64 jt=0 jf=0 k=0 } { code=21 jt=0 jf=1 k=983041 } { code=6 jt=0 jf=0 k=65535 } { code=6 jt=0 jf=0 k=0 } ]

(первая команда в данном случае лишняя и её можно выкинуть, но можно ли это делать зависит от того какая команда стоит за ней, в общем случае проще оставлять программу как есть).

Netgraph

Для использования узлов типа ng_bpf и ng_ipfw нужно загрузить соответствующие модули (если они не были включены в ядро):

:~# kldload ng_ipfw
:~# kldload ng_bpf

Чтобы после перезагрузки они загружались автоматически нужно добавить в /boot/loader.conf:

ng_ipfw_load="YES"
ng_bpf_load="YES"

При загрузке модуля ng_ipfw автоматически создается одни узел с именем ipfw (дополнительные узлы типа ipfw создавать нельзя). Создаем узел типа bpf и подключаем его к ipfw:

:~# ngctl mkpeer ipfw: bpf 1 main

Задаем созданному узлу имя:

~# ngctl name ipfw:1 dns_mx_q_filter

Конфигурируем его:

:~# ngctl msg dns_mx_q_filter: setprogram { thisHook="main" ifMatch="" ifNotMatch="main" bpf_prog_len=17 bpf_prog=[ { code=48 jt=0 jf=0 k=9 } { code=21 jt=0 jf=14 k=17 } { code=40 jt=0 jf=0 k=6 } { code=69 jt=12 jf=0 k=8191 } { code=177 jt=0 jf=0 k=0 } { code=72 jt=0 jf=0 k=2 } { code=21 jt=0 jf=9 k=53 } { code=80 jt=0 jf=0 k=10 } { code=69 jt=7 jf=0 k=128 } { code=72 jt=0 jf=0 k=4 } { code=20 jt=0 jf=0 k=4 } { code=12 jt=0 jf=0 k=0 } { code=7 jt=0 jf=0 k=0 } { code=64 jt=0 jf=0 k=0 } { code=21 jt=0 jf=1 k=983041 } { code=6 jt=0 jf=0 k=65535 } { code=6 jt=0 jf=0 k=0 } ] }

thisHook — хук, входящие пакеты с которого будут фильтроваться заданной программой. ifMatch — хук куда будут отправляться пакеты для которых выполнено условия фильтра. Если задать пустым, то пакеты будут отбрасываться (что в данном случае и требовалось — фильтровать определенные пакеты). ifNotMatch — все остальные пакеты отправляем обратно в ipfw3)

Можно посмотреть, что программа действительно задана:

:~# ngctl msg dns_mx_q_filter: getprogram "main"

Теперь осталось интересующие нас пакеты отправить из ipfw через хук с именем 1 в netgraph. Т. к. к хуку с именем 1 подключен узел типа ng_bpf, то пакеты попадут к нему:

:~# ipfw add 123 netgraph 1 udp from 192.168.0.0/16 to me 53

Для просмотра статистики есть сообщение getstats:

:~# ngctl msg dns_mx_q_filter: getstats "main"
Rec'd response "getstats" (3) from "[4fa]:":
Args:   { recvFrames=16333 recvOctets=977179 recvMatchFrames=9133 recvMatchOctets=512317 xmitFrames=7200 xmitOctets=464862 }

Из 16333 пакетов отправленных правилом ipfw в ng_bpf, 9133 пакетов были запросами на mx-записи.

Для конфигурации ng_ipfw+ng_bpf при загрузке можно положить скрипт в /usr/local/etc/rc.d/ (расширение .sh нужно только во FreeBSD 4, 5. Для 6-ки его лучше убрать).

комментарии по поводу этой заметки можно писать в ЖЖ

1) первоисточник этой информации RFC, но в RFC эта информация представлена не так наглядно и удобно
2) 8 байт, заголовок UDP и 2 байта идентификатор DNS запроса
3) что с ними будет дальше зависит от значения sysctl net.inet.ip.fw.one_pass — либо будет разрешен, либо продолжится проверка следующих правил

Автор: Антон Южанинов, Оригинал: http://citrin.ru/freebsd:ng_ipfw_ng_bpf

От админа:

таким же способом можно отфильтровывать uTP (torrent), пакеты можно увидеть выполнив:

tcpdump -ni IFACE_NAME -n "ip[40:4]=0x7FFFFFFF"

Еще полезные ссылки по теме:

Ничего не понялТак себе...Не плохоДовольно интересноОтлично ! То что нужно ! (голосов: 3, среднее: 5,00 из 5)
Загрузка...
Отправить на почту Отправить на почту

Возникла задача предоставить сервис для клиентов использующих внешние динамические адреса. Доступ к сервису ограничен правилами IPTABLES.

Клиенты, которым необходимо получить услугу предлагается создать учетную запись на ресурсе dyndns.org, клиент получит доменное имя в виде client.dyndns.org.

При каждом изменении ip адреса клиента мы всегда узнаем его адрес по доменному имени. Если мы добавим правило в iptables для этого доменного имени, правило будет работать только для текущего  ip адреса клиента и при последующем изменении ip адреса, доступ к сервису будет ограничен.

Это статья посвящена решению этой проблемы, и за комментарии, добавления и поправки к статье большое спасибо)

Оригинал решения был найден здесь: http://dave.thehorners.com/content/view/86/65/ , а мы всего лишь доработаем этот скрипт.

Создаем несколько каталогов:

/root/dynhosts/ — общий каталог

/root/dynhosts/zones/ — здесь будем хранить файлы доменных зон клиентов

/root/dynhosts/logs/ — лог файлы работы скрипта

/root/dynhosts/scripts/ — здесь будет находится сам запускаемый скрипт

Создаем лог-файл:

#touch /root/dynhosts/logs/dynhosts.log

Создаем файл зоны клиента:

#touch /root/dynhosts/zones/client.dyndns.org

Создаем сам скрипт:

# vi /root/dynhosts/scripts/firewall-dynhosts.sh

#!/bin/bash
#
# filename: firewall-dynhosts.sh
#
NOW=$(date)
CHAIN="dynamichosts"  # change this to whatever chain you want.
IPTABLES="/sbin/iptables"

# create the chain in iptables.
`$IPTABLES -N $CHAIN`
# insert the chain into the input chain @ the head of the list.
`$IPTABLES -I INPUT 1 -j $CHAIN`
# flush all the rules in the chain
`$IPTABLES -F $CHAIN`

FILES=`ls --format=single-column /root/dynhosts/zones/`

echo $FILES

for file in $FILES
do
HOSTFILE="/root/dynhosts/zones/$file"
echo $HOSTFILE

# lookup host name from dns tables
IP=`/usr/bin/dig +short $file | /usr/bin/tail -n 1`
if [ "${#IP}" = "0" ]; then
echo "$NOW Couldn't lookup hostname for $file, failed." >> /root/dynhosts/logs/dynhosts.log

continue
fi

OLDIP=""
if [ -a $HOSTFILE ]; then
OLDIP=`cat $HOSTFILE`
echo "CAT returned: $?"
fi

# save off new ip.
echo $IP>$HOSTFILE

echo "Updating $file in iptables."
echo "Inserting new rule ($IP)"
`$IPTABLES -A $CHAIN -s $IP/32 -j ACCEPT`

done
exit0

Запускаем скрипт:

# /root/dynhosts/scripts/firewall-dynhosts.sh

iptables: Chain already exists

client.dyndns.org

CAT returned: 0
Updating client.dyndns.org in iptables.
Inserting new rule (213.64.141.6)

Проверяем,

# cat /root/dynhosts/zones/client.dyndns.org
213.64.141.6

#/sbin/iptables -nL dynamichosts

Chain dynamichosts

target     prot opt source               destination
ACCEPT     all  —  213.64.141.6         0.0.0.0/0

Если такого доменного имени не существует в /root/dynhosts/logs/dynhosts.log была бы запись следующего содержания:

Tue Aug 25 09:47:15 MSD 2009 Couldn’t lookup hostname for client.dyndns.org, failed.

После того как контракт с клиентом истек достаточно удалить файл его зоны из /root/dynhosts/zones/.

Осталось добавить выполнение скрипта в крон и предоставлять сервисы этим абонентам.

З.Ы. При копировании статьи ссылка на источник ОБЯЗАТЕЛЬНА !

Автор: zaikini


Ничего не понялТак себе...Не плохоДовольно интересноОтлично ! То что нужно ! (голосов: 2, среднее: 5,00 из 5)
Загрузка...
Отправить на почту Отправить на почту

ng_ipacct — Netgraph IP accounting

Для работы этого примера необходимо иметь подгруженные модули:

  • ng_ipacct.ko
  • ng_ipfw.ko
  • ng_ksocket.ko

Убедиться в их наличии можно командой:

/sbin/kldstat

Id Refs Address Size Name
1 11 0xc0400000 35e5f8 kernel
...
3 1 0xc4ceb000 3000 ng_ipacct.ko
4 1 0xc4cee000 4000 ng_ksocket.ko
5 1 0xc4d6d000 2000 ng_ipfw.ko

Если модули не загружены, то можно пересобрать ядро добавив следующее:

options NETGRAPH
options NETGRAPH_ETHER
options NETGRAPH_SOCKET
options NETGRAPH_TEE

options IPFIREWALL
options IPFIREWALL_DEFAULT_TO_ACCEPT
options IPFIREWALL_FORWARD
options IPFIREWALL_VERBOSE
options IPFIREWALL_VERBOSE_LIMIT=1000

либо загрузить это модулями:

/sbin/kldload /boot/kernel/ng_ipfw.ko

/sbin/kldload /boot/kernel/ng_ipacct.ko

/sbin/kldload /boot/kernel/ng_ksocket.ko

Устанавливаем порт /usr/ports/net-mgmt/ng_ipacct:

cd /usr/ports/net-mgmt/ng_ipacct

make install clean
В /etc/rc.conf добавляем:

ng_ipacct_enable="YES"
ng_ipacct_modules_load="YES"


Для примера будем собирать трафик для подсети 172.16.5.0/24 с интерфейса bge1

Итак сам скрипт на PERL, пусть он находится в папке /scripts и называется ipacctd_ng.pl

#! /usr/bin/perl

$rul=64000;                                                         #номер начального правила в файере
$iface="bge1";                                                     #интерфейс
$threshold=100000;                                              #максимальное количество записей
$verbose="1";                                                      #расширенная статистика
$savetime="1";                                                     #метка юникс тайма в файл статистики
$nodename=sprintf("ipacct_%s",$iface);                   #имя ноды
$hookprefix=$iface;                                               #крючочки (хуки) в нетграф ;-)

if($ARGV[0] ne "start" and $ARGV[0] ne "show" and $ARGV[0] ne "stop"  and $ARGV[0] ne "restart"){
            error();
}else{
          if($ARGV[0] eq "stop"){                          #stop
                   stop_ng_ipacctd($nodename);
          }elsif($ARGV[0] eq "show"){                    #дампим трафик в файл
                   #проверяем загружен ли ipacctd
                   if(check_ipacctd($iface,$rul)==0){
                              stop_ng_ipacctd($nodename);
                              `/bin/sleep 3`;
                              start_ng_ipacctd($nodename,$hookprefix,$rul,$iface,$verbose,$threshold,$savetime);
                   }else{
                              $cmd=sprintf("/usr/local/sbin/ipacctctl %s:%s checkpoint",$nodename,$hookprefix);
                              `$cmd`;
                              $cmd=sprintf("/usr/local/sbin/ipacctctl %s:%s show",$nodename,$hookprefix);
                              `$cmd`;
                              $cmd=sprintf("/usr/local/sbin/ipacctctl %s:%s clear",$nodename,$hookprefix);
                              `$cmd`;
                   }
          }elsif($ARGV[0] eq "start"){
                  start_ng_ipacctd($dbh,$nodename,$hookprefix,$rul,$iface,$verbose,$threshold,$savetime);
          }elsif($ARGV[0] eq "restart"){
                 stop_ng_ipacctd($nodename);
                 `/bin/sleep 3`;
                start_ng_ipacctd($dbh,$nodename,$hookprefix,$rul,$iface,$verbose,$threshold,$savetime);
          }
}

###функция выводящая аргументы запуска==============================
sub error{
      printf "\nUsage: (start|stop|restart|show)";
      exit;
}

###функция start==================================================
sub start_ng_ipacctd{
         $net="172.16.5.0/24";
         #проверяем загруженность модулей
         @modules=("ng_ipacct.ko","ng_ipfw.ko","ng_ksocket.ko");
         foreach(@modules){
             if(chk_mdl($_)==0){
                `/sbin/kldload $_`;
             }
         }
         #формирование ноды нетграфа
         $cmd_ng=sprintf("/usr/sbin/ngctl -f- <<-SEQ
         mkpeer ipacct ctl ctl
         name .:ctl %s
         mkpeer %s: ksocket %s_in inet/raw/divert
         name %s:%s_in %s_in
         msg %s_in: bind inet/0.0.0.0:3021
         mkpeer %s: ksocket %s_out inet/raw/divert
         name %s:%s_out %s_out
         msg %s_out: bind inet/0.0.0.0:3022
         rmhook .:ctl",$nodename,$nodename,$hookprefix,$nodename,$hookprefix,$nodename,$nodename,$nodename,$hookprefix,$nodename,$hookprefix,$nodename,$nodename);

        `$cmd_ng`;
         $cmd=sprintf("/usr/local/sbin/ipacctctl %s:%s dlt RAW",$nodename,$hookprefix);
         `$cmd`;
         $cmd=sprintf("/usr/local/sbin/ipacctctl %s:%s verbose %s",$nodename,$hookprefix,$verbose);
         `$cmd`;
         $cmd=sprintf("/usr/local/sbin/ipacctctl %s:%s threshold %s",$nodename,$hookprefix,$threshold);
         `$cmd`;
          $cmd=sprintf("/usr/local/sbin/ipacctctl %s:%s savetime %s",$nodename,$hookprefix,$savetime);
         `$cmd`;

          #формируем правила в фаирволе IPFW для перенаправления трафика в ноду нетграфа
          $cmd=sprintf("/sbin/ipfw add %s divert 3021 ip from %s to any",$rul,$net);
          `$cmd`;
          $cmd=sprintf("/sbin/ipfw add %s divert 3022 ip from any to %s",$rul,$net);
          `$cmd`;
           print "ipacct has started..\n";
}

###функция stop==================================================
sub stop_ng_ipacctd{
        `sh /etc/rc.firewall`;
         $cmd=sprintf("/usr/sbin/ngctl shutdown %s:",$nodename);
         `$cmd`;
         print "ipacct has stoped..\n";
}

###функция проверки загрузки модулей================================
sub chk_mdl{
       $chk=`/sbin/kldstat | /usr/bin/awk '/$_/ {print 1}'`;
       if(!$chk){
           return 0;
        }else{
          return 1;
        }
}

###функция проверки ipacctd========================================
sub check_ipacctd{
        $ch1=$ch2=$ch3=0;
        $cmd=sprintf("/usr/sbin/ngctl list | grep %s_in",$iface); #проверяем входящий хук нетграфа
        $check=`$cmd`;
        if($check){
              $ch1=1;
        }

        $cmd=sprintf("/usr/sbin/ngctl list | grep %s_out",$iface); #проверяем исходящий хук нетграфа
        $check=`$cmd`;
        if($check){
              $ch2=1;
        }

        $cmd=sprintf("/sbin/ipfw show | grep divert"); #проверяем наличие правил в файерволе
        $check=`$cmd`;
        if($check){
             $ch3=1;
        }

         $all_ch=$ch1+$ch2+$ch3;
         if ($all_ch < 3){
                return 0; #чего-то явно не хватает
         }else{
               return 1; #все ОК!
         }
}

После старта мы можем посмотреть правила в фаирволе:
/sbin/ipfw show 64000
64000 1551459105 504714065010 divert 3021 ip from 172.16.5.0/24 to any
64000 2103320289 2367292643626 divert 3022 ip from any to 172.16.5.0/24

По команде:

/usr/sbin/ngctl list

можем посмотреть ноды и хуки нетграфа:

There are 7 total nodes:
Name: ngctl12701 Type: socket ID: 000c36ff Num hooks: 0
Name: ipacct_bge1_out Type: ksocket ID: 00097d52 Num hooks: 1
Name: ipacct_bge1_in Type: ksocket ID: 00097d51 Num hooks: 1
Name: ipacct_bge1 Type: ipacct ID: 00097d50 Num hooks: 2
Name: ipfw Type: ipfw ID: 0005f4a3 Num hooks: 0
Name: bge1 Type: ether ID: 00000002 Num hooks: 0
Name: bge0 Type: ether ID: 00000001 Num hooks: 0

Сделаем еще один маленький скриптик, который будет нам складывать статистику в файл.

Назовем его trafgen.pl

#!/usr/bin/perl

$tmp="/usr/local/var/trafd/tmp";    #папка для логов
opendir DIR,$tmp or mkdir $tmp;
closedir DIR;
$log=sprintf("%s/ipacctd.log",$tmp);
system("/scripts/ipacctd_ng.pl show >> $log");  #вызываем наш предыдущий скрипт с аргументом show

в /etc/crontab добавляем строчку:
*/5 * * * * root /scripts/trafgen.pl >/dev/null

Формат данны файла статистики при включенных опциях verbose=1 и savetime=1:
src_IP src_Port dst_IP dst_Port Proto packets bytes unixtime

Пример данных в фале:

172.16.5.211 57349 95.132.7.128 19904 6 1069 822400 1239961920
172.16.5.102 2208 217.118.24.17 7777 6 321 14958 1239961920
172.16.5.91 64835 92.100.50.249 59039 6 426 596900 1239961920
172.16.5.209 64829 77.41.95.94 43768 17 1 58 1239961923
172.16.5.76 1425 195.218.181.123 80 6 4 976 1239961924
172.16.5.188 61651 195.50.197.187 63375 6 1 48 1239961925
172.16.5.220 28988 94.179.59.61 20473 6 5 747 1239961929
....
80.252.240.202 11417 172.16.5.108 60682 17 1 47 1239961922
78.37.156.14 1451 172.16.5.220 28988 6 6 685 1239961922
97.84.143.186 17834 172.16.5.209 64829 17 2 134 1239961922
77.234.8.71 36523 172.16.5.220 28988 17 1 95 1239961924
195.189.47.2 2987 172.16.5.220 28988 17 1 131 1239961925
195.230.112.239 63403 172.16.5.220 28988 6 6 801 1239961930
60.220.156.222 27808 172.16.5.157 34613 17 4 504 1239961932
93.186.239.96 80 172.16.5.101 2720 6 3 358 1239961933

Обратите внимание, что сначала идет трафик исходящий и лишь затем входящий!!!
Все, дальше зависит только от полета Вашей фантазии (или извращенности 🙂 )

Вы можете обрабатывать файлы и складировать их в БД (напрмер MySQL) и т.п.

Плюсы от использования ng_ipacct:

  • держит большие объемы трафика
  • меньшая загрузка cpu по сравнению с обычным ipacct (/usr/ports/net-mgmt/ipacctd)

P.S. После пересборки ядра обязательно пересобрать порт /usr/ports/net-mgmt/ng_ipacct (если он был установлен до этого)

Чтиво:

  • man 4 ipacct
  • man 8 ipfw
  • man 4 netgraph
  • man 4 ng_ipfw

З.Ы. При копировании статьи ссылка на источник ОБЯЗАТЕЛЬНА !

Автор: Folio
Ничего не понялТак себе...Не плохоДовольно интересноОтлично ! То что нужно ! (голосов: 4, среднее: 3,75 из 5)
Загрузка...
Отправить на почту Отправить на почту