github.com/Azure/aad-pod-identity@v1.8.17/pkg/nmi/iptables/iptables.go (about) 1 package iptables 2 3 import ( 4 "errors" 5 "strings" 6 7 "github.com/coreos/go-iptables/iptables" 8 "k8s.io/klog/v2" 9 ) 10 11 var ( 12 tablename = "nat" 13 customchainname = "aad-metadata" 14 localhost = "127.0.0.1/32" 15 ) 16 17 // AddCustomChain adds the rule to the host's nat table custom chain 18 // all tcp requests NOT originating from localhost destined to 19 // destIp:destPort are routed to targetIP:targetPort 20 func AddCustomChain(destIP, destPort, targetip, targetport string) error { 21 if destIP == "" { 22 return errors.New("destIP must be set") 23 } 24 if destPort == "" { 25 return errors.New("destPort must be set") 26 } 27 if targetip == "" { 28 return errors.New("targetip must be set") 29 } 30 if targetport == "" { 31 return errors.New("targetport must be set") 32 } 33 34 ipt, err := iptables.New() 35 if err != nil { 36 return err 37 } 38 if err := ensureCustomChain(ipt, destIP, destPort, targetip, targetport); err != nil { 39 return err 40 } 41 if err := placeCustomChainInChain(ipt, tablename, "PREROUTING"); err != nil { 42 return err 43 } 44 45 return nil 46 } 47 48 // LogCustomChain logs added rules to the custom chain 49 func LogCustomChain() error { 50 ipt, err := iptables.New() 51 if err != nil { 52 return err 53 } 54 rules, err := ipt.List(tablename, customchainname) 55 if err != nil { 56 return err 57 } 58 klog.V(5).Infof("rules for table(%s) chain(%s) rules(%+v)", tablename, customchainname, strings.Join(rules, ", ")) 59 60 return nil 61 } 62 63 // iptables -t nat -I "chain" 1 -j "customchainname" 64 func placeCustomChainInChain(ipt *iptables.IPTables, table, chain string) error { 65 exists, err := ipt.Exists(table, chain, "-j", customchainname) 66 if err != nil || !exists { 67 if err := ipt.Insert(table, chain, 1, "-j", customchainname); err != nil { 68 return err 69 } 70 } 71 72 return nil 73 } 74 75 func ensureCustomChain(ipt *iptables.IPTables, destIP, destPort, targetip, targetport string) error { 76 rules, err := ipt.List(tablename, customchainname) 77 if err != nil { 78 err = ipt.NewChain(tablename, customchainname) 79 if err != nil { 80 return err 81 } 82 } 83 84 /* 85 iptables -t nat -S aad-metadata returns 3 rules 86 -N aad-metadata 87 -A aad-metadata ! -s 127.0.0.1/32 -d 169.254.169.254/32 -p tcp -m tcp --dport 80 -j DNAT --to-destination 127.0.0.1:<nmi port> 88 -A aad-metadata -j RETURN 89 90 For this reason we check if the length of rules is 3. If not 3, then we flush and create chain again. 91 */ 92 93 expectedRules := map[string]struct{}{ 94 "-N aad-metadata": {}, 95 "-A aad-metadata ! -s 127.0.0.1/32 -d " + destIP + "/32 -p tcp -m tcp --dport " + destPort + " -j DNAT --to-destination " + targetip + ":" + targetport: {}, 96 "-A aad-metadata -j RETURN": {}, 97 } 98 99 matchingRules := 0 100 // ensure all the rules are as expected with the right IPs 101 // if any rule has been changed, then we need to flush the 102 // entire chain and reconcile with the correct IPs 103 for _, rule := range rules { 104 if _, ok := expectedRules[rule]; !ok { 105 break 106 } 107 matchingRules++ 108 } 109 // all the required rules exist, so no need to flush custom chain 110 if matchingRules == len(expectedRules) { 111 return nil 112 } 113 114 if err := flushCreateCustomChainrules(ipt, destIP, destPort, 115 targetip, targetport); err != nil { 116 return err 117 } 118 119 return nil 120 } 121 122 func flushCreateCustomChainrules(ipt *iptables.IPTables, destIP, destPort, targetip, targetport string) error { 123 klog.Warning("flushing iptables to add aad-metadata custom chains") 124 if err := ipt.ClearChain(tablename, customchainname); err != nil { 125 return err 126 } 127 if err := ipt.AppendUnique( 128 tablename, customchainname, "-p", "tcp", "!", "-s", localhost, "-d", destIP, "--dport", destPort, 129 "-j", "DNAT", "--to-destination", targetip+":"+targetport); err != nil { 130 return err 131 } 132 if err := ipt.AppendUnique( 133 tablename, customchainname, "-j", "RETURN"); err != nil { 134 return err 135 } 136 137 return nil 138 } 139 140 // DeleteCustomChain removes the custom chain aad-metadata reference from PREROUTING 141 // chain and then removes the chain aad-metadata from nat table 142 func DeleteCustomChain() error { 143 ipt, err := iptables.New() 144 if err != nil { 145 return err 146 } 147 if err := removeCustomChainReference(ipt, tablename, "PREROUTING"); err != nil { 148 return err 149 } 150 if err := removeCustomChain(ipt, tablename); err != nil { 151 return err 152 } 153 return nil 154 } 155 156 // removeCustomChainReference - iptables -t "table" -D "chain" -j "customchainname" 157 func removeCustomChainReference(ipt *iptables.IPTables, table, chain string) error { 158 exists, err := ipt.Exists(table, chain, "-j", customchainname) 159 if err == nil && exists { 160 return ipt.Delete(table, chain, "-j", customchainname) 161 } 162 return nil 163 } 164 165 // removeCustomChain - flush and then delete custom chain 166 // iptables -t "table" -F "customchainname" 167 // iptables -t "table" -X "customchainname" 168 func removeCustomChain(ipt *iptables.IPTables, table string) error { 169 if err := ipt.ClearChain(table, customchainname); err != nil { 170 return err 171 } 172 if err := ipt.DeleteChain(table, customchainname); err != nil { 173 return err 174 } 175 return nil 176 }