diff --git a/example.svg b/example.svg index 14ca587..783f548 100644 --- a/example.svg +++ b/example.svg @@ -1,359 +1,892 @@ - - - + + %3 - - -filter_DOCKERUSER - - -DOCKER-USER - -filter - --j RETURN - -end - - -filter_DOCKERISOLATIONSTAGE1 - - -DOCKER-ISOLATION-STAGE-1 - -filter - --i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2 - --j RETURN - -end - - -filter_DOCKERISOLATIONSTAGE2 - - -DOCKER-ISOLATION-STAGE-2 - -filter - --o docker0 -j DROP - --j RETURN - -end - - -filter_DOCKERISOLATIONSTAGE1:rule_0->filter_DOCKERISOLATIONSTAGE2:begin - - - - -filter_OUTPUT - - - -OUTPUT - - -filter - -end - - -mangle_POSTROUTING - - - -POSTROUTING - - -mangle - -end - - -filter_OUTPUT:end->mangle_POSTROUTING:begin - - + + + +raw_PREROUTING + + + + + + +raw:PREROUTING + + + +-j ACCEPT - -filter_FORWARD - - - -FORWARD - - -filter - --j DOCKER-USER - --j DOCKER-ISOLATION-STAGE-1 - --o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT - --o docker0 -j DOCKER - --i docker0 ! -o docker0 -j ACCEPT - --i docker0 -o docker0 -j ACCEPT - -end - - -filter_FORWARD:rule_0->filter_DOCKERUSER:begin - - - - -filter_FORWARD:rule_1->filter_DOCKERISOLATIONSTAGE1:begin - - - - -filter_DOCKER - - -DOCKER - -filter - -end - - -filter_FORWARD:rule_3->filter_DOCKER:begin - - - - -filter_FORWARD:end->mangle_POSTROUTING:begin - - + + +mangle_PREROUTING + + + + + + +mangle:PREROUTING + + + +-j ACCEPT - -filter_INPUT - - - -INPUT - - -filter - -end + + +raw_PREROUTING:end->mangle_PREROUTING:begin + + -raw_OUTPUT - - - -OUTPUT - - -raw - -end - - -filter_INPUT:end->raw_OUTPUT:begin - - + +raw_OUTPUT + + + + + + +raw:OUTPUT + + + +-j ACCEPT -mangle_OUTPUT - - - -OUTPUT - - -mangle - -end + +mangle_OUTPUT + + + + + + +mangle:OUTPUT + + + +-j ACCEPT -raw_OUTPUT:end->mangle_OUTPUT:begin - - + +raw_OUTPUT:end->mangle_OUTPUT:begin + + - -raw_PREROUTING - - - -PREROUTING - - -raw - -end + + +filter_INPUT + + + + + + +filter:INPUT + + +-m comment --comment "kubernetes ipvs access filter" -j KUBE-IPVS-FILTER + +-m comment --comment "kube-proxy firewall rules" -j KUBE-PROXY-FIREWALL + +-m comment --comment "kubernetes health check rules" -j KUBE-NODE-PORT + +-j KUBE-FIREWALL + + +-j ACCEPT + + + +filter_KUBEIPVSFILTER + + + + + + +kubernetes ipvs access filter + + + +-m set --match-set KUBE-LOAD-BALANCER dst,dst -j RETURN + + +-m set --match-set KUBE-CLUSTER-IP dst,dst -j RETURN + + +-m set --match-set KUBE-EXTERNAL-IP dst,dst -j RETURN + + +-m set --match-set KUBE-EXTERNAL-IP-LOCAL dst,dst -j RETURN + + +-m set --match-set KUBE-HEALTH-CHECK-NODE-PORT dst -j RETURN + + +-m conntrack --ctstate NEW -m set --match-set KUBE-IPVS-IPS dst -j REJECT --reject-with icmp-port-unreachable + +-j RETURN + + + +filter_INPUT:rule_0->filter_KUBEIPVSFILTER:begin + + + + + +filter_KUBEPROXYFIREWALL + + + + + + +kube-proxy firewall rules + + +-j RETURN + + + +filter_INPUT:rule_1->filter_KUBEPROXYFIREWALL:begin + + + + + +filter_KUBENODEPORT + + + + + + +kubernetes health check rules + + + +-m comment --comment "Kubernetes health check node port" -m set --match-set KUBE-HEALTH-CHECK-NODE-PORT dst -j ACCEPT + +-j RETURN + + + +filter_INPUT:rule_2->filter_KUBENODEPORT:begin + + + + + +filter_KUBEFIREWALL + + + + + + +filter:KUBE-FIREWALL + + + +! -s 127.0.0.0/8 -d 127.0.0.0/8 -m comment --comment "block incoming localnet connections" -m conntrack ! --ctstate RELATED,ESTABLISHED,DNAT -j DROP + +-j RETURN + + + +filter_INPUT:rule_3->filter_KUBEFIREWALL:begin + + + + + +security_INPUT + + + + + + +security:INPUT + + + +-j ACCEPT + + + +filter_INPUT:end->security_INPUT:begin + + - -mangle_PREROUTING - - - -PREROUTING - - -mangle - -end + + +filter_OUTPUT + + + + + + +filter:OUTPUT + + +-m comment --comment "kubernetes ipvs access filter" -j KUBE-IPVS-OUT-FILTER + +-j KUBE-FIREWALL + + +-j ACCEPT + + + +filter_OUTPUT:rule_1->filter_KUBEFIREWALL:begin + + + + + +filter_KUBEIPVSOUTFILTER + + + + + + +kubernetes ipvs access filter + + +-j RETURN + + + +filter_OUTPUT:rule_0->filter_KUBEIPVSOUTFILTER:begin + + + + + +security_OUTPUT + + + + + + +security:OUTPUT + + + +-j ACCEPT + + + +filter_OUTPUT:end->security_OUTPUT:begin + + - -raw_PREROUTING:end->mangle_PREROUTING:begin - - + + +filter_FORWARD + + + + + + +filter:FORWARD + + +-m comment --comment "kube-proxy firewall rules" -j KUBE-PROXY-FIREWALL + +-m comment --comment "kubernetes forwarding rules" -j KUBE-FORWARD + +-m comment --comment "flanneld forward" -j FLANNEL-FWD + + +-j ACCEPT + + + +filter_FORWARD:rule_0->filter_KUBEPROXYFIREWALL:begin + + + + + +filter_KUBEFORWARD + + + + + + +kubernetes forwarding rules + + + +-m comment --comment "kubernetes forwarding rules" -j ACCEPT + + +-m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + +-j RETURN + + + +filter_FORWARD:rule_1->filter_KUBEFORWARD:begin + + + + + +filter_FLANNELFWD + + + + + + +flanneld forward + + + +-s 10.244.0.0/16 -m comment --comment "flanneld forward" -j ACCEPT + + +-d 10.244.0.0/16 -m comment --comment "flanneld forward" -j ACCEPT + +-j RETURN + + + +filter_FORWARD:rule_2->filter_FLANNELFWD:begin + + + + + +security_FORWARD + + + + + + +security:FORWARD + + + +-j ACCEPT + + + +filter_FORWARD:end->security_FORWARD:begin + + + + + +filter_KUBESOURCERANGESFIREWALL + + + + + + +filter:KUBESOURCERANGESFIREWALL + + + +-j DROP + +-j RETURN + + + +nat_INPUT + + + + + + +nat:INPUT + + + +-j ACCEPT + + + +security_INPUT:end->nat_INPUT:begin + + - -mangle_FORWARD - - - -FORWARD - - -mangle - -end + + +mangle_POSTROUTING + + + + + + +mangle:POSTROUTING + + + +-j ACCEPT + + + +security_OUTPUT:end->mangle_POSTROUTING:begin + + + + + +security_FORWARD:end->mangle_POSTROUTING:begin + + - -mangle_FORWARD:end->filter_FORWARD:begin - - + + +nat_PREROUTING + + + + + + +nat:PREROUTING + + +-m comment --comment "kubernetes service portals" -j KUBE-SERVICES + +-d 172.18.0.1/32 -j DOCKER_OUTPUT + + +-j ACCEPT + + + +nat_KUBESERVICES + + + + + + +kubernetes service portals + + + +-s 127.0.0.0/8 -j RETURN + +-m comment --comment "Kubernetes service lb portal" -m set --match-set KUBE-LOAD-BALANCER dst,dst -j KUBE-LOAD-BALANCER + +! -s 10.244.0.0/16 -m comment --comment "Kubernetes service cluster ip + port for masquerade purpose" -m set --match-set KUBE-CLUSTER-IP dst,dst -j KUBE-MARK-MASQ + +-m addrtype --dst-type LOCAL -j KUBE-NODE-PORT + + +-m set --match-set KUBE-CLUSTER-IP dst,dst -j ACCEPT + + +-m set --match-set KUBE-LOAD-BALANCER dst,dst -j ACCEPT + +-j RETURN + + + +nat_PREROUTING:rule_0->nat_KUBESERVICES:begin + + + + + +nat_DOCKEROUTPUT + + + + + + +nat:DOCKER_OUTPUT + + + +-d 172.18.0.1/32 -p tcp -m tcp --dport 53 -j DNAT --to-destination 127.0.0.11:33955 + + +-d 172.18.0.1/32 -p udp -m udp --dport 53 -j DNAT --to-destination 127.0.0.11:39855 + +-j RETURN + + + +nat_PREROUTING:rule_1->nat_DOCKEROUTPUT:begin + + -mangle_INPUT - - - -INPUT - - -mangle - -end + +mangle_INPUT + + + + + + +mangle:INPUT + + + +-j ACCEPT - -mangle_INPUT:end->filter_INPUT:begin - - + + +nat_PREROUTING:end->mangle_INPUT:begin + + - -nat_POSTROUTING - - - -POSTROUTING - - -nat - --s 172.18.0.0/24 ! -o docker0 -j MASQUERADE - -end + + +mangle_FORWARD + + + + + + +mangle:FORWARD + + + +-j ACCEPT - -mangle_POSTROUTING:end->nat_POSTROUTING:begin - - + + +nat_PREROUTING:end->mangle_FORWARD:begin + + + + + +APPLICATION + +APPLICATION + + + +nat_INPUT:end->APPLICATION + + - -nat_PREROUTING - - - -PREROUTING - - -nat - --m addrtype --dst-type LOCAL -j DOCKER - -end + + +nat_OUTPUT + + + + + + +nat:OUTPUT + + +-m comment --comment "kubernetes service portals" -j KUBE-SERVICES + +-d 172.18.0.1/32 -j DOCKER_OUTPUT + + +-j ACCEPT + + + +nat_OUTPUT:end->filter_OUTPUT:begin + + + + + +nat_OUTPUT:rule_0->nat_KUBESERVICES:begin + + + + + +nat_OUTPUT:rule_1->nat_DOCKEROUTPUT:begin + + + + + +nat_POSTROUTING + + + + + + +nat:POSTROUTING + + +-m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING + +-d 172.18.0.1/32 -j DOCKER_POSTROUTING + +-m comment --comment "flanneld masq" -j FLANNEL-POSTRTG + + +-j ACCEPT + + + +nat_KUBEPOSTROUTING + + + + + + +kubernetes postrouting rules + + + +-m comment --comment "Kubernetes endpoints dst ip:port, source ip for solving hairpin purpose" -m set --match-set KUBE-LOOP-BACK dst,dst,src -j MASQUERADE + + +-j RETURN + +-j MARK --set-xmark 0x4000/0x0 + + +-m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE --random-fully + +-j RETURN + + + +nat_POSTROUTING:rule_0->nat_KUBEPOSTROUTING:begin + + + + + +nat_DOCKERPOSTROUTING + + + + + + +nat:DOCKER_POSTROUTING + + + +-s 127.0.0.11/32 -p tcp -j SNAT --to-source 172.18.0.1:53 + + +-s 127.0.0.11/32 -p udp -j SNAT --to-source 172.18.0.1:53 + +-j RETURN + + + +nat_POSTROUTING:rule_1->nat_DOCKERPOSTROUTING:begin + + + + + +nat_FLANNELPOSTRTG + + + + + + +flanneld masq + + + +-m comment --comment "flanneld masq" -j RETURN + + +-s 10.244.0.0/24 -d 10.244.0.0/16 -m comment --comment "flanneld masq" -j RETURN + + +-s 10.244.0.0/16 -d 10.244.0.0/24 -m comment --comment "flanneld masq" -j RETURN + + +! -s 10.244.0.0/16 -d 10.244.0.0/24 -m comment --comment "flanneld masq" -j RETURN + + +-s 10.244.0.0/16 ! -d 224.0.0.0/4 -m comment --comment "flanneld masq" -j MASQUERADE --random-fully + + +! -s 10.244.0.0/16 -d 10.244.0.0/16 -m comment --comment "flanneld masq" -j MASQUERADE --random-fully + +-j RETURN + + + +nat_POSTROUTING:rule_2->nat_FLANNELPOSTRTG:begin + + + + + +END + +END + + + +nat_POSTROUTING:end->END + + + + + +nat_KUBELOADBALANCER + + + + + + +Kubernetes service lb portal + + +-j KUBE-MARK-MASQ + +-j RETURN + + + +nat_KUBESERVICES:rule_1->nat_KUBELOADBALANCER:begin + + + + + +nat_KUBEMARKMASQ + + + + + + +Kubernetes nodeport TCP port for masquerade purpose + + +Kubernetes service cluster ip + port for masquerade purpose + + +-j MARK --set-xmark 0x4000/0x4000 + +-j RETURN + + + +nat_KUBESERVICES:rule_2->nat_KUBEMARKMASQ:begin + + + + + +nat_KUBENODEPORT + + + + + + +nat:KUBE-NODE-PORT + + +-p tcp -m comment --comment "Kubernetes nodeport TCP port for masquerade purpose" -m set --match-set KUBE-NODE-PORT-TCP dst -j KUBE-MARK-MASQ + +-j RETURN + + + +nat_KUBESERVICES:rule_3->nat_KUBENODEPORT:begin + + + + + +nat_KUBELOADBALANCER:rule_0->nat_KUBEMARKMASQ:begin + + + + + +nat_KUBENODEPORT:rule_0->nat_KUBEMARKMASQ:begin + + -mangle_PREROUTING:end->nat_PREROUTING:begin - - + +mangle_PREROUTING:end->nat_PREROUTING:begin + + - -nat_OUTPUT - - - -OUTPUT - - -nat - -! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER - -end + + +mangle_INPUT:end->filter_INPUT:begin + + -mangle_OUTPUT:end->nat_OUTPUT:begin - - - - -nat_MASQUERADE - - -MASQUERADE - -nat - -end - - -nat_OUTPUT:end->filter_OUTPUT:begin - - - - -nat_DOCKER - - -DOCKER - -nat - --i docker0 -j RETURN - -end - - -nat_OUTPUT:rule_0->nat_DOCKER:begin - - + +mangle_OUTPUT:end->nat_OUTPUT:begin + + - -nat_PREROUTING:end->mangle_FORWARD:begin - - + + +mangle_FORWARD:end->filter_FORWARD:begin + + - -nat_PREROUTING:end->mangle_INPUT:begin - - - - -nat_PREROUTING:rule_0->nat_DOCKER:begin - - - - -nat_POSTROUTING:rule_0->nat_MASQUERADE:begin - - + + +mangle_POSTROUTING:end->nat_POSTROUTING:begin + + + + + +START + +START + + + +START->raw_PREROUTING:begin + + + + + +APPLICATION->raw_OUTPUT:begin + + diff --git a/example.txt b/example.txt index 8b6c7b7..238731f 100644 --- a/example.txt +++ b/example.txt @@ -1,35 +1,96 @@ -# Generated by iptables-save v1.6.0 on Thu Apr 8 16:44:20 2021 -*nat -:PREROUTING ACCEPT [1:44] -:INPUT ACCEPT [1:44] -:OUTPUT ACCEPT [108934:8322365] -:POSTROUTING ACCEPT [108934:8322365] -:DOCKER - [0:0] --A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER --A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER --A POSTROUTING -s 172.18.0.0/24 ! -o docker0 -j MASQUERADE --A DOCKER -i docker0 -j RETURN +# Generated by iptables-save v1.8.7 on Tue Jan 23 02:39:22 2024 +*mangle +:PREROUTING ACCEPT [0:0] +:INPUT ACCEPT [0:0] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +:POSTROUTING ACCEPT [0:0] +:KUBE-IPTABLES-HINT - [0:0] +:KUBE-KUBELET-CANARY - [0:0] COMMIT -# Completed on Thu Apr 8 16:44:20 2021 -# Generated by iptables-save v1.6.0 on Thu Apr 8 16:44:20 2021 +# Completed on Tue Jan 23 02:39:22 2024 +# Generated by iptables-save v1.8.7 on Tue Jan 23 02:39:22 2024 *filter -:INPUT ACCEPT [5732373:3510919135] -:FORWARD DROP [0:0] -:OUTPUT ACCEPT [3381411:259078259] -:DOCKER - [0:0] -:DOCKER-ISOLATION-STAGE-1 - [0:0] -:DOCKER-ISOLATION-STAGE-2 - [0:0] -:DOCKER-USER - [0:0] --A FORWARD -j DOCKER-USER --A FORWARD -j DOCKER-ISOLATION-STAGE-1 --A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT --A FORWARD -o docker0 -j DOCKER --A FORWARD -i docker0 ! -o docker0 -j ACCEPT --A FORWARD -i docker0 -o docker0 -j ACCEPT --A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2 --A DOCKER-ISOLATION-STAGE-1 -j RETURN --A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP --A DOCKER-ISOLATION-STAGE-2 -j RETURN --A DOCKER-USER -j RETURN +:INPUT ACCEPT [0:0] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +:FLANNEL-FWD - [0:0] +:KUBE-FIREWALL - [0:0] +:KUBE-FORWARD - [0:0] +:KUBE-IPVS-FILTER - [0:0] +:KUBE-IPVS-OUT-FILTER - [0:0] +:KUBE-KUBELET-CANARY - [0:0] +:KUBE-NODE-PORT - [0:0] +:KUBE-PROXY-FIREWALL - [0:0] +:KUBE-SOURCE-RANGES-FIREWALL - [0:0] +-A INPUT -m comment --comment "kubernetes ipvs access filter" -j KUBE-IPVS-FILTER +-A INPUT -m comment --comment "kube-proxy firewall rules" -j KUBE-PROXY-FIREWALL +-A INPUT -m comment --comment "kubernetes health check rules" -j KUBE-NODE-PORT +-A INPUT -j KUBE-FIREWALL +-A FORWARD -m comment --comment "kube-proxy firewall rules" -j KUBE-PROXY-FIREWALL +-A FORWARD -m comment --comment "kubernetes forwarding rules" -j KUBE-FORWARD +-A FORWARD -m comment --comment "flanneld forward" -j FLANNEL-FWD +-A OUTPUT -m comment --comment "kubernetes ipvs access filter" -j KUBE-IPVS-OUT-FILTER +-A OUTPUT -j KUBE-FIREWALL +-A FLANNEL-FWD -s 10.244.0.0/16 -m comment --comment "flanneld forward" -j ACCEPT +-A FLANNEL-FWD -d 10.244.0.0/16 -m comment --comment "flanneld forward" -j ACCEPT +-A KUBE-FIREWALL ! -s 127.0.0.0/8 -d 127.0.0.0/8 -m comment --comment "block incoming localnet connections" -m conntrack ! --ctstate RELATED,ESTABLISHED,DNAT -j DROP +-A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -j ACCEPT +-A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT +-A KUBE-IPVS-FILTER -m set --match-set KUBE-LOAD-BALANCER dst,dst -j RETURN +-A KUBE-IPVS-FILTER -m set --match-set KUBE-CLUSTER-IP dst,dst -j RETURN +-A KUBE-IPVS-FILTER -m set --match-set KUBE-EXTERNAL-IP dst,dst -j RETURN +-A KUBE-IPVS-FILTER -m set --match-set KUBE-EXTERNAL-IP-LOCAL dst,dst -j RETURN +-A KUBE-IPVS-FILTER -m set --match-set KUBE-HEALTH-CHECK-NODE-PORT dst -j RETURN +-A KUBE-IPVS-FILTER -m conntrack --ctstate NEW -m set --match-set KUBE-IPVS-IPS dst -j REJECT --reject-with icmp-port-unreachable +-A KUBE-NODE-PORT -m comment --comment "Kubernetes health check node port" -m set --match-set KUBE-HEALTH-CHECK-NODE-PORT dst -j ACCEPT +-A KUBE-SOURCE-RANGES-FIREWALL -j DROP +COMMIT +# Completed on Tue Jan 23 02:39:22 2024 +# Generated by iptables-save v1.8.7 on Tue Jan 23 02:39:22 2024 +*nat +:PREROUTING ACCEPT [15036:904858] +:INPUT ACCEPT [14908:894762] +:OUTPUT ACCEPT [724068:43444067] +:POSTROUTING ACCEPT [244344:14660705] +:DOCKER_OUTPUT - [0:0] +:DOCKER_POSTROUTING - [0:0] +:FLANNEL-POSTRTG - [0:0] +:KUBE-KUBELET-CANARY - [0:0] +:KUBE-LOAD-BALANCER - [0:0] +:KUBE-MARK-MASQ - [0:0] +:KUBE-NODE-PORT - [0:0] +:KUBE-POSTROUTING - [0:0] +:KUBE-SERVICES - [0:0] +-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES +-A PREROUTING -d 172.18.0.1/32 -j DOCKER_OUTPUT +-A OUTPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES +-A OUTPUT -d 172.18.0.1/32 -j DOCKER_OUTPUT +-A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING +-A POSTROUTING -d 172.18.0.1/32 -j DOCKER_POSTROUTING +-A POSTROUTING -m comment --comment "flanneld masq" -j FLANNEL-POSTRTG +-A DOCKER_OUTPUT -d 172.18.0.1/32 -p tcp -m tcp --dport 53 -j DNAT --to-destination 127.0.0.11:33955 +-A DOCKER_OUTPUT -d 172.18.0.1/32 -p udp -m udp --dport 53 -j DNAT --to-destination 127.0.0.11:39855 +-A DOCKER_POSTROUTING -s 127.0.0.11/32 -p tcp -j SNAT --to-source 172.18.0.1:53 +-A DOCKER_POSTROUTING -s 127.0.0.11/32 -p udp -j SNAT --to-source 172.18.0.1:53 +-A FLANNEL-POSTRTG -m comment --comment "flanneld masq" -j RETURN +-A FLANNEL-POSTRTG -s 10.244.0.0/24 -d 10.244.0.0/16 -m comment --comment "flanneld masq" -j RETURN +-A FLANNEL-POSTRTG -s 10.244.0.0/16 -d 10.244.0.0/24 -m comment --comment "flanneld masq" -j RETURN +-A FLANNEL-POSTRTG ! -s 10.244.0.0/16 -d 10.244.0.0/24 -m comment --comment "flanneld masq" -j RETURN +-A FLANNEL-POSTRTG -s 10.244.0.0/16 ! -d 224.0.0.0/4 -m comment --comment "flanneld masq" -j MASQUERADE --random-fully +-A FLANNEL-POSTRTG ! -s 10.244.0.0/16 -d 10.244.0.0/16 -m comment --comment "flanneld masq" -j MASQUERADE --random-fully +-A KUBE-LOAD-BALANCER -j KUBE-MARK-MASQ +-A KUBE-MARK-MASQ -j MARK --set-xmark 0x4000/0x4000 +-A KUBE-NODE-PORT -p tcp -m comment --comment "Kubernetes nodeport TCP port for masquerade purpose" -m set --match-set KUBE-NODE-PORT-TCP dst -j KUBE-MARK-MASQ +-A KUBE-POSTROUTING -m comment --comment "Kubernetes endpoints dst ip:port, source ip for solving hairpin purpose" -m set --match-set KUBE-LOOP-BACK dst,dst,src -j MASQUERADE +-A KUBE-POSTROUTING -j RETURN +-A KUBE-POSTROUTING -j MARK --set-xmark 0x4000/0x0 +-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE --random-fully +-A KUBE-SERVICES -s 127.0.0.0/8 -j RETURN +-A KUBE-SERVICES -m comment --comment "Kubernetes service lb portal" -m set --match-set KUBE-LOAD-BALANCER dst,dst -j KUBE-LOAD-BALANCER +-A KUBE-SERVICES ! -s 10.244.0.0/16 -m comment --comment "Kubernetes service cluster ip + port for masquerade purpose" -m set --match-set KUBE-CLUSTER-IP dst,dst -j KUBE-MARK-MASQ +-A KUBE-SERVICES -m addrtype --dst-type LOCAL -j KUBE-NODE-PORT +-A KUBE-SERVICES -m set --match-set KUBE-CLUSTER-IP dst,dst -j ACCEPT +-A KUBE-SERVICES -m set --match-set KUBE-LOAD-BALANCER dst,dst -j ACCEPT COMMIT -# Completed on Thu Apr 8 16:44:20 2021 +# Completed on Tue Jan 23 02:39:22 2024 diff --git a/iptables-graph b/iptables-graph index 9e09c94..e8e84de 100755 --- a/iptables-graph +++ b/iptables-graph @@ -2,109 +2,433 @@ import sys import re import string +import argparse -all_chains = { 'raw': {'PREROUTING':list(), 'OUTPUT':list()}, - 'filter': {'INPUT':list(), 'OUTPUT':list(), 'FORWARD':list()}, - 'nat': {'PREROUTING':list(), 'OUTPUT':list(), 'POSTROUTING':list()}, - 'mangle': {'PREROUTING':list(), 'INPUT':list(), 'OUTPUT':list(), 'FORWARD':list(), 'POSTROUTING':list()}} +parser = argparse.ArgumentParser() +parser.add_argument( + "-e", + "--eliminate", + help="eliminate empty/unused chain", + action=argparse.BooleanOptionalAction, +) +parser.add_argument("-f", "--final-targets", help="final targets") +parser.add_argument("-m", "--middle-targets", help="middle targets") +argv = parser.parse_args() -defualt_chain_list = ['PREROUTING', 'FORWARD', 'INPUT', 'OUTPUT', 'POSTROUTING'] +all_chains = { + "raw": {"PREROUTING": list(), "OUTPUT": list()}, + "filter": {"INPUT": list(), "OUTPUT": list(), "FORWARD": list()}, + "security": {"INPUT": list(), "OUTPUT": list(), "FORWARD": list()}, + "nat": { + "PREROUTING": list(), + "INPUT": list(), + "OUTPUT": list(), + "POSTROUTING": list(), + }, + "mangle": { + "PREROUTING": list(), + "INPUT": list(), + "OUTPUT": list(), + "FORWARD": list(), + "POSTROUTING": list(), + }, +} + + +def get_node_name(table_name, chain_name): + return ( + re.sub("[^a-zA-Z0-9]", "", table_name) + + "_" + + re.sub("[^a-zA-Z0-9]", "", chain_name) + ) + + +defualt_chain_list = ["PREROUTING", "FORWARD", "INPUT", "OUTPUT", "POSTROUTING"] + +default_chain_policy = {} +for table in all_chains: + for chain in defualt_chain_list: + default_chain_policy[get_node_name(table, chain)] = "ACCEPT" + +endness_chain = [ + get_node_name("raw", "PREROUTING"), + get_node_name("nat", ":POSTROUTING"), + get_node_name("nat", "INPUT"), + get_node_name("raw", "OUTPUT"), +] + +default_middle_targets = ["LOG", "MARK", "SECMARK", "CONNSECMARK", "CHECKSUM"] +default_final_targets = [ + "ACCEPT", + "REJECT", + "DROP", + "RETURN", + "REDIRECT", + "MASQUERADE", + "DNAT", + "SNAT", + "DNPT", + "SNPT", + "QUEUE", +] + +tables_comment = {} +tables_target = {} + + +def get_escape(text): + text = text.replace("&", "&") + text = text.replace('"', """) + text = text.replace(">", ">") + text = text.replace("<", "<") + return text + + +def parse_line(line, separators): + token_list = [] + if not line: + return token_list + if line[0] == "#": + token_list.append("#") + token_list.append(line[1:]) + return token_list + buf = [] + qoute = False + for i, c in enumerate(line): + if qoute: + buf.append(c) + if c == '"' and line[i - 1] != "\\": + qoute = False + token_list.append("".join(buf)) + buf.clear() + else: + if c in separators: + if len(buf) > 0: + token_list.append("".join(buf)) + buf.clear() + continue + if c == '"': + qoute = True + buf.append(c) + if not qoute and len(buf) > 0: + token_list.append("".join(buf)) + if len(token_list) > 0: + first = token_list[0][0] + if first == "*" or first == ":": + token_list.insert(0, first) + token_list[1] = token_list[1][1:] + return token_list + + +def set_targets(args, targets): + if not args: + return + for target in parse_line(args, ","): + target = target.strip().upper() + if len(target) > 0: + targets.append(target) + + +set_targets(argv.final_targets, default_final_targets) +set_targets(argv.middle_targets, default_middle_targets) input_string = sys.stdin.read() line_list = input_string.splitlines() current_table = None for line in line_list: - token_list = line.split() - if token_list[0][1:] in all_chains.keys(): - current_table = token_list[0][1:] + args = parse_line(line, [" "]) + if len(args) < 1 or args[0] == "#": continue - if token_list[0] == '-A': - current_chain = token_list[1] - if current_chain not in all_chains[current_table]: - all_chains[current_table][current_chain] = list() - - rule_body = '' - target = '' - if (token_list[-2] == '-j' or token_list[-2] == '-g') and token_list[-1] not in ['RETURN', 'ACCEPT', 'DROP']: - target = token_list[-1] + if args[0] == "*": + if args[1] in all_chains.keys(): + current_table = args[1] + continue + if args[0] == ":": + node_name = get_node_name(current_table, args[1]) + if args[2] == "-": + args[2] = "RETURN" + default_chain_policy[node_name] = args[2] + continue + if args[0] != "-A": + continue + current_chain = args[1] + if current_chain not in all_chains[current_table]: + all_chains[current_table][current_chain] = list() + + i = -1 + target = None + if "-j" in args: + i = args.index("-j") + 1 + elif "-g" in args: + i = args.index("-g") + 1 + if i > 0 and i < len(args): + target = args[i] + + final_rule = False + if target: + if target in default_middle_targets: + target = None + elif target in default_final_targets: + final_rule = True + target = None + else: if target not in all_chains[current_table]: all_chains[current_table][target] = list() - rule_body = ' '.join(token_list[2:]) - else: - rule_body = ' '.join(token_list[2:]) + # remove JUMP + if argv.eliminate: + del args[i-1] + del args[i-1] + node_name = get_node_name(current_table, target) + if node_name not in tables_target: + tables_target[node_name] = 0 + tables_target[node_name] += 1 + if node_name not in tables_comment: + tables_comment[node_name] = list() + comment = current_table + ":" + target + if "--comment" in args: + i = args.index("--comment") + 1 + if i < len(args): + tmp = args[i].replace("\\", "") + i = len(tmp) + if i > 0 and tmp[0] == '"' and tmp[i-1] == '"': + tmp = get_escape(tmp[1 : i-1]) + i = len(tmp) + if i > 0: + if comment in tables_comment[node_name]: + i = tables_comment[node_name].index(comment) + del tables_comment[node_name][i] + comment = tmp + if comment not in tables_comment[node_name]: + tables_comment[node_name].append(comment) - all_chains[current_table][current_chain].append({'rule_body':rule_body, 'target':target}) - continue - else: - continue + all_chains[current_table][current_chain].append( + {"rule": args[2:], "target": target, "final": final_rule} + ) + continue -def get_node_name(table_name, chain_name): - return re.sub('[^a-zA-Z0-9]', '', table_name) + '_' + re.sub('[^a-zA-Z0-9]', '', chain_name) +def get_next_chain(table_name, chain_name): + rules = all_chains[table_name][chain_name] + if len(rules) == 1: + target = rules[0]["target"] + rule = rules[0]["rule"] + if target and len(rule) == 0: + tables_target[get_node_name(table_name, chain_name)] -= 1 + return get_next_chain(table_name, target) + return chain_name + + +if argv.eliminate: + for table in all_chains: + for chain in all_chains[table]: + rules = all_chains[table][chain] + for i in range(len(rules)): + rule = rules[i]["rule"] + if len(rule) == 2 and rule[0] == "-j": + if chain in defualt_chain_list: + i += 1 + while i < len(rules): + del rules[i] + break + target = rules[i]["target"] + if target and target not in defualt_chain_list: + rules[i]["target"] = get_next_chain(table, target) + def get_port_name(rule_index): return "rule_" + str(rule_index) -output="""digraph { + +output = """digraph { graph [pad="0.5", nodesep="0.5", ranksep="2"]; - node [shape=plain] + node [shape=box3d] rankdir=LR; - """ for table in all_chains: for chain in all_chains[table]: + if argv.eliminate and not chain in defualt_chain_list: + node_name = get_node_name(table, chain) + if ( + node_name not in tables_target + or tables_target[node_name] < 1 + or len(all_chains[table][chain]) == 0 + ): + continue + node_name = get_node_name(table, chain) - tmp_body = node_name + """ [label=<""" + tmp_body = ( + """ + """ + + node_name + + """ [label=<
""" + ) if chain in defualt_chain_list: - tmp_body +=""" - - """ + bgcolor = "tomato" + if node_name in endness_chain: + bgcolor = "lightblue" + tmp_body += ( + """ + + """ + ) else: - tmp_body +=""" - - """ + if not node_name in tables_comment: + tables_comment[node_name] = [node_name.replace("_", ":")] + for comment in sorted(tables_comment[node_name]): + tmp_body += ( + """ + """ + ) + tmp_body += """ + """ for i in range(len(all_chains[table][chain])): rule = all_chains[table][chain][i] + empty_target = False + if ( + argv.eliminate + and rule["target"] + and rule["target"] not in defualt_chain_list + and len(all_chains[table][rule["target"]]) == 0 + ): + if len(rule["rule"]) == 0: + continue + empty_target = True tmp_body += """ - """ - #tmp_body += """>""" + """ tmp_body += """ - -
""" + chain + """
""" + table + """
""" + + node_name.replace("_", ":") + + """
""" + chain + """
""" + table + """
""" + + comment + + """
""" + rule["rule_body"] + """
""" + get_escape(" ".join(rule["rule"])) + """
end
>]; + -j """ + + policy + + """ + >]; """ + ) output += tmp_body for table in all_chains: for chain in all_chains[table]: for i in range(len(all_chains[table][chain])): - rule = all_chains[table][chain][i] - if rule['target']: - source_node = get_node_name(table, chain) + ':' + get_port_name(i) - target_node = get_node_name(table, rule['target']) + ':begin' - output += source_node + """ -> """ + target_node + """; -""" + target = all_chains[table][chain][i]["target"] + if target: + node_name1 = get_node_name(table, chain) + node_name2 = get_node_name(table, target) + if argv.eliminate: + if ( + chain not in defualt_chain_list + and ( + node_name1 not in tables_target + or tables_target[node_name1] < 1 + or len(all_chains[table][chain]) == 0 + ) + or target not in defualt_chain_list + and ( + node_name2 not in tables_target + or tables_target[node_name2] < 1 + or len(all_chains[table][target]) == 0 + ) + ): + continue + + source_node = node_name1 + ":" + get_port_name(i) + target_node = node_name2 + ":begin" + output += ( + """ + """ + + source_node + + """ -> """ + + target_node + + """;""" + ) + def default_chain_link(src_table_name, src_chain_name, dst_table_name, dst_chain_name): - source_node = get_node_name(src_table_name, src_chain_name) + ':end' - target_node = get_node_name(dst_table_name, dst_chain_name) + ':begin' - return source_node + """ -> """ + target_node + """ [color=red]; -""" + source_node = get_node_name(src_table_name, src_chain_name) + color = "red" + if ( + source_node in default_chain_policy + and default_chain_policy[source_node] != "ACCEPT" + ): + color = "grey" + target_node = get_node_name(dst_table_name, dst_chain_name) + return ( + """ + """ + + source_node + + """:end -> """ + + target_node + + """:begin [color=""" + + color + + """];""" + ) + + +def default_link(): + return ( + """ + START[shape=circle fillcolor=black fontcolor=white style=filled]; + END[shape=circle fillcolor=black fontcolor=white style=filled]; + APPLICATION[shape=circle fillcolor=black fontcolor=white style=filled]; + START->""" + + get_node_name("raw", "PREROUTING") + + """:begin[color=blue]; + """ + + get_node_name("nat", "INPUT") + + """:end-> APPLICATION[color=blue]; + APPLICATION->""" + + get_node_name("raw", "OUTPUT") + + """:begin[color=blue]; + """ + + get_node_name("nat", "POSTROUTING") + + """:end-> END[color=blue];""" + ) + + +output += default_link() + +output += default_chain_link("raw", "PREROUTING", "mangle", "PREROUTING") +output += default_chain_link("mangle", "PREROUTING", "nat", "PREROUTING") + +output += default_chain_link("nat", "PREROUTING", "mangle", "INPUT") +output += default_chain_link("mangle", "INPUT", "filter", "INPUT") +output += default_chain_link("filter", "INPUT", "security", "INPUT") +output += default_chain_link("security", "INPUT", "nat", "INPUT") + +output += default_chain_link("nat", "PREROUTING", "mangle", "FORWARD") +output += default_chain_link("mangle", "FORWARD", "filter", "FORWARD") +output += default_chain_link("filter", "FORWARD", "security", "FORWARD") + +output += default_chain_link("raw", "OUTPUT", "mangle", "OUTPUT") +output += default_chain_link("mangle", "OUTPUT", "nat", "OUTPUT") +output += default_chain_link("nat", "OUTPUT", "filter", "OUTPUT") +output += default_chain_link("filter", "OUTPUT", "security", "OUTPUT") -output += default_chain_link('raw', 'PREROUTING', 'mangle', 'PREROUTING') -output += default_chain_link('mangle', 'PREROUTING', 'nat', 'PREROUTING') -output += default_chain_link('nat', 'PREROUTING', 'mangle', 'INPUT') -output += default_chain_link('mangle', 'INPUT', 'filter', 'INPUT') -output += default_chain_link('filter', 'INPUT', 'raw', 'OUTPUT') -output += default_chain_link('raw', 'OUTPUT', 'mangle', 'OUTPUT') -output += default_chain_link('mangle', 'OUTPUT', 'nat', 'OUTPUT') -output += default_chain_link('nat', 'OUTPUT', 'filter', 'OUTPUT') -output += default_chain_link('filter', 'OUTPUT', 'mangle', 'POSTROUTING') -output += default_chain_link('mangle', 'POSTROUTING', 'nat', 'POSTROUTING') -output += default_chain_link('nat', 'PREROUTING', 'mangle', 'FORWARD') -output += default_chain_link('mangle', 'FORWARD', 'filter', 'FORWARD') -output += default_chain_link('filter', 'FORWARD', 'mangle', 'POSTROUTING') +output += default_chain_link("security", "OUTPUT", "mangle", "POSTROUTING") +output += default_chain_link("security", "FORWARD", "mangle", "POSTROUTING") +output += default_chain_link("mangle", "POSTROUTING", "nat", "POSTROUTING") output += """ }"""