OSPF маршрут видит, а абонент — нет: как proxy ARP вернул связность на MikroTik

Обложка

Практический разбор операторской сети с IPoE, PPPoE, OSPF и NAT.

Все названия узлов, интерфейсов и IP-адреса изменены. Для примеров используется документационный диапазон 198.51.100.0/24. Сетевая логика и последовательность диагностики сохранены.

Иногда диагностика выглядит почти издевательски. На MikroTik есть маршрут до нужного адреса. OSPF-соседи в состоянии Full. С самого маршрутизатора цель доступна. Но абонент говорит: «не работает», и он тоже прав.

В нашем случае пакет проигрывал не в OSPF, не в firewall и даже не в NAT. Он вообще не добирался до маршрутизатора: CPE решил, что адрес назначения находится рядом с ним в одном L2-сегменте, отправил ARP-запрос и остался ждать ответа.

Разберём по порядку: как к этому привели общая публичная /24, тысячи изолированных VLAN и arp=reply-only, почему помог proxy-arp, какие побочные эффекты у такого лечения — и уже после разбора кейса пройдёмся по всем режимам ARP в RouterOS как по справочнику.

Исходная схема

В сети было несколько MikroTik-шлюзов. Между ними работал OSPF, через который распространялись абонентские /32 и другие нужные маршруты.

Одновременно на общей uplink-сети использовался публичный блок 198.51.100.0/24. Адреса из него встречались сразу в нескольких ролях:

Упрощённая топология: четыре шлюза, OSPF, IPoE, PPPoE и NAT

IPoE-клиенту DHCP выдавал адрес из этого блока, шлюз и маску /24. Физически соседние адреса могли находиться на разных VLAN и даже на разных маршрутизаторах, но CPE об этом не знал: для него весь 198.51.100.0/24 выглядел одной локальной сетью.

Это и было заложенной миной.

Симптом

Типичная жалоба: IPoE-абонент 198.51.100.70 не пингует 198.51.100.123. На шлюзе при этом виден маршрут 198.51.100.123/32, полученный через OSPF.

Логика инженера понятна:

  1. маршрут есть;
  2. next hop доступен;
  3. значит, пакет должен уйти на соседний GW.

Но CPE с маской /24 рассуждает иначе:

  1. адрес назначения входит в мою локальную сеть;
  2. шлюз мне не нужен;
  3. сначала узнаю MAC-адрес 198.51.100.123 через ARP.

ARP broadcast остаётся внутри абонентского VLAN. Настоящего владельца адреса там нет. Ответить за него мог бы маршрутизатор, но на интерфейсе был включён arp=reply-only.

До исправления: ARP-запрос остаётся без ответа, а OSPF даже не получает пакет

Именно поэтому хороший маршрут не помогал: маршрутизация начинается только после того, как CPE сформировал Ethernet-кадр. Без MAC-адреса назначения кадра нет, IP-пакет не уходит со стороны клиента, и OSPF в этой сцене просто не получает реплики.

Что именно делал reply-only

Тут важна аккуратная формулировка. reply-only — не режим «отвечать только за адрес шлюза». В RouterOS он отключает динамическое ARP-обучение и опирается на заранее заданные соответствия IP/MAC в /ip arp. Такой режим часто используют вместе с DHCP add-arp=yes, чтобы неизвестное устройство не могло свободно подменить адрес.

Но reply-only не делает маршрутизатор ARP-посредником для адресов за другими интерфейсами. Валидный клиент может обращаться к самому шлюзу, однако на ARP-запрос о чужом 198.51.100.x маршрутизатор своим MAC не ответит.

Короткая памятка:

Режим Что происходит Где уместен
enabled Обычное динамическое ARP-обучение Стандартный L2-сегмент
reply-only Работа по статическим IP/MAC-записям, без динамического обучения Контролируемый access с DHCP add-arp=yes или ручными ARP-записями
proxy-arp Роутер отвечает своим MAC за адрес, путь к которому лежит через другой интерфейс Разнесённые L2-сегменты, которым выдали адреса из общего IP-префикса
local-proxy-arp Роутер проксирует ARP между узлами на одном и том же интерфейсе Изоляция клиентов внутри общего интерфейса/сегмента

В нашем кейсе адрес назначения находился за другим интерфейсом, поэтому нужен был именно proxy-arp, а не local-proxy-arp.

Как сработал proxy-arp

Proxy ARP — приём, описанный ещё в RFC 1027: маршрутизатор отвечает своим MAC-адресом на ARP-запросы о тех IP, которые лежат не в этом сегменте, а за другими его интерфейсами, и до которых у него есть маршрут. Хост получает ответ, считает, что цель находится рядом на канальном уровне, и отправляет кадр маршрутизатору. Тот, ничего не меняя в IP-заголовке, делает обычный L3-forwarding.

Важно, что «склейка» происходит не на канальном уровне, а через таблицу маршрутизации: маршрутизатор отвечает не за всё подряд, а только за адреса с активным маршрутом, и только если маршрут указывает не на тот интерфейс, откуда пришёл запрос.

На выбранных абонентских VLAN режим ARP сменили на proxy-arp, и последовательность стала такой:

  1. CPE спрашивает: «Кто такой 198.51.100.123?»
  2. MikroTik проверяет таблицу маршрутизации и видит путь к адресу через другой интерфейс.
  3. Маршрутизатор отвечает собственным MAC.
  4. CPE отправляет Ethernet-кадр на MikroTik, хотя IP-адрес назначения остаётся прежним.
  5. После этого начинается обычный L3-forwarding: маршрут /32, OSPF, соседний GW и нужный абонентский интерфейс.

После исправления: MikroTik отвечает своим MAC и передаёт пакет по маршруту

Пример точечной настройки:

/interface vlan print detail where arp=reply-only
/interface vlan set [find where name="access-101"] arp=proxy-arp
/interface vlan print detail where name="access-101"

Соблазн сразу выполнить что-то вроде set [find arp=reply-only] понятен, особенно когда VLAN несколько тысяч. Но сначала нужно определить, какие интерфейсы действительно относятся к этой модели IPoE: reply-only мог быть включён осознанно как часть защиты IP/MAC, а глобальное переключение изменит поведение всей сети доступа.

Если проксировать нужно буквально несколько адресов, RouterOS позволяет создать точечную опубликованную ARP-запись вместо включения proxy ARP для всего интерфейса:

/ip arp add address=198.51.100.123 interface=access-101 published=yes

Устройство ответит за этот IP только при наличии активного маршрута до него. Для тысяч динамически размещённых абонентов такой способ быстро превращается в отдельную систему учёта, но для единичного сервисного адреса он бывает аккуратнее — и, что важно, не отменяет reply-only для остальных адресов сегмента.

Перед массовой правкой стоит:

Что получилось после изменения

Сценарий До После proxy-arp на IPoE-VLAN
IPoE ↔ IPoE, разные VLAN/GW CPE ждёт ARP, пакет не доходит до GW CPE отправляет кадр на MAC шлюза, дальше работает L3
PPPoE ↔ PPPoE Обычно работало через peer /32 По сути без изменений
PPPoE ↔ IPoE Часто ломался обратный путь на стороне IPoE Работает при корректных маршрутах и firewall
IPoE ↔ публичный NAT IP Выглядело как поломка связи двух абонентов ARP-часть исправлена, но результат всё ещё зависит от NAT/firewall

Последняя строка таблицы — не формальность: именно на ней разбор чуть не увёл в неверную сторону.

Ловушка: адрес выглядит абонентским, но это NAT

Во время разбора попалась пара адресов, которая сначала казалась идеальным тестом:

Но второй адрес оказался назначен uplink-интерфейсу другого маршрутизатора и использовался как внешний адрес для NAT частного пула. Никакого CPE с адресом .210 не существовало.

Это меняет смысл проверки. Пинг «абонент ↔ абонент» внезапно становится проверкой «IPoE-клиент ↔ адрес самого GW или сервис за dst-nat», а результат зависит уже от правил NAT, firewall и того, есть ли вообще трансляция для ICMP.

Четыре разных сценария, которые снаружи выглядят как связь между адресами одной /24

Поэтому перед выводом «абоненты друг друга не видят» полезно установить владельца каждого IP:

/ip address print detail where address~"198.51.100.210"
/ip arp print detail where address=198.51.100.210
/ppp active print detail where address=198.51.100.210
/ip firewall nat print detail where dst-address~"198.51.100.210"

А затем проверить, есть ли для него host route и где он был получен.

При чём здесь OSPF

OSPF в этой истории не был причиной поломки — он лишь доставлял между шлюзами информацию о том, где находится конкретный абонентский /32. Но чтобы proxy-arp заработал, должны выполняться два условия:

Для RouterOS v7 маршрут удобно смотреть так:

/routing route print detail where dst-address=198.51.100.123/32
/routing ospf neighbor print detail

В RouterOS v6 таблица маршрутов проверяется через:

/ip route print detail where dst-address=198.51.100.123/32

Если /32 не анонсируется, соседство застряло в ExStart/Exchange или маршрут отфильтрован, proxy-arp проблему не исправит: он помогает клиенту передать пакет маршрутизатору, но маршрут до цели всё равно должен существовать. Это прямое следствие механики режима — решение об ARP-ответе принимается по таблице маршрутизации, поэтому пустая FIB означает тишину в ответ на who-has.

Практический порядок диагностики

Из всего этого сложилась рабочая последовательность.

1. Проверить логику CPE

Посмотреть выданную маску. Если клиент получил /24, он будет ARP-ить любой адрес из этой /24, даже если оператор разнёс адреса по разным VLAN.

2. Посмотреть ARP на access-интерфейсе

/interface vlan print detail where name="access-101"
/tool sniffer quick interface=access-101 mac-protocol=arp

Характерный симптом: от CPE приходит who-has, но ответа за удалённый адрес нет.

3. Проверить маршрут до точного адреса

Смотреть нужно не только общий connected /24, но и специфичный /32. Иначе трафик может уйти на общий uplink или не к тому GW.

4. Установить реального владельца IP

Адрес может принадлежать IPoE-клиенту, PPP-сессии, интерфейсу маршрутизатора, NAT-пулу или вообще быть свободным. Одинаковая запись в заявке «белый IP» ещё не означает одинаковую сетевую сущность.

5. Проверить OSPF и обратный путь

Соседство должно быть Full, нужный /32 — установлен, а обратный маршрут — симметричен или хотя бы допустим правилами firewall и rp-filter.

6. Только после этого включать proxy-arp

Сначала на одном VLAN, затем на небольшой группе, и лишь потом — массово. После изменения проверяются ARP, ping, TCP-сессия и счётчики firewall в обоих направлениях.

Как устроен proxy ARP: режимы RouterOS

Кейс на этом закрыт. Дальше — справочная часть: что именно RouterOS делает с ARP в каждом режиме и почему в нашей ситуации выбор был безальтернативным.

Начать стоит с логики хоста. Собираясь отправить IP-пакет, он сначала решает, «локальный» адрес назначения или нет: применяет свою маску к своему и к целевому адресу. Если адреса попали в одну подсеть, шлюз не используется вовсе — хост рассылает широковещательный ARP-запрос who-has и ждёт, кто отзовётся своим MAC. Ethernet-кадр без MAC назначения не собирается, поэтому при отсутствии ответа никакого IP-трафика просто не появляется.

Proxy ARP в RFC 1027 прямо называли «ARP-хаком» для подсетей: механизм придумали для стеков, которые не умели работать с подсетями. Живёт он ровно по той же причине, что и в нашем кейсе: адреса одной подсети оказались разнесены по разным линкам, VLAN или тоннелям, а хосты об этом не знают. Побочный эффект хорошо видно в ARP-таблице клиента: десятки разных IP там отображаются на один и тот же MAC шлюза.

Теперь по режимам, которые RouterOS позволяет задать на интерфейсе (подробности — в официальной документации по ARP):

