Skip to content

Виртуальная лаба в домашних условиях. Часть 1: Сеть

На новогодних каникулах появилось, наконец, свободное время, чтобы заняться домашним сервером. Вместо Ubuntu 12.04 LTS был установлен VMWare ESXi 6.5, а сама система была разделена на несколько виртуалок, каждая под свою задачу.
С контейнерами пока решил не связываться – я пока не могу придумать реальную задачу, чтобы ради неё засесть за изучение Docker или LXC. Так что у нас будет классика – Debian 8 с последними апдейтами, свежая VMWare и Mikrotik (“железный”) в качестве роутера для всего этого счастья.

0. Disclaimer

Для начала о том, чего тут НЕ будет.
– Здесь не будет описываться установка VMWare или Debian
– Здесь не будет описываться настройка Mikrotik “с нуля”
– Здесь не будет описываться установка пакетов через apt (будь то ansible, zabbix или apache)
Я предполагаю, что компетенция моих читателей достаточна для того, чтобы не только прочитать всё то, что написано ниже, но и применять на практике с умом и пониманием, что вообще делается и для чего.

1. Связь. Настройка аплинков, failover, nat

С чего начинается лаба? Правильно, с сети. У меня в наличии роутер Mikrotik, два интернет-провайдера и некоторое количество клиентов, часть из которых – собственно сервер с виртуалками, часть – обычная домашняя сеть.
Разделять локалку на подсети не будем (пока), без ipv6 тоже обойдемся (хотя в будущем, разумеется, попробуем). Зато сделаем балансировку трафика (виртуалки должны ходить через резервный канал связи по умолчанию) и failover. А т.к. у меня на виртуалках есть ресурсы, опубликованные в интернет, то хотелось бы иметь к ним доступ изнутри сети, не заморачиваясь с перенастройкой DNS.
Нечто похожее я описывал 4,5 года назад в своей статье про policy-based routing на Mikrotik. С тех пор утекло много воды (и версий ROS), так что пользоваться ip rule уже не модно – гораздо проще маркировать пакеты с помощью mangle-цепочки фаервола.

1.1 Два провайдера: балансировка нагрузки

Имеем: два провайдера.
Один из них отдаёт нам честный белый ip-адрес по DHCP. Его мы будем использовать для доступа к виртуалкам снаружи и выпуска самих виртуалок в инет. Для остальных клиентов в локалке он является резервным.
Второй провайдер интернет даёт через l2tp-подключение, и выделенный ip не предоставляет. Его мы будем использовать для всей остальной локалки, как основной, и резервный для виртуалок. В принципе, можно даже настроить DynDNS, чтобы не терять связи с виртуалками в случае падения первого канала. Но не будем пытаться объять необъятное и впихнуть невпихуемое.
Основная задача – настроить автоматическое переключение между каналами в случае падения одного из линков.

Начальная конфигурация:
Активируем dhcp-клиенты на интерфейсах, куда включены провайдеры (у меня это первый и пятый порты)

ip dhcp-client
1
2
3
4
5
/ip dhcp-client option
add code=55 name=parameter_request_list value=0x01F90321062A
/ip dhcp-client
add add-default-route=no comment=BeeLine dhcp-options=parameter_request_list disabled=no interface=ether1-gateway
add comment=Skynet default-route-distance=10 dhcp-options=hostname,clientid disabled=no interface=ether5-slave-local

Поднимаем l2tp-сессию с оператором:

interface l2tp-client
1
2
/interface l2tp-client
add add-default-route=yes allow=chap connect-to=tp.internet.beeline.ru disabled=no keepalive-timeout=disabled max-mru=1420 max-mtu=1420 name=l2tp-beeline password=Aa123456789 profile=ppp-profile-beeline user=0123456789

Настраиваем роутинг. Т.к. нам нужно иметь два активных маршрута, то используем routing-mark. Да, маршруты придётся дублировать с теми, что прилетели по dhcp, а что делать?
В некоторых мануалах по настройке мультипровайдерной конфигурации советуют использовать директиву check-gateway в вариантe arp или ping. Это разумно, но нужно быть внимательным – шлюз провайдера на icmp-запросы отвечать, в общем случае, не обязан.

