Ніщо в сокеті не пам'ятає, який інтерфейс переніс запит, тому маршрут за замовчуванням VPN із повним тунелем може перехопити відповідь, що належить WAN. Служба не ігнорує вхідний інтерфейс; Linux маршрутизує локально створену відповідь за призначенням і політикою джерела. Правило на основі джерела може натомість надсилати лише відповіді служби через повну таблицю WAN, залишаючи звичайний вихід у тунелі. Порт залишається відкритим, поки відповідь виходить хибним шляхом, і тому симптом виглядає одностороннім.

Помилка: відповіді йдуть тим інтерфейсом, на який прийшли

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

Щойно служба приймає з'єднання, її відповідь — це новий локально створений пакет. Ядро переглядає правила маршрутизації для призначення та джерела відповіді, і маршрут за замовчуванням VPN є цілком припустимою відповіддю. Ніщо в сокеті не пам'ятає, який інтерфейс переніс запит.

Тому симптом виглядає одностороннім: запити надходять, відповіді зникають. Тому й правило брандмауера для вхідного порту нічого не змінює. Пакет не блокується на шляху всередину; він маршрутизується кудись інде на шляху назовні. Простежте відповідь пошуком із зазначенням джерела, і обхідний шлях стане видимим.

Що ядро насправді маршрутизує: адреса джерела

Потрібна зачіпка — це локальна адреса, яку служба використовує для відповідей. На хості з ілюстративною адресою eth0 192.0.2.10/24 і шлюзом 192.0.2.1 ця адреса присутня на інтерфейсі. На хмарній ВМ публічна адреса може бути трансльована вище й відсутня в гостьовій системі, тому використовуйте адресу, яку хост справді має.

Перевірте поточний стан, перш ніж резервувати номер таблиці або пріоритет правила. Наявні правила політики можуть затінити нове, а стара таблиця з тим самим номером може вже нести не пов'язані маршрути:

ip -4 addr show dev eth0
ip -4 rule show
ip -4 route show table all

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

Будуйте повну таблицю повернення, а не половину маршруту за замовчуванням

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

ip -4 route add table 100 192.0.2.0/24 dev eth0 src 192.0.2.10
ip -4 route add table 100 default via 192.0.2.1 dev eth0
ip -4 rule add priority 1000 from 192.0.2.10/32 lookup 100

Використовуйте справжній префікс і шлюз, а не копіюйте приклад. Хмарному інтерфейсу, налаштованому як /32 зі шлюзом на каналі, потрібен інший підключений маршрут, а таблиця, побудована з хибного префікса, відмовляє на першому кроці. Атрибут src указує бажане джерело для цього маршруту; він не замінює правило джерела.

Порядок теж важливий. Широке правило з меншим номером пріоритету оцінюється першим, тому до правила джерела треба дістатися раніше за будь-яке правило, яке повернуло б цей трафік до головної таблиці. Перевірте пріоритети за допомогою ip rule show після додавання, а не лише під час завантаження.

Перевірте пошуком із зазначенням джерела

Попросіть ядро маршрутизувати тестове призначення з адреси служби. Відповідь має назвати eth0 і шлюз WAN, а не тунель:

ip -4 route get 198.51.100.25 from 192.0.2.10

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

Розмістіть підсумкові маршрути й правило під мережевим менеджером, якому належить інтерфейс. Зміни адреси, оновлення DHCP і перепідключення VPN переписують стан ядра, а правило, додане вручну, зникає або вказує на застарілий шлюз після наступної події.

Де закінчується цей виняток

Правило виключає локально завершений трафік з однієї адреси джерела. Воно не охоплює порти, які публікує Docker, DNAT або служби, переслані через хост, бо такі пакети маршрутизуються як пересланий трафік і ніколи не несуть локальне джерело хоста тим самим способом. Такі схеми зазвичай потребують мітки, встановленої на вході, і правила, що збігається з міткою.

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

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

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

Схожі статті