Ви можете дістатися до сервера з офісу. Ви можете дістатися до нього з сусідньої стійки. Перевірка здоров’я зелена в приватній підмережі. А потім клієнт з інтернету пробує — і все розвалюється, як дешевий складаний стілець.
Це класична помилка «працює в 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» звужується до кількох повторюваних винуватців:
- Неправильний маршрут за замовчуванням (або невірна метрика) для зворотнього трафіку.
- Відсутній SNAT/masquerade для виходу або зламаний DNAT для входу.
- Фаєрвол дозволяє підмережі LAN, але відкидає «невідомі» джерела або стан related/established.
- Зворотне фільтрування шляху (rp_filter) відкидає пакети, бо Linux вважає, що джерело не повинно приходити через цей інтерфейс.
- 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
- Відтворіть ззовні. Використовуйте справжню зовнішню точку спостереження. Якщо не можете — зупиніться, ваша діагностика буде упереджена.
- Підтвердіть DNS vs маршрутизацію. Порівняйте результати
digзсередини і ззовні; тестуйте напряму за IP. - Перевірте, чи сервіс справді слухає. Використайте
ss -lntpі підтвердіть, що bind-адреси відповідають шляху трафіку. - Відстежте прихід пакета. tcpdump на WAN-інтерфейсі: чи приходять SYN-и?
- Відстежте пересилання/NAT. tcpdump на LAN-стороні шлюзу: чи DNAT пересилає SYN на сервер?
- Відстежте відповідь сервера. tcpdump на egress серверу: чи відповідає він і через який інтерфейс/IP?
- Підтвердіть рішення маршрутизації.
ip route get <client_ip>має показувати правильний egress і джерело. - Підтвердіть рішення фаєрвола. nftables/iptables лічильники мають інкрементуватися там, де ви очікуєте. Якщо ні — ваше правило не відповідає реальності.
- Перевірте rp_filter і conntrack. rp_filter для мультихому; розмір conntrack якщо стан відсутній або флапає.
- Тільки потім дивіться додаток. Тепер ви знатимете, чи додаток взагалі бачив пакети, відкинув їх чи відповів у порожнечу.
Покроково: безпечно виправити проблеми зворотнього шляху (мультихомований хост)
- Виберіть один основний default route у
main. Нехай він буде egress-ом для більшості трафіку. - Створіть окрему таблицю маршрутизації (наприклад,
wan) з власним default gateway. - Додайте
ip rule, що співпадає для трафіку, який має виходити з публічної IP (або fwmark), щоб використовувати ту таблицю. - Встановіть rp_filter у loose mode там, де мультихом вимагає, або тримайте strict, якщо можете гарантувати симетрію.
- Підтвердьте за допомогою
ip route getдля репрезентативних клієнтських IP. - Підтвердьте за допомогою tcpdump: SYN входить, SYN-ACK виходить тим самим краєм.
Покроково: перевірити NAT на Linux-шлюзі
- Підтвердьте, що forwarding увімкнено:
sysctl net.ipv4.ip_forward. - Підтвердьте, що правила NAT існують (PREROUTING для DNAT, POSTROUTING для SNAT/masquerade).
- Підтвердьте, що FORWARD ланцюг дозволяє потік (new і established).
- Підтвердьте, що записи conntrack змінюються з
UNREPLIEDна replied під час тесту. - Підтвердьте, що маршрут за замовчуванням внутрішнього хоста вказує на 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», перестаньте трактувати це як загадку. Це проблема шляху пакета, поки не доведено інше.
- Запустіть
ip routeіip route getдля реальної зовнішньої IP-клієнта. Виправте симетрію шляху або додайте політичну маршрутизацію. - Огляньте
nft list ruleset(або iptables) і підтвердьте, що WAN-трафік явно дозволений там, де потрібно (INPUT для сервісів хоста, FORWARD для DNAT). - Використайте tcpdump на вхідних і вихідних інтерфейсах під час зовнішнього тесту. Підтвердьте: прихід, трансляція, пересилання, відповідь.
- Перевірте rp_filter і MTU, коли симптоми вибіркові або «переривчасті».
- Перетворіть знахідки на малий runbook для вашої команди: команди, очікувані виходи і одне рішення, яке кожен вихід диктує.
Мета — не запам’ятати кожен netfilter-хук. Мета — виробити звичку: ніколи не гадати, коли ядро може сказати вам, що воно робить.