Ich habe gerade angefangen, Docker unter CentOS 8 zu studieren. Also wollte ich den Paketfluss im externen Host <---> Container verfolgen, also habe ich viel recherchiert.
Ich konnte jedoch dem Ablauf der Anfrage folgen, aber ich konnte der Antwort nicht folgen. .. .. Vorerst werde ich nur die Anforderungsroute zusammenfassen.
Ich verfolge in der folgenden Umgebung.
userland proxy(docker-proxy) Ich habe Docker-Pxory nicht verwendet, weil ich die grundlegende Funktionsweise des Docker-Netzwerks mit iptables / nftables sehen wollte. (Haarnadel NAT) Die folgenden Dateien werden platziert und überprüft.
/etc/docker/daemon.json
{
"userland-proxy": false
}
Referenz: https://github.com/nigelpoulton/docker/blob/master/docs/userguide/networking/default_network/binding.md
docker network and containers
Verwenden Sie als Überprüfungsumgebung die durch den folgenden Eintrag generierte.
Der Docker-Host 10.254.10.252
ist mit CentOS8 konfiguriert. Die Erklärung bezieht sich auf den Radius.
** Docker Compose kann Netzwerkdienste in 5 Minuten erstellen (dhcp / radius / proxy / tftp / syslog) **
Die folgenden Container werden erstellt.
server | app | address | listen |
---|---|---|---|
proxy | squid | 172.20.0.2 | 8080/tcp |
syslog | rsyslog | 172.20.0.3 | 514/udp |
radius | freeRADIUS | 172.20.0.4 | 1812/udp |
dhcp | ISC-Kea | 172.20.0.5 | 67/udp |
tftp | tftp-server | - | 69/udp |
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b11308767849 infraserv:proxy "/usr/sbin/init" 3 minutes ago Up 3 minutes 0.0.0.0:8080->8080/tcp proxy
33054f8b7d58 infraserv:tftp "/usr/sbin/init" 35 hours ago Up 2 hours tftp
851ea861d04e infraserv:syslog "/usr/sbin/init" 35 hours ago Up 2 hours 0.0.0.0:514->514/udp syslog
dd3a657cfda2 infraserv:dhcp "/usr/sbin/init" 35 hours ago Up 2 hours 0.0.0.0:67->67/udp dhcp
7249b9c4f11d infraserv:radius "/usr/sbin/init" 35 hours ago Up 2 hours 0.0.0.0:1812->1812/udp radius
Ein Netzwerk mit den folgenden Parametern wird generiert.
key | value |
---|---|
name | infraserv_infranet |
subnet | 172.20.0.0/24 |
interface | docker1 |
Da tftp in der Umgebung von "--net = host" arbeitet, befindet sich "Docker-Netzwerk" im folgenden Zustand.
# docker network inspect infraserv_infranet
[
{
"Name": "infraserv_infranet",
"Id": "7ed8face2e4fec3110384fa3366512f8c78db6e10be6e7271b3d92452aefd254",
"Created": "2020-02-15T05:37:59.248249755-05:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.20.0.0/24",
"Gateway": "172.20.0.1"
}
]
},
"Internal": false,
"Attachable": true,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"7249b9c4f11de1f986892965671086d20957a6021269a5f5bc6dd85263bc0d70": {
"Name": "radius",
"EndpointID": "03ae6a9b9ff7817eea101955d2d6ff016982beb65c7dd6631c75c7299682c2dd",
"MacAddress": "02:42:ac:14:00:04",
"IPv4Address": "172.20.0.4/24",
"IPv6Address": ""
},
"851ea861d04edeb5f5c2498cc60f58532c87a44592db1f6c51280a8ce27940bd": {
"Name": "syslog",
"EndpointID": "d18e466d27def913ac74b7555acc9ef79c88c62e62085b50172636546d2e72bb",
"MacAddress": "02:42:ac:14:00:03",
"IPv4Address": "172.20.0.3/24",
"IPv6Address": ""
},
"b11308767849c7227fbde53234c1b1816859c8e871fcc98c4fcaacdf7818e89e": {
"Name": "proxy",
"EndpointID": "ffa6479b4f28c9c1d106970ffa43bd149461b4728b64290541643eb895a02892",
"MacAddress": "02:42:ac:14:00:02",
"IPv4Address": "172.20.0.2/24",
"IPv6Address": ""
},
"dd3a657cfda211c08b7c5c2166f10d189986e4779f1dfea227b3afe284cbafec": {
"Name": "dhcp",
"EndpointID": "7371f4cf652d8b1bdbf2dc1e5e8ae97013a9a70b890c2caa36c2a7cc93b165df",
"MacAddress": "02:42:ac:14:00:05",
"IPv4Address": "172.20.0.5/24",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker1"
},
"Labels": {
"com.docker.compose.network": "infranet",
"com.docker.compose.project": "infraserv",
"com.docker.compose.version": "1.25.3"
}
}
]
Der Kürze halber haben wir uns auf IPv4 konzentriert.
Dieses Mal nehmen wir ein Beispiel für das Senden einer Radiusanforderung von einem externen Terminal (10.254.10.105) an den Docker-Host (10.254.10.252). Der Haken der interessierenden Kette ist Prerouting-> Forward-> Postrouting, da er weitergeleitet wird, nachdem er beim lokalen Host angekommen ist. Daher wird der Kettentyp erläutert, wobei nur Filter und Nat im Mittelpunkt stehen.
Die Regeln schließen unnötige Regeln aus dem "nft list ruleset" aus, sind jedoch keine sehr nützlichen Informationen. Deshalb habe ich sie in [Supplement] zusammengefasst (#Überprüfen Sie die erforderlichen Tabellen).
Wenn der Hook aus dem Regelsatz "nft list" vorläuft, ist dies wie folgt.
table ip nat {
chain PREROUTING {
(1) type nat hook prerouting priority -100; policy accept;
(2)-> fib daddr type local COUNTER jump DOCKER
}
->(2) chain DOCKER {
↓ meta l4proto udp udp dport 514 COUNTER dnat to 172.20.0.3:514
↓ meta l4proto udp udp dport 67 COUNTER dnat to 172.20.0.5:67
↓ meta l4proto tcp tcp dport 8080 COUNTER dnat to 172.20.0.2:8080
(3) meta l4proto udp udp dport 1812 COUNTER dnat to 172.20.0.4:1812
}
}
Die aktuelle Mitteilung lautet "10.254.10.105:random-> 10.254.10.252: 1812".
(1) Es wird eine Kette namens PREROUTING ausgewählt, die das Prerouting einbindet und nat ausführt.
(2) Da DstAddr lokal ist, springen Sie zu der Kette namens DOCKER
Der Adr-Typ local ist die Adresse des lokalen Hosts (in diesem Fall Docker-Host).
In diesem Fall ist es lo: 127.0.0.1`` ens192: 10.254.10.252`` docker1: 172.20.0.1
.
(3) Da DstPort 1812 ist, ** DNAT DstAddr bis 172.20.0.4:1812 **
Richtlinie anwenden-> ** akzeptieren **, da keine weitere Verarbeitung erfolgt
Die Mitteilung an dieser Stelle lautet "10.254.10.105:random-> 172.20.0.4: 1812". Da das Ziel in 172.20.0.4 geändert wurde, führt Sie die Routing-Entscheidung zum Forward-Hook.
Wenn der Hook vom nft list ruleset
weitergeleitet wird, ist dies wie folgt.
table ip filter {
chain FORWARD {
(1) type filter hook forward priority 0; policy drop;
(2)-> COUNTER jump DOCKER-USER
->(3)(4)-> COUNTER jump DOCKER-ISOLATION-STAGE-1
->(5) oifname "docker1" ct state related,established COUNTER accept
(6)-> oifname "docker1" COUNTER jump DOCKER
iifname "docker1" oifname != "docker1" COUNTER accept
iifname "docker1" oifname "docker1" COUNTER accept
}
->(4) chain DOCKER-ISOLATION-STAGE-1 {
(5)-> COUNTER return
}
->(2) chain DOCKER-USER {
(3)-> COUNTER return
}
->(6) chain DOCKER {
↓ iifname != "docker1" oifname "docker1" meta l4proto udp ip daddr 172.20.0.3 udp dport 514 COUNTER accept
↓ iifname != "docker1" oifname "docker1" meta l4proto udp ip daddr 172.20.0.5 udp dport 67 COUNTER accept
↓ iifname != "docker1" oifname "docker1" meta l4proto tcp ip daddr 172.20.0.2 tcp dport 8080 COUNTER accept
(7) iifname != "docker1" oifname "docker1" meta l4proto udp ip daddr 172.20.0.4 udp dport 1812 COUNTER accept
}
}
table inet firewalld {
chain filter_FORWARD {
(8) type filter hook forward priority 10; policy accept;
↓ ct state established,related accept
(9) ct status dnat accept
iifname "lo" accept
jump filter_FORWARD_IN_ZONES
jump filter_FORWARD_OUT_ZONES
ct state invalid drop
reject with icmpx type admin-prohibited
}
chain filter_FORWARD_IN_ZONES {
iifname "ens192" goto filter_FWDI_public
goto filter_FWDI_public
}
chain filter_FORWARD_OUT_ZONES {
oifname "ens192" goto filter_FWDO_public
goto filter_FWDO_public
}
chain filter_FWDI_public { meta l4proto { icmp, ipv6-icmp } accept }
chain filter_FWDO_public { jump filter_FWDO_public_allow }
chain filter_FWDO_public_allow { ct state new,untracked accept }
}
Die aktuelle Mitteilung lautet "10.254.10.105:random-> 172.20.0.4: 1812". (1) Da es die höchste Priorität unter den Vorwärts-Hooks hat, wird eine Kette namens FORWARD ausgewählt, die eine Filterung durchführt (pri: 0). (2) Fliegen Sie unbedingt zu DOCKER-USER (3) Kehre zurück, ohne etwas zu tun (4) Fliegen Sie bedingungslos zur DOCKER-ISOLATION-STAGE-1 (5) Kehre zurück, ohne etwas zu tun (6) Da die Ausgangs-IF Docker1 ist, springen Sie zu DOCKER (7) Die Eingangs-IF ist ens192, die Ausgangs-IF ist Docker1 und DstAddr ist 172.20.0.4:1812, also ** akzeptieren ** Die reguläre Kette DOCKER wird von der Basiskette FORWARD aufgerufen. Bei Annahme durch DOCKER wird der FORWARD des Anrufers ausgewertet und diese Kette endet. (8) Da es die zweithöchste Priorität unter den Vorwärts-Hooks hat, wird eine Kette namens filter_FORWARD ausgewählt, die eine Filterung durchführt (pri: 10). (9) Da das Paket DNAT ist, ** akzeptiere ** Die Kommunikation an dieser Stelle ist dieselbe wie die erste, "10.254.10.105: random-> 172.20.0.4: 1812".
Wenn der Hook vom nft list ruleset
nachroutet, ist dies wie folgt.
table ip nat {
chain POSTROUTING {
(1) type nat hook postrouting priority 100; policy accept;
↓ oifname "docker1" fib saddr type local COUNTER masquerade
↓ oifname != "docker1" ip saddr 172.20.0.0/24 COUNTER masquerade
↓ meta l4proto udp ip saddr 172.20.0.3 ip daddr 172.20.0.3 udp dport 514 COUNTER masquerade
↓ meta l4proto udp ip saddr 172.20.0.5 ip daddr 172.20.0.5 udp dport 67 COUNTER masquerade
↓ meta l4proto tcp ip saddr 172.20.0.2 ip daddr 172.20.0.2 tcp dport 8080 COUNTER masquerade
↓ meta l4proto udp ip saddr 172.20.0.4 ip daddr 172.20.0.4 udp dport 1812 COUNTER masquerade
}
table ip firewalld {
chain nat_POSTROUTING {
(2) type nat hook postrouting priority 110; policy accept;
(3)-> jump nat_POSTROUTING_ZONES
}
->(3) chain nat_POSTROUTING_ZONES {
↓ oifname "ens192" goto nat_POST_public
(4)-> goto nat_POST_public
}
->(4) chain nat_POST_public {
(5)-> jump nat_POST_public_allow
}
->(5) chain nat_POST_public_allow {
(6) oifname != "lo" masquerade
}
}
}
Die aktuelle Mitteilung lautet "10.254.10.105:random-> 172.20.0.4: 1812". (1) Da es die höchste Priorität unter den Postrouting-Hooks hat, wird eine Kette namens POSTROUTING ausgewählt, die nat ausführt (pri: 100). Richtlinie anwenden-> ** akzeptieren **, da keine weitere Verarbeitung erfolgt (2) Da es die zweithöchste Priorität unter den Postrouting-Hooks hat, wird eine Kette mit dem Namen nat_POSTROUTING ausgewählt, die nat ausführt (pri: 110). (3) Fliegen Sie unbedingt zu nat_POSTROUTING_ZONES (4) Fliegen Sie unbedingt nach nat_POST_public (5) Fliegen Sie unbedingt nach nat_POST_public_allow (6) Da die Ausgangs-IF Docker1 ist, ** Maskerade ** Da die Kette an dem von goto aufgerufenen Ziel endet, wird die Richtlinie angewendet-> ** accept ** Die reguläre Kette nat_POST_public_allow wird von der regulären Kette nat_POST_public aufgerufen. Die reguläre Kette nat_POST_public wird durch die Anweisung goto aus der regulären Kette nat_POSTROUTING_ZONES aufgerufen. Wenn die vom Befehl goto aufgerufene Verarbeitung von nat_POST_public abgeschlossen ist, endet der Aufruf von nat_POSTROUTING_ZONES. Das aufgerufene nat_POSTROUTING wird ebenfalls beendet und die Richtlinienakzeptanz wird angewendet.
Nach der Verarbeitung durch Maskerade lautet das Endergebnis "172.20.0.1: random-> 172.20.0.4: 1812". (Da es von Docker1 gesendet wird, lautet die Quelladresse Docker1, wenn es von Maskerade verarbeitet wird.)
Vom Radiuscontainer empfangene Anfragen
172.20.0.1:random --> 172.20.0.4:1812
Der Radius-Server prüft die Verfügbarkeit und gibt eine Antwort an den Radius-Client zurück.
Antwort Der Radiuscontainer antwortet
172.20.0.4:1812 --> 172.20.0.1:random
Ich bin erschöpft. .. .. Wenn ich einen Zähler mit nftables einrichtete, konnte ich die Adresse sehen, wenn ich die folgende Kette durchlief. Da es sich um einen einmaligen Authentifizierungsaustausch handelte, war in jeder Kette ein Paket sichtbar.
type filter hook prerouting : 172.20.0.4:1812 --> 172.20.0.1:random
type filter hook input : 172.20.0.4:1812 --> 10.254.10.105:random
type filter hook forward : 172.20.0.4:1812 --> 10.254.10.105:random
type filter hook postrouting : 172.20.0.4:1812 --> 10.254.10.105:random
Die Antwort vom Radiuscontainer lautet "172.20.0.4:1812-> 172.20.0.1: zufällig". Wenn Sie einen eingehenden Anruf erhalten, sieht es aus wie eine an Sie gerichtete Kommunikation, sodass Sie wissen, dass Sie "hook: input" durchlaufen. Fahren Sie danach mit LocalProcess fort? Ich bin mir darüber nicht sicher. .. ..
Ich kenne die Route des Antwortpakets vom Radius nicht.
Warum geht keine Kette type: nat
vorbei? .. ..
Warum durchlaufen Sie gleichzeitig "hook: input" und "hook: forward"? .. ..
Obwohl es sich im Typ: Filter Hook: Input Pri: -200 des Tabellenbrückenfilters befindet
Ich bin nicht auf den Typ: Filter Hook: Input Pri: 0 des Tabellen-IP-Filters eingegangen.
Führen Sie eine unterschiedliche Verarbeitung zwischen der L2-Bridge und der L3-IP durch?
https://knowledge.sakura.ad.jp/22636/ https://ja.wikipedia.org/wiki/Iptables https://ja.wikipedia.org/wiki/Nftables https://wiki.archlinux.jp/index.php/Nftables https://wiki.archlinux.jp/index.php/Iptables https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks https://www.frozentux.net/iptables-tutorial/iptables-tutorial.html#TRAVERSINGOFTABLES https://wiki.archlinux.jp/index.php/Nftables https://knowledge.sakura.ad.jp/22636/ https://www.codeflow.site/ja/article/a-deep-dive-into-iptables-and-netfilter-architecture
Recommended Posts