It pakket fan 'e kontener berikt nea tun0 en ekstra mooglikheden op 'e kontener sille dat net feroarje. Tusken de gast en de tunnel steane twa rûtesykjen: ien binnen de netwurknammeromte fan 'e gast, ien op 'e host neidat it frame op 'e brêge lâne is, en de twadde rieplachtet in oare tabel mei oare oerienkomstregels. Myn referinsje-opstelling is in Linux-host mei in OpenVPN klient dy't 10.8.0.10 op tun0 hâldt, in Docker-brêge op 172.18.0.0/16, en in privee-adres dat allinnich de tunnelkant berikke kin. It doel bliuwt smel: dat gastsubnet giet troch de tunnel nei bûten wylst de host syn gewoane uplink hâldt.

De VPN-klient yn 'e kontener draaie is in oar ûntwerp, gjin koarte wei. De kontener hat dan syn eigen tunnel en syn eigen bewizen, en it wurk ferhúzet nei in Dockerfile ynstee fan yn iptables te bliuwen.

Trochstjoeren kiest in rûte op bestimming, dan skriuwt NAT de boarne oer

Mei net.ipv4.ip_forward=1 ynsteld, wurdt in trochstjoerd pakket allinnich op bestimming rûte, yn 'e haadtabel. De boarne spilet gjin rol yn dy beslissing. Pas neidat de rûte keazen is, lit de kernel POSTROUTING rinne, en dêr sit de eigen regel fan Docker: -s 172.18.0.0/16 ! -o br-appnet -j MASQUERADE. Alles wat de brêge nei in oare interface ferlit, wurdt oerset, en it adres dat it wurdt hinget ôf fan 'e interface dêr't de rûte it hinne stjoerd hat.

Dy regel ferklearret de measte symptomen dêr't ik oer frege wurd. As de haadtabel gjin rûte foar de priveebestimming hat, ferlit it pakket de uplink mei it fysike adres fan 'e host. Jo provider smyt de bestimming fuort, of de fiere side smyt in RFC 1918-boarne fuort dy't it nea ferwachte, en de kontener rint op tiid út wylst de tunnel oerein en sûn bliuwt. In opname op tun0 lit neat sjen, en dat is it teken. As de rûte wol nei tun0 wiist, skriuwt MASQUERADE de boarne oer nei 10.8.0.10 en wurket deselde kontener sûnder dat jo eat oanreitsje.

Freegje om it sykjen dat de boarne fan 'e gast neamt. Sûnder from en iif antwurdet de host foar syn eigen socket en meldt in paad dat it trochstjoerde pakket nea nimme sil:

ip route get 192.168.11.222 from 172.18.0.5 iif br-appnet

As dat antwurd de uplink neamt, is de tunnel net yn byld en gjin ynstelling oan 'e tunnelkant sil helpe.

Bring de gast nei it eigen adres fan 'e tunnel

De lytste feroaring dy't wurket is in dúdlike boarne-oerskriuwing op 'e wei út. Foegje dy yn ynstee fan ta: Docker sit al oan 'e kop fan POSTROUTING, dus in regel dy't mei -A tafoege wurdt, wurdt efter dy fan Docker beoardiele en giet nea ôf.

iptables -t nat -I POSTROUTING 1 -s 172.18.0.0/16 -o tun0 -j SNAT --to-source 10.8.0.10

Twa betingsten beslisse oft dat hâldt. It adres moat ien wêze dy't de klient echt hat, dus pin it fêst mei in ynfier per klient dy't ifconfig-push 10.8.0.10 255.255.255.0 befettet; in regel dy't in adres neamt dat nea tawiisd is, jout stille fuortsmittings, gjin flater. En de fiere kant moat dy boarne akseptearje en antwurden werom rûte, dêrom neamt in tastiene list dêr it tunneladres ynstee fan it gastsubnet. As it klientadres dynamysk is, -j MASQUERADE mei -o tun0 folget wat de interface hat, tsjin 'e priis fan fiere belied dêr't jo gjin fêste wearde tsjin skriuwe kinne.

Filterjen is de oare helte. Docker set it FORWARD belied op drop en leget by elke daemon-restart de keatlings dy't it hat, dus set lokaal belied yn DOCKER-USER, dat oerlibbet:

iptables -I DOCKER-USER -i br-appnet -o tun0 -j ACCEPT
iptables -I DOCKER-USER -i tun0 -o br-appnet -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

De weromregel is wichtich: in antwurd dat op tun0 oankomt foar in ferbining dy't de brêge iepene hat, wurdt net akseptearre allinnich om't de rjochting út it wie.

Hâld de host direkt mei in boarneregel

As de hiele brêge de tunnel brûke moat mar neat oars op 'e host, slaan NAT oer en jou dy boarne syn eigen tabel. Gastadressen bliuwe dan fan begjin oant ein sichtber.

echo "200 vpnbox" >> /etc/iproute2/rt_tables
ip rule add from 172.18.0.0/16 lookup vpnbox pref 1000
ip route add default dev tun0 table vpnbox

Regels wurde foar de haadtabel rieplachte, en from komt oerien mei de boarne. De eigen bûtenste pakketten fan 'e tunnel drage it fysike adres fan 'e host, dus se komme nea oerien mei from 172.18.0.0/16 en de tunnel kin himsels net werom yn himsels rûte. Krekt dy selsútsluting makket de opstelling stabyl.

It werompaad hat no help nedich. De fiere kant sjocht in net-oerset 172.18.0.x en hat gjin reden om te witten wêr't it wennet. Op 'e server hat in bestân per klient iroute 172.18.0.0 255.255.0.0 nedich, sadat de ynterne tabel fan 'e server dat foarheaksel oan dizze klient jout, en in triuwd route 172.18.0.0 255.255.0.0, sadat oare klienten witte dat it bestiet.

Twa kontrôles foardat jo it fertrouwe. Rin ip route show default: mei redirect-gateway def1 hat de tabel 0.0.0.0/1 en 128.0.0.0/1 fia tun0, en de host is hielendal net direkt, om't dy heale standertrûtes winne sûnder default te ferfangen. Regels tafoege mei ip rule add ferdwine ek by in restart, dus drage se yn in up-skript.

Pakketgrutte is de twadde mislearring dy't jo treffe

In brêge-interface op 1500 bytes jout de tunnel mear as er drage kin sadree't de bûtenste UDP- en IP-kopteksten tafoege wurde. Lytse útwikselings geane troch, dus DNS lost op en de TLS-hânskieding makket klear, dan hinget in gruttere upload sûnder flater earne. De stjoerder bliuwt deselde segmintgrutte werhelje om't it ICMP-berjocht oer fragmintaasje nedich, dat him sizze soe te krimpen, nea oankomt.

Reparearje it by de interface, by de MSS, of beide. Klemmen hat gjin gearwurking fan 'e gast nedich:

ip link set dev tun0 mtu 1400
iptables -t mangle -A FORWARD -o tun0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

It klemmen skriuwt allinnich TCP oer. UDP, QUIC ynbegrepen, hat ynstee in legere gastinterface nedich, mei --opt com.docker.network.driver.mtu=1400 by it meitsjen fan it netwurk of de oerienkommende compose-kaai.

DNS en de kontrôles dy't it wurdich binne om te werheljen

Namme-oplossing folget itselde paad. De ynboude resolver fan Docker op 127.0.0.11 stjoert troch nei de konfigurearre servers fan 'e host, dus in kontener erft wat de host brûkt. As de priveesône allinnich beantwurde wurdt troch in resolver dy't fia de tunnel berikber is, rjocht de gast op dat adres, en test mei getent hosts yn 'e kontener ynstee fan op 'e host.

  • Rin it mislearjende fersyk yn 'e gast; in test oan 'e hostkant brûkt in oar boarne-adres en ferberget it probleem.
  • Lês de tellers op 'e NAT- en filterregels dy't jo tafoege hawwe. In regel sûnder oerienkomst is in rûteflater, gjin beliedsflater.
  • Befêstigje dat it tunneladres yn jo SNAT-regel ien is dy't de klient echt hat.
  • Ferleegje de MTU fan 'e gast of klem de MSS foardat jo de server de skuld jouwe fan in stilstân.

Wurkje dy list ôf en stop by de earste mislearring. Dy laach is dejinge dy't reparearre wurde moat; alles wat fierder nei ûnderen tafoege wurdt, ferberget allinnich de grins dy't brekt.

Relatearre artikelen