Инструменты пользователя

Инструменты сайта


ru:software:freebsd:igmpproxy_on_netgraph

Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
ru:software:freebsd:igmpproxy_on_netgraph [2015/05/14 10:12]
root [Использование]
ru:software:freebsd:igmpproxy_on_netgraph [2015/07/18 23:14] (текущий)
root [История]
Строка 2: Строка 2:
  
 Скрипт собирающий netgraph мост для мультикаст трафика (IGMP, UDP) между двумя сетевыми интерфейсами предназначен для замены igmpproxy/​mrouted.\\ Скрипт собирающий netgraph мост для мультикаст трафика (IGMP, UDP) между двумя сетевыми интерфейсами предназначен для замены igmpproxy/​mrouted.\\
- +[[http://​www.netlab.linkpc.net/​download/​software/​FreeBSD/​mcastbridge/​mcastbr2.sh|mcastbr2.sh]]
-[url=http://​www.netlab.linkpc.net/​download/​software/​FreeBSD/​mcastbridge/​mcastbr2.sh]mcastbr2.sh[/url]+
  
 Обсуждения:​\\ Обсуждения:​\\
-[url=http://​lists.freebsd.org/​pipermail/​freebsd-net/​2011-December/​030643.html]FreeBSD maillist[/url+[[http://​lists.freebsd.org/​pipermail/​freebsd-net/​2011-December/​030643.html|FreeBSD maillist]]\\ 
-[url=http://​www.opennet.ru/​tips/​2649_multicast_proxy_igmp_freebsd_netgraph.shtml]На OpenNet[/url]+[[http://​www.opennet.ru/​tips/​2649_multicast_proxy_igmp_freebsd_netgraph.shtml|На OpenNet]]\\
  
  
Строка 15: Строка 14:
 или если нужно чтобы трафик попадал в сетевой стёк ОС, как было до установки моста: или если нужно чтобы трафик попадал в сетевой стёк ОС, как было до установки моста:
 <​code>​mcastbr2.sh start re0 em0 enable</​code>​ <​code>​mcastbr2.sh start re0 em0 enable</​code>​
- 
  
 Удалить мост: Удалить мост:
Строка 22: Строка 20:
  
 ===== Принцип работы ===== ===== Принцип работы =====
 +==== netgraph ====
 +Его можно сравнить с LUA: он даёт широкие возможности по манипуляции с сетевыми пакетами,​ относительно прост в использовании и максимально быстр тк всё происходит в ядре.\\
 +У меня было много разных вариантов но в конце мне удалось свести количество нод к двум: **ng_ether** и **ng_bpf**.\\
 +**ng_ether** — имеет несколько хуков: __lower__ — это вход/​выход сетевого адаптера,​ __upper__ — ввод/​выход в сетевой стёк OS.\\
 +**ng_bpf** — программируемая нода, общий смысл программ:​ один вход и два выхода:​ пакет соответствует заданному условии и для пакетов которые не соответствуют. В ноде есть собственный ассемблер для матчинга пакетов. Но можно написать условия для tcpdump и получить код для **ng_bpf**.\\
 +Не большая хитрость ноды в том, что программа устанавливается на входную ноду. Но ноды которые указаны как выходные тоже могут принимать пакеты и обрабатывать они их будут по тем программам которые ассоциированы с ними.\\
 +
 +==== Передача пакетов ====
 {{:​ru:​software:​freebsd:​ng_bpf_bridge.png|}}\\ {{:​ru:​software:​freebsd:​ng_bpf_bridge.png|}}\\
 **BPF** настроен таким образом чтобы пропускать все без исключения пакеты с __upper__ хуков **ng_ether** нод на __lower__ хуки (пакеты от системы в сеть). Приходящие из сети пакеты с __lower__ хуков нод проверяются в **BPF**, и\\ **BPF** настроен таким образом чтобы пропускать все без исключения пакеты с __upper__ хуков **ng_ether** нод на __lower__ хуки (пакеты от системы в сеть). Приходящие из сети пакеты с __lower__ хуков нод проверяются в **BPF**, и\\
Строка 31: Строка 37:
  
  
-===== Тонкости ===== +==== Фильтры ​==== 
-1. Пришлось включить **promisc** режим на обоих интерфейсах, иначе ​мультикаст ​дропается самим сетевым адаптером, это нормальное поведение.+IGMP (IPv4) подпадает под такой фильтр в tcpdump:​\\ 
 +<​code>​ether[0] & 1 1 and (ether[0:4] !0xffffffff or ether[4:2] !0xffff) and ip[9] 2</​code>​ 
 +где:\\ 
 +**ether[0] & = 1** — проверяем первый байт эзернет пакета, там dst mac адрес, если его первый бит = 1 то пакет multicast или broadcast\\ 
 +**(ether[0:4] != 0xffffffff or ether[4:2] != 0xffff)** — здесь проверяем что dst mac пакета ​не broadcast ff:​ff:​ff:​ff:​ff:​ff. Делается за два сравнения:​ первое сравнение 4 байта ​и второе два. Сравнивать 6 байт в одной операции нельзя, ассемблер!\\ 
 +**ip[9] = 2** — Проверяем что IP proto = IGMP\\ 
 +**ether** — означает что смещение и длинна считаются относительно эзернет заголовка, при этом ​сам bpf не знает если в пакете эзернет заголовок или же он начинается с чего то другого.\\ 
 +ip — это смещение относительно эзернет заголовкапримерно эквивалентно: ip[9] = ether[23], где 23 = 14 + 9, 14 — размер эзернет заголовка. Ещё оно проверяет что ether[12:2] = IP.\\ 
 +В случае инкапсуляции в VLAN придётся переписывать условия.\\
  
-2. Пришлось включить **autosrc** ​на интерфейсе в сети провайдера, тк у провайдера на коммутаторе настроен ​Port Security ​на пропускание только одного MAC адреса ​первого изученного на порту после поднятия линка.+Теперь получим ассемблерный код для bpf: 
 +<​code>​tcpdump -i em0 -s 65535 -ddd '​ether[0] & 1 = 1 and ( ether[0:4] != 0xffffffff or ether[4:2] != 0xffff ) and ip[9] = 2'</​code>​ 
 +(имя интерфейса указывать не обязательно,​ но возможны ошибки тк не все ​интерфейсы в системе могут работать с tcpdump а берёт первый попавшийся):\\ 
 +<​code> ​   13 
 +    48 0 0 0 
 +    84 0 0 1 
 +    21 0 9 1 
 +    32 0 0 0 
 +    21 0 2 4294967295 
 +    40 0 0 4 
 +    21 5 0 65535 
 +    40 0 0 12 
 +    21 0 3 2048 
 +    48 0 0 23 
 +    21 0 1 2 
 +    6 0 0 65535 
 +    6 0 0 0</​code>​ 
 +Это и нужно скармливать в ng_bpf чтобы отделить IGMP (IPv4) от всего остального.\\ 
 + 
 +IGMP (IPv4) + UDP (IPv4) в tcpdump: 
 +<​code>​ether[0] & 1 = 1 and (ether[0:4] != 0xffffffff or ether[4:2] != 0xffff) and (ip[9] = 17 or ip[9] = 2)</​code>​ 
 +Всё аналогичноip[9] = 17 — IP proto = UDP.\\ 
 + 
 +И чтобы ​просто пересылать с upper хуков в lower я использовал такое:\\ 
 +<​code>​bpf_prog_len=1 bpf_prog=[ { code=6 jt=0 jf=0 k=0 } ]</​code>​ 
 +Это одно строчная «программа» для BPF всегда возвращает NotMatch. 
 + 
 + 
 +==== Тонкости ==== 
 +1. Адаптеры нужно перевести в «не ​разборчивый» = promisc режим, иначе они аппаратно отфильтрую весь мультикат,​ тк OS не настраивала его ​пропускание.\\ 
 +<​code>​ngctl msg ${IF_UPSTREAM}:​ setpromisc 1 ngctl msg ${IF_DOWNSTREAM}:​ setpromisc 1</​code>​ 
 + 
 +2. autosrc на WAN интерфейсе ​лучше включить. Таким образом все отбриджованные пакеты будут улетать провайдеру с мак ​адресом WAN адаптера. Это особенно актуально когда ​провайдер включает __Port Security__ ​и задаёт ​лимит в один адрес. 
 +<​code>​ngctl msg ${IF_UPSTREAM}:​ setautosrc 1</​code>​
  
 3. Моему провайдеру нет дела до того какой src-ip в IP приходит от меня, если бы было, то я бы попробовал гнать трафик в сторону провайдера через **ng_patch** ноду, которая бы заменяла src-ip на нужны, и выставляла CSUM_IP и CSUM_UDP в заголовке пакета - есть шанс что драйвер сетевого адаптера сам рассчитает эти суммы либо что оборудование провайдера проигнорирует неверную контрольную сумму в IGMP пакетах от меня. Нода также подключается обоими хуками к BPF, выход настраивается на passtrouth (пересылку всех пакетов) на __lower__ хук __ng_ether__ на адаптере в сети провайдера,​ а вход __ng_patch__ должен быть //match// выходом от __lower__ на адаптере в локальной сети. Те совсем не большая модификация графа. 3. Моему провайдеру нет дела до того какой src-ip в IP приходит от меня, если бы было, то я бы попробовал гнать трафик в сторону провайдера через **ng_patch** ноду, которая бы заменяла src-ip на нужны, и выставляла CSUM_IP и CSUM_UDP в заголовке пакета - есть шанс что драйвер сетевого адаптера сам рассчитает эти суммы либо что оборудование провайдера проигнорирует неверную контрольную сумму в IGMP пакетах от меня. Нода также подключается обоими хуками к BPF, выход настраивается на passtrouth (пересылку всех пакетов) на __lower__ хук __ng_ether__ на адаптере в сети провайдера,​ а вход __ng_patch__ должен быть //match// выходом от __lower__ на адаптере в локальной сети. Те совсем не большая модификация графа.
Строка 42: Строка 89:
  
 ===== История ===== ===== История =====
-igmpproxy и mrouted у меня работать отказалисьпосле нескольких часов проб, чтения и новых проб я решил не заниматься ремонтом ядра и этих приложений,​ а просто выборочно сбриджевать два сетевых интерфейса:​\\ +igmpproxy и mrouted у меня работать отказались: PF по умолчанию убивает все пакеты с IP опциями в заголовке (IGMP они нужны для работы) и поэтому нужно добавлять правило:​ 
- **IGMP** на multicast адреса из локалки в сеть провайдера и обратно;​\\ +<​code>​pass quick proto igmp from any to 224.0.0.0/4 allow-opts</​code>​ 
- **UDP** на multicast адреса из сети провайдера в локалку. Броадкаст не нужен, и направляется в ядро как обычно.\\+а я этого не сделал.\\ 
 +После нескольких часов проб, чтения и новых проб я решил не заниматься ремонтом ядра и этих приложений,​ а просто выборочно сбриджевать два сетевых интерфейса:​\\ 
 +  ​* ​**IGMP** на multicast адреса из локалки в сеть провайдера и обратно;​ 
 +  ​* ​**UDP** на multicast адреса из сети провайдера в локалку. Броадкаст не нужен, и направляется в ядро как обычно.
  
 Несмотря на цифру 2, по сути эта третья версия графа, получившая в результате оптимизации первых двух.\\ Несмотря на цифру 2, по сути эта третья версия графа, получившая в результате оптимизации первых двух.\\
-* Первая содержала **ng_ether**,​ **ng_tee**, **ng_one2many**,​ **ng_bpf**.\\ +  ​* Первая содержала **ng_ether**,​ **ng_tee**, **ng_one2many**,​ **ng_bpf**. 
-* Вторая содержала **ng_ether**,​ <​del>​ng_tee</​del>,​ **ng_one2many**,​ **ng_bpf**.\\ +  * Вторая содержала **ng_ether**,​ <​del>​ng_tee</​del>,​ **ng_one2many**,​ **ng_bpf**. 
-* Окончательная содержит:​ **ng_ether**,​ <​del>​ng_left2right,</​del>​ <​del>​ng_tee,</​del>​ **ng_bpf**.\\+  * Окончательная содержит:​ **ng_ether**,​ <​del>​ng_left2right,</​del>​ <​del>​ng_tee,</​del>​ **ng_bpf**.
 В первых двух версиях создавалась копия пакета,​ и один уходил через мост в другую сеть либо отбрасывался,​ а второй попадал в ядро. Поскольку ядро всё равно их дропало где то внутри и нетграф их очень много отбрасывал,​ ничего полезного не делая, то я решил их вообще туда не посылать и организовать так чтобы не создавать дубликатов и не уничтожать пакеты.\\ В первых двух версиях создавалась копия пакета,​ и один уходил через мост в другую сеть либо отбрасывался,​ а второй попадал в ядро. Поскольку ядро всё равно их дропало где то внутри и нетграф их очень много отбрасывал,​ ничего полезного не делая, то я решил их вообще туда не посылать и организовать так чтобы не создавать дубликатов и не уничтожать пакеты.\\
- * Добавлено опционально использование **ng_hub** - для режима когда мультикаст/​игмп трафик попадает в сетевой стёк.+  ​* Добавлено опционально использование **ng_hub** - для режима когда мультикаст/​игмп трафик попадает в сетевой стёк.
  
  
Строка 57: Строка 107:
 ===== PS ===== ===== PS =====
 Для создания аналогичного по функционалу моста, в котором будет несколько сетевых интерфейсов в разных сетях с мультикастом и несколько сетевых адаптеров в сетях куда его нужно переправить потребуется на каждый сетевой адаптер вешать по **ng_split** + **ng_one2many** и по одной **ng_one2many** с каждой стороны моста для рассылки копий мультикаста на все интерфейсы. __upper__ хуки **ng_ether** нод по прежнему будут напрямую подключатся к BPF. В случае нескольких сетей - источников мультикаста будет ещё проблема с возможным перекрытием адресных пространств,​ которую можно частично разрешить настроив в BPF фильтрацию по адресам. Для создания аналогичного по функционалу моста, в котором будет несколько сетевых интерфейсов в разных сетях с мультикастом и несколько сетевых адаптеров в сетях куда его нужно переправить потребуется на каждый сетевой адаптер вешать по **ng_split** + **ng_one2many** и по одной **ng_one2many** с каждой стороны моста для рассылки копий мультикаста на все интерфейсы. __upper__ хуки **ng_ether** нод по прежнему будут напрямую подключатся к BPF. В случае нескольких сетей - источников мультикаста будет ещё проблема с возможным перекрытием адресных пространств,​ которую можно частично разрешить настроив в BPF фильтрацию по адресам.
 +
 +
 +===== Ссылки =====
 +[[http://​www.freebsd.org/​cgi/​man.cgi?​query=ng_bpf&​apropos=0&​sektion=4&​manpath=FreeBSD+9.2-RELEASE&​arch=default&​format=html|man ng_bpf]]\\
 +[[http://​nuclight.livejournal.com/​124989.html?​nojs=1|Как работает tcpdump: ассемблер BPF; фильтрация с ng_bpf на FreeBSD]]\\
 +[[http://​citrin.ru/​freebsd:​ng_ipfw_ng_bpf|Использование ng_ipfw + ng_bpf для фильтрации по телу пакета]]\\
 +[[http://​nuclight.livejournal.com/​122098.html?​nojs=1|Программирование ng_bpf(4) и L7 filtering на FreeBSD]]\\
ru/software/freebsd/igmpproxy_on_netgraph.1431598321.txt.gz · Последние изменения: 2015/05/14 10:12 — root