Заметки про сетевой мост

FreeBSD
Наверно, многие замечали — в Windows существует такая штука — как организация сетевого моста. Выбираются две сетевых карты и из низ получается один сетевой мост. Выглядит так, как будто витую пару из первой сетевой карты скрутили с витой парой второй сетевой карты. И все это дело прекрасно работает. Но это только введение, попробуем разобраться как это работает.

Что же из себя представляет так называемый сетевой мост? Попробуем разобраться. Думаю, все представляют как работает один из базовых элементов ЛВС — коммутатор. В него вставляются хвосты витой пары и все товарищи объединяются в один локальный домен рассылки, или ethernet-сегмент. Компьютер, подключенный в порт 1 может без каких либо проблем обмениваться информацией с компьютером, подключенным к порту 2.
Разумеется, этот свич запоминает, за каким портом закреплен определенный компьютер на основании MAC-адреса. Все элементарно.

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

Представим себе след. картину:

Есть компьюер, у которого существует 4 сетевых интерфейса. Причем не обязательно, что сетевой интерфейс — это сетевая карта, это может спокойно и виртуальный интерфейс.
Теперь добавим виртуальный свич:

bridge0 — это как раз и есть наш сетевой мост. Как и обычный свич, он скоммутировал на себе 4 разных узла.

Теперь попробуем применить эту теорию для решения такой вот задачки:
1. Есть сервер доступа, одним интерфейсом подключенный в интернет, вторым — в нашу ЛВС;
2. Есть удаленный клиент, которому необходимо обеспечить доступ к ресурсам ЛВС;
3. Клиент в ЛВС должен выглядеть так — слово подключен к ethernet-сегменту ЛВС.

Итак, сразу несколько замечаний. Для подключения клиентов — используется OpenVPN. Почему? Легок в настройке, шифрованный трафик и существует под разные платформы. Как устанавливать и настраивать OpenVPN — выходит за рамки этой статьи. Просто сойдемся на том — что он работает, и клиенты подключаются на виртуальный интерфейс tap2. Так же стоит заметить, что на сервере доступа работает фаервол (pf), но об этом позже.
В сервере так же существует сетевой интерфейс vlan102, который подключен к нашей ЛВС, интерфейс vlan101 — который подключен к Интернет.

Приведу рисунок физической топологии:


Логическая топология:

Как видно — добавился интерфейс tap2 и сеть VPN.

Теперь наша задача сводится к тому — чтобы объединить две сети, ЛВС и ВПН. Используя наши знания о сетевых мостах — попробуем это зарисовать:

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

Подготовим сетевой мост, для этого потребуется загрузить модуль if_bridge:
mira# kldload if_bridge

Создаем наш мост:
mira# ifconfig bridge0 create addm vlan102 addm tap2 up
mira# ifconfig bridge0
bridge0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        ether 12:dc:9f:7a:35:0d
        id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15
        maxage 20 holdcnt 6 proto rstp maxaddr 100 timeout 1200
        root id 00:00:00:00:00:00 priority 32768 ifcost 0 port 0
        member: tap2 flags=143<LEARNING,DISCOVER,AUTOEDGE,AUTOPTP>
                ifmaxaddr 0 port 13 priority 128 path cost 2000000
        member: vlan102 flags=143<LEARNING,DISCOVER,AUTOEDGE,AUTOPTP>
                ifmaxaddr 0 port 7 priority 128 path cost 20000

Обратите внимание на слово «up» в конце. По умолчания, мост создается в отключенном состоянии. «up» — как раз его включает (аналогия с кабелем питания на свиче).

Внутри нашей ЛВС используется ip-подсеть 10.2.2.0/23. Выдадим клиенту адрес 10.2.2.48 и посмотрим, все ли заработало как ожидалось, для этого с клиента попробуем пропинговать узел 10.2.2.222. Пинг не пошел ..., пробуем разобраться — смотрим снифером, что творится на ближайшем интерфейсе к клиенту:
[21:24 dk@mira ~]> sudo tcpdump -n -i tap2 icmp
tcpdump: WARNING: tap2: no IPv4 address assigned
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tap2, link-type EN10MB (Ethernet), capture size 68 bytes
21:24:47.468821 IP 10.2.2.48 > 10.2.2.222: ICMP echo request, id 13886, seq 35, length 64
21:24:48.469878 IP 10.2.2.48 > 10.2.2.222: ICMP echo request, id 13886, seq 36, length 64
21:24:49.470676 IP 10.2.2.48 > 10.2.2.222: ICMP echo request, id 13886, seq 37, length 64

