Linux bridge + хочется странного
Доброго времени суток!
Имеем следующую задачу:
Хост A: удаленный сервер (в реальности, дешевая виртуальная машина в
облаке) с выделенным белым IP адресом A.A.A.A. На хосте запущен
openvpn сервер в режиме моста, т.е., предполагается тунеллирование
трафика канального уровня (ethernet трафика). Кроме openvpn на
сервере запущен еще sshd. Никаких других сервисов на А запускать на
предполагается.
Конфигурация сети на A:
# The bridged primary network interface
auto br0
iface br0 inet static
bridge_ports eth0
bridge_stp off
address A.A.A.A
netmask 255.255.255.0
broadcast A.A.A.255
gateway A.A.A.1
# The persistent tap interface
auto tap0
iface tap0 inet manual
up openvpn --mktun --dev tap0
up brctl addif br0 tap0
up ip link set dev tap0 up
up /etc/network/ebtables
down openvpn --rmtun --dev tap0
down /etc/network/ebtables
Интерфейс eth0 смотрит в локалку облака. tap0 смотрит в openvpn
туннель.
Хост B: локальный хост с доступом в инет, на котором запущен openvpn
клиент. Целеполагается, что при поднятии VPN туннеля до А хост В будет
в основном ходить в интернет через туннель (за исключением того, что
до самого хоста A он должен, ессно, ходить через физический
интерфейс).
Настройки сети на В (упрощены для ясности):
# The primary network interface
iface eth0 inet dhcp
metric 10
# The tunnel
iface tap0 inet static
address A.A.A.A
netmask 255.255.255.0
broadcast A.A.A.255
gateway A.A.A.1
dns-nameservers 208.67.222.222 208.67.220.220
pre-up /etc/network/fix-routes-to-hosts 192.0.2.1
pre-down /etc/network/fix-routes-to-hosts
Интерфейс eth0 - физический, смотрит в инет. Интерфейс tap0
поднимается при запуске openvpn на B и смотрит в туннель. Да, это не
опечатка, на хосте В интерфейсу tap0 присваивается _тот же_ IP адрес,
что и у br0 на A. Такой странности хочется, чтобы в результате
a) иметь на tap0 на B белый IP адрес и избежать IP NAT на A;
б) представляться в локалке облака неотличимым клоном A;
в) ну и на самом деле просто потому, что интересно.
Чтобы при такой настройке можно было на хосте B отличить А от
локального интерфейса, на В делается следующее:
Вывод iptables-save (часть)
-------------------------------------------------------------------------
*rawpost
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -d 192.0.2.1/32 -j RAWDNAT --to-destination A.A.A.A/32
COMMIT
*raw
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A PREROUTING -s A.A.A.A/32 -j RAWSNAT --to-source 192.0.2.1/32
COMMIT
-------------------------------------------------------------------------
(RAWSNAT в prerouting и RAWDNAT в postrouting доступны с
xtables-addons; объяснять почему нужно именно так, а стандартные SNAT
и DNAT здесь не годятся, я не буду, оставлю как задачку на
сообразительность)
То есть, для хоста B хост A виден, как 192.0.2.1 (этот адрес из
зарезервированного в IANA диапазона, реальных хостов с такими адресами
не существует).
Скрипт /etc/network/fix-routes-to-hosts добавляет нужный маршрут до
192.0.2.1 в таблицу маршрутизации на В (маршрут идет через физический
интерфейс eth0; извне хоста В, dst ip = A.A.A.A). Это нужно, так как
при поднятии tap0 появляется дефолтовый маршрут c меньшей метрикой,
идущий через tap0, и все IP пакеты будут заворачивать туда, а не в
eth0.
Возвращаемся к настройкам сервера A. Необходимо сделать так, чтобы TCP
пакеты, идущие из инета на 22-ой порт на A.A.A.A, доставлялись
локальному (на А) sshd. Также, UDP пакеты, идущие на 443-й порт,
должны доставляться привязанному к этому порту локальному (на А)
openvpn-у. Весь остальной трафик, включая трафик канального уровня,
входящий в A через eth0, должен перенаправляться в openvpn туннель и
"выныривать" на tap0 на хосте В, так что хост B эффективно оказывается
в локальной сети облака. При этом, ethernet фреймы адресованные A,
должны выглядеть, как адресованные напрямую B.
Обратно, весь ethernet трафик, идущий по туннелю от B к A, должен
выйти из eth0 на A и выглядеть, как исходящий непосредственно от A.
Так мы не напоремся на antispoofing protection в облаке.
Делаем это с помощью ebtables:
--
Stanislav
Reply to: