Симптом: мультихомований вузол на Ubuntu 24.04 «переважно працює», доки раптом — ні. Деякі вхідні з’єднання зависають. Відповіді зникають. Моніторинг каже, що канал у порядку. Команда застосунку наполягає, що це DNS. Це не DNS.
Реальність: ядро тихо відкидає пакети, тому що rp_filter вирішив, що ваш маршрут виглядає підозрілим. І якщо у вас дві мережеві карти, два uplink’и, VRF, політика маршрутизації, Kubernetes, VIP-и або щось, що нагадує реальний світ, підозра стає способом життя.
Випадок №54: мультихомінг-аутейдж, який ви не очікували
Сформуємо це як реальний інцидент, бо саме так ви з ним зустрінетесь: напіваутейдж з дуже дивною симптоматикою.
У сервісного вузла два uplink’и:
- eth0 до «внутрішньої» мережі (east-west трафік, кластер, сховище).
- eth1 до «dmz/edge» мережі (north-south трафік, партнери, моніторинг, іноді VPN).
Обидва лінки підняті. Обидва мають адреси. Є політика маршрутизації, щоб певні IP-джерела віддавали перевагу певним шлюзам. Може також бути VIP для фейловеру (VRRP/keepalived) або інтерфейс WireGuard, який стає дефолтним маршрутом для частини трафіку.
Потім хтось оновлює до Ubuntu 24.04 або перебудовує вузол і застосовує «посилення безпеки» через sysctl. Раптом:
- вхідні SYN-и приходять на eth1, але SYN-ACK ніколи не йде назад.
- ICMP-пінг працює з деяких мереж, але не з інших.
- з’єднання від одного партнера флапають кожні кілька хвилин.
- трафік до сховища працює; трафік до балансувальника — ні; здоров’я Kubernetes — лотерея.
Першу годину всі винуватять очевидне: правила файрволу, MTU, «поганий порт комутатора» і—неуникно—DNS. Тим часом ядро відкидає пакети, бо перевірка зворотного шляху не знаходить маршруту назад через той самий інтерфейс, на якому пакет прийшов, отже визначає підробку і відкидає.
Цитата, яку варто записати у ранбуки: «Надія — це не стратегія.» — парафраз ідеї, яку часто приписують інженерам з надійності
Груба правда така: мультихомінг без явного дизайну маршрутизації — це азартна гра з більшою кількістю кабелів.
Що насправді робить фільтрація зворотного шляху (і чому це боляче)
rp_filter — це функція валідації джерела в Linux. Мета хороша: відкидати пакети, що вказують адресу джерела, до якої система не змогла б надіслати відповідь. Це блокує часткові підробки адрес і зменшує площу ураження від поганих маршрутів. В простих одноінтерфейсних налаштуваннях це зазвичай непомітно і в основному корисно.
Ментальна модель
Коли пакет приходить на інтерфейс X з IP-адреси джерела S, ядро запитує: «Якщо я мав би відправити пакет до S, він вийшов би через інтерфейс X?»
- Якщо відповідь «так» — приймаємо пакет.
- Якщо відповідь «ні» — відкидаємо його (або обробляємо особливим чином залежно від режиму).
Строгий vs вільний vs вимкнений
Linux реалізує це через net.ipv4.conf.*.rp_filter:
- 0 (вимкнений): не виконувати перевірку зворотного шляху.
- 1 (строгий): вхідний інтерфейс має збігатися з маршрутом назад до джерела. Добре для одношляхових конфігурацій. Небезпечно при асиметрії.
- 2 (вільний): джерело має бути досяжним через якийсь інтерфейс (маршрут існує), але не обов’язково через інтерфейс, на якому пакет прийшов. Зазвичай це здравомислящий режим для мультихомованих хостів.
Мультихомінг навмисно створює асиметрію. Трафік може легітимно увійти через один інтерфейс і вийти через інший через:
- policy routing (
ip rule) - кілька дефолтних шлюзів (навіть «випадково»)
- ECMP-рішення в мережах провайдера
- NAT або зміни в рекламі VIP (VRRP/keepalived)
- тунелі (WireGuard, IPsec), де «шлях назад» не відповідає фізичній NIC
Строгий rp_filter трактує ці легітимні пакети як підробки. Ви отримуєте «випадкову» втрату пакетів, яка корелює з тим, який шлях обрав upstream — саме тому ви можете годину дивитись на машину і впевнено казати, що вона зачарована.
Жарт #1: Фільтрація зворотного шляху — як швейцар, що перевіряє, чи вийдете ви тією ж дверима, якою ввійшли. Добре для пожежної безпеки, жахливо для будівель з кількома виходами.
Цікаві факти та контекст (чому це повторюється)
- rp_filter існує, бо підробки адрес колись були звичайною справою. У ранні, менш відфільтровані дні Інтернету сфабриковані джерела були досить поширені, щоб валідація на хості мала сенс.
- Це частина ширшої родини “перевірки адреси джерела”. Мережі реалізують схожі механізми на краях, але валідація на хості все ще допомагає, коли upstream-фільтрація непослідовна.
- Режим “вільний” створено спеціально для толерантності до асиметрії. Мультихомінг і складна маршрутизація вже не «крайні випадки» — це буденні завдання.
- Налаштування є per-interface і також “all”/”default”. Люди змінюють одне і вважають, що це впливає на інші. Ні — не завжди і не так, як ви думаєте.
- Контейнери та Kubernetes додають інтерфейси, яких ви не просили. CNI-плагіни створюють veth-пари, мости і маршрути, що можуть несподівано змінити рішення про зворотний шлях.
- VRRP/keepalived VIP-и можуть спричиняти відсіювання rp_filter під час фейловеру. VIP може з’явитися на одному інтерфейсі, тоді як «найкращий» шлях назад тимчасово лежить іншим шляхом під час конвергенції.
- Хмарна мережа часто створює асиметричні шляхи назад. Другорядні NIC, перевірки source/destination, оверлейна маршрутизація — пакети можуть приходити «з» місць, які ваша головна таблиця не обере для відповіді.
- rp_filter взаємодіє з політичною маршрутизацією неочевидними способами. Зворотній пошук може не консультуватися з тією таблицею маршрутів, яку ви очікуєте, якщо правила і вибір джерела налаштовані неправильно.
- Люди плутають rp_filter з файрволом. Відкидання відбувається до того, як ви побачите його в логах
iptables/nftables, якщо ви явно не ведете журнал kernel martians.
Швидкий план діагностики
Якщо ви на виклику і маєте 10 хвилин до ескалації, робіть це в порядку. Мета — швидко довести або виключити rp_filter, потім вирішити, чи потрібні зміни в маршрутах або sysctl.
1) Підтвердіть, що симптом спрямований та залежить від інтерфейсу
- Чи бачите ви вхідні пакети на очікуваному інтерфейсі?
- Чи виходять відповіді, і якщо так — через який інтерфейс?
- Чи пов’язана помилка з певною мережею джерела?
2) Перевірте значення rp_filter (all, default та інтерфейси)
Якщо rp_filter=1 де-небудь релевантно — вважайте його підозрюваним, поки не доведете протилежне.
3) Зробіть пошук маршруту для IP-адреси джерела в контексті інтерфейсу
Використайте ip route get і переконайтесь, що egress-інтерфейс збігається з ingress-інтерфейсом, якщо увімкнено строгий режим. Якщо не збігається — строгий режим відкине.
4) Подивіться kernel-логи: martians та скарги на зворотний шлях
Увімкніть тимчасовий логгінг за потреби, але не лишайте це ввімкненим назавжди на системах з великим трафіком, якщо вам не подобається заповнений диск.
5) Якщо мультихомінг задуманий — перемикайтесь на вільний режим (2) або виправляйте політику маршрутизації
Строгий режим — окей для однохомінгових серверів. Мультихомовані сервери — не однохомінгові. Підходьте до них по-іншому.
Практичні завдання: команди, виводи, рішення (12+)
Ось ті завдання, які я реально виконую, коли мультихомований Ubuntu-хост починає «без причини» відкидати трафік. Кожне містить: команду, приклад виводу, що це означає і яке рішення прийняти.
Завдання 1: Перелічити інтерфейси та адреси (виявити мультихомінг і VIP-и)
cr0x@server:~$ ip -br addr
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 10.10.10.20/24
eth1 UP 172.20.5.20/24
wg0 UP 10.99.0.2/32
Значення: у вас принаймні два L3-домени плюс тунель. Асиметрія — не гіпотеза.
Рішення: вважайте хост мультихомованим; строгий rp_filter ймовірно невірний, якщо тільки маршрути не прив’язані дуже ретельно.
Завдання 2: Показати дефолтні маршрути та метрики (виявити випадкові «два дефолти»)
cr0x@server:~$ ip route show default
default via 10.10.10.1 dev eth0 proto dhcp src 10.10.10.20 metric 100
default via 172.20.5.1 dev eth1 proto static src 172.20.5.20 metric 200
Значення: існують два дефолтні маршрути. Linux віддасть перевагу нижчій метриці, але вхідний трафік може приходити обома інтерфейсами залежно від upstream.
Рішення: або реалізуйте policy routing за джерелом/інтерфейсом, або очікуйте, що строгий rp_filter відкидатиме пакети.
Завдання 3: Перевірити rp_filter глобально та по інтерфейсу (звичайний курок)
cr0x@server:~$ sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.default.rp_filter net.ipv4.conf.eth0.rp_filter net.ipv4.conf.eth1.rp_filter
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 1
net.ipv4.conf.eth1.rp_filter = 1
Значення: скрізь строгий режим.
Рішення: якщо хост дійсно мультихомований (а не «один інтерфейс — баласт»), змініть на вільний режим (2) для релевантних інтерфейсів або перерахуйте маршрути так, щоб строгий контроль працював.
Завдання 4: Підтвердити проблему через пошук маршруту до проблемного джерела (логіка зворотного шляху)
cr0x@server:~$ ip route get 203.0.113.55
203.0.113.55 via 10.10.10.1 dev eth0 src 10.10.10.20 uid 0
cache
Значення: ядро відправило б трафік до 203.0.113.55 через eth0. Якщо пакети від 203.0.113.55 приходять на eth1, строгий rp_filter відкине їх.
Рішення: або виправте маршрути так, щоб шлях назад використовував eth1 для цього джерела (policy routing), або ослабте rp_filter.
Завдання 5: Захоплення на інтерфейсі ingress (підтвердити, що пакети приходять)
cr0x@server:~$ sudo tcpdump -ni eth1 host 203.0.113.55 and tcp port 443 -c 5
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:10:01.100001 IP 203.0.113.55.51512 > 172.20.5.20.443: Flags [S], seq 123456789, win 64240, options [mss 1460,sackOK,TS val 1 ecr 0], length 0
12:10:02.100002 IP 203.0.113.55.51512 > 172.20.5.20.443: Flags [S], seq 123456789, win 64240, options [mss 1460,sackOK,TS val 2 ecr 0], length 0
^C
2 packets captured
Значення: SYN-и приходять на eth1. Якщо сервіс слухає, ви маєте бачити SYN-ACK назовні. Якщо ні — підозрюйте відкидання ядром або локальний файрвол.
Рішення: зловіть трафік і на egress; якщо нічого не виходить, переходьте до rp_filter/martian перевірок.
Завдання 6: Захоплення на очікуваному egress (перевірити, чи відповіді йдуть в інше місце)
cr0x@server:~$ sudo tcpdump -ni eth0 host 203.0.113.55 and tcp port 443 -c 5
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
^C
0 packets captured
Значення: ніяких відповідей через eth0 для того потоку (принаймні під час захоплення). У поєднанні з Завданням 5 — ймовірне відкидання перед тим, як TCP-стек відповість, або відповіді блоковані десь ще.
Рішення: перевірте kernel-логи і rp_filter; впевніться, що сервіс слухає; перевіряйте nftables/iptables після того, як виключите rp_filter.
Завдання 7: Переглянути kernel-логи на предмет martians і відкидань rp_filter
cr0x@server:~$ sudo journalctl -k --since "10 min ago" | tail -n 20
Dec 30 12:09:58 server kernel: IPv4: martian source 203.0.113.55 from 203.0.113.55, on dev eth1
Dec 30 12:09:58 server kernel: ll header: 00000000: 00 11 22 33 44 55 66 77 88 99 aa bb 08 00
Dec 30 12:09:58 server kernel: IPv4: martian source 203.0.113.55 from 203.0.113.55, on dev eth1
Значення: ядро повідомляє, що вважає це джерело недопустимим на цьому інтерфейсі. Це дія перевірки зворотного шляху (або пов’язані martian-перевірки).
Рішення: перемкніть на вільний rp_filter або виправте policy routing, щоб зворотний шлях збігався.
Завдання 8: Тимчасово встановити rp_filter у вільний режим (швидкий тест, не назавжди)
cr0x@server:~$ sudo sysctl -w net.ipv4.conf.eth1.rp_filter=2
net.ipv4.conf.eth1.rp_filter = 2
Значення: eth1 тепер у вільному режимі.
Рішення: перетестуйте проблемного клієнта. Якщо проблема зникає одразу — ви підтвердили корінь проблеми. Тоді зробіть постійне, документоване змінення (та оцініть наслідки для безпеки).
Завдання 9: Зробити rp_filter постійним через окремий sysctl-файл
cr0x@server:~$ printf '%s\n' \
'net.ipv4.conf.all.rp_filter=2' \
'net.ipv4.conf.default.rp_filter=2' \
'net.ipv4.conf.eth0.rp_filter=2' \
'net.ipv4.conf.eth1.rp_filter=2' | sudo tee /etc/sysctl.d/60-multihome-rpfilter.conf
net.ipv4.conf.all.rp_filter=2
net.ipv4.conf.default.rp_filter=2
net.ipv4.conf.eth0.rp_filter=2
net.ipv4.conf.eth1.rp_filter=2
cr0x@server:~$ sudo sysctl --system | tail -n 8
* Applying /etc/sysctl.d/60-multihome-rpfilter.conf ...
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2
net.ipv4.conf.eth0.rp_filter = 2
net.ipv4.conf.eth1.rp_filter = 2
Значення: налаштування переживуть перезавантаження і застосовуватимуться передбачувано.
Рішення: зафіксуйте це в системі управління конфігураціями і додайте пояснення; «посилення безпеки» без винятків — джерело дзвінків о півночі.
Завдання 10: Валідовати правила політичної маршрутизації (якщо ви хочете залишити строгий rp_filter)
cr0x@server:~$ ip rule show
0: from all lookup local
100: from 172.20.5.20 lookup 200
110: from 10.10.10.20 lookup 100
32766: from all lookup main
32767: from all lookup default
Значення: трафік із кожного IP використовує різну таблицю. Це початок порядку.
Рішення: перегляньте таблиці 100 і 200, щоб переконатися, що в них правильні дефолтні шлюзи і on-link маршрути. Якщо таблиця неповна — зворотні шляхи і маршрути відповідей все ще будуть неправильні.
Завдання 11: Переглянути кастомні таблиці маршрутів (чи є дефолт і підключені маршрути?)
cr0x@server:~$ ip route show table 100
default via 10.10.10.1 dev eth0 src 10.10.10.20
10.10.10.0/24 dev eth0 proto kernel scope link src 10.10.10.20
cr0x@server:~$ ip route show table 200
default via 172.20.5.1 dev eth1 src 172.20.5.20
172.20.5.0/24 dev eth1 proto kernel scope link src 172.20.5.20
Значення: кожна таблиця самодостатня (дефолт + підключена підмережа). Це бажаний стан.
Рішення: якщо ви хочете строгий rp_filter, потрібно гарантувати, що шляхи для відповідей збігаються з інтерфейсом входу. Policy routing допомагає, але переконайтесь, що вибір джерела і бінд аплікацій коректні.
Завдання 12: Пошук маршруту з явним джерелом (перевірити policy routing)
cr0x@server:~$ ip route get 203.0.113.55 from 172.20.5.20
203.0.113.55 via 172.20.5.1 dev eth1 src 172.20.5.20 uid 0
cache
Значення: якщо відповідь буде походити з 172.20.5.20, вона вийде через eth1. Це відповідає очікуванням строгого зворотнього шляху для потоків, що приходять на eth1.
Рішення: якщо це не збігається — виправляйте ip rule і таблиці маршрутів замість того, щоб сліпо відключати rp_filter.
Завдання 13: Перевірити налаштування логування martian (корисно під час інциденту)
cr0x@server:~$ sysctl net.ipv4.conf.all.log_martians net.ipv4.conf.eth1.log_martians
net.ipv4.conf.all.log_martians = 0
net.ipv4.conf.eth1.log_martians = 0
Значення: ядро може відкидати пакети без повідомлень.
Рішення: тимчасово увімкніть логування на підозрілому інтерфейсі під час діагностики; вимкніть потім, щоб уникнути спаму в логах.
Завдання 14: Тимчасово увімкнути martian-логування (цільово, обмежено за часом)
cr0x@server:~$ sudo sysctl -w net.ipv4.conf.eth1.log_martians=1
net.ipv4.conf.eth1.log_martians = 1
Значення: тепер ви побачите докази в journalctl -k, коли логіка зворотного шляху відкидає трафік.
Рішення: відтворіть проблему один раз, збережіть логи, потім вимкніть.
Завдання 15: Перевірити налаштування, пов’язані з ARP flux (часто супроводжують мультихомінг)
cr0x@server:~$ sysctl net.ipv4.conf.all.arp_ignore net.ipv4.conf.all.arp_announce
net.ipv4.conf.all.arp_ignore = 0
net.ipv4.conf.all.arp_announce = 0
Значення: поведінка ARP за замовчуванням може бути «творчою» на мультихомованих хостах (відповідь на «не той» інтерфейс). Це не rp_filter, але породжує схожі дивні симптоми.
Рішення: якщо ви використовуєте VIP-и або кілька підмереж, розгляньте посилення ARP-настроювань разом із налаштуванням rp_filter, особливо на bare metal або L2-суміжних мережах.
Три корпоративні міні-історії з практики
Міні-історія 1: аутейдж через невірне припущення
Компанія мала пару «ідентичних» API-вузлів у двох дата-центрах. Кожен вузол мав дві NIC: одну для внутрішніх сервісів, іншу для трафіку партнерів. У документі дизайну було написано «traffic from partners uses eth1». Цей рядок сприйняли як фізичний закон.
Сталася зміна в мережі upstream — рутинне обслуговування, tweak переваг BGP, нічого драматичного. Шлях назад від одного партнера почав приходити через інший edge, і пакети почали приземлятися на eth0 в одному з сайтів через новий L3-hop. API-вузол все ще відповідав через eth1 через policy routing, що базувався на адресу відповіді.
Строгий rp_filter був увімкнений як частина базового пакету посилення. Він завжди був увімкнений. Він також завжди щастив. Коли прийшла асиметрія — ядро почало відкидати вхідні пакети як «martians». Команда додатка бачила переривчасті 5xx. SRE на виклику не бачив помилок інтерфейсу, відмов файрволу чи підвищеного CPU. Лише повільний потік невдалих сесій.
Невірне припущення було тонким: «partner traffic uses eth1» означало, що він має приходити на eth1. У маршрутизованих мережах «має» — це бажання, не гарантія.
Фікс був не героїчний. Вони перемкнулися на вільний режим для інтерфейсу, спрямованого до партнерів, і оновили policy routing для узгодженості. Потім додали regression test: перевірки пошуку маршруту з кожної source IP до представницьких префіксів партнерів. Ключовий рядок у постмортемі: «Ми припускали симетрію; мережа не підписала цей контракт.»
Міні-історія 2: оптимізація, що відпомстилася
Платформна команда хотіла зменшити ризик латерального руху. Вони розгорнули новий набір sysctl по флоту: строгий rp_filter, martian logging вимкнений (щоб зменшити «шум») і кілька додаткових перемикачів, які добре виглядали у таблиці відповідності.
Це працювало на веб-шарі: одна NIC, один дефолтний маршрут, передбачувано. Тож команда внесла це у базовий образ, що використовувався для всього, включно зі станними системами з реплікацією, резервними мережами та іноді «міграційною NIC», що приходила й відходила.
Відплата була відкладеною. Через місяць сервіс, близький до сховища, почав падати тільки під час вікон резервного копіювання. Чому? Система бекапу використовувала іншу мережу, і під час тих годин сервіс іноді відправляв трафік з «бекапної» адреси через занадто широку прив’язку аплікації. Відповіді йшли іншим інтерфейсом, ніж вхідні запити. Строгий rp_filter трактував частину вхідних потоків як підробку і відкидав їх, але лише коли були певні маршрути.
Оптимізація — посилення валідації скрізь — створила переривчастий баг, який збігався з операційним графіком. Найгірший тип переривчастих помилок: відтворюється лише тоді, коли ви втомлені і кава скінчилася.
Вони відновились, розділивши профілі sysctl: один для однохомінгових, безстанних шарів, інший — для мультихомованих і routing-complex систем. Також змінили підхід до «тихих логів». Не треба martian-логів цілий день, але потрібен легкий перемикач для включення під час інцидентів. Тихі системи приємні; тихі збої — дорогі.
Міні-історія 3: нудна, але правильна практика, що врятувала день
Регульована компанія експлуатувала мультихомовані bastion-хости: одна NIC до адміністративної мережі, інша — до контрольованого сегмента партнерів. Серед змін був любов до «швидких фіксів». Ці хости не любили швидких фіксів.
Команда мала правило: кожен мультихомований вузол повинен мати невеликий routing self-test, що запускається при завантаженні і при перезавантаженні мережі. Він виконував ip route get для кількох репрезентативних дестинацій з кожної source-адреси і порівнював вихід з очікуваним. Якщо відхилення — сповіщення до появи користувацьких проблем.
Одного дня після оновлення ядра і зміни netplan тест упав: шлях назад з IP партнера почав віддавати перевагу адміністртивному дефолтному маршруту. Ніхто не помітив цього в нормальній активності, бо єдиний впливовий потік був низькооб’ємним колбеком моніторингу. Але тест помітив це голосно.
Фікс — одна рядок виправлення порядку ip rule і свідомий вибір: залишити rp_filter=2 на партнерському інтерфейсі, бо асиметричний вхід все ще міг статися. Ключовий момент — нудний: проблему спіймав детермінований чек, а не героїчне відлагодження у продакшні.
Жарт #2: Найнадійніша система — та, що падає в staging. Друга по надійності — та, що одразу скаржиться.
Проєктування мультихомінгу, що виживає rp_filter
Виберіть філософію: сувора коректність або операційна толерантність
У вас є два обґрунтовані підходи. Змішання їх без обдумування — шлях до «випадку №54».
Підхід A: Залишити строгий rp_filter, спроєктувати симетрію
Це працює, але це праця:
- Гарантуйте, що трафік, що входить на інтерфейс X, завжди маршрутується назад до джерела через X.
- Реалізуйте policy routing:
ip ruleза source IP (та іноді fwmarks) для вибору таблиці маршрутів на кожний інтерфейс/uplink. - Зробіть кожну таблицю маршрутів повною: підключені маршрути плюс дефолт (та потрібні специфічні маршрути).
- Переконайтесь, що аплікації прив’язуються до потрібних source-адрес або використовують
SO_BINDTODEVICE/bind()там, де потрібно.
Це добре, коли ви дійсно контролюєте обидва кінці шляху (приватний WAN, передбачуваний upstream). Менш добре в публічному Інтернеті або в хмарах із «дружньою» маршрутизацією.
Підхід B: Використовувати вільний rp_filter для мультихомінгу, зосередитись на досяжності і логуванні
Це те, що я рекомендую для більшості мультихомованих хостів з непередбачуваними шляхами:
- Встановіть
rp_filter=2на релевантних інтерфейсах (або глобально, якщо хост постійно мультихомований). - Все ще тримайте policy routing, бо ви хочете стабільну поведінку egress і коректний вибір source-адрес.
- Увімкніть martian-логи лише під час розслідування або направляйте їх у rate-limited логінгові канали.
- Спирайтесь на upstream anti-spoofing на краях мережі, плюс локальний файрвол і принцип найменших привілеїв. rp_filter — не єдиний ваш захист.
Особливості Ubuntu 24.04: де люди дивуються
Ubuntu 24.04 сама по собі не зла. Сюрприз зазвичай походить від того, що ви змінили одночасно:
- нові базові образи
- нові набори hardening sysctl
- netplan-переписи, які ненавмисно додають другий дефолтний маршрут або змінюють метрики
- оновлення ядра, що змінюють імена інтерфейсів або поведінку драйверів і перешаровують маршрути
- оновлення мережевого стека контейнерів (CNI), що додають правила і маршрути
Режим відмови відчувається як «мережа Ubuntu некоректна». Це не так. Ваша політика маршрутизації не узгоджується зі строгим валідаційним запитом. Ядро просто застосовує те, що ви попросили.
Як вирішити: практична рубрика
- Якщо сервер однохомований і залишається таким: строгий (1) підходить і часто бажаний.
- Якщо сервер має два активні uplink’и: за замовчуванням — вільний (2), якщо у вас немає сильної причини і сильної дисципліни маршрутизації.
- Якщо сервер використовує VIP-и, VRRP, direct server return або anycast-подібні трюки: припускайте асиметрію; використовуйте вільний (2) і тестуйте фейловери.
- Якщо сервер запускає Kubernetes з кількома CNI або спеціальною маршрутизацією: вільний (2) зазвичай безпечніший; потім валідовуйте через
ip route getдля кожної pod-мережі за потреби. - Якщо політика безпеки вимагає строгого режиму: забезпечте симетрію через policy routing і явні прив’язки аплікацій, додайте постійні тести щоб це не відхилилося.
Поширені помилки: симптом → корінь → виправлення
1) «Вхідні з’єднання таймаутяться, але лише з деяких мереж»
Симптом: певні підмережі клієнтів не можуть підключитись; інші — в порядку. SYN-и приходять, SYN-ACK не відправляється.
Корінь: строгий rp_filter відкидає пакети, що приходять на інтерфейс, який не є переважним шляхом повернення для цього джерела (асиметричний шлях).
Виправлення: встановіть net.ipv4.conf.<if>.rp_filter=2 або реалізуйте source-based routing, щоб шлях назад збігався з інтерфейсом входу.
2) «Після додавання другого дефолтного маршруту для стійкості все зламалось»
Симптом: після додавання backup gateway з’єднання стали нестабільними.
Корінь: два дефолти плюс строгий rp_filter створюють невідповідність, коли трафік приходить на інтерфейс з вищою метрикою.
Виправлення: не покладайтеся лише на «резервний дефолт»; використовуйте policy routing або протоколи маршрутизації. Якщо залишаєте два дефолти — віддавайте перевагу вільному rp_filter.
3) «Логи файрволу нічого не показують, але пакети зникають»
Симптом: лічильники nftables/iptables не рухаються; tcpdump бачить вхідні пакети; аплікація не відповідає.
Корінь: відкидання rp_filter відбувається до хуків файрволу, і martian-логування вимкнене.
Виправлення: перевірте sysctl net.ipv4.conf.*.rp_filter, тимчасово увімкніть log_martians, потім налаштуйте rp_filter вільним або виправте маршрути.
4) «VRRP фейловер спричиняє короткий аутейдж, потім відновлення»
Симптом: VIP перемістився, і деякі клієнти падають на 10–60 секунд.
Корінь: під час конвергенції «найкращий шлях повернення» змінюється швидше/повільніше за рекламу VIP; строгий rp_filter відкидає пакети, що приходять на «не той» інтерфейс.
Виправлення: використовуйте вільний rp_filter на інтерфейсах з VIP-ами і перевірте ARP-настроювання (arp_ignore/arp_announce) щоб уникнути плутанини інтерфейсів.
5) «WireGuard працює назовні, але вхідний рукопотиск ненадійний»
Симптом: тунель іноді піднімається; віддалений пір бачить повторні спроби.
Корінь: пакети до endpoint тунелю приходять на одну NIC, а шлях назад віддає перевагу іншій через дефолт/метрики; строгий rp_filter відкидає.
Виправлення: rp_filter вільний, плюс закріпіть маршрути до endpoint-піра на правильний uplink, якщо потрібна детермінована поведінка.
6) «Ми встановили rp_filter=2 у /etc/sysctl.conf, але після перезавантаження воно все ще 1»
Симптом: runtime-значення повертаються назад.
Корінь: інший файл в sysctl.d переоприділяє це пізніше, або cloud-init/hardening застосовує свої налаштування після вашого файлу.
Виправлення: помістіть окремий файл з порядком, що перемагає (вищий лексичний порядок), потім перевірте через sysctl --system.
7) «Лише один інтерфейс страждає»
Симптом: eth1 відкидає, eth0 ні.
Корінь: per-interface rp_filter різний, або лише один інтерфейс отримує асиметричний трафік.
Виправлення: перевірте per-interface налаштування. Не думайте, що all означає, що кожний інтерфейс такий самий.
Контрольні списки / покроковий план
Чекліст A: зупинити кровотечу (режим інциденту)
- Доведіть прихід: tcpdump на підозрілому інтерфейсі для IP/порту проблемного клієнта.
- Перевірте rp_filter: прочитайте
net.ipv4.conf.all/default/<if>.rp_filter. - Перевірте шлях назад:
ip route get <client-ip>і порівняйте очікуваний egress-інтерфейс. - Пошукайте martians:
journalctl -k. Якщо нічого — тимчасово увімкнітьlog_martians=1на інтерфейсі. - Швидке пом’якшення: встановіть rp_filter вільним (2) на уражених інтерфейсах, перетестуйте.
- Відкличте ризикові зміни: якщо пакет hardening розгортається по флоту — зупиніть його і ізолюйте мультихомовані ролі.
Чекліст B: виправити коректно (після інциденту)
- Визначте модель: strict-with-symmetry або loose-with-policy-routing.
- Приберіть випадкові подвійні дефолти: якщо обидва дефолти потрібні — документуйте і забезпечте метрики та правила навмисно.
- Реалізуйте policy routing: одна таблиця на uplink/source IP. Тримайте таблиці повними.
- Валідовуйте через route probes: запуск
ip route getз кожної source IP до репрезентативних дестинацій. - Зробіть sysctl постійним: окремий файл у
/etc/sysctl.d/; перевірте порядок застосування. - Документуйте винятки: мультихомовані хости — не «менш безпечні», а потребують інших контролів.
- Додайте детектор відхилень: простий скрипт, що сповіщує при зміні rp_filter або при відсутності потрібних маршрутів.
Чекліст C: хардення без самосаботажу
- Класифікуйте хости: однохомовані, мультихомовані, з VIP, кінці тунелів, вузли Kubernetes.
- Застосуйте rp_filter за класом: строгий для однохомованих; вільний для мультихомованих та VIP/тунелів, якщо симетрію не гарантують.
- Логування тактично: тримайте martian-логи вимкненими за замовчуванням, але забезпечте on-demand перемикач і rate-limiting.
- Тестуйте режими відмов: фейловери, down/up лінків, оновлення DHCP, netplan apply, перезапуск CNI.
Питання і відповіді
1) Чи є rp_filter файрволом?
Ні. Це валідація джерела в маршрутизуючому шляху ядра. Воно може відкинути пакети до того, як ваші правила файрволу або логи покажуть проблему.
2) Чи варто ставити rp_filter=0 скрізь, щоб «виправити мережу»?
Тільки якщо ви любите обмін одного класу відмов на регресію безпеки. Для мультихомованих хостів у більшості випадків краще використовувати 2 (вільний) і тримати політику маршрутизації в порядку.
3) Яке найбезпечніше налаштування для мультихомованих Ubuntu-серверів?
rp_filter=2 зазвичай найкращий баланс. Поєднайте його з policy routing, щоб egress був детермінований. Якщо ви можете надійно забезпечити симетрію — строгий режим можливий, але це не безкоштовно.
4) Чому це з’являється після оновлення Ubuntu 24.04?
Бо оновлення часто збігаються з новими базовими sysctl, netplan-змінами, іншими метриками дефолту або новими інтерфейсами (тунелі, контейнери). rp_filter не став більш «злобним»; ваша середа стала складнішою.
5) Як підтвердити rp_filter як винуватця за кілька хвилин?
Перевірте sysctl net.ipv4.conf.<if>.rp_filter, виконайте ip route get <source-ip>, перевірте martian-логи. Тимчасово переключіть інтерфейс у вільний режим і перетестуйте. Якщо це вирішує — причина знайдена.
6) Чи дозволяє вільний режим (2) підробки адрес?
Він послаблює перевірку відповідності інтерфейсу, але зберігає вимогу до досяжності джерела. Це слабший механізм проти підробок, тож використовуйте upstream-фільтрацію і хост-файрвол як основні контролі.
7) Чому я бачу «martian source» в логах?
Це ядро каже, що отримало пакет з джерелом, яке не проходить санітарні перевірки для цього інтерфейсу — часто через строгий rp_filter або невідповідність маршрутів.
8) Чи можу я зберегти строгий rp_filter і все одно робити policy routing?
Так, але потрібна дисципліна: правильний порядок ip rule, повні таблиці маршрутів і передбачуваний вибір source-адрес. Якщо щось відхилиться — строгий rp_filter швидко це покарає.
9) Чи повинні вузли Kubernetes використовувати строгий rp_filter?
Зазвичай ні, якщо ваш CNI і маршрутизація не спроєктовані для цього. Мультиінтерфейсні вузли, оверлейні мережі і сервісні VIP-и роблять асиметрію звичною. Вільний режим практичніший.
10) Де це постійно задавати на Ubuntu 24.04?
Створіть файл у /etc/sysctl.d/ (наприклад 60-multihome-rpfilter.conf), застосуйте sysctl --system і перевірте кінцеві значення.
Висновок: кроки, що не розбудять вас о 03:00
Фільтрація зворотного шляху — одна з тих фіч, що виглядає як «безкоштовна безпека», поки ви не зіткнетесь із реальною мережею. Мультихомінг, VIP-и, тунелі і policy routing — нормальні речі в продакшні. Строгий rp_filter трактує «нормальне» як «злочинне».
Зробіть таке:
- Класифікуйте хости за складністю мережі. Припиніть застосовувати один і той же sysctl-профіль до всього.
- Для мультихомованих ролей встановіть rp_filter=2 (вільний), якщо ви не можете довести симетрію наскрізь.
- Реалізуйте policy routing, щоб egress був детермінований і дебаг був людяним.
- Додайте routing self-test (кілька
ip route getперевірок), щоб ловити дрейф до користувачів. - Тримайте перемикач martian-логів під рукою для інцидентів і вимикайте після збору доказів.
Якщо запам’ятати лише одне: мультихомінг — це дизайн, а не чекбокс. rp_filter лише показує, чи ви його проєктували.