Debian/Ubuntu: «Працює в LAN, не працює в WAN» — перевірки маршрутизації/NAT, що виявляють причину (case #85)

Було корисно?

Ви можете дістатися до сервера з офісу. Ви можете дістатися до нього з сусідньої стійки. Перевірка здоров’я зелена в приватній підмережі. А потім клієнт з інтернету пробує — і все розвалюється, як дешевий складаний стілець.

Це класична помилка «працює в LAN, не працює в WAN». Зрідка причина в додатку. Зазвичай це маршрутизація, NAT, стан фаєрвола або падіння PMTUD/MTU. Хороша новина: ви можете довести джерело проблеми за кілька хвилин — якщо перестанете гадати і почнете допитувати шлях пакета.

Ментальна модель: успіх у LAN — не доказ здоров’я WAN

Коли щось «працює в LAN», ви довели лише одне: хости в межах однієї доменної маршрутизації можуть завершити кругову поїздку. І тільки це. WAN-трафік додає:

  • інші IP-адреси джерела (публічні мережі проти RFC1918). Ваш сервер, фаєрвол і апстрім можуть ставитися до них по-іншому.
  • стан NAT (SNAT/DNAT/masquerade), якого немає на чистих LAN-шляхах.
  • інші шляхи повернення (асиметрична маршрутизація), коли у вас кілька шлюзів, VPN або «корисна» політика маршрутизації.
  • інші MTU (PPPoE, тунелі, оверлеї), які можуть непомітно вбити певні потоки.
  • інші зони ACL (security groups у хмарі, крайові фаєрволи, фільтрація ISP), які не тестуються LAN-трафіком.

На практиці «LAN OK, WAN broken» звужується до кількох повторюваних винуватців:

  1. Неправильний маршрут за замовчуванням (або невірна метрика) для зворотнього трафіку.
  2. Відсутній SNAT/masquerade для виходу або зламаний DNAT для входу.
  3. Фаєрвол дозволяє підмережі LAN, але відкидає «невідомі» джерела або стан related/established.
  4. Зворотне фільтрування шляху (rp_filter) відкидає пакети, бо Linux вважає, що джерело не повинно приходити через цей інтерфейс.
  5. MTU/PMTUD-«чорні діри»: SYN проходить, TLS зависає, «воно переривчасте».

Не починайте з перезапуску сервісів. Почніть з доведення, як пакет входить, як він перетворюється (якщо взагалі), і як він виходить. Якщо ви не можете описати шлях одним реченням, ви не діагностуєте — ви надієтеся.

Цікаві факти та історія (мережі носять багаж)

  • RFC1918 приватна адресація (1996) зробила NAT типовою підтримкою через брак IPv4; вона також узаконила «всередині працює» як оманливий сигнал комфорту.
  • Linux netfilter/iptables з’явився в еру ядра 2.4, замінивши ipchains; ментальна модель «таблиці/ланцюги/хуки» все ще важлива, навіть коли ви використовуєте nftables сьогодні.
  • Стан conntrack — це причина, чому «allow established/related» працює — і чому повна таблиця conntrack робить здоровий фаєрвол схожим на привида.
  • Зворотне фільтрування шляху (rp_filter) було створене для зменшення спуфінгу; на мультихомованих системах воно може відкидати легітимний трафік і створювати WAN-специфічні відмови.
  • Path MTU Discovery покладається на ICMP «Fragmentation needed» повідомлення; фільтрація ICMP може зламати великі потоки, тоді як малі ping-и усе ще проходять.
  • TCP MSS clamping стало поширеним обхідним рішенням для проблем MTU в тунелях; це корисно, але також приховує корінні причини і може знизити продуктивність.
  • Асиметрична маршрутизація поширена в реальному світі (подвійні uplink-и, SD-WAN, ECMP), але станні фаєрволи часто очікують симетрії і карають за креативність.
  • NAT reflection (hairpin NAT) — причина, чому внутрішні клієнти іноді можуть дістатися сервісу через його публічну IP; коли його немає — отримуєте заплутане «LAN не працює, WAN окей».
  • nftables уніфікував семантику фільтрації IPv4/IPv6 і покращив продуктивність/виразність, але перехідний період залишив багато систем зі змішаним набором інструментів і невідповідними очікуваннями.

Одна цитата варта стікера:

«Надія — це не стратегія.» — Gen. Gordon R. Sullivan

Цю фразу повторюють в ops, бо вона болісно правдива. Ви не «відчуваєте» маршрутизацію. Ви її вимірюєте.

Швидкий плейбук діагностики (перший/другий/третій)

Перший: підтвердьте, що симптом дійсно специфічний для WAN

  • Тестуйте з зовні вашої мережі (cell hotspot, зовнішній probe, хмарна VM).
  • Тестуйте за IP і за ім’ям (DNS може маскуватися під проблеми маршрутизації).
  • Тестуйте TCP і ICMP окремо (фаєрволи трактують їх інакше).

Другий: доведіть маршрутизацію і шлях повернення на сервері

  • ip route get <client_ip> на сервері: обраний інтерфейс egress і IP джерела мають бути логічними.
  • Перевірте кілька маршрутів і метрик; «правильний» маршрут за замовчуванням марний, якщо він не є пріоритетним.
  • Якщо мультихом або включений VPN: перегляньте ip rule і маршрути в окремих таблицях.

Третій: доведіть NAT і стан на крайовому пристрої (або на хості, якщо він робить NAT)

  • Шукайте відсутній DNAT/SNAT, неправильні співпадіння інтерфейсів або правила, які діють лише на LAN-підмережі.
  • Переглядайте записи conntrack під час тестування; якщо пакети приходять, але стан не створюється, порядок хуків/правил невірний.
  • Перевірте rp_filter і поведінку MTU/PMTUD перед тим, як звинувачувати «ISP».

Якщо можете зробити лише одну річ: запустіть tcpdump на вхідних і вихідних інтерфейсах під час зовнішнього тесту. Пакети не брешуть; люди брешуть.

Практичні завдання: команди, виходи та рішення (12+)

Ці команди призначені для запуску на серверах Debian/Ubuntu і/або на Linux-шлюзі, що виконує маршрутизацію/NAT. Кожне завдання містить, що означає вивід та яке рішення прийняти далі.

Завдання 1 — Підтвердьте інтерфейси та адреси (перше — саніті)

cr0x@server:~$ ip -br addr
lo               UNKNOWN        127.0.0.1/8 ::1/128
ens160           UP             10.20.0.10/24 fe80::a00:27ff:fe12:3456/64
ens192           UP             203.0.113.10/29 fe80::a00:27ff:fe98:7654/64

Значення: Ця машина мультихомована: приватний LAN на ens160, публічний/WAN на ens192. Мультихом — це місце, де «LAN працює, WAN ламається» розмножується.

Рішення: Припускайте ризик зворотнього шляху і rp_filter. Прямуйте до перевірки маршрутизації і правил, а не в логи додатків.

Завдання 2 — Прочитайте таблицю маршрутизації як серйозно

cr0x@server:~$ ip route
default via 10.20.0.1 dev ens160 proto dhcp metric 100
default via 203.0.113.9 dev ens192 proto static metric 200
10.20.0.0/24 dev ens160 proto kernel scope link src 10.20.0.10 metric 100
203.0.113.8/29 dev ens192 proto kernel scope link src 203.0.113.10 metric 200

Значення: Два маршрути за замовчуванням. LAN-дашрут має нижчу метрику (100), тож він перемагає. WAN-клієнти можуть звертатися на публічну IP, але відповіді можуть намагатися вийти через LAN-шлюз. Це асиметрія.

Рішення: Виправте пріоритет маршруту за замовчуванням або впровадьте політичну маршрутизацію, щоб трафік, що приходить по WAN, повертався через WAN.

Завдання 3 — Запитайте ядро: «як би ти дійшов до цього WAN-клієнта?»

cr0x@server:~$ ip route get 198.51.100.77
198.51.100.77 via 10.20.0.1 dev ens160 src 10.20.0.10 uid 0
    cache

Значення: Відповіді публічному клієнту виходили б через приватний інтерфейс з приватною адресою джерела. Це не «трохи неправильно». Це повне пояснення вашого збою.

Рішення: Додайте політичну маршрутизацію або видаліть конкуренційний маршрут за замовчуванням. Не чіпайте додаток.

Завдання 4 — Виявіть політичну маршрутизацію, яка тихо викрадає трафік

cr0x@server:~$ ip rule show
0:      from all lookup local
1000:   from 203.0.113.10 lookup wan
32766:  from all lookup main
32767:  from all lookup default

Значення: Є правило для трафіку, що походить з публічної IP, щоб використовувати таблицю wan. Це допомагає, але тільки якщо трафік справді має джерело 203.0.113.10.

Рішення: Переконайтесь, що вхідні з’єднання на публічну IP зберігають цей джерелевий IP для відповідей (без SNAT на LAN), і що сервіси коректно прив’язані. Перевірте ip route show table wan.

Завдання 5 — Перевірте таблицю маршрутизації WAN, використовувану політичною маршрутизацією

cr0x@server:~$ ip route show table wan
default via 203.0.113.9 dev ens192
203.0.113.8/29 dev ens192 scope link src 203.0.113.10

Значення: Таблиця адекватна. Якщо WAN все ще не працює, проблема ймовірно в тому, що відповіді не відповідають цьому правилу (неправильна IP-адреса джерела) або пакети відкидаються (rp_filter/фаєрвол/NAT).

Рішення: Підтвердьте фактичну IP-адресу джерела у відповідях за допомогою tcpdump.

Завдання 6 — Перевірте зворотне фільтрування шляху (те «анти-спуфінг», що їсть ваш обід)

cr0x@server:~$ sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.ens160.rp_filter net.ipv4.conf.ens192.rp_filter
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.ens160.rp_filter = 1
net.ipv4.conf.ens192.rp_filter = 1

Значення: Строгий rp_filter (1) на мультихомованому хості може відкидати пакети, коли «кращий маршрут назад» не відповідає інтерфейсу входу. Це саме ваша ситуація з двома маршрутами за замовчуванням.

Рішення: Встановіть rp_filter в режим loose (2) на відповідних інтерфейсах, або виправте симетрію маршрутизації, щоб можна було залишити строгий режим.

Завдання 7 — Перевірте переадресацію IP (якщо хост — маршрутизатор/NAT)

cr0x@server:~$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 0

Значення: Якщо цей вузол має маршрутизувати між LAN і WAN, зараз він відмовляється це робити.

Рішення: Увімкніть переадресацію та перевірте фаєрвол/NAT. Якщо він не повинен маршрутизувати — зупиніться і переосмисліть дизайн (можливо ви дебагуєте не ту машину).

Завдання 8 — Огляньте набір правил nftables (сучасний дефолт Debian/Ubuntu)

cr0x@server:~$ sudo nft list ruleset
table inet filter {
  chain input {
    type filter hook input priority 0; policy drop;
    ct state established,related accept
    iif "ens160" ip saddr 10.20.0.0/24 accept
    tcp dport 22 accept
  }
  chain forward {
    type filter hook forward priority 0; policy drop;
    ct state established,related accept
    iif "ens160" oif "ens192" accept
  }
}
table ip nat {
  chain postrouting {
    type nat hook postrouting priority 100; policy accept;
    oif "ens192" masquerade
  }
}

Значення: Політика input — drop. Вона приймає established/related і все з підмережі LAN. Також дозволяє SSH звідусіль. Але вона не дозволяє WAN-доступ до порта вашого сервісу. Це просте, банальне пояснення.

Рішення: Додайте явні правила дозволу з WAN для потрібних портів і обмежуйте їх. Не «policy accept» собі шлях до звіту про інцидент.

Завдання 9 — Якщо ви на iptables, перевірте і таблиці filter, і nat

cr0x@server:~$ sudo iptables -S
-P INPUT DROP
-P FORWARD DROP
-P OUTPUT ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -s 10.20.0.0/24 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT

Значення: Та ж історія, що і з nft: WAN-трафік до вашого порта додатку не дозволений. LAN працює, бо підмережа LAN дозволена.

Рішення: Додайте правило allow для порта сервісу, обмеживши очікуваними джерелами якщо можливо. Якщо сервіс за DNAT — також потрібні правила у FORWARD.

Завдання 10 — Підтвердьте правила DNAT/порт-форвардингу (крайовий бокс або хостовий)

cr0x@gateway:~$ sudo nft list table ip nat
table ip nat {
  chain prerouting {
    type nat hook prerouting priority -100; policy accept;
    iif "ens192" tcp dport 443 dnat to 10.20.0.10:443
  }
  chain postrouting {
    type nat hook postrouting priority 100; policy accept;
    oif "ens192" masquerade
  }
}

Значення: Порт 443 з WAN пересилається на внутрішній хост. Якщо WAN не може підключитися, або пакети не доходять до ens192, або FORWARD ланцюг блокує їх, або внутрішній хост має неправильний маршрут/відповідь.

Рішення: Захопіть трафік обома інтерфейсами і перевірте лічильники FORWARD.

Завдання 11 — Спостерігайте conntrack під час тесту з WAN

cr0x@gateway:~$ sudo conntrack -E -p tcp --dport 443
    [NEW] tcp      6 120 SYN_SENT src=198.51.100.77 dst=203.0.113.10 sport=51234 dport=443 [UNREPLIED] src=10.20.0.10 dst=198.51.100.77 sport=443 dport=51234

Значення: Шлюз бачить вхідний SYN і створив NAT-запис, але він [UNREPLIED]. Внутрішній сервер не відповів, або відповідь не повернулась через цей шлюз.

Рішення: tcpdump на внутрішньому інтерфейсі, щоб побачити чи SYN досягає сервера; tcpdump на сервері, щоб побачити чи він відповідає; перевірте маршрут за замовчуванням сервера до цього шлюзу.

Завдання 12 — tcpdump на WAN: чи пакети взагалі доходять?

cr0x@gateway:~$ sudo tcpdump -ni ens192 tcp port 443
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens192, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:04:21.123456 IP 198.51.100.77.51234 > 203.0.113.10.443: Flags [S], seq 1234567890, win 64240, options [mss 1460,sackOK,TS val 1 ecr 0,nop,wscale 7], length 0

Значення: Вхідний SYN доходить до шлюзу. Це не блокування ISP. Тепер це ваша проблема (вітаємо).

Рішення: Захопіть трафік на LAN-інтерфейсі теж, щоб підтвердити пересилання і DNAT.

Завдання 13 — tcpdump на LAN: чи пересланий SYN до сервера?

cr0x@gateway:~$ sudo tcpdump -ni ens160 host 10.20.0.10 and tcp port 443
listening on ens160, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:04:21.124001 IP 198.51.100.77.51234 > 10.20.0.10.443: Flags [S], seq 1234567890, win 64240, options [mss 1460,sackOK,TS val 1 ecr 0,nop,wscale 7], length 0

Значення: DNAT працює; сервер бачить трафік з оригінальною IP клієнта (добре). Тепер сервер має відповісти назад через шлюз, щоб SNAT і відстеження стану завершили хендшейк.

Рішення: Перевірте маршрут сервера назад до клієнта і запустіть tcpdump на egress серверу.

Завдання 14 — tcpdump на сервері: чи відповідає він і з якої IP?

cr0x@server:~$ sudo tcpdump -ni ens160 tcp port 443 and host 198.51.100.77
listening on ens160, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:04:21.124050 IP 198.51.100.77.51234 > 10.20.0.10.443: Flags [S], seq 1234567890, win 64240, options [mss 1460,sackOK,TS val 1 ecr 0,nop,wscale 7], length 0
12:04:21.124090 IP 10.20.0.10.443 > 198.51.100.77.51234: Flags [R.], seq 0, ack 1234567891, win 0, length 0

Значення: Сервер відкидає (RST) на 443, отже додаток/сервіс не слухає або прив’язаний до іншої адреси. LAN «працює» могло означати, що ви потрапляєте на інший VIP/порт або локальний проксі.

Рішення: Перевірте слухаючі сокети та прив’язки. Якщо це був SYN-ACK, тоді перевірте, що відповідь йде до шлюзу (наступне завдання).

Завдання 15 — Перевірте слухаючі сокети та адреси прив’язки

cr0x@server:~$ sudo ss -lntp | egrep ':443|:80'
LISTEN 0      4096       127.0.0.1:443       0.0.0.0:*    users:(("nginx",pid=2031,fd=7))

Значення: Сервіс прив’язаний лише до loopback. Він працюватиме для «локальних» тестів і можливо для LAN-зворотного проксі, але він не спрацює для пересланого WAN-трафіку, що доходить до 10.20.0.10.

Рішення: Переприв’яжіть до правильної адреси (0.0.0.0 або конкретного IP) і повторно протестуйте з WAN.

Завдання 16 — Швидка перевірка MTU коли «SYN працює, TLS зависає»

cr0x@server:~$ ping -M do -s 1472 198.51.100.77 -c 2
PING 198.51.100.77 (198.51.100.77) 1472(1500) bytes of data.
ping: local error: message too long, mtu=1492
ping: local error: message too long, mtu=1492

--- 198.51.100.77 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1026ms

Значення: Ваш ефективний MTU — 1492 (класичний PPPoE). Якщо ви припускаєте 1500 і блокуєте ICMP, ви можете створити WAN-специфічну проблему, де малі пакети працюють, а великі зависають.

Рішення: Виправте MTU по всьому шляху або зажміть MSS на тунелі/краю. Не просто «відкривайте випадкові порти».

Жарт #1: NAT — як офісна політика: ніхто не визнає, що вона існує, але вона вирішує, хто може говорити з ким.

Шаблони маршрутизації/NAT, що спричиняють успіх лише в LAN

1) Сервер має два маршрути за замовчуванням, і «неправильний» перемагає

