Site Tools


software:freebsd:igmpproxy_on_netgraph

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Next revisionBoth sides next revision
software:freebsd:igmpproxy_on_netgraph [2015/05/14 10:12]
– [Использование] root
software:freebsd:igmpproxy_on_netgraph [2015/05/15 15:20]
– [netgraph] root
Line 2: Line 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]]\\
  
  
Line 15: Line 14:
 или если нужно чтобы трафик попадал в сетевой стёк ОС, как было до установки моста: или если нужно чтобы трафик попадал в сетевой стёк ОС, как было до установки моста:
 <code>mcastbr2.sh start re0 em0 enable</code> <code>mcastbr2.sh start re0 em0 enable</code>
- 
  
 Удалить мост: Удалить мост:
Line 22: Line 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**, и\\
Line 31: Line 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__ на адаптере в локальной сети. Те совсем не большая модификация графа.
Line 42: Line 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** - для режима когда мультикаст/игмп трафик попадает в сетевой стёк.
  
  
Line 57: Line 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]]\\
software/freebsd/igmpproxy_on_netgraph.txt · Last modified: 2022/02/05 05:30 by root