MikroTik. Правильний dst nat при використанні 2-х і більше провайдерів

Приступаючи до виконання завдання я розраховував на легку прогулянку в тіні дубового парку, споглядаючи природу і вдаючись до роздумів… Проте пізніше стало зрозуміло, що це буде тернистий і складний похід крізь гірські річки з підводними каменями, обмерзлими скелями і глибокими печерами.
Через медитації, боротьбу зі стихіями і власною тупістю подолання себе я, все таки, досяг бажаної нірвани.

У цій статті я не тільки надам готовий набір правил, але і постараюся максимально доступно пояснити чому і як саме вони працюють.


Конкретно в моєму випадку, потрібно було налаштувати роутер так, щоб web-сервер в локальній мережі за ним був доступний по IP будь-якого з 3-х провайдерів.

Частина 1.
Для початку пробіжимося по всіх налаштувань, щоб найбільш нетерплячі могли скопипастить не читаючи.

Версія RouterOS:
# oct/11/2016 22:02:32 by RouterOS 6.37.1
# software id = X62B-STGZ

Інтерфейси:
/interface list
add name=WAN
/interface list member
add interface=ISP1 list=WAN
add interface=ISP2 list=WAN
add interface=ISP3 list=WAN

Не пам'ятаю починаючи з якої версії RouterOS з'явилася ця фішка. Вона дозволяє групувати інтерфейси, що дуже зручно (наприклад, у правилах /ip firewall). У мене створена група з 3-х WAN інтерфейсів.
AcidVenom підказав, що в 6.36

IP-адреси (адреси, за зрозумілих причин, «ліві»):
/ip address
add address=192.168.0.1/24 comment=defconf interface=bridge network=192.168.0.0
add address=95.11.29.240/24 interface=ISP1 network=95.11.29.0
add address=5.35.59.162/27 interface=ISP2 network=5.35.59.160
add address=5.98.112.30/30 interface=ISP3 network=5.98.112.28

Роутинг:
/ip route
add distance=1 gateway=95.11.29.254 routing-mark=ISP1-route
add distance=1 gateway=5.35.59.161 routing-mark=ISP2-route
add distance=1 gateway=5.98.112.29 routing-mark=ISP3-route
add check-gateway=ping distance=1 gateway=8.8.8.8
add check-gateway=ping distance=2 gateway=8.8.4.4
add check-gateway=ping distance=3 gateway=1.1.36.3
add distance=1 dst-address=8.8.4.4/32 gateway=5.35.59.161 scope=10
add distance=1 dst-address=8.8.8.8/32 gateway=95.11.29.254 scope=10
add distance=1 dst-address=1.1.36.3/32 gateway=5.98.112.29 scope=10

Для організації Failover'а я налаштував рекурсивні маршрутизацію, детальніше розповім в 2-ої частини.

Firewall (для даної публікації я свідомо наводжу правила, що дозволяють все.
Не робіть так!):

/ip firewall filter
add action=accept chain=forward
add action=accept chain=input
add action=accept chain=output

dst й src nat:
/ip nat firewall
add action=masquerade chain=srcnat out-interface-list=WAN
add action=dst-nat chain=dstnat comment="HTTP" dst-port=80 \
in-interface-list=WAN protocol=tcp to-addresses=192.168.0.83 to-ports=80
add action=dst-nat chain=dstnat comment="HTTPs" dst-port=443 \
in-interface-list=WAN protocol=tcp to-addresses=192.168.0.83 to-ports=443

mangle
/ip firewall mangle
add action=mark-connection chain=input in-interface=ISP1 \
new-connection-mark=ISP1-conn passthrough=yes
add action=mark-routing chain=output connection-mark=ISP1-conn \
new-routing-mark=ISP1-route passthrough=no
add action=mark-connection chain=input in-interface=ISP2 new-connection-mark=\
ISP2-conn passthrough=yes
add action=mark-routing chain=output connection-mark=ISP2-conn \
new-routing-mark=ISP2-route passthrough=no
add action=mark-connection chain=input in-interface=ISP3 \
new-connection-mark=ISP3-conn passthrough=yes
add action=mark-routing chain=output connection-mark=ISP3-conn \
new-routing-mark=ISP3-route passthrough=no
add action=mark-connection chain=forward in-interface=ISP1 \
new-connection-mark=ISP1-conn-f passthrough=no
add action=mark-routing chain=prerouting connection-mark=ISP1-conn-f \
in-interface=new bridge-routing-mark=ISP1-route 
add action=mark-connection chain=forward in-interface=ISP2 \
new-connection-mark=ISP2-conn-f passthrough=no
add action=mark-routing chain=prerouting connection-mark=ISP2-conn-f \
in-interface=new bridge-routing-mark=ISP2-route 
add action=mark-connection chain=forward in-interface=ISP3 \
new-connection-mark=ISP3-conn-f passthrough=no
add action=mark-routing chain=prerouting connection-mark=ISP3-conn-f \
in-interface=new bridge-routing-mark=ISP3-route 

Частина 2.
Розглянемо все це докладніше.

Роутинг:
глянь під спойлер, щоб не гортати
/ip route
add distance=1 gateway=95.11.29.254 routing-mark=ISP1-route
add distance=1 gateway=5.35.59.161 routing-mark=ISP2-route
add distance=1 gateway=5.98.112.29 routing-mark=ISP3-route

add check-gateway=ping distance=1 gateway=8.8.8.8
add check-gateway=ping distance=2 gateway=8.8.4.4
add check-gateway=ping distance=3 gateway=1.1.36.3

add distance=1 dst-address=8.8.4.4/32 gateway=5.35.59.161 scope=10
add distance=1 dst-address=8.8.8.8/32 gateway=95.11.29.254 scope=10
add distance=1 dst-address=1.1.36.3/32 gateway=5.98.112.29 scope=10


/ip route
У перших трьох рядках ми вказуємо default gateway кожного з 3-х наших провайдерів.
Маршрути мають однакову вагу (distance), але працюють у різних таблицях маршрутизації.

Іншими словами, ці маршрути працюють для пакетів промаркованих відповідним тегомrouting-mark). Теги пакетах ми будемо навішувати у /ip firewall mangle (про що я подібно розповім нижче).

Наступні 3 рядки — вказівка маршрутів за замовчуванням в основній таблиці маршрутизації.

Тут варто звернути увагу на:

  1. Параметр distance. Для кожного маршруту різний і, відповідно, вага маршрутів теж різний.

    ISP1 — основний, за ним ISP2 і ISP3 замикає, тобто при відмові провайдера ISP1 працювати будемо через ISP2, якщо і ISP2 спочив у бозі, то за справу візьметься ISP3.

  2. Кілька незрозумілих може бути значення параметра gateway. Як це гугловые DNS і якийсь лівий IP-адреса раптом стали маршрутами по-замовчуванню? Магія полягає в параметрі scope з останніх трьох рядків, а так само в самому механізмі Nexthop lookup.

    Насправді трафік відправиться активного провайдера, а далі той відправить його в Інтернет через свої аплінки.

  3. Про параметрі check-gateway=ping. Суть в тому, що в самій простій схемі побудови Failover, вказуючи check-gateway=ping маршрутах за замовчуванням, ми перевіряємо зв'язок тільки до маршрутизатора провайдера. Якщо ж за маршрутизатором провайдера буде недоступний Інтернет, то ми цього не зрозуміємо. А з допомогою фінта з параметром scope ми перевіряємо зв'язок вже не з провайдером, а дивимося за нього, в Інтернет.
Під спойлером мій докладний переказ/адаптація вікі MikroTik на цю тему.

MikroTik. Nexthop_lookupАнглійська статті http://wiki.mikrotik.com/wiki/Manual:IP/Routeна мій погляд, злегка упорот. Це не Cisco CCNA Exploration, який читається на одному диханні, але я постараюся перевести її уривок максимально зрозуміло. Якщо десь побачите таку ж упоротость, поправте мене, будь ласка.

По-перше, визначимося з деякими термінами.
Nexthop — наступний стрибок, якщо дослівно. Наступний шлюз/роутер/маршрутизатор на шляху проходження пакету з точки А(від мого роутера, наприклад) в точку Б (припустимо до гуглового DNS 8.8.8.8), тобто наступний транзитний ділянку, на якій буде оброблятися пакет. У перекладі буде використовуватися словосполучення «наступний хоп» (вибачте за англицизм).

Immediate nexthop — наступний шлюз/роутер/маршрутизатор на шляху проходження пакету з точки А в точку Б, доступний безпосередньо. Для мого домашнього MikroTik, з маршрутом по-замовчуванню:

dst-address=0.0.0.0/0 gateway=89.189.163.1 gateway-status=89.189.163.1 reachable via ether1-gateway

89.189.163.1 — це і є immediate nexthop, т. к. він доступний через ether1-gateway. У перекладі буде використовуватися словосполучення «безпосередньо доступний наступний хоп».

Connected route — пов'язаний маршрут. Маршрут, шлюз якого доступний безпосередньо.

Gateway — шлюз/роутер/маршрутизатор.
Я буду користуватися всіма трьома варіантами перекладу.

scope — Використовується у механізмі пошуку наступного хопу, тобто вирішення якої ж хоп стане наступним. Потрібний маршрут може бути вибраний тільки серед маршрутів, значення scope яких менше або дорівнює значенню target-scope. Значення за замовчуванням залежать від протоколу:

  • пов'язані маршрути: 10 (якщо інтерфейс запущений(running))
  • OSPF, RIP, MME маршрути: 20
  • статичні маршрути: 30
  • BGP маршрути: 40
  • пов'язані маршрути: 200 (якщо інтерфейс не запущений)
target-scope — Використовується у механізмі пошуку наступного хопу, тобто вирішення якої ж хоп стане наступним. Це максимальне значення параметра scope для маршруту, за допомогою якого може бути знайдений наступний хоп. Для iBGP значення встановлено у 30 за замовчуванням.

Табличка значень обох параметрів.



Пошук наступного хопу.
Пошук наступного хопу є частиною процесу вибору маршруту.

Маршрутам, що знаходяться в FIB, потрібен інтерфейс, відповідний кожному з адрес шлюзів. Адреса наступного хопу-шлюзу повинен бути безпосередньо доступний через цей інтерфейс. Інтерфейс, який слід використовувати для здійснення вихідного пакету кожному з шлюзів, знаходиться за допомогою пошуку наступного хопу.

Деякі маршрути (наприклад, iBGP), в якості адреси шлюзу, можуть мати адреса належить маршрутизатору, який розташований через кілька стрибків-шлюзів від нашого MikroTik. Для установки таких маршрутів в FIB необхідно знайти адресу шлюзу, доступного безпосередньо (an immediate nexthop), тобто безпосередньо від нас, який і буде використовуватися для досягнення адреси шлюзу у цьому маршруті. Безпосередній адреса наступного хопу також може бути знайдений за допомогою механізму пошуку наступного хопу.

Пошук наступного хопу виконується тільки в основній таблиці маршрутизації main, навіть для маршрутів, що мають відмінне значення параметра routing-mark. Це необхідно для обмеження установки маршрутів, які можуть бути використані для пошуку безпосередньо доступних хоперів (immediate nexthops). У маршрутах для протоколів RIP або OSPF передбачається, що наступний маршрутизатор доступний безпосередньо і повинен бути знайдені використовуючи тільки пов'язані маршрути(connected routes).

Маршрути з ім'ям інтерфейсу в якості шлюзу не використовуються у пошуку наступного хопу. Якщо є маршрут з ім'ям інтерфейсу, а також маршрут з активним IP-адресою, то маршрут з інтерфейсом ігнорується.

Маршрути, які мають значення параметра scope більше максимально допустимого не використовуються у пошуку наступного хопу. У кожному маршруті вказується максимально допустиме значення параметра scope, для його наступного хопу, у параметрі target-scope. Значення за замовчуванням для цього параметра дозволяє виконати пошук наступного хопу тільки через пов'язані маршрути (connected routes), за винятком iBGP-маршрутів, які мають більше значення за замовчуванням і можуть виконати пошук наступного хопу також через IGP і статичні маршрути.



Інтерфейс і адреса наступного безпосередньо доступного маршрутизатора вибираються ґрунтуючись на результатах пошуку наступного хопу:

  • Якщо найбільш точний активний маршрут, який був виявлений в ході пошуку адреси наступного хопу, є пов'язаним маршрутом, то інтерфейс цього пов'язаного маршруту використовується як інтерфейс наступного хопу і шлюз позначається як reachable. Після того як маршрутизатор стає безпосередньо доступним через цей інтерфейс (саме це і слід розуміти як «пов'язаний маршрут» або «connected route») його адресу використовується як адреса безпосередньо доступного маршрутизатора (immediate nexthop address).

  • Якщо найбільш точний активний маршрут, який був виявлений в ході пошуку адреси наступного хопу, має адресу шлюзу, який уже був виявлений, безпосередньо доступний хоп і інтерфейс копіюються з цього маршруту, а шлюз позначається як recursive.

  • Якщо найбільш точний активний маршрут, який був виявлений в ході пошуку адреси наступного хопу є ECMP маршрутом, то використовується перший доступний маршрутизатор цього маршруту.

  • Якщо механізм пошуку адреси наступного хопу не знайшов ні одного маршруту, то шлюз позначається як unreachable.
А тепер, як кажуть у КВК, навіщо ж я показав цей номер. Зверніть увагу, ми встановлюємо scope=10 для статичних маршрутів в останніх трьох рядках, тим самим «змушуємо» MikroTik брати до уваги ці маршрути при пошуку наступного хопу.

Він і приймає, і таким чином маршрути за замовчуванням через:

  • 8.8.8.8
  • 8.8.4.4
  • 1.1.36.3
стають recursive, тобто безпосередньо доступними хопами будуть шлюзи провайдерів і трафік ми пошлемо через них, але check-gateway=ping буде перевіряти доступність адрес ЗА провайдерськими мережами.

Сподіваюся мій переклад та пояснення будуть вам корисні.

Поки що найбільш охочі до знань читають під спойлером, розповім трохи коротше і простіше.
Коли ми вказуємо scope=10 в останніх трьох рядках, ми даємо зрозуміти MikroTik', що:

  • 8.8.8.8
  • 8.8.4.4
  • 1.1.36.3
йому доступні не безпосередньо, а рекурсивно через дані статичні маршрути. З одного IP на брата-провайдера.

ip forewall mangle
правила тут
/ip firewall mangle
add action=mark-connection chain=input in-interface=ISP1 \
new-connection-mark=ISP1-conn passthrough=yes
add action=mark-routing chain=output connection-mark=ISP1-conn \
new-routing-mark=ISP1-route passthrough=no

add action=mark-connection chain=input in-interface=ISP2 new-connection-mark=\
ISP2-conn passthrough=yes
add action=mark-routing chain=output connection-mark=ISP2-conn \
new-routing-mark=ISP2-route passthrough=no

add action=mark-connection chain=input in-interface=ISP3 \
new-connection-mark=ISP3-conn passthrough=yes
add action=mark-routing chain=output connection-mark=ISP3-conn \
new-routing-mark=ISP3-route passthrough=no

add action=mark-connection chain=forward in-interface=ISP1 \
new-connection-mark=ISP1-conn-f passthrough=no
add action=mark-routing chain=prerouting connection-mark=ISP1-conn-f \
in-interface=new bridge-routing-mark=ISP1-route 

add action=mark-connection chain=forward in-interface=ISP2 \
new-connection-mark=ISP2-conn-f passthrough=no
add action=mark-routing chain=prerouting connection-mark=ISP2-conn-f \
in-interface=new bridge-routing-mark=ISP2-route 

add action=mark-connection chain=forward in-interface=ISP3 \
new-connection-mark=ISP3-conn-f passthrough=no
add action=mark-routing chain=prerouting connection-mark=ISP3-conn-f \
in-interface=new bridge-routing-mark=ISP3-route 


Для пояснення правил цього розділу запросимо кілька помічників.

  1. MANGLE — дана таблиця призначена для операцій з класифікації і маркування пакетів і з'єднань, а також модифікації заголовків пакетів (поля TTL і TOS) (вікіпідручник).

    Таблиця mangle містить наступні ланцюжка:
    1. PREROUTING — дозволяє модифікувати пакет прийняття рішення про маршрутизацію.
    2. INPUT — дозволяє модифікувати пакет, призначений самому хосту.
    3. FORWARD — ланцюжок, що дозволяє модифікувати транзитні пакети.
    4. OUTPUT — дозволяє модифікувати пакети, які виходять від самого хоста.
    5. POSTROUTING — дає можливість модифікувати всі вихідні пакети, як згенеровані самим хостом, так і транзитні.
  2. CONNECTION TRACKING — спеціальна підсистема, що відстежує стану з'єднань і дозволяє використовувати цю інформацію при прийнятті рішень про долю окремих пакетів.
  3. Packet flow MikroTik'а
Я розбив правила на групи, для полегшення їх розуміння. У першій групі 6 правил, які відповідають за трафік до/з самого роутера, і у другій групі 6, для транзитного трафіку.

Чому з перших двох.
В першому ми повідомляємо роутеру, що всі вхідні chain=input з'єднання на інтерфейс ISP1 потрібно маркувати action=mark-new connection-connection-mark=ISP1-conn, а так само указаваем passthrough=yes, щоб пакет, після проходження цього правила, не залишив таблицю і продовжив слідування за правилами.

У другому говоримо MikroTik', щоб він відловив вихідні з'єднання chain=output позначені як ISP1-conn і присвоїв їм мітку роутінга(для приміщення у відповідну таблицю маршрутизації, адже ви пам'ятаєте перші три маршруту?), а також повідомляємо passthrough=no , як би кажучи — нічого робити тут пакету після цього правила, тобто пакет покине таблицю.

Все описане вище справедливо і для ISP2 і для ISP3. Таким чином ми домоглися того, що роутер відповість саме з того інтерфейсу, на який до нього прийде запит.

Переходимо до завершальним шести правилами.
Вже зрозуміло, вони також розбиті на підгрупи по 2, для кожного з наших ISP.
Перше з них доручає роутеру стежити за ланцюжком FORWARD і якщо відбувається з'єднання через інтерфейс ISP1, то воно маркується action=mark-connection новим тегом new-connection-mark=ISP1-conn-f (зверніть увагу! відмінним від тега трафіку самого маршрутизатора, в даному випадку ми маркируем транзитний трафік). passthrough=no, оскільки ми не хочемо, щоб пакет, після попадання в це правило, оброблявся в таблиці якось ще.

Друге навішує потрібну позначку роутінга new-routing-mark=ISP1-route в ланцюжку PREROUTING, тобто ДО прийняття рішення про маршрутизацію, і відстежує трафік, який прийшов до нас з локальної мережі in-interface=bridge.
Тут нас виручає механізм CONNECTION TRACKING, що дозволяє зловити промарковані правилом вище з'єднання з локальної мережі(від WEB-сервера) і навісити їм необхідний тег роутінга.

Це дозволяє транзитного трафіку(тут до/від web-сервера) йти саме тим шляхом, яким він і прийшов, т. е. прийшов через ISP1 — йди через нього ж.

Висновок
Дуже радий, якщо мої пояснення зрозумілі, а дана праця стане корисним.
Пішов медитувати, всім удачі!

Дякую за увагу!
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.