github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/libnetwork/drivers/bridge/setup_ip_tables.go (about) 1 package bridge 2 3 import ( 4 "fmt" 5 "net" 6 7 "github.com/Sirupsen/logrus" 8 "github.com/docker/libnetwork/iptables" 9 ) 10 11 // DockerChain: DOCKER iptable chain name 12 const ( 13 DockerChain = "DOCKER" 14 IsolationChain = "DOCKER-ISOLATION" 15 ) 16 17 func setupIPChains(config *configuration) (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) { 18 // Sanity check. 19 if config.EnableIPTables == false { 20 return nil, nil, nil, fmt.Errorf("cannot create new chains, EnableIPTable is disabled") 21 } 22 23 hairpinMode := !config.EnableUserlandProxy 24 25 natChain, err := iptables.NewChain(DockerChain, iptables.Nat, hairpinMode) 26 if err != nil { 27 return nil, nil, nil, fmt.Errorf("failed to create NAT chain: %v", err) 28 } 29 defer func() { 30 if err != nil { 31 if err := iptables.RemoveExistingChain(DockerChain, iptables.Nat); err != nil { 32 logrus.Warnf("failed on removing iptables NAT chain on cleanup: %v", err) 33 } 34 } 35 }() 36 37 filterChain, err := iptables.NewChain(DockerChain, iptables.Filter, false) 38 if err != nil { 39 return nil, nil, nil, fmt.Errorf("failed to create FILTER chain: %v", err) 40 } 41 defer func() { 42 if err != nil { 43 if err := iptables.RemoveExistingChain(DockerChain, iptables.Filter); err != nil { 44 logrus.Warnf("failed on removing iptables FILTER chain on cleanup: %v", err) 45 } 46 } 47 }() 48 49 isolationChain, err := iptables.NewChain(IsolationChain, iptables.Filter, false) 50 if err != nil { 51 return nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err) 52 } 53 54 if err := addReturnRule(IsolationChain); err != nil { 55 return nil, nil, nil, err 56 } 57 58 return natChain, filterChain, isolationChain, nil 59 } 60 61 func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInterface) error { 62 var err error 63 64 d := n.driver 65 d.Lock() 66 driverConfig := d.config 67 d.Unlock() 68 69 // Sanity check. 70 if driverConfig.EnableIPTables == false { 71 return fmt.Errorf("Cannot program chains, EnableIPTable is disabled") 72 } 73 74 // Pickup this configuraton option from driver 75 hairpinMode := !driverConfig.EnableUserlandProxy 76 77 maskedAddrv4 := &net.IPNet{ 78 IP: i.bridgeIPv4.IP.Mask(i.bridgeIPv4.Mask), 79 Mask: i.bridgeIPv4.Mask, 80 } 81 if config.Internal { 82 if err = setupInternalNetworkRules(config.BridgeName, maskedAddrv4, true); err != nil { 83 return fmt.Errorf("Failed to Setup IP tables: %s", err.Error()) 84 } 85 n.registerIptCleanFunc(func() error { 86 return setupInternalNetworkRules(config.BridgeName, maskedAddrv4, false) 87 }) 88 } else { 89 if err = setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil { 90 return fmt.Errorf("Failed to Setup IP tables: %s", err.Error()) 91 } 92 n.registerIptCleanFunc(func() error { 93 return setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false) 94 }) 95 natChain, filterChain, _, err := n.getDriverChains() 96 if err != nil { 97 return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error()) 98 } 99 100 err = iptables.ProgramChain(natChain, config.BridgeName, hairpinMode, true) 101 if err != nil { 102 return fmt.Errorf("Failed to program NAT chain: %s", err.Error()) 103 } 104 105 err = iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, true) 106 if err != nil { 107 return fmt.Errorf("Failed to program FILTER chain: %s", err.Error()) 108 } 109 110 n.registerIptCleanFunc(func() error { 111 return iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, false) 112 }) 113 114 n.portMapper.SetIptablesChain(natChain, n.getNetworkBridgeName()) 115 } 116 117 if err := ensureJumpRule("FORWARD", IsolationChain); err != nil { 118 return err 119 } 120 121 return nil 122 } 123 124 type iptRule struct { 125 table iptables.Table 126 chain string 127 preArgs []string 128 args []string 129 } 130 131 func setupIPTablesInternal(bridgeIface string, addr net.Addr, icc, ipmasq, hairpin, enable bool) error { 132 133 var ( 134 address = addr.String() 135 natRule = iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: []string{"-s", address, "!", "-o", bridgeIface, "-j", "MASQUERADE"}} 136 hpNatRule = iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: []string{"-m", "addrtype", "--src-type", "LOCAL", "-o", bridgeIface, "-j", "MASQUERADE"}} 137 skipDNAT = iptRule{table: iptables.Nat, chain: DockerChain, preArgs: []string{"-t", "nat"}, args: []string{"-i", bridgeIface, "-j", "RETURN"}} 138 outRule = iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"}} 139 inRule = iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-o", bridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}} 140 ) 141 142 // Set NAT. 143 if ipmasq { 144 if err := programChainRule(natRule, "NAT", enable); err != nil { 145 return err 146 } 147 } 148 149 if ipmasq && !hairpin { 150 if err := programChainRule(skipDNAT, "SKIP DNAT", enable); err != nil { 151 return err 152 } 153 } 154 155 // In hairpin mode, masquerade traffic from localhost 156 if hairpin { 157 if err := programChainRule(hpNatRule, "MASQ LOCAL HOST", enable); err != nil { 158 return err 159 } 160 } 161 162 // Set Inter Container Communication. 163 if err := setIcc(bridgeIface, icc, enable); err != nil { 164 return err 165 } 166 167 // Set Accept on all non-intercontainer outgoing packets. 168 if err := programChainRule(outRule, "ACCEPT NON_ICC OUTGOING", enable); err != nil { 169 return err 170 } 171 172 // Set Accept on incoming packets for existing connections. 173 if err := programChainRule(inRule, "ACCEPT INCOMING", enable); err != nil { 174 return err 175 } 176 177 return nil 178 } 179 180 func programChainRule(rule iptRule, ruleDescr string, insert bool) error { 181 var ( 182 prefix []string 183 operation string 184 condition bool 185 doesExist = iptables.Exists(rule.table, rule.chain, rule.args...) 186 ) 187 188 if insert { 189 condition = !doesExist 190 prefix = []string{"-I", rule.chain} 191 operation = "enable" 192 } else { 193 condition = doesExist 194 prefix = []string{"-D", rule.chain} 195 operation = "disable" 196 } 197 if rule.preArgs != nil { 198 prefix = append(rule.preArgs, prefix...) 199 } 200 201 if condition { 202 if err := iptables.RawCombinedOutput(append(prefix, rule.args...)...); err != nil { 203 return fmt.Errorf("Unable to %s %s rule: %s", operation, ruleDescr, err.Error()) 204 } 205 } 206 207 return nil 208 } 209 210 func setIcc(bridgeIface string, iccEnable, insert bool) error { 211 var ( 212 table = iptables.Filter 213 chain = "FORWARD" 214 args = []string{"-i", bridgeIface, "-o", bridgeIface, "-j"} 215 acceptArgs = append(args, "ACCEPT") 216 dropArgs = append(args, "DROP") 217 ) 218 219 if insert { 220 if !iccEnable { 221 iptables.Raw(append([]string{"-D", chain}, acceptArgs...)...) 222 223 if !iptables.Exists(table, chain, dropArgs...) { 224 if err := iptables.RawCombinedOutput(append([]string{"-A", chain}, dropArgs...)...); err != nil { 225 return fmt.Errorf("Unable to prevent intercontainer communication: %s", err.Error()) 226 } 227 } 228 } else { 229 iptables.Raw(append([]string{"-D", chain}, dropArgs...)...) 230 231 if !iptables.Exists(table, chain, acceptArgs...) { 232 if err := iptables.RawCombinedOutput(append([]string{"-I", chain}, acceptArgs...)...); err != nil { 233 return fmt.Errorf("Unable to allow intercontainer communication: %s", err.Error()) 234 } 235 } 236 } 237 } else { 238 // Remove any ICC rule. 239 if !iccEnable { 240 if iptables.Exists(table, chain, dropArgs...) { 241 iptables.Raw(append([]string{"-D", chain}, dropArgs...)...) 242 } 243 } else { 244 if iptables.Exists(table, chain, acceptArgs...) { 245 iptables.Raw(append([]string{"-D", chain}, acceptArgs...)...) 246 } 247 } 248 } 249 250 return nil 251 } 252 253 // Control Inter Network Communication. Install/remove only if it is not/is present. 254 func setINC(iface1, iface2 string, enable bool) error { 255 var ( 256 table = iptables.Filter 257 chain = IsolationChain 258 args = [2][]string{{"-i", iface1, "-o", iface2, "-j", "DROP"}, {"-i", iface2, "-o", iface1, "-j", "DROP"}} 259 ) 260 261 if enable { 262 for i := 0; i < 2; i++ { 263 if iptables.Exists(table, chain, args[i]...) { 264 continue 265 } 266 if err := iptables.RawCombinedOutput(append([]string{"-I", chain}, args[i]...)...); err != nil { 267 return fmt.Errorf("unable to add inter-network communication rule: %v", err) 268 } 269 } 270 } else { 271 for i := 0; i < 2; i++ { 272 if !iptables.Exists(table, chain, args[i]...) { 273 continue 274 } 275 if err := iptables.RawCombinedOutput(append([]string{"-D", chain}, args[i]...)...); err != nil { 276 return fmt.Errorf("unable to remove inter-network communication rule: %v", err) 277 } 278 } 279 } 280 281 return nil 282 } 283 284 func addReturnRule(chain string) error { 285 var ( 286 table = iptables.Filter 287 args = []string{"-j", "RETURN"} 288 ) 289 290 if iptables.Exists(table, chain, args...) { 291 return nil 292 } 293 294 err := iptables.RawCombinedOutput(append([]string{"-I", chain}, args...)...) 295 if err != nil { 296 return fmt.Errorf("unable to add return rule in %s chain: %s", chain, err.Error()) 297 } 298 299 return nil 300 } 301 302 // Ensure the jump rule is on top 303 func ensureJumpRule(fromChain, toChain string) error { 304 var ( 305 table = iptables.Filter 306 args = []string{"-j", toChain} 307 ) 308 309 if iptables.Exists(table, fromChain, args...) { 310 err := iptables.RawCombinedOutput(append([]string{"-D", fromChain}, args...)...) 311 if err != nil { 312 return fmt.Errorf("unable to remove jump to %s rule in %s chain: %s", toChain, fromChain, err.Error()) 313 } 314 } 315 316 err := iptables.RawCombinedOutput(append([]string{"-I", fromChain}, args...)...) 317 if err != nil { 318 return fmt.Errorf("unable to insert jump to %s rule in %s chain: %s", toChain, fromChain, err.Error()) 319 } 320 321 return nil 322 } 323 324 func removeIPChains() { 325 for _, chainInfo := range []iptables.ChainInfo{ 326 {Name: DockerChain, Table: iptables.Nat}, 327 {Name: DockerChain, Table: iptables.Filter}, 328 {Name: IsolationChain, Table: iptables.Filter}, 329 } { 330 if err := chainInfo.Remove(); err != nil { 331 logrus.Warnf("Failed to remove existing iptables entries in table %s chain %s : %v", chainInfo.Table, chainInfo.Name, err) 332 } 333 } 334 } 335 336 func setupInternalNetworkRules(bridgeIface string, addr net.Addr, insert bool) error { 337 var ( 338 inDropRule = iptRule{table: iptables.Filter, chain: IsolationChain, args: []string{"-i", bridgeIface, "!", "-d", addr.String(), "-j", "DROP"}} 339 outDropRule = iptRule{table: iptables.Filter, chain: IsolationChain, args: []string{"-o", bridgeIface, "!", "-s", addr.String(), "-j", "DROP"}} 340 ) 341 if err := programChainRule(inDropRule, "DROP INCOMING", insert); err != nil { 342 return err 343 } 344 if err := programChainRule(outDropRule, "DROP OUTGOING", insert); err != nil { 345 return err 346 } 347 return nil 348 }