ip route
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/ip route
#Дефолтные маршруты. Для каждой марки их две, т.к. нам нужно проверять оба шлюза и выпускать трафик тоже через обоих.
add distance=1 gateway=128.75.224.1 routing-mark=route_to_bee
add distance=100 gateway=94.20.244.1 routing-mark=route_to_bee
add distance=1 gateway=94.20.244.1 routing-mark=route_to_sky
add distance=100 gateway=128.75.224.1 routing-mark=route_to_sky

#Маршруты на внутрисеть провайдера, который является основным для локалки (у меня это билайн)
add distance=1 dst-address=10.0.0.0/8 gateway=10.75.64.1 routing-mark=route_to_bee
add distance=1 dst-address=78.107.196.0/22 gateway=10.75.64.1 routing-mark=route_to_bee
add distance=1 dst-address=85.21.0.0/24 gateway=10.75.64.1 routing-mark=route_to_bee
add distance=1 dst-address=85.21.59.0/24 gateway=10.75.64.1 routing-mark=route_to_bee
add distance=1 dst-address=85.21.192.0/24 gateway=10.75.64.1 routing-mark=route_to_bee
add distance=1 dst-address=89.179.76.0/24 gateway=10.75.64.1 routing-mark=route_to_bee
add distance=1 dst-address=213.234.192.0/24 gateway=10.75.64.1 routing-mark=route_to_bee

#Маршруты на внутрисеть второго провайдера (для торрентов будет полезно, чтобы почём зря не грузить l2tp-подключение)
add distance=1 dst-address=93.100.0.0/16 gateway=94.20.244.1 routing-mark=route_to_sky
add distance=1 dst-address=94.19.0.0/16 gateway=94.20.244.1 routing-mark=route_to_sky
add distance=1 dst-address=188.242.0.0/15 gateway=94.20.244.1 routing-mark=route_to_sky

#Специальные маршруты до DNS-серверов и l2tp-терминаторов Билайн, чтобы соединение, ненароком, не установилось через другого провайдера
add distance=1 dst-address=83.102.254.223/32 gateway=10.75.64.1
add distance=100 dst-address=83.102.254.223/32 type=blackhole
add distance=1 dst-address=83.102.255.55/32 gateway=10.75.64.1
add distance=100 dst-address=83.102.255.55/32 type=blackhole
add distance=1 dst-address=85.21.192.3/32 gateway=10.75.64.1
add distance=1 dst-address=213.234.192.8/32 gateway=10.75.64.1

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

ip firewall mangle
1
2
3
4
5
6
7
8
9
10
11
12
/ip firewall mangle
add action=mark-connection chain=input in-interface=l2tp-beeline new-connection-mark=conn_bee passthrough=no
add action=mark-connection chain=input in-interface=ether5-slave-local new-connection-mark=conn_sky passthrough=no

add action=mark-routing chain=output connection-mark=conn_bee new-routing-mark=route_to_bee passthrough=no
add action=mark-routing chain=output connection-mark=conn_sky new-routing-mark=route_to_sky passthrough=no

#Здесь мы балансируем каналы между потребителями. По умолчанию в SkyNet отправляются виртуалки (address-list "VMs"), а в билайн все остальные (address-list "LAN"). Для сетей обоих провайдеров пакеты маркируются вне зависимости от источника.
add action=mark-routing chain=prerouting comment="Routes to SkyNet LAN" dst-address-list=Skynet new-routing-mark=route_to_sky passthrough=no src-address-list=LAN
add action=mark-routing chain=prerouting comment="Routes to BeeLine LAN" dst-address-list=BeeLine new-routing-mark=route_to_bee passthrough=no src-address-list=LAN
add action=mark-routing chain=prerouting comment="VMs go to Internet over SkyNet by default" new-routing-mark=route_to_sky passthrough=no src-address-list=VMs
add action=mark-routing chain=prerouting comment="LAN go to Internet over BeeLine by default" new-routing-mark=route_to_bee passthrough=no src-address-list=LAN

Правила NAT. Ну тут совсем всё просто: делаем src-nat на всех исходящих интерфейсах (у меня это два eth-интерфейса и l2tp).

ip firewall nat
1
2
3
4
/ip firewall nat
add action=masquerade chain=srcnat comment="NAT to SkyNet" out-interface=ether5
add action=masquerade chain=srcnat comment="NAT to Beeline" out-interface=l2tp-beeline
add action=masquerade chain=srcnat comment="NAT to BeeLine LAN" out-interface=ether1

