Ethernet-туннель с помощью OpenVPN
2016-02-08 05:19 pmOpenVPN — это программное решение для организации шифрованного проброса через интернет трафика между вашими локальными сетями. Он поддерживает два режима: tun и tap.
Режим "tun" легче настроить, однако он умеет передавать только IP-пакеты с NAT-трансляцией (что недостаточно для работы сетевых дисков Windows, плохо подходит для SIP-телефонии, RTSP-видеонаблюдения и т.д.).
Режим "tap" передаёт Ethernet-кадры независимо от содержимого (IPv4, IPv6, ARP/RARP, NetBIOS, IPX/SPX, STP, всё что угодно) и представляет собой как бы разделённый свитч, один порт которого "тут", а второй — "там". Никакой NAT-трансляции, по VPN-у в обе стороны свободно гуляет широковещательный UDP трафик, ICMP и всё остальное, очень удобно. Единственный недостаток режима "tap" — его сложно настроить (об этом сразу честно предупреждает официальное руководство по OpenVPN). В интернете мало информации, она противоречивая, неполная, устаревшая.
У нас есть два клиента, которые подключаются к интернету по IPv4, и возможно находятся за провайдерским NAT (cgNAT). Т.е. у них динамические серые IP-адреса. Также у нас есть сервер (dedicated или VPS), который имеет статический белый IPv4-адрес. Через этот сервер клиенты обмениваются трафиком друг с другом, но не ходят в интернет.
Все компьютеры в локальной сети имеют IP-адреса 172.21.13.N и маску подсети 255.255.255.0. Все компьютеры из первой локальной подсети (N<128) имеет свободный доступ друг к другу, а также ко всем комьютерам из второй локальной подсети (N>=128). Так же и в обратную сторону.
Наш сервер будет VPSкой под управлением FreeBSD 10. Клиенты — FreeBSD 10 (выделенный сервер, архитектура amd64) и Linux (архитектура mips, а точнее dd-wrt vpn edition на WRT54GL). Клиентам этого VPN'а вовсе не обязательно быть маршрутизаторами в своих подсетях, они могут быть обычными рядовыми хостами.
Для разнообразия — под Windows. Качаем дистрибутив OpenVPN, при установке не забываем отметить птичкой скрипты EasyRSA. Всё это хозяйство находится в папке "C:\Program Files (x86)\OpenVPN\easy-rsa". Остальное удобно делать из Far.
Переименовываем vars.bat.sample в vars.bat, там же правим "set HOME=%ProgramFiles%\OpenVPN\easy-rsa" -> "set HOME=C:\Program Files (x86)\OpenVPN\easy-rsa" и добавляем в начало "set PATH=C:\Program Files (x86)\OpenVPN\bin;%PATH%". По ходу можно подкорректировать переменные KEY_ на более осмысленные, чтобы не вводить потом каждый раз вручную одно и то же. Далее удаляем файл "init-config.bat", а в начало всех остальных добавляем строчку "call vars.bat".
Сначала инициализируем хранилище ключей, затем учреждаем новый центр сертификации, затем генерируем параметры Диффи-Хеллмана, и только после этого собственно генерируем ключи для сервера и обоих клиентов. Как видите, всё просто, это же EasyRSA:
Country, Province, City, Org должны содержать любой совпадающий между ключами бред, и желательно покороче, например код вашей страны по ISO 3166 Alpha-2. Email, Common Name, Name, Org.Unit должны немножко отличаться между ключами, например для Email: ca@myvpn server@myvpn client1@myvpn client2@myvpn. Никто вам почту на эти e-mail'ы слать не будет и резолвить домены в Common Name — тоже. Все пароли, связанные с экспортом ключей, должны быть пусты. Если запутаетесь или сделаете что-то неправильно — не пытайтесь исправлять, начинайте сначала.
Напоследок понадобится ключик для TLS-авторизации. Перейдите в "C:\Program Files (x86)\OpenVPN\bin" и оттуда дайте команду:
Результат ваших усилий — папка "C:\Program Files (x86)\OpenVPN\easy-rsa\keys". Её следует заархивировать, всё остальное — можно снести.
В интернете полно советов, как сделать конфигурацию OpenVPN-сервера в tap-режиме, но для чего-то все они используют какие-то IP-адреса в настройках со стороны сервера. При чём тут к L2-мосту IP-адреса — я так и не понял, наверное это какие-то наркоманы копипастят разный бред друг у друга. IP-адреса в L2 не нужны, потому что на уровне 2 модели OSI по сети ходят не пакеты, а кадры. Кадр (фрейм) ethernet может нести в себе IPv4-пакет, а может нести и что-то совсем другое, например IPv6, ARP/RARP, STP, NetBIOS (весь этот L2-трафик заканчивается на ближайшем маршрутизаторе).
Второй важный момент касается опции client-to-client. Её можно указывать, тогда OpenVPN-сервер будет работать как мост (программный свитч) между клиентами, а можно и не указывать, тогда клиенты не будут видеть друг друга. Недостаток этой опции в том, что tcpdump, запущенный на tap-интерфейсе сервера не видит межклиентский трафик, т.к. OpenVPN-сервер не отправляет его операционной системе. Лично я предпочитаю вариант с запуском двух openvpn-серверов на двух разных tap-интерфейсах с организацией моста между ними силами операционной системы. Если что-то не работает на клиентах — можно запустить tcpdump на сервере и весь трафик как на ладони.
Третий нюанс заключается в том, что tap-интерфейсы, которые открыл OpenVPN, по умолчанию выключены (находятся в состоянии down). Их должен включать (переводить в up) специальный up-скрипт, вызываемый openvpn'ом.
Также есть сюрпризы, связанные с протоколом STP. "В мирное время" этот малоприметный протокол используют свитчи для исключения циклов в топологии Ethernet. Если между двумя свитчами нашлось более одного пути, тогда свитч во избежание network congestion на время блокирует один из своих портов. Когда происходит пересоздание сетевых интерфейсов tap и bridge, у них меняются MAC-адреса, что (с точки зрения стационарных свитчей по обе стороны тоннеля) эквивалентно наличию другого пути в L2-топологии и может приводить к затыку трафика на несколько минут. Чтобы этого не происходило, MAC-адреса tap'ов и бриджей вдоль всего пути необходимо зафиксировать.
Ещё один момент связан с фильтрацией трафика, который не должен проникать на другую сторону тоннеля. Напомню, работа tap-интерфейса основана на том, что каждый из VPN-клиентов по обе стороны тоннеля переводит свою сетевую карту (Ethernet или Wi-Fi) в promiscuous mode и начинает слышать весь L2-трафик в своей подсети. Тот L2-трафик, который не должен передаваться на другую сторону тоннеля, теоретически, должен отсекаться как физическими свитчами в обеих подсетях, так и bridge-драйвером операционной системы (программным свитчом между сетевой картой и tap-интерфейсом OpenVPN). Но так происходит не всегда. Иногда, по каким-то лунным причинам, драйвер бриджа почему-то решает зациклить в тоннель openvpn-трафик, идущий во внешний интернет. Разумеется, сервер, который оказался в таком состоянии, нуждается в перезагрузке. Во избежание подобных спецэффектов, бриджи на клиентах крайне желательно зафайерволлить. Это называется filtered bridge и работает так: пространство IPv4-адресов всей сети делится надвое, а затем создаются правила файерволла, которые разрешают межсетевой локальный трафик через бридж, а весь остальной IPv4-трафик — запрещают. При этом ARPы и прочее L2-only продолжают циркулировать свободно во всех направлениях.
Изменения в файле автозагрузки /etc/rc.conf:
Виртуальные сетевые карты tap0, tap1 и мостик между ними создаются и настраиваются ещё при загрузке сервера, чтобы не делать лишних движений при (пере)запуске серверных процессов OpenVPN.
Замените 4 последних байта в MAC-адресах на случайные числа.
В папке /usr/local/etc/openvpn_myvpn/keys/ находятся ключи — ca.crt, dh1024.pem, server.crt, server.key и ta.key.
Файл настроек сервера: /usr/local/etc/openvpn_myvpn/server1.conf ### server2.conf:
Пара комментариев: как видите, никаких IP-адресов и никто не умер; шифроалгоритмы побыстрее, ключи покороче, выключение LZO — это потому, что один из клиентов — Linksys WRT54GL; {snd,rcv}buf 0 — это старый, хорошо известный хак; verb 1 — это для того, чтобы логи были покороче, на время отладки следует поставить verb 4; порты 21766 и 28737 — это просто случайные числа.
Скрипты по управлению tap-интерфейсами на сервере:
/usr/local/etc/openvpn_myvpn/up.sh:
/usr/local/etc/openvpn_myvpn/down.sh:
Подготовка ключей: понадобятся файлы ca.crt, client1.p12 и ta.key. Они должны быть скопированы в папку /usr/local/etc/openvpn.
В /boot/loader.conf следует добавить:
В /etc/sysctl.conf следует добавить:
Вопреки популярным рекомендациям из других источников, net.link.bridge.ipfw=1 делать не надо — пакетики попадают в файерволл и счётчики тикают, но драйвер бриджа игнорирует запреты файерволла.
Хотя ifconfig умеет автоматически загружать модули ядра if_bridge.ko и bridgestp.ko при создании первого моста, мы организуем их одновременную загрузку вместе с ядром для того, чтобы настройки из файла /etc/sysctl.conf не отработали вхолостую (переменные net.link.bridge.* не существуют до загрузки модуля ядра if_bridge.ko).
В /etc/rc.conf следует добавить:
Мы создаём виртуальную сетевую карту tap0 и связываем её с реальной re0 в мост bridge0 ещё при загрузке клиента, чтобы при каждом обрыве клиентского OpenVPN-подключения не происходил перевод re0 в promiscuous mode и обратно. Заодно, при каждом обрыве клиентского OpenVPN-подключения бридж не будет забывать свой кэш MAC-адресов по обе стороны тоннеля.
Внимание: ваша сетевая карта может называться не re0, а em0 или как-то ещё; см. вывод ifconfig. В таком случае понадобится соответствующая замена.
Замените 4 последних байта в MAC-адресах на случайные числа.
Вопреки популярным рекомендациям из других источников, gateway_enable="YES" ни на что в нашем случае не влияет и не обязателен.
Правила файерволла /etc/firewall.rules:
Комментарий: убираем из тоннеля IPv6-сквозняки (например, винда что-то постоянно дрючит на 1900 порту в широковещательном режиме), разрешаем IPv4 между подсетями и UDP broadcast, остальное — фтопку. Отдельно запрещаем прохождение DHCP-запросов и ответов через бридж, чтобы локальные хосты не получали динамические IP-адреса от DHCP-серверов с другой стороны тоннеля, и наоборот.
Посмотреть счётчики файерволла можно с помощью команды ipfw -a list.
Посмотреть трафик через тоннель можно с помощью команды tcpdump -i tap0.
Файл настроек клиента: /usr/local/etc/openvpn/client.conf
Как видите, никаких IP-адресов и никто не умер. Параметры resolv-retry infinite, connect-retry-max infinite и auth-retry nointeract крайне полезны на клиентской стороне, от них ваши волосы станут здоровыми и шелковистыми.
Скрипты по управлению tap-интерфейсом на первом клиенте:
/usr/local/etc/openvpn/up.sh:
/usr/local/etc/openvpn/down.sh:
Подготовка ключей: понадобятся файлы ca.crt, client2.crt, client2.key и ta.key (dd-wrt не понимает файлы .p12). Из client2.crt следует выбросить всё, кроме base64-кодированного блока, ограниченного строками с префиксом ---, после чего он будет называться cert.pem. Файл client2.key после аналогичных манипуляций будет называться key.pem.
Ключи заливаются через web-интерфейс, на вкладке "Службы — PPTP — OpenVPN — OpenVPN Daemon". ca.crt идёт в поле "Public Server Cert", cert.pem в "Public Client Cert", key.pem в "Private Client Key", ta.key в "OpenVPN TLS Auth", а openvpn.conf в "OpenVPN Config".
Кстати, вот он:
Ваши ключики вместе с up/down-скриптами и конфигом лежат в папке /tmp/openvpn/ ; порт 5001 обязателен для того, чтобы видеть статус OpenVPN-подключения в web-интерфейсе роутера (на вкладке "Статус — OpenVPN").
Для автоматической перезаписи файлов /tmp/openvpn/route-{up,down}.sh на наш манер и для управления бриджем с файерволлом понадобится соорудить вот такой скрипт автозагрузки. Он вводится через web-интерфейс, вкладка "Тех.обслуживание — Команды — Параметры запуска":
Фокус с переводом часов нужен потому, что тупая железка, если не увидит NTP-сервер на WAN-интерфейсе в момент загрузки, не увидит его уже никогда и останется в 1970 году, по поводу чего библиотека OpenSSL в составе OpenVPN начнёт хныкать, что дата выдачи клиентского сертификата ещё не наступила, и OpenVPN никуда не подключится. Угомоните тупорылое создание путём подстановки любой даты позже даты генерации ключей.
Мост br0 существует априори между WiFi-интерфейсом и Ethernet-интерфейсом, поэтому мы просто добавляем tap0 к уже существующему мосту. При этом, правила фильтрации, очевидно, пишутся для tap0, а не для br0. Хотя Linux всё равно их применяет к другим интерфейсам, входящим в состав моста, отсюда их "разрешительная по умолчанию" природа.
Впрочем, это же Linux, так что виртуальный сетевой интерфейс tap0 какого-то лешего отваливается от моста br0, время от времени. Почему так происходит — х.з., но если приговнокодить watchdog (см. выше), то вроде всё нормально работает.
Наш файервол не пытается помешать проникновению внешне-интернетного трафика в тоннель, но это и не нужно, т.к. в данном случае OpenVPN выполняется на роутере, а роутер и так хорошо знает по IP-адресам и маскам на интерфейсах, какой трафик должен направляться на внешний интерфейс, а какой на внутренний.
Статистику файерволла можно смотреть через ssh, командой ipconfig -vL. tcpdump на этом устройстве не поддерживается, остаётся только tcpdump на сервере.
Режим "tun" легче настроить, однако он умеет передавать только IP-пакеты с NAT-трансляцией (что недостаточно для работы сетевых дисков Windows, плохо подходит для SIP-телефонии, RTSP-видеонаблюдения и т.д.).
Режим "tap" передаёт Ethernet-кадры независимо от содержимого (IPv4, IPv6, ARP/RARP, NetBIOS, IPX/SPX, STP, всё что угодно) и представляет собой как бы разделённый свитч, один порт которого "тут", а второй — "там". Никакой NAT-трансляции, по VPN-у в обе стороны свободно гуляет широковещательный UDP трафик, ICMP и всё остальное, очень удобно. Единственный недостаток режима "tap" — его сложно настроить (об этом сразу честно предупреждает официальное руководство по OpenVPN). В интернете мало информации, она противоречивая, неполная, устаревшая.
1. Сетевая топология
У нас есть два клиента, которые подключаются к интернету по IPv4, и возможно находятся за провайдерским NAT (cgNAT). Т.е. у них динамические серые IP-адреса. Также у нас есть сервер (dedicated или VPS), который имеет статический белый IPv4-адрес. Через этот сервер клиенты обмениваются трафиком друг с другом, но не ходят в интернет.
Все компьютеры в локальной сети имеют IP-адреса 172.21.13.N и маску подсети 255.255.255.0. Все компьютеры из первой локальной подсети (N<128) имеет свободный доступ друг к другу, а также ко всем комьютерам из второй локальной подсети (N>=128). Так же и в обратную сторону.
Наш сервер будет VPSкой под управлением FreeBSD 10. Клиенты — FreeBSD 10 (выделенный сервер, архитектура amd64) и Linux (архитектура mips, а точнее dd-wrt vpn edition на WRT54GL). Клиентам этого VPN'а вовсе не обязательно быть маршрутизаторами в своих подсетях, они могут быть обычными рядовыми хостами.
2. Генерация ключей
Для разнообразия — под Windows. Качаем дистрибутив OpenVPN, при установке не забываем отметить птичкой скрипты EasyRSA. Всё это хозяйство находится в папке "C:\Program Files (x86)\OpenVPN\easy-rsa". Остальное удобно делать из Far.
Переименовываем vars.bat.sample в vars.bat, там же правим "set HOME=%ProgramFiles%\OpenVPN\easy-rsa" -> "set HOME=C:\Program Files (x86)\OpenVPN\easy-rsa" и добавляем в начало "set PATH=C:\Program Files (x86)\OpenVPN\bin;%PATH%". По ходу можно подкорректировать переменные KEY_ на более осмысленные, чтобы не вводить потом каждый раз вручную одно и то же. Далее удаляем файл "init-config.bat", а в начало всех остальных добавляем строчку "call vars.bat".
Сначала инициализируем хранилище ключей, затем учреждаем новый центр сертификации, затем генерируем параметры Диффи-Хеллмана, и только после этого собственно генерируем ключи для сервера и обоих клиентов. Как видите, всё просто, это же EasyRSA:
clean-all.bat build-ca.bat build-dh.bat build-key-server.bat server build-key-pkcs12.bat client1 build-key-pkcs12.bat client2
Country, Province, City, Org должны содержать любой совпадающий между ключами бред, и желательно покороче, например код вашей страны по ISO 3166 Alpha-2. Email, Common Name, Name, Org.Unit должны немножко отличаться между ключами, например для Email: ca@myvpn server@myvpn client1@myvpn client2@myvpn. Никто вам почту на эти e-mail'ы слать не будет и резолвить домены в Common Name — тоже. Все пароли, связанные с экспортом ключей, должны быть пусты. Если запутаетесь или сделаете что-то неправильно — не пытайтесь исправлять, начинайте сначала.
Напоследок понадобится ключик для TLS-авторизации. Перейдите в "C:\Program Files (x86)\OpenVPN\bin" и оттуда дайте команду:
openvpn.exe --genkey --secret ..\easy-rsa\keys\ta.key
Результат ваших усилий — папка "C:\Program Files (x86)\OpenVPN\easy-rsa\keys". Её следует заархивировать, всё остальное — можно снести.
3. Подводные камни
В интернете полно советов, как сделать конфигурацию OpenVPN-сервера в tap-режиме, но для чего-то все они используют какие-то IP-адреса в настройках со стороны сервера. При чём тут к L2-мосту IP-адреса — я так и не понял, наверное это какие-то наркоманы копипастят разный бред друг у друга. IP-адреса в L2 не нужны, потому что на уровне 2 модели OSI по сети ходят не пакеты, а кадры. Кадр (фрейм) ethernet может нести в себе IPv4-пакет, а может нести и что-то совсем другое, например IPv6, ARP/RARP, STP, NetBIOS (весь этот L2-трафик заканчивается на ближайшем маршрутизаторе).
Второй важный момент касается опции client-to-client. Её можно указывать, тогда OpenVPN-сервер будет работать как мост (программный свитч) между клиентами, а можно и не указывать, тогда клиенты не будут видеть друг друга. Недостаток этой опции в том, что tcpdump, запущенный на tap-интерфейсе сервера не видит межклиентский трафик, т.к. OpenVPN-сервер не отправляет его операционной системе. Лично я предпочитаю вариант с запуском двух openvpn-серверов на двух разных tap-интерфейсах с организацией моста между ними силами операционной системы. Если что-то не работает на клиентах — можно запустить tcpdump на сервере и весь трафик как на ладони.
Третий нюанс заключается в том, что tap-интерфейсы, которые открыл OpenVPN, по умолчанию выключены (находятся в состоянии down). Их должен включать (переводить в up) специальный up-скрипт, вызываемый openvpn'ом.
Также есть сюрпризы, связанные с протоколом STP. "В мирное время" этот малоприметный протокол используют свитчи для исключения циклов в топологии Ethernet. Если между двумя свитчами нашлось более одного пути, тогда свитч во избежание network congestion на время блокирует один из своих портов. Когда происходит пересоздание сетевых интерфейсов tap и bridge, у них меняются MAC-адреса, что (с точки зрения стационарных свитчей по обе стороны тоннеля) эквивалентно наличию другого пути в L2-топологии и может приводить к затыку трафика на несколько минут. Чтобы этого не происходило, MAC-адреса tap'ов и бриджей вдоль всего пути необходимо зафиксировать.
Ещё один момент связан с фильтрацией трафика, который не должен проникать на другую сторону тоннеля. Напомню, работа tap-интерфейса основана на том, что каждый из VPN-клиентов по обе стороны тоннеля переводит свою сетевую карту (Ethernet или Wi-Fi) в promiscuous mode и начинает слышать весь L2-трафик в своей подсети. Тот L2-трафик, который не должен передаваться на другую сторону тоннеля, теоретически, должен отсекаться как физическими свитчами в обеих подсетях, так и bridge-драйвером операционной системы (программным свитчом между сетевой картой и tap-интерфейсом OpenVPN). Но так происходит не всегда. Иногда, по каким-то лунным причинам, драйвер бриджа почему-то решает зациклить в тоннель openvpn-трафик, идущий во внешний интернет. Разумеется, сервер, который оказался в таком состоянии, нуждается в перезагрузке. Во избежание подобных спецэффектов, бриджи на клиентах крайне желательно зафайерволлить. Это называется filtered bridge и работает так: пространство IPv4-адресов всей сети делится надвое, а затем создаются правила файерволла, которые разрешают межсетевой локальный трафик через бридж, а весь остальной IPv4-трафик — запрещают. При этом ARPы и прочее L2-only продолжают циркулировать свободно во всех направлениях.
4. Конфигурация сервера
Изменения в файле автозагрузки /etc/rc.conf:
cloned_interfaces="tap0 tap1 bridge0" ifconfig_tap0="ether 00:bd:2e:29:2a:00 up" ifconfig_tap1="ether 00:bd:d0:1d:2a:01 up" ifconfig_bridge0="ether 02:52:e1:21:58:00 addm tap0 addm tap1" openvpn_myvpn1_enable="YES" openvpn_myvpn1_configfile="/usr/local/etc/openvpn_myvpn/server1.conf" openvpn_myvpn1_dir="/usr/local/etc/openvpn_myvpn" openvpn_myvpn2_enable="YES" openvpn_myvpn2_configfile="/usr/local/etc/openvpn_myvpn/server2.conf" openvpn_myvpn2_dir="/usr/local/etc/openvpn_myvpn"
Виртуальные сетевые карты tap0, tap1 и мостик между ними создаются и настраиваются ещё при загрузке сервера, чтобы не делать лишних движений при (пере)запуске серверных процессов OpenVPN.
Замените 4 последних байта в MAC-адресах на случайные числа.
В папке /usr/local/etc/openvpn_myvpn/keys/ находятся ключи — ca.crt, dh1024.pem, server.crt, server.key и ta.key.
Файл настроек сервера: /usr/local/etc/openvpn_myvpn/server1.conf ### server2.conf:
proto tcp-server port 21766 ### port 28737 dev tap0 ### dev tap1 script-security 2 up /usr/local/etc/openvpn_myvpn/up.sh down /usr/local/etc/openvpn_myvpn/down.sh mode server cipher BF-CBC ca /usr/local/etc/openvpn_myvpn/keys/ca.crt cert /usr/local/etc/openvpn_myvpn/keys/server.crt key /usr/local/etc/openvpn_myvpn/keys/server.key dh /usr/local/etc/openvpn_myvpn/keys/dh1024.pem tls-auth /usr/local/etc/openvpn_myvpn/keys/ta.key 0 tls-server tls-timeout 120 auth SHA1 comp-lzo no keepalive 10 120 max-clients 32 sndbuf 0 rcvbuf 0 status /var/log/openvpn/openvpn-myvpn1-status.log ### status /var/log/openvpn/openvpn-myvpn2-status.log log /var/log/openvpn/openvpn-myvpn1.log ### log /var/log/openvpn/openvpn-myvpn2.log verb 1
Пара комментариев: как видите, никаких IP-адресов и никто не умер; шифроалгоритмы побыстрее, ключи покороче, выключение LZO — это потому, что один из клиентов — Linksys WRT54GL; {snd,rcv}buf 0 — это старый, хорошо известный хак; verb 1 — это для того, чтобы логи были покороче, на время отладки следует поставить verb 4; порты 21766 и 28737 — это просто случайные числа.
Скрипты по управлению tap-интерфейсами на сервере:
/usr/local/etc/openvpn_myvpn/up.sh:
#!/usr/local/bin/bash echo "*** Up script called for interface $1 ***" /sbin/ifconfig $1 up
/usr/local/etc/openvpn_myvpn/down.sh:
#!/usr/local/bin/bash echo "*** Down script called for interface $1 ***"
5. Конфигурация первого клиента (FreeBSD), сеть 172.21.13.0/25
Подготовка ключей: понадобятся файлы ca.crt, client1.p12 и ta.key. Они должны быть скопированы в папку /usr/local/etc/openvpn.
В /boot/loader.conf следует добавить:
if_bridge_load="YES" bridgestp_load="YES" if_tap_load="YES"
В /etc/sysctl.conf следует добавить:
net.inet.ip.fw.one_pass=0 net.link.bridge.pfil_bridge=1
Вопреки популярным рекомендациям из других источников, net.link.bridge.ipfw=1 делать не надо — пакетики попадают в файерволл и счётчики тикают, но драйвер бриджа игнорирует запреты файерволла.
Хотя ifconfig умеет автоматически загружать модули ядра if_bridge.ko и bridgestp.ko при создании первого моста, мы организуем их одновременную загрузку вместе с ядром для того, чтобы настройки из файла /etc/sysctl.conf не отработали вхолостую (переменные net.link.bridge.* не существуют до загрузки модуля ядра if_bridge.ko).
В /etc/rc.conf следует добавить:
cloned_interfaces="tap0 bridge0" ifconfig_tap0="ether 00:bd:7e:56:62:00 up" ifconfig_bridge0="ether 02:00:87:54:a9:00 addm tap0 addm re0" firewall_enable="YES" firewall_type="/etc/firewall.rules" firewall_logging="YES" openvpn_enable="YES" openvpn_configfile="/usr/local/etc/openvpn/client.conf" openvpn_dir="/usr/local/etc/openvpn"
Мы создаём виртуальную сетевую карту tap0 и связываем её с реальной re0 в мост bridge0 ещё при загрузке клиента, чтобы при каждом обрыве клиентского OpenVPN-подключения не происходил перевод re0 в promiscuous mode и обратно. Заодно, при каждом обрыве клиентского OpenVPN-подключения бридж не будет забывать свой кэш MAC-адресов по обе стороны тоннеля.
Внимание: ваша сетевая карта может называться не re0, а em0 или как-то ещё; см. вывод ifconfig. В таком случае понадобится соответствующая замена.
Замените 4 последних байта в MAC-адресах на случайные числа.
Вопреки популярным рекомендациям из других источников, gateway_enable="YES" ни на что в нашем случае не влияет и не обязателен.
Правила файерволла /etc/firewall.rules:
add 10 deny ipv6 from any to any via bridge0 add 11 deny udp from any to any 67,68 via bridge0 add 12 allow udp from 172.21.13.0/24 to 172.21.13.255 via bridge0 add 13 allow udp from 172.21.13.0/24 to 255.255.255.255 via bridge0 add 14 allow ipv4 from 172.21.13.0/25 to 172.21.13.128/25 via bridge0 add 15 allow ipv4 from 172.21.13.128/25 to 172.21.13.0/25 via bridge0 add 16 deny all from any to any via bridge0 add 60000 allow all from any to any
Комментарий: убираем из тоннеля IPv6-сквозняки (например, винда что-то постоянно дрючит на 1900 порту в широковещательном режиме), разрешаем IPv4 между подсетями и UDP broadcast, остальное — фтопку. Отдельно запрещаем прохождение DHCP-запросов и ответов через бридж, чтобы локальные хосты не получали динамические IP-адреса от DHCP-серверов с другой стороны тоннеля, и наоборот.
Посмотреть счётчики файерволла можно с помощью команды ipfw -a list.
Посмотреть трафик через тоннель можно с помощью команды tcpdump -i tap0.
Файл настроек клиента: /usr/local/etc/openvpn/client.conf
proto tcp-client dev tap0 remote myvpn.example.com 21766 nobind resolv-retry infinite connect-timeout 10 connect-retry-max infinite auth-retry nointeract pkcs12 /usr/local/etc/openvpn/keys/client1.p12 ns-cert-type server # Require peer to be server cipher BF-CBC tls-client tls-auth /usr/local/etc/openvpn/keys/ta.key 1 tls-timeout 120 auth SHA1 comp-lzo no keepalive 10 120 sndbuf 0 rcvbuf 0 script-security 2 up /usr/local/etc/openvpn/up.sh down /usr/local/etc/openvpn/down.sh status /var/log/openvpn/openvpn-status.log log /var/log/openvpn/openvpn.log verb 1
Как видите, никаких IP-адресов и никто не умер. Параметры resolv-retry infinite, connect-retry-max infinite и auth-retry nointeract крайне полезны на клиентской стороне, от них ваши волосы станут здоровыми и шелковистыми.
Скрипты по управлению tap-интерфейсом на первом клиенте:
/usr/local/etc/openvpn/up.sh:
#!/usr/local/bin/bash echo "*** Up script called for interface $1 ***" /sbin/ifconfig $1 up
/usr/local/etc/openvpn/down.sh:
#!/usr/local/bin/bash echo "*** Down script called for interface $1 ***"
6. Конфигурация второго клиента (Linux dd-wrt), сеть 172.21.13.128/25
Подготовка ключей: понадобятся файлы ca.crt, client2.crt, client2.key и ta.key (dd-wrt не понимает файлы .p12). Из client2.crt следует выбросить всё, кроме base64-кодированного блока, ограниченного строками с префиксом ---, после чего он будет называться cert.pem. Файл client2.key после аналогичных манипуляций будет называться key.pem.
Ключи заливаются через web-интерфейс, на вкладке "Службы — PPTP — OpenVPN — OpenVPN Daemon". ca.crt идёт в поле "Public Server Cert", cert.pem в "Public Client Cert", key.pem в "Private Client Key", ta.key в "OpenVPN TLS Auth", а openvpn.conf в "OpenVPN Config".
Кстати, вот он:
proto tcp-client dev tap0 remote myvpn.example.com 28737 nobind resolv-retry infinite connect-timeout 10 connect-retry-max infinite script-security 2 up /tmp/openvpn/route-up.sh down /tmp/openvpn/route-down.sh auth-retry nointeract ca /tmp/openvpn/ca.crt cert /tmp/openvpn/cert.pem key /tmp/openvpn/key.pem ns-cert-type server # Require peer to be server cipher BF-CBC tls-client tls-auth /tmp/openvpn/ta.key 1 tls-timeout 120 auth SHA1 comp-lzo no keepalive 10 120 sndbuf 0 rcvbuf 0 verb 1 management localhost 5001
Ваши ключики вместе с up/down-скриптами и конфигом лежат в папке /tmp/openvpn/ ; порт 5001 обязателен для того, чтобы видеть статус OpenVPN-подключения в web-интерфейсе роутера (на вкладке "Статус — OpenVPN").
Для автоматической перезаписи файлов /tmp/openvpn/route-{up,down}.sh на наш манер и для управления бриджем с файерволлом понадобится соорудить вот такой скрипт автозагрузки. Он вводится через web-интерфейс, вкладка "Тех.обслуживание — Команды — Параметры запуска":
/usr/sbin/openvpn --mktun --dev tap0 /sbin/ifconfig tap0 hw ether 00:FF:05:30:A3:88 /sbin/ifconfig tap0 up /usr/sbin/iptables -I INPUT -i tap0 -j ACCEPT /usr/sbin/iptables -I INPUT -i tap0 -s 172.21.13.0/25 -d 172.21.13.0/25 -j DROP /usr/sbin/iptables -I INPUT -i tap0 -s 172.21.13.128/25 -d 172.21.13.128/25 -j DROP /usr/sbin/iptables -I OUTPUT -o tap0 -j ACCEPT /usr/sbin/iptables -I OUTPUT -o tap0 -s 172.21.13.0/25 -d 172.21.13.0/25 -j DROP /usr/sbin/iptables -I OUTPUT -o tap0 -s 172.21.13.128/25 -d 172.21.13.128/25 -j DROP /sbin/ifconfig br0 hw ether 00:22:6B:95:8D:71 /usr/sbin/brctl addif br0 tap0 /sbin/ifconfig br0 up if [ $(date | grep -c 'UTC 19') -gt 0 ]; then date 2016.02.08-18:00 fi echo "#!/bin/sh" > /tmp/openvpn/route-up.sh echo "/sbin/ifconfig tap0 up" >> /tmp/openvpn/route-up.sh chmod +x /tmp/openvpn/route-up.sh echo "#!/bin/sh" > /tmp/openvpn/route-down.sh chmod +x /tmp/openvpn/route-down.sh echo "#!/bin/sh" > /tmp/openvpn/watchdog.sh echo "while true; do" >> /tmp/openvpn/watchdog.sh echo ' if [ $(/usr/sbin/brctl show br0 | grep -c tap0) -eq 0 ]; then' >> /tmp/openvpn/watchdog.sh echo " /usr/sbin/brctl addif br0 tap0" >> /tmp/openvpn/watchdog.sh echo " fi" >> /tmp/openvpn/watchdog.sh echo " sleep 5" >> /tmp/openvpn/watchdog.sh echo "done" >> /tmp/openvpn/watchdog.sh chmod +x /tmp/openvpn/watchdog.sh /tmp/openvpn/watchdog.sh &
Фокус с переводом часов нужен потому, что тупая железка, если не увидит NTP-сервер на WAN-интерфейсе в момент загрузки, не увидит его уже никогда и останется в 1970 году, по поводу чего библиотека OpenSSL в составе OpenVPN начнёт хныкать, что дата выдачи клиентского сертификата ещё не наступила, и OpenVPN никуда не подключится. Угомоните тупорылое создание путём подстановки любой даты позже даты генерации ключей.
Мост br0 существует априори между WiFi-интерфейсом и Ethernet-интерфейсом, поэтому мы просто добавляем tap0 к уже существующему мосту. При этом, правила фильтрации, очевидно, пишутся для tap0, а не для br0. Хотя Linux всё равно их применяет к другим интерфейсам, входящим в состав моста, отсюда их "разрешительная по умолчанию" природа.
Впрочем, это же Linux, так что виртуальный сетевой интерфейс tap0 какого-то лешего отваливается от моста br0, время от времени. Почему так происходит — х.з., но если приговнокодить watchdog (см. выше), то вроде всё нормально работает.
Наш файервол не пытается помешать проникновению внешне-интернетного трафика в тоннель, но это и не нужно, т.к. в данном случае OpenVPN выполняется на роутере, а роутер и так хорошо знает по IP-адресам и маскам на интерфейсах, какой трафик должен направляться на внешний интерфейс, а какой на внутренний.
Статистику файерволла можно смотреть через ssh, командой ipconfig -vL. tcpdump на этом устройстве не поддерживается, остаётся только tcpdump на сервере.