Це шаблон №1 на мультихомованих системах: один інтерфейс для management/LAN, інший для публічного/WAN, іноді третій для VPN. Linux вибирає маршрут з найнижчою метрикою. Якщо DHCP дає вам шлюз за замовчуванням на LAN NIC і ви додаєте статичний default для WAN, ви створили лотерею, де «неправильний» маршрут послідовно обирається.

WAN-запит приходить через WAN-інтерфейс, але відповідь виходить через LAN-шлюз. Апстрім відкидає її, бо джерелевий IP неправильний, або бо stateful фаєрвол посередині не бачить відповіді.

Що робити: оберіть один маршрут за замовчуванням у main, і використовуйте політичну маршрутизацію для винятків. Якщо ви мусите тримати кілька default, будьте явними щодо метрик і джерелевих адрес.

2) DNAT працює, але FORWARD відкидає

На Linux-шлюзі DNAT у PREROUTING може бути ідеальним, але все одно нічого не працює, бо ланцюг FORWARD за замовчуванням drop і не має правила дозволу для пересланого сервісу. Люди перевіряють «правила NAT» і зупиняються на цьому. Так ви проводите вівторок з tcpdump і жалем.

Що робити: розглядайте NAT та фільтрацію як окремі шари. Потрібні обидва: трансляція і дозволи.