Осталось только собрать всё это вместе и проверить, что всё работает. Отключить сначала один шнурок, потом второй. Переключение должно произойти автоматически.

В таблице маршрутизации после всех настроек мы увидим примерно следующее (сейчас работают оба провайдера):

ip route print
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Flags: X - disabled, A - active, D - dynamic, C - connect, S - static, r - rip, b - bgp, o - ospf, m - mme, B - blackhole, U - unreachable, P - prohibit
 #      DST-ADDRESS        PREF-SRC        GATEWAY            DISTANCE
 0 A S  0.0.0.0/0                          128.75.224.1              1
 1   S  0.0.0.0/0                          94.20.244.1             100
 2 A S  10.0.0.0/8                         10.75.64.1                1
 3 A S  78.107.196.0/22                    10.75.64.1                1
 4 A S  85.21.0.0/24                       10.75.64.1                1
 5 A S  85.21.59.0/24                      10.75.64.1                1
 6 A S  85.21.192.0/24                     10.75.64.1                1
 7 A S  89.179.76.0/24                     10.75.64.1                1
 8 A S  213.234.192.0/24                   10.75.64.1                1
 9 A S  0.0.0.0/0                          94.20.244.1               1
10   S  0.0.0.0/0                          128.75.224.1            100
11 A S  93.100.0.0/16                      94.20.244.1               1
12 A S  94.19.0.0/16                       94.20.244.1               1
13 A S  188.242.0.0/15                     94.20.244.1               1
14 ADS  0.0.0.0/0                          128.75.224.1              0
15  DS  0.0.0.0/0                          94.20.244.1              10
16 ADC  10.0.10.1/32       10.0.10.2       l2tp-nixman               0
17 ADC  10.75.64.0/21      10.75.64.93     ether1-gateway            0
18 A S  83.102.254.223/32                  10.75.64.1                1
19   SB 83.102.254.223/32                                          100
20 ADS  83.102.255.55/32                   10.75.64.1                0
21   S  83.102.255.55/32                   10.75.64.1                1
22   SB 83.102.255.55/32                                           100
24 A S  85.21.192.3/32                     10.75.64.1                1
25 ADC  94.20.244.0/24     94.20.244.244   ether5-slave-local        0
26 ADC  128.75.224.1/32    128.75.249.101  l2tp-beeline              0
30   S  192.168.1.0/24                     192.168.10.0              1
31 ADC  192.168.88.0/24    192.168.88.1    bridge-local              0
34 A S  213.234.192.8/32                   10.75.64.1                1

1.2 Hairpin NAT в условиях балансировки трафика

Балансировку мы настроили, теперь идем дальше. Некоторые ресурсы, расположенные на виртуалках, опубликованы в инет. Изнутри локалки тоже хотелось бы иметь к ним доступ, и при этом не мудрить с подменой DNS-записей. При обычном DST-NAT у нас ничего не получится – т.к. сервер увидит, что src-ip находится в одной с ним подсети, и просто пошлёт ему ответный пакет, минуя роутер. Таким образом, TCP-соединение не сможет установиться. Чтобы обойти эту проблему, был придуман механизм hairpin NAT, когда при обращении из локалки на внешний ip роутера делается не только DST-NAT, но и SRC-NAT в адрес роутера, смотрящий в локалку.

Настраивается всё это достаточно просто. Для начала, добавляем нужные записи в настройки NAT:

ip firewall nat
1
2
3
4
5
/ip firewall nat
add action=masquerade chain=srcnat comment="HTTP Hairpin" dst-address=192.168.88.189 dst-port=80 out-interface=bridge-local protocol=tcp src-address=192.168.88.0/24
add action=masquerade chain=srcnat comment="HTTPS Hairpin" dst-address=192.168.88.189 dst-port=443 out-interface=bridge-local protocol=tcp src-address=192.168.88.0/24
add action=dst-nat chain=dstnat comment="HTTPS proxy" dst-address=94.20.244.244 dst-port=443 protocol=tcp to-addresses=192.168.88.189 to-ports=443
add action=dst-nat chain=dstnat comment="HTTP proxy" dst-address=94.20.244.244 dst-port=80 protocol=tcp to-addresses=192.168.88.189 to-ports=80
Здесь 192.168.88.189 – это адрес моего прокси-сервера, который уже более “детально” разбирает запросы и раскидывает их по нужным виртуалкам.