Отлично, пакеты до нас долетают.
Теперь посмотрим, проходят ли пакеты через сетевой мост:
[21:27 dk@mira ~]> sudo tcpdump -n -i bridge0 icmp
tcpdump: WARNING: bridge0: no IPv4 address assigned
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on bridge0, link-type EN10MB (Ethernet), capture size 68 bytes
21:27:04.641482 IP 10.2.2.48 > 10.2.2.222: ICMP echo request, id 13886, seq 172, length 64
21:27:05.646513 IP 10.2.2.48 > 10.2.2.222: ICMP echo request, id 13886, seq 173, length 64
21:27:06.651425 IP 10.2.2.48 > 10.2.2.222: ICMP echo request, id 13886, seq 174, length 64

Порядок, пакеты есть.
Смотрим, есть ли пакеты на интерфейсе ЛВС:
[21:27 dk@mira ~]> sudo tcpdump -n -i vlan102 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on vlan102, link-type EN10MB (Ethernet), capture size 68 bytes
^C
0 packets captured
3409 packets received by filter
0 packets dropped by kernel

А пакетов-то и нет… Итак, определили — через сетевой мост пакеты не проходят.
Бегло окинув взглядом man if_bridge узнаем:
When filtering is enabled, bridged packets will
pass through the filter inbound on the originating interface, on the
bridge interface and outbound on the appropriate interfaces.

Когда включена фильтрация ( а по-умолчанию она включена), пакет пробирается по цепочке входящий интерфейс -> сетевой мост -> исходящий интерфейс. Можно сказать, что у нас не просто L2 свич, а полноценный с L3 фильтрацией. Разрешаем в фаерволе проход пакетов по такому маршруту:
pass quick on tap2
pass quick on bridge0
pass quick on vlan102

и еще раз смотрим, что творится в нашем свиче:
mira# tcpdump -n -i bridge0 icmp
tcpdump: WARNING: bridge0: no IPv4 address assigned
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on bridge0, link-type EN10MB (Ethernet), capture size 68 bytes
21:35:45.226275 IP 10.2.2.48 > 10.2.2.222: ICMP echo request, id 13886, seq 690, length 64
21:35:45.226727 IP 10.2.2.222 > 10.2.2.48: ICMP echo reply, id 13886, seq 690, length 64
21:35:46.231187 IP 10.2.2.48 > 10.2.2.222: ICMP echo request, id 13886, seq 691, length 64
21:35:46.231639 IP 10.2.2.222 > 10.2.2.48: ICMP echo reply, id 13886, seq 691, length 64
21:35:47.236188 IP 10.2.2.48 > 10.2.2.222: ICMP echo request, id 13886, seq 692, length 64
21:35:47.236659 IP 10.2.2.222 > 10.2.2.48: ICMP echo reply, id 13886, seq 692, length 64

Отлично, все работает как надо. Но вариант — чтоб под каждого клиента делать исключения в фаервол — не совсем то, что хотелось. Попробуем из нашего L3 свича сделать старенький добрый L2. man if_bridge по этому поводу говорит:
net.link.bridge.pfil_member  Set to 1 to enable filtering on the incoming
                                  and outgoing member interfaces, set to 0 to
                                  disable it.
— фильтрация на интерфейсах сетевого моста (в данном случае — это vlan102 и tap2)
и:
net.link.bridge.pfil_bridge  Set to 1 to enable filtering on the bridge
                                  interface, set to 0 to disable it.
— фильтрация на самом сетевом мосте (в нашем случае — bridge0).
То что надо, превращаем на свич в тупой L2 двумя командами:
mira# sysctl net.link.bridge.pfil_member=0
net.link.bridge.pfil_member: 1 -> 0
mira# sysctl net.link.bridge.pfil_bridge=0
net.link.bridge.pfil_bridge: 1 -> 0

И проверяем, что получилось:
mira# tcpdump -n -i bridge0 icmp
tcpdump: WARNING: bridge0: no IPv4 address assigned
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on bridge0, link-type EN10MB (Ethernet), capture size 68 bytes
21:42:02.548499 IP 10.2.2.48 > 10.2.2.222: ICMP echo request, id 26686, seq 11, length 64
21:42:02.548917 IP 10.2.2.222 > 10.2.2.48: ICMP echo reply, id 26686, seq 11, length 64
21:42:03.549394 IP 10.2.2.48 > 10.2.2.222: ICMP echo request, id 26686, seq 12, length 64
21:42:03.549948 IP 10.2.2.222 > 10.2.2.48: ICMP echo reply, id 26686, seq 12, length 64

Пакеты исправно летают в обе стороны.

Надеюсь, данная заметка внесет некоторую ясность в понимание сетевого моста в ОС FreeBSD :)

0 комментариев

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.