3) Відсутній SNAT/masquerade для egress

LAN-хости можуть дістатися шлюзу, можуть дістатися внутрішніх сервісів, навіть резолвити DNS. Але не можуть дістатися інтернету, бо пакети виходять з приватними IP і загинаються у апстріма. Локально все виглядає добре.

Що робити: підтвердіть, що в POSTROUTING є SNAT/masquerade і що воно співпадає з правильним вихідним інтерфейсом. Потім підтвердіть, що повернення дозволене і conntrack не вичерпано.

4) rp_filter відкидає пакети лише від «дивних» джерел

Строге зворотне фільтрування шляху ок на одне-інтерфейсних хостах. На мультихомованих або політично-рутених системах воно може відкидати легітимні WAN-пакети, бо ядро каже: «якби я маршрутизував назад до цього джерела, я б не використав цей інтерфейс, отже це спуфінг».

Це розумна політика безпеки, доки ви не пояснюєте, чому тільки WAN не працює. Loose mode (2) часто правильний компроміс на крайових системах з кількома uplink-ами.

5) MTU/PMTUD чорна діра

Малі пакети працюють. PING-и працюють. SYN/SYN-ACK працює. Потім TLS-хендшейк зависає, HTTP-завантаження зависають або потоки gRPC скидаються. Причина часто PMTUD, зламаний через фільтрацію ICMP, плюс зменшений шлях MTU через PPPoE або тунелі.

