Kedja två OpenVPN-klienter på en Linux-värd med fwmark
Båda klienterna vill ha standardrutten. Fäst den inre servern med en värdrutt, hindra den andra klienten från att skriva om tabeller och styr sedan flödena med fwmark.
Att stapla en andra OpenVPN-klient på en Linux-värd misslyckas på en av två platser. Antingen når den inre klienten inte sin egen server eftersom den yttre tunneln har fångat den trafiken, eller så skriver den andra klienten om routingtabellen och den första tunneln slutar fungera. Båda problemen ligger i routingen, inte i krypteringen, och båda löses innan den nya tunneln bär någon applikationstrafik. Adresserna här är illustrativa: tun0 är den yttre tunneln, 203.0.113.9 är den inre servern och TCP 9999 är flödet som måste använda den inre vägen.
Två felmoduser, en routingtabell
En inre klient öppnar en UDP-uttag mot sin server, och den uttaget följer den aktuella routingtabellen som vilken annan som helst. Om den yttre tunneln redan äger standardrutten går handskakningspaketen in i den yttre tunneln. Det fungerar bara när den yttre servern kan nå den inre servern och andra sidan går med på att bära flödet; annars stannar handskakningen och klienten försöker igen.
Det andra felet kommer från serverns push. Den vanliga pushen är redirect-gateway def1, som installerar 0.0.0.0/1 och 128.0.0.0/1 i stället för att ersätta standardrutten. Två klienter som var och en installerar sitt eget /1-par kolliderar därför, och det nyaste paret vinner för nästan varje destination. Leta efter de två prefixen i tabellen när en tunnel dör efter att den andra ansluter, eftersom standardrutten själv kanske aldrig har ändrats.
Markera flödet och ge det en tabell
Styr den valda trafiken genom att markera den i mangle-tabellen och matcha markeringen i en policyregel. Regeln pekar på en egen tabell vars standardrutt är den inre enheten, så bara markerade paket tar den inre vägen.
iptables -t mangle -A PREROUTING -p tcp -m multiport --dport 9999 -j MARK --set-mark 0x9999
ip rule add fwmark 0x9999 table 200 pref 1000
ip route add default dev tun1 table 200De flesta fel i den här regeluppsättningen kommer från två misstag. Markvärdet som brandväggen sätter och värdet som regeln matchar måste vara identiska, eftersom en avvikelse varken ger fel eller effekt. Och PREROUTING ser bara paket som kommer utifrån, så en anslutning som startas på den här värden behöver en OUTPUT-regel med samma matchning innan den ens markeras.
Ta ruttägandet från den andra klienten
Två alternativ hindrar den andra klienten från att redigera tabellen, och de verkar på olika ställen. route-nopull ignorerar de pushade ruttalternativen, så ingenting installeras. route-noexec accepterar de pushade alternativen i klientens miljö men lämnar tabelländringen till en hook, och det är vad du vill när du behöver se vad servern erbjöd.
Hooken körs med de pushade värdena i sin miljö, och den bör bara lägga till de poster du godkänt. Gör den idempotent: töm tabellen den äger innan du bygger upp den igen, och anta inte att föregående körning lämnade ett rent tillstånd. En återanslutning anropar hooken igen, och en hook som lägger till utan att rensa samlar dubbletter av rutter.
Välj en ägare och skriv ner den. En profil som ställer in båda alternativen, eller en hook som konkurrerar med ett manuellt skript, ger en tabell som ingen kan förklara senare.
Fäst båda serveradresserna
Den inre servern behöver en värdrutt via den yttre enheten innan den inre klienten ansluter. Den posten är det som håller den inre trafiken inne i den yttre tunneln i stället för att låta den följa standardrutten.
ip route add 203.0.113.9/32 dev tun0
ip route get 203.0.113.9Lägg också till en matchande värdrutt för den yttre servern i huvudtabellen, annars kan en återanslutning routa den yttre klientens egen trafik in i dess egen tunnel. Ordningen är inte valfri: lägg till dessa poster efter att det relevanta gränssnittet finns, vilket betyder en hook eller ett skript som körs efter anslutningen. En rutt som pekar på en enhet som är nere tas bort eller ignoreras, så en post som skrivs vid uppstart överlever inte sekvensen du antog.
Kontrollera sökningen i stället för att läsa hela tabellen. Utskriften från ruttsökningen anger enheten och källadressen som kärnan kommer att använda, och det är exakt vad klienten får när den öppnar sin uttag.
Testa kedjan och gör felet synligt
Fånga på det yttre gränssnittet medan den inre klienten ansluter. Den inre handskakningen ska visas som krypterad nyttolast inne i den yttre tunneln; om den visas som vanlig UDP till 203.0.113.9 saknas värdrutten och kedjan byggdes aldrig.
En kedja som tyst faller tillbaka till den fysiska upplänken är det värsta utfallet, eftersom gränssnittets tillstånd inte tillkännager något och den inre trafiken går ut från fel källadress. Om den andra klienten kan återansluta direkt när den yttre tunneln faller, inaktivera den vägen eller bind den till det yttre gränssnittet så att felet blir synligt.
Avsluta med två flöden och en regelutskrift: en markerad och en omarkerad anslutning bör ta olika vägar, och ip rule show bör lista den prioritet du avsett. Om båda flödena tar samma väg tillämpas inte markeringen där du tror.