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 revisionBoth sides next revision
software:freebsd:igmpproxy_on_netgraph [2015/07/18 23:14]
– [История] root
software:freebsd:igmpproxy_on_netgraph [2022/02/04 18:32]
– removed - external edit (Unknown date) 127.0.0.1
Line 1: Line 1:
-====== Замена igmpproxy на netgraph ====== 
  
-Скрипт собирающий netgraph мост для мультикаст трафика (IGMP, UDP) между двумя сетевыми интерфейсами предназначен для замены igmpproxy/mrouted.\\ 
-[[http://www.netlab.linkpc.net/download/software/FreeBSD/mcastbridge/mcastbr2.sh|mcastbr2.sh]] 
- 
-Обсуждения:\\ 
-[[http://lists.freebsd.org/pipermail/freebsd-net/2011-December/030643.html|FreeBSD maillist]]\\ 
-[[http://www.opennet.ru/tips/2649_multicast_proxy_igmp_freebsd_netgraph.shtml|На OpenNet]]\\ 
- 
- 
-===== Использование ===== 
-Создать мост между em0 и re0, где re0 подключён к сети с мультикастом: 
-<code>mcastbr2.sh start re0 em0</code> 
-или если нужно чтобы трафик попадал в сетевой стёк ОС, как было до установки моста: 
-<code>mcastbr2.sh start re0 em0 enable</code> 
- 
-Удалить мост: 
-<code>mcastbr2.sh stop re0 em0</code> 
- 
- 
-===== Принцип работы ===== 
-==== netgraph ==== 
-Его можно сравнить с LUA: он даёт широкие возможности по манипуляции с сетевыми пакетами, относительно прост в использовании и максимально быстр тк всё происходит в ядре.\\ 
-У меня было много разных вариантов но в конце мне удалось свести количество нод к двум: **ng_ether** и **ng_bpf**.\\ 
-**ng_ether** — имеет несколько хуков: __lower__ — это вход/выход сетевого адаптера, __upper__ — ввод/выход в сетевой стёк OS.\\ 
-**ng_bpf** — программируемая нода, общий смысл программ: один вход и два выхода: пакет соответствует заданному условии и для пакетов которые не соответствуют. В ноде есть собственный ассемблер для матчинга пакетов. Но можно написать условия для tcpdump и получить код для **ng_bpf**.\\ 
-Не большая хитрость ноды в том, что программа устанавливается на входную ноду. Но ноды которые указаны как выходные тоже могут принимать пакеты и обрабатывать они их будут по тем программам которые ассоциированы с ними.\\ 
- 
-==== Передача пакетов ==== 
-{{:ru:software:freebsd:ng_bpf_bridge.png|}}\\ 
-**BPF** настроен таким образом чтобы пропускать все без исключения пакеты с __upper__ хуков **ng_ether** нод на __lower__ хуки (пакеты от системы в сеть). Приходящие из сети пакеты с __lower__ хуков нод проверяются в **BPF**, и\\ 
- - если это мультикаст; 
- - и не броадкаст; 
- - и **IGMP** [или **UDP** в случае если пакет от адаптера подключённого к провайдеру] 
-то такой пакет целиком пересылается на __lower__ хук другого адаптера, минуя сетевой стёк операционной системы. 
-Либо пакет пересылается на хук **ng_hub** откуда одна копия уходит на __upper__ хук этого же адаптера, а другая на __lower__ хук противоположного адаптера. 
- 
- 
-==== Фильтры ==== 
-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 = 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 придётся переписывать условия.\\ 
- 
-Теперь получим ассемблерный код для 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__ на адаптере в локальной сети. Те совсем не большая модификация графа. 
- 
-4. Работает на vlan интерфейсах. 
- 
- 
-===== История ===== 
-igmpproxy и mrouted у меня работать отказались: PF по умолчанию убивает все пакеты с IP опциями в заголовке (IGMP они нужны для работы) и поэтому нужно добавлять правило: 
-<code>pass quick proto igmp from any to 224.0.0.0/4 allow-opts</code> 
-а я этого не сделал.\\ 
-После нескольких часов проб, чтения и новых проб я решил не заниматься ремонтом ядра и этих приложений, а просто выборочно сбриджевать два сетевых интерфейса:\\ 
-  * **IGMP** на multicast адреса из локалки в сеть провайдера и обратно; 
-  * **UDP** на multicast адреса из сети провайдера в локалку. Броадкаст не нужен, и направляется в ядро как обычно. 
- 
-Несмотря на цифру 2, по сути эта третья версия графа, получившая в результате оптимизации первых двух.\\ 
-  * Первая содержала **ng_ether**, **ng_tee**, **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_hub** - для режима когда мультикаст/игмп трафик попадает в сетевой стёк. 
- 
- 
- 
-===== PS ===== 
-Для создания аналогичного по функционалу моста, в котором будет несколько сетевых интерфейсов в разных сетях с мультикастом и несколько сетевых адаптеров в сетях куда его нужно переправить потребуется на каждый сетевой адаптер вешать по **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