Що робити: виміряйте MTU, дозволіть потрібні ICMP-типи і зажміть MSS, коли потрібно.

6) Плутанина з hairpin NAT

Іноді звіт: «з інтернету працює, але з офісу через публічне ім’я не працює». Це hairpin NAT (NAT reflection). Це дзеркальний лабіринт NAT: корисно, коли потрібно; дезорієнтує, коли немає.

Що робити: реалізуйте split-horizon DNS (внутрішній DNS повертає внутрішню IP) або налаштуйте hairpin NAT на крайовому пристрої.

Жарт #2: Якщо ви вважаєте, що ваша маршрутизація «проста», ви або щасливчик, або ще не дивилися на ip rule.

Три корпоративні міні-історії (реальні, знайомі)

Міні-історія #1 — Аварія через хибне припущення

Вони мігрували клієнтоорієнтований сервіс з VM з одним NIC на VM з двома NIC: один інтерфейс для «внутрішнього east-west», інший для «публічного ingress». Інженер мав правильний намір: «розділити трафік, зменшити ризик».

Хибне припущення було тонким: вони подумали, що публічний NIC автоматично стане маршрутом за замовчуванням для відповідей публічним клієнтам. Ні. DHCP на внутрішній мережі надав default gateway з нижчою метрикою, і Linux залюбки ним скористався.