В таблице mangle мы добавляем правила hairpin в “исключения” (я просто навесил routing-mark, который нигде более не используется), чтобы они не попадали в правила балансировки исходящего трафика. Эти правила необходимо поместить ДО правил, отвечающих за маркировку пакетов

ip firewall mangle
1
2
3
4
5
6
7
8
/ip firewall mangle
...
add action=mark-packet chain=prerouting comment="Hairpin NAT" dst-address-list=Self new-packet-mark=hairpin passthrough=no src-address-list=LAN
add action=mark-packet chain=prerouting comment="Hairpin NAT" dst-address-list=LAN new-packet-mark=hairpin passthrough=no src-address-list=Self
add action=mark-routing chain=prerouting comment="Routes to SkyNet LAN" dst-address-list=Skynet new-routing-mark=route_to_sky passthrough=no src-address-list=LAN
add action=mark-routing chain=prerouting comment="Routes to BeeLine LAN" dst-address-list=BeeLine new-routing-mark=route_to_bee passthrough=no src-address-list=LAN
add action=mark-routing chain=prerouting comment="VMs go to Internet over SkyNet by default" new-routing-mark=route_to_sky passthrough=no src-address-list=VMs
add action=mark-routing chain=prerouting comment="LAN go to Internet over BeeLine by default" new-routing-mark=route_to_bee passthrough=no src-address-list=LAN

Если у вас есть на роутере еще VPN для качания торрентов доступа, например, к рабочим ресурсам и сетям, то нужно поступить по аналогии и добавить правило, вешающее соответствующий routing-mark:

1
2
3
/ip firewall mangle
...
add action=mark-packet chain=prerouting comment="VPN to Nixman" dst-address-list=VPN new-packet-mark=nixman passthrough=no src-address-list=LAN

В dst-address VPN помещаем ресурсы, к которым мы ходим через VPN.

На этом всё. Сеть мы настроили, теперь можно идти дальше – к настройке reverse proxy, ssl и прочего хозяйства.

Бонус

Бонусом к этой части я оставлю два скрипта, которые существенно ускоряют процесс переключения. Первый определяет шлюз по умолчанию, выданный по l2tp (а он время от времени меняется), и подставляет его в наш маршрут.

system script
1
2
3
4
5
6
7
/system script
add comment="Detect changes of BeeLine gateway IP" name=beegwipchecker owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive source="#default gw in marked route\
    \n:local currbeegwip [/ip route get [find dst-address="0.0.0.0/0" and routing-mark="route_to_bee"] gateway]\
    \n#Detect actual beeline default gw\
    \n:local newbeegwip [/ip route get [find gateway=l2tp-beeline] dst-address]\
    \n:set newbeegwip [:pick \$newbeegwip 0 [:find \$newbeegwip "/"]]\
    \n:if (\$currbeegwip!=\$newbeegwip) do={/ip route set [find dst-address="0.0.0.0/0" and routing-mark="route_to_bee"] gateway=\$newbeegwip}"

Теперь добавляем наш скрипт в шедулер.
Заодно пишем второй – он раз в 30 секунд резолвит имя l2tp-терминатора Билайн через его же DNS-сервер (т.к. при переключении на резервный канал становятся активными его DNS-сервера, и достучаться до точки входа становится невозможно).

system scheduler
1
2
3
4
/system scheduler
add interval=5s name=bee_gwip_checker on-event=beegwipchecker policy=read,write,policy,test,sniff start-date=jan/07/2017 start-time=18:58:42
add comment="Resolve l2tp gateway for beeline" interval=30s name=bee_tp_resolver on-event=":resolve tp.internet.beeline.ru server=213.234.192.8" policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive start-date=jan/08/2017 start-time=02:41:55

Вот теперь точно всё. Ждите следующую серию ;)

2 Comments

  1. Сергей Сергей

    Возможно ли пояснить четвёртый раздел кода с маркировкой по листам. В коде присутствуют три листа: Skynet, который судя из комента должен быть VMs, LAN ну тут всё понятно, и собственно VMs. Можно подробнее пояснить содержание этих листов?

    • Сергей Сергей

      Ну да ещё и address-list=BeeLine. Что перечисляется в листе с именем провайдера?

Leave a Reply

%d bloggers like this: