Вложен WireGuard: средният хоп не може да отговори на собствения си порт
Когато средният хоп изпраща всичко в един тунел, отговорите към входящата му услуга излизат по грешен път. Правило за порт на източника на интерфейса го поправя.
Три хопа WireGuard достигат до мрежа без публичен адрес и тогава средната машина спира да отговаря на порта, на който е трябвало да слуша. Тунелът напред продължава да работи, отдалеченият хост продължава да отговаря и само средният сървър е замлъкнал отвън. Тази комбинация е объркваща точно защото е самонанесена: средният хоп се подчинява на собствената си таблица за маршрутизация, а таблицата изпраща отговорите му в грешната посока.
Верига, която работи, докато не заговориш със средната кутия
Вземете илюстративна верига: клиент A достига сървър B по UDP 500, а B преминава напред към сървър C по UDP 500. C приема трафик само от адреса на единствения си партньор, което го прави листо и запазва поведението му просто. B не е листо и всичко интересно в тази повреда се случва там.
Разликата е важна, защото ролите на листо и на среда дърпат в противоположни посоки. Листото може да изпрати всичко в един тунел без последствия, тъй като нищо друго не зависи от него. Средният хоп е едновременно крайна точка за клиентите и клиент към далечната страна, а тези две задачи искат различна маршрутизация.
Защо отговорът излиза през тунела
На B интерфейсът към C носи AllowedIPs = 0.0.0.0/0 заедно със съответния маршрут по подразбиране. Затова всеки пакет, който B създава, влиза в този тунел, освен ако нещо по-конкретно не вземе предимство.
Пакет от A, адресиран до B, пристига и се приема, защото B е дестинацията и локалната доставка се случва първа. Отговорът е чисто нов локално генериран пакет, насочен към публичния адрес на A, и тази дестинация съвпада с маршрута по подразбиране в тунела. C го получава, не притежава този адрес и го изхвърля.
Симптомът изглежда като проблем със защитна стена или несъответствие на ключове и тук нито едното не е вярно. Снимка на тунела към C показва, че отговорите тръгват в грешната посока. Това единствено наблюдение спестява повече време от всякакво четене на конфигурация, затова го запишете, преди да започнете да сменяте ключове. Всеки, който не е видял снимката, ще предположи, че самият тунел е счупен.
Тясната поправка: правила за политика, съвпадащи с порт на източника
Отговорите от слушащия сокет на B излизат с порт на източника 500. Правило за политика може да съвпадне с това и да върне тези пакети към обикновената таблица:
ip rule add sport 500 table main priority 100
ip rule add sport 8080 table main priority 101
Правилата за политика се преглеждат в ред на приоритет, а основната таблица е на 32766, така че правило на 100 се пита преди маршрутът по подразбиране на тунела да получи дума. Добавете по един запис за всеки порт, който трябва да остане достъпен отвън, и нищо повече, така че препращаният трафик да продължи да използва тунела, за който е построен.
Познавайте границата на този трик. Селекторът sport съвпада с локално генерирани пакети, което покрива точно случая с отговора и умишлено не покрива трафик, който B само препраща за някой друг. Услуга, хоствана зад B, все още се нуждае от собствен отговор и преструвката за обратното дава поправка, която работи за първата услуга и се проваля за втората.
Дайте на правилото собственик
Правило, въведено в подкана, изчезва следващия път, когато интерфейсът бъде изграден наново. При настройка на WireGuard го поставете там, където интерфейсът се създава и премахва:
PostUp = ip rule add sport 500 table main priority 100
PostDown = ip rule del sport 500 table main priority 100
Ако интерфейсът се притежава от NetworkManager, хук на дистрибуцията или входна точка на контейнер, двойката принадлежи на този собственик, а не на ръчно редактиран файл. Проверявайте ефективните правила след повторно свързване, а не само след първия старт, защото първият старт е случаят, който винаги работи.
Сравнете алтернативите честно
Правилото за порт на източника е един от четири изхода и е най-тесният от тях. Предимството му е, че изобщо не пипа политиката на тунела, поради което обикновено оцелява след по-късни промени. Тесните поправки също се провалят шумно, когато спрат да важат, докато широкото изключение продължава да работи тихо дълго след като причината за него е изчезнала. Тази разлика има по-голямо значение от елегантността, когато след две години кутията е на някой друг.
| Approach | What it costs | Where it breaks |
|---|---|---|
| Source-port policy rule | One rule per exposed port | Anything B forwards rather than originates |
| Destination exception route | A route pinned to specific client addresses | Clients whose address changes |
| Stop full-tunnelling on B | Loses the catch-all path toward C | Designs that depend on it |
| Split into two tunnels | More interfaces and more policy | Nothing, at the cost of complexity |
Проверете от двата края, след като изберете. От A започнете връзка към порта на B и я поддържайте заета известно време. На B накарайте ядрото да обоснове пътя на отговора с нещо като ip route get <address-of-A> sport 500 и потвърдете, че посочва WAN интерфейса, а не тунела. След това проверете, че нещо зад C все още отговаря през веригата, което доказва, че изключението е останало тясно, вместо да се превърне в обходен път. Накрая запишете портовете в бележките за дизайна, иначе следващият оператор ще открие това на друга услуга.