З внутрішньої мережі сервіс виглядав ідеально. Моніторинг зсередини VPC був зелений. On-call дивився внутрішні перевірки й сказав команді продукту, що «ймовірно, DNS propagation». Це не було так. Зовнішні клієнти бачили SYN-ACK-и з неправильною IP-адресою джерела або взагалі не бачили відповіді, залежно від того, де асиметрія фільтрувала трафік.

Виправлення не було героїчним. Вони видалили внутрішній default gateway, використали специфічні маршрути для внутрішніх підмереж і додали політичну маршрутизацію для тих вихідних викликів, які мусили йти через внутрішній інтерфейс. Справжній урок постмортему: пройдене LAN-тестування — це не WAN-тест, а метрики маршрутів — операційна конфігурація, а не дрібниця.

Міні-історія #2 — Оптимізація, що обернулася проти

Платформна команда хотіла «стандартизувати правила фаєрвола» по флотах. Вони перейшли від дозвільної політики до default-drop з невеликим allowlist-ом. Це зазвичай правильний напрям—поки ви не впровадите це без розуміння джерел трафіку.

Вони дозволили порти додатків для корпоративного RFC1918 простору і для партнерської підмережі. Забули, що реальні клієнти не приходять із тих діапазонів. У staging все пройшло, бо тести запускалися зсередини мережі. У продакшені WAN-трафік доходив до краю, пересилався правильно, а потім помирав на input-ланцюгу хост-фаєрвола.

On-call провів години, перевіряючи health checks балансувальника і TLS сертифікати, бо «в середині працює». Зрештою хтось запустив nft list ruleset і помітив, що allow-правило обмежене лише внутрішніми джерелами. «Оптимізація» була правильна за духом, але неповна за охопленням.

Вони виправили це, визначивши явні зони: internal, partner, internet. Internet отримав мінімальний allowlist для публічних портів сервісу, з rate-limit і логуванням. Вони також додали зовнішню синтетичну перевірку як gate релізу. Справжній бумеранг не був у безпеці — а в припущенні, що внутрішні тести представляють світ.

Міні-історія #3 — Нудна практика, що врятувала день

Фінансова компанія мала невеликий, але строгий runbook: кожного разу, коли з’являвся новий публічний endpoint, інженер мав прикріпити до тікета три артефакти: ip route get до публічного probe, фрагмент tcpdump, що показує SYN/SYN-ACK, і diff правила фаєрвола.

Люди скаржилися. Здавалося бюрократією. Потім rollout нового VPN-клієнта змінив пріоритети маршрутів на підмножині хостів. VPN підсунув новий default route з кращою метрикою. Всередині все ще працювало. Ззовні endpoints стали час від часу темніти — тільки для трафіку, що відразу виходив з певних мереж, залежно від того, який egress обирався.

Бо в них були «нудні артефакти», on-call порівняв сьогоднішні ip route і ip rule з тими з минулотижневого тікета. Різниця була очевидною: VPN default тепер перемагав. Вони додали політичне правило для IP сервісу і зафіксували повернення трафіку до правильної таблиці. Ніяких ворожок, ніяких магій.

Практика не була гламурною. Вона була відтворюваною доказовою базою. Саме це й врятувало день, а не war room.

Поширені помилки: симптоми → корінь → виправлення

1) Симптом: працює з LAN IP, не працює з публічною IP

Корінь: сервіс прив’язаний до 127.0.0.1 або лише до LAN-адреси.

Виправлення: змініть bind/listen адресу на 0.0.0.0 або на публічний/VIP і підтвердіть за допомогою ss -lntp. Якщо за DNAT — прив’язуйте до внутрішньої адреси, на яку спрямовує DNAT.

2) Симптом: зовнішній SYN приходить, але немає SYN-ACK у відповідь

Корінь: асиметричний шлях повернення (неправильний default, неправильна метрика, відсутня політична маршрутизація) або rp_filter відкидає запити/відповіді.

Виправлення: запустіть ip route get <client_ip>, відкоригуйте маршрути/метрики або додайте ip rule + per-table default. Встановіть rp_filter у loose там, де потрібно.

3) Симптом: DNAT виглядає правильно; все одно немає зв’язку

Корінь: FORWARD ланцюг відкидає або відсутнє правило дозволу для пересланого трафіку.

Виправлення: додайте явний allow у ланцюг forward для iif wan oif lan і потрібного порту; зберігайте established/related дозволеним.

4) Симптом: LAN-хости не можуть вийти в інтернет, але шлюз може

Корінь: відсутній SNAT/masquerade для egress або SNAT прив’язане до неправильної назви інтерфейсу.

Виправлення: додайте masquerade в postrouting для WAN-інтерфейсу, підтвердіть tcpdump-ом, що вихідні пакети мають публічну адресу джерела.

5) Симптом: ping працює, HTTP працює для малих сторінок, завантаження/TLS зависають

Корінь: MTU/PMTUD чорна діра (часто ICMP блокується) через PPPoE/тунелі.

Виправлення: дозволіть ICMP «fragmentation needed», зменшіть MTU на інтерфейсах або зжміть TCP MSS на краю.

6) Симптом: деякі зовнішні мережі працюють, інші — ні

Корінь: фільтрація/піринг апстріма, або політика маршрутизації за префіксом джерела, або ACL обмежене «відомими» підмережами.

Виправлення: тестуйте з кількох зовнішніх probe-ів; перевірте правила фаєрвола на надто специфічні співпадіння джерел; перевірте BGP/крайову політику якщо застосовується.

7) Симптом: працює на IPv4, не працює на IPv6 (або навпаки)

Корінь: часткова dual-stack конфігурація: DNS повертає AAAA, але фаєрвол/маршрути не готові, або припущення NAT64.

Виправлення: явно тестуйте -4/-6, переконайтесь, що nftables має inet-правила для обох, і підтвердіть таблиці маршрутизації для v6.

8) Симптом: внутрішні клієнти не можуть дістатися сервісу через публічне ім’я

Корінь: відсутній hairpin NAT або відсутній split-horizon DNS.

Виправлення: реалізуйте split DNS або налаштуйте NAT reflection; не «виправляйте» це шляхом широкого відкриття фаєрвола.

Контрольні списки / покроковий план

Покроково: діагностувати публічний сервіс, що працює лише в LAN

  1. Відтворіть ззовні. Використовуйте справжню зовнішню точку спостереження. Якщо не можете — зупиніться, ваша діагностика буде упереджена.
  2. Підтвердіть DNS vs маршрутизацію. Порівняйте результати dig зсередини і ззовні; тестуйте напряму за IP.
  3. Перевірте, чи сервіс справді слухає. Використайте ss -lntp і підтвердіть, що bind-адреси відповідають шляху трафіку.
  4. Відстежте прихід пакета. tcpdump на WAN-інтерфейсі: чи приходять SYN-и?
  5. Відстежте пересилання/NAT. tcpdump на LAN-стороні шлюзу: чи DNAT пересилає SYN на сервер?
  6. Відстежте відповідь сервера. tcpdump на egress серверу: чи відповідає він і через який інтерфейс/IP?
  7. Підтвердіть рішення маршрутизації. ip route get <client_ip> має показувати правильний egress і джерело.
  8. Підтвердіть рішення фаєрвола. nftables/iptables лічильники мають інкрементуватися там, де ви очікуєте. Якщо ні — ваше правило не відповідає реальності.
  9. Перевірте rp_filter і conntrack. rp_filter для мультихому; розмір conntrack якщо стан відсутній або флапає.
  10. Тільки потім дивіться додаток. Тепер ви знатимете, чи додаток взагалі бачив пакети, відкинув їх чи відповів у порожнечу.

Покроково: безпечно виправити проблеми зворотнього шляху (мультихомований хост)

  1. Виберіть один основний default route у main. Нехай він буде egress-ом для більшості трафіку.
  2. Створіть окрему таблицю маршрутизації (наприклад, wan) з власним default gateway.
  3. Додайте ip rule, що співпадає для трафіку, який має виходити з публічної IP (або fwmark), щоб використовувати ту таблицю.
  4. Встановіть rp_filter у loose mode там, де мультихом вимагає, або тримайте strict, якщо можете гарантувати симетрію.
  5. Підтвердьте за допомогою ip route get для репрезентативних клієнтських IP.
  6. Підтвердьте за допомогою tcpdump: SYN входить, SYN-ACK виходить тим самим краєм.

Покроково: перевірити NAT на Linux-шлюзі

  1. Підтвердьте, що forwarding увімкнено: sysctl net.ipv4.ip_forward.
  2. Підтвердьте, що правила NAT існують (PREROUTING для DNAT, POSTROUTING для SNAT/masquerade).
  3. Підтвердьте, що FORWARD ланцюг дозволяє потік (new і established).
  4. Підтвердьте, що записи conntrack змінюються з UNREPLIED на replied під час тесту.
  5. Підтвердьте, що маршрут за замовчуванням внутрішнього хоста вказує на NAT-шлюз (або має маршрут назад до підмережі клієнта).

FAQ

1) Якщо LAN працює, хіба це не доводить, що фаєрвол в порядку?

Ні. Багато фаєрволів широко дозволяють RFC1918 джерела і трактують інтернет-джерела як ворожі. Успіх у LAN часто доводить лише, що ваше allow-правило для LAN співпадає.

2) Чому curl з самого сервера працює, а WAN не працює?

Локальний curl не проходить через DNAT, не доводить симетрію маршрутизації і може потрапляти на loopback-прив’язки. Завжди тестуйте з зовнішнього хоста і дивіться потік пакетів.

3) Як швидко виявити асиметричну маршрутизацію?

Запустіть ip route get <external_client_ip> і порівняйте з інтерфейсом входу. Якщо відповідь вийде іншим інтерфейсом — у вас ризик асиметрії.

4) Чи варто вимикати rp_filter?

Краще використовувати rp_filter=2 (loose) на мультихомованих інтерфейсах, ніж повністю відключати. Якщо ви можете забезпечити симетрію маршрутизації, строгий режим (1) безпечніший і підходить.

5) Я використовую nftables, але інструменти все ще показують iptables-правила. Що реальне?

На Debian/Ubuntu iptables може бути підкладкою над nft (iptables-nft). Ядро оцінює nftables. Використовуйте nft list ruleset, щоб побачити істину.

6) Чому я бачу UNREPLIED у conntrack?

Перший пакет був побачений і стан створений, але зворотній трафік не завершив потік. Це вказує на те, що сервер не відповів, шлях повернення неправильний або відповідь була заблокована/відкинута.

7) Чи може MTU справді ламати тільки WAN?

Так. LAN-шляхи часто мають 1500. WAN-края (PPPoE, VPNи, тунелі) можуть зменшувати MTU. При блокуванні ICMP PMTUD не працює і великі пакети зникають.

8) Який найобережніший спосіб відкрити порт для WAN-доступу?

Додайте явне allow-правило для порта сервісу на шляху ingress (хост або шлюз), зберігайте default-drop і додайте логування/rate-limit там, де потрібно.

9) Мій сервіс за DNAT. Де починати дебаг: шлюз чи сервер?

Почніть з WAN-інтерфейсу шлюзу: чи доходять пакети? Потім LAN-інтерфейс: чи вони пересилаються? Потім сервер: чи він відповідає? Така послідовність запобігає марним фантазіям.

10) Я змінив маршрути, але нічого не змінилося. Чому?

Кеш маршрутів і існуючий conntrack-стан можуть зберігати стару поведінку деякий час. Очистіть кеш маршрутів (ip route flush cache) і повторіть тест з новими підключеннями.

Висновок: практичні наступні кроки

Якщо ви дивитеся на «працює в LAN, не працює в WAN», перестаньте трактувати це як загадку. Це проблема шляху пакета, поки не доведено інше.

  1. Запустіть ip route і ip route get для реальної зовнішньої IP-клієнта. Виправте симетрію шляху або додайте політичну маршрутизацію.
  2. Огляньте nft list ruleset (або iptables) і підтвердьте, що WAN-трафік явно дозволений там, де потрібно (INPUT для сервісів хоста, FORWARD для DNAT).
  3. Використайте tcpdump на вхідних і вихідних інтерфейсах під час зовнішнього тесту. Підтвердьте: прихід, трансляція, пересилання, відповідь.
  4. Перевірте rp_filter і MTU, коли симптоми вибіркові або «переривчасті».
  5. Перетворіть знахідки на малий runbook для вашої команди: команди, очікувані виходи і одне рішення, яке кожен вихід диктує.

Мета — не запам’ятати кожен netfilter-хук. Мета — виробити звичку: ніколи не гадати, коли ядро може сказати вам, що воно робить.

← Попередня
MariaDB проти PostgreSQL: сплески CPU — хто швидше «зжирає» ядра під піковим навантаженням
Наступна →
WordPress «Вас перенаправляють»: зупинка циклів перенаправлень через SSL і cookie

Залишити коментар