Geneste WireGuard: de middelste hop kan zijn eigen poort niet beantwoorden
Wanneer de middelste hop alles in één tunnel stuurt, verlaten antwoorden op zijn inkomende dienst de verkeerde weg. Een bronpoortregel op de interface lost dat op.
Drie WireGuard-hops bereiken een netwerk zonder openbaar adres, en dan stopt de middelste machine met antwoorden op de poort waarop hij zou moeten luisteren. De tunnel verderop werkt nog, de verre host reageert nog, en alleen de middelste server zelf is van buitenaf stil geworden. Die combinatie is verwarrend juist omdat ze zelf veroorzaakt is: de middelste hop volgt zijn eigen routingtabel, en de tabel stuurt zijn antwoorden de verkeerde kant op.
Een keten die werkt tot je met de middelste doos praat
Neem een illustratieve keten: client A bereikt server B op UDP 500, en B gaat verder naar server C op UDP 500. C accepteert alleen verkeer van het adres van zijn enige peer, waardoor het een blad wordt en zijn gedrag eenvoudig blijft. B is geen blad, en alles wat interessant is aan deze storing gebeurt daar.
Het onderscheid is belangrijk omdat blad- en middenrollen tegengesteld trekken. Een blad kan alles in één tunnel sturen zonder gevolgen, omdat niets anders ervan afhangt. Een middelste hop is tegelijk een eindpunt voor clients en een client richting de verre kant, en die twee taken willen verschillende routing.
Waarom het antwoord via de tunnel vertrekt
Op B draagt de interface richting C AllowedIPs = 0.0.0.0/0 samen met de bijbehorende standaardroute. Elk pakket dat B maakt gaat dus die tunnel in, tenzij iets specifiekers voorrang krijgt.
Een pakket van A aan B komt aan en wordt geaccepteerd, omdat B de bestemming is en lokale aflevering eerst gebeurt. Het antwoord is een gloednieuw lokaal gegenereerd pakket gericht aan het openbare adres van A, en die bestemming komt overeen met de standaardroute de tunnel in. C ontvangt het, bezit dat adres niet en laat het vallen.
Het symptoom leest als een firewallprobleem of een sleutelmismatch, en geen van beide klopt hier. Een capture op de tunnel richting C laat zien dat de antwoorden de verkeerde kant op gaan. Die ene observatie bespaart meer tijd dan welke hoeveelheid configuratie lezen dan ook, dus schrijf het op voordat je sleutels gaat wisselen. Iedereen die de capture niet heeft gezien, zal aannemen dat de tunnel zelf stuk is.
De smalle reparatie: beleidsregels die op een bronpoort passen
Antwoorden van B’s luisterende socket vertrekken met bronpoort 500. Een beleidsregel kan daarop passen en die pakketten terug naar de gewone tabel sturen:
ip rule add sport 500 table main priority 100
ip rule add sport 8080 table main priority 101
Beleidsregels worden in prioriteitsvolgorde geraadpleegd, en de hoofdtabel staat op 32766, dus een regel op 100 wordt gevraagd voordat de standaardroute van de tunnel iets te zeggen heeft. Voeg één vermelding per poort toe die van buitenaf bereikbaar moet blijven en niets meer, zodat doorgestuurd verkeer de tunnel blijft gebruiken waarvoor hij is gebouwd.
Ken de grens van deze truc. De selector sport past op lokaal gegenereerde pakketten, wat precies het antwoordgeval dekt en bewust geen verkeer dekt dat B slechts doorstuurt voor iemand anders. Een dienst die achter B wordt gehost heeft nog steeds zijn eigen antwoord nodig, en doen alsof dat niet zo is levert een oplossing die voor de eerste dienst werkt en voor de tweede faalt.
Geef de regel een eigenaar
Een regel die bij een prompt is getypt verdwijnt de volgende keer dat de interface opnieuw wordt opgebouwd. Zet hem in een WireGuard-opstelling waar de interface wordt aangemaakt en verwijderd:
PostUp = ip rule add sport 500 table main priority 100
PostDown = ip rule del sport 500 table main priority 100
Als NetworkManager, een distributiehook of een container-entrypoint de interface bezit, hoort het paar bij die eigenaar in plaats van in een handmatig bewerkt bestand. Controleer de effectieve regels na een herverbinding, niet alleen na de eerste start, want de eerste start is het geval dat altijd werkt.
Vergelijk de alternatieven eerlijk
De bronpoortregel is een van vier uitwegen, en de smalste daarvan. Hij heeft het voordeel dat hij het tunnelbeleid helemaal niet aanraakt, waardoor hij latere wijzigingen meestal overleeft. Smalle reparaties falen ook luid wanneer ze niet meer gelden, terwijl een brede uitzondering stil blijft werken lang nadat de reden ervoor is verdwenen. Dat verschil telt meer dan elegantie wanneer iemand anders de doos over twee jaar bezit.
| 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 |
Verifieer van beide kanten zodra je hebt gekozen. Start vanaf A een verbinding naar de poort van B en houd die een tijdje bezet. Laat op B de kernel het antwoordpad rechtvaardigen met iets als ip route get <address-of-A> sport 500, en bevestig dat het de WAN-interface noemt en niet de tunnel. Controleer daarna dat iets achter C nog steeds via de keten antwoordt, wat bewijst dat de uitzondering smal bleef in plaats van een omweg te worden. Noteer ten slotte de poorten in de ontwerpnotities, anders herontdekt de volgende beheerder dit op een andere dienst.