Разница между двумя proxy-режимами — исключительно в том, где находится цель: за другим интерфейсом или в том же сегменте. Подменить один другим не получится, это отдельные значения параметра, и на интерфейсе действует одно из них. Соответственно, включая proxy-arp, вы отказываетесь от строгости reply-only на этом интерфейсе, и защиту от подмены адресов приходится переносить на DHCP snooping, ACL и firewall.

Когда proxy-arp полезен

Несмотря на репутацию «костыля», у режима есть сценарии, где он не просто работает, а является наиболее логичным решением.

Цена решения

proxy-arp оказался рабочим операционным исправлением, но он не превращает исходный дизайн в идеальный. Что приходится учитывать:

«Костылём» этот режим называют вполне обоснованно. Во-первых, он поощряет клиента ARP-ить весь префикс: каждое новое направление добавляет запись в ARP-кэш CPE и порождает широковещательный запрос в сегменте, а на масштабе тысяч VLAN и десятков тысяч устройств это заметная фоновая нагрузка и раздутые таблицы соседств. Во-вторых, он размывает границу между L2 и L3: логически адреса маршрутизируются, но топология в голове хоста остаётся плоской, из-за чего диагностика перестаёт совпадать со схемой — «локальный» по мнению CPE адрес фактически лежит через два хопа и чужой firewall. В-третьих, страдает изоляция: пока ARP-ответа не было, соседи по префиксу физически не могли достучаться друг до друга, а теперь между ними есть исправно работающий посредник, и единственное, что их разделяет, — правила в forward.

Отдельная категория неприятностей — неоднозначность. Если один и тот же префикс присутствует на нескольких шлюзах, за один и тот же адрес потенциально может ответить не тот маршрутизатор, у которого лучший путь, а тот, чей ARP-ответ пришёл первым; клиент закрепит в кэше «случайный» MAC на время жизни записи. Дальше подключается асимметрия: трафик уходит через одного GW, возвращается через другого, и rp-filter вместе с connection tracking начинают отбрасывать вполне легитимные пакеты, а причина выглядит как «иногда работает, иногда нет». Всё это лечится специфичными /32, аккуратной фильтрацией анонсов OSPF и предсказуемой политикой обратного пути.

И всё же в операторских IPoE-сетях proxy-arp регулярно оказывается единственным быстрым фиксом. Абонентские устройства оператору не принадлежат, маску и шлюз в них меняет только DHCP, а массовое переучивание парка CPE на новую адресную модель — это согласования, окна работ и обращения в поддержку. Когда связность нужна сейчас, а адресация исторически плоская, включение прокси на нужных access-интерфейсах даёт результат в пределах одной сессии в терминале и оставляет время на нормальный редизайн.

Стратегически чище выдавать абоненту /32 с маршрутом через gateway либо использовать адресную модель, в которой CPE не считает весь публичный блок своим L2-сегментом. PPPoE изначально ближе к этой логике: у клиента есть peer, и чужой адрес сразу отправляется маршрутизатору.

Но миграция адресации — отдельный проект. Когда сеть уже построена на общей /24, а простоя быть не должно, точечно включённый proxy-arp позволяет восстановить связность без переделки всех CPE за одну ночь.

Вывод

Главный урок этого случая простой: наличие маршрута ещё не доказывает, что пакет дошёл до уровня маршрутизации. При слишком широкой маске CPE сначала ищет удалённый адрес через ARP, и с reply-only этот запрос остаётся без ответа. proxy-arp подставляет MAC шлюза, после чего уже начинают работать OSPF, NAT и привычная L3-диагностика.

В следующий раз, когда OSPF уверенно показывает нужный /32, а абонент всё равно никого не видит, стоит посмотреть не только route print, но и один скромный who-has, который так и не получил ответа.


Официальная документация MikroTik: ARP и режимы proxy/reply-only, DHCP и параметр add-arp, OSPF в RouterOS, Packet Sniffer, отличия маршрутизации RouterOS v6 и v7. Термин proxy ARP и исходное описание механизма — RFC 1027.

#network #mikrotik #ospf