func (s *DockerDaemonSuite) TestDaemonLinksIpTablesRulesWhenLinkAndUnlink(c *check.C) { bridgeName := "external-bridge" bridgeIp := "192.169.1.1/24" out, err := createInterface(c, "bridge", bridgeName, bridgeIp) c.Assert(err, check.IsNil, check.Commentf(out)) defer deleteInterface(c, bridgeName) args := []string{"--bridge", bridgeName, "--icc=false"} err = s.d.StartWithBusybox(args...) c.Assert(err, check.IsNil) defer s.d.Restart() _, err = s.d.Cmd("run", "-d", "--name", "child", "--publish", "8080:80", "busybox", "top") c.Assert(err, check.IsNil) _, err = s.d.Cmd("run", "-d", "--name", "parent", "--link", "child:http", "busybox", "top") c.Assert(err, check.IsNil) childIP := s.d.findContainerIP("child") parentIP := s.d.findContainerIP("parent") sourceRule := []string{"-i", bridgeName, "-o", bridgeName, "-p", "tcp", "-s", childIP, "--sport", "80", "-d", parentIP, "-j", "ACCEPT"} destinationRule := []string{"-i", bridgeName, "-o", bridgeName, "-p", "tcp", "-s", parentIP, "--dport", "80", "-d", childIP, "-j", "ACCEPT"} if !iptables.Exists("filter", "DOCKER", sourceRule...) || !iptables.Exists("filter", "DOCKER", destinationRule...) { c.Fatal("Iptables rules not found") } s.d.Cmd("rm", "--link", "parent/http") if iptables.Exists("filter", "DOCKER", sourceRule...) || iptables.Exists("filter", "DOCKER", destinationRule...) { c.Fatal("Iptables rules should be removed when unlink") } s.d.Cmd("kill", "child") s.d.Cmd("kill", "parent") }
// Control Inter Network Communication. Install/remove only if it is not/is present. func setINC(network1, network2 string, enable bool) error { var ( table = iptables.Filter chain = "FORWARD" args = [2][]string{{"-s", network1, "-d", network2, "-j", "DROP"}, {"-s", network2, "-d", network1, "-j", "DROP"}} ) if enable { for i := 0; i < 2; i++ { if iptables.Exists(table, chain, args[i]...) { continue } if output, err := iptables.Raw(append([]string{"-I", chain}, args[i]...)...); err != nil { return fmt.Errorf("unable to add inter-network communication rule: %s", err.Error()) } else if len(output) != 0 { return fmt.Errorf("error adding inter-network communication rule: %s", string(output)) } } } else { for i := 0; i < 2; i++ { if !iptables.Exists(table, chain, args[i]...) { continue } if output, err := iptables.Raw(append([]string{"-D", chain}, args[i]...)...); err != nil { return fmt.Errorf("unable to remove inter-network communication rule: %s", err.Error()) } else if len(output) != 0 { return fmt.Errorf("error removing inter-network communication rule: %s", string(output)) } } } return nil }
// Control Inter Network Communication. Install/remove only if it is not/is present. func setINC(iface1, iface2 string, enable bool) error { var ( table = iptables.Filter chain = IsolationChain args = [2][]string{{"-i", iface1, "-o", iface2, "-j", "DROP"}, {"-i", iface2, "-o", iface1, "-j", "DROP"}} ) if enable { for i := 0; i < 2; i++ { if iptables.Exists(table, chain, args[i]...) { continue } if err := iptables.RawCombinedOutput(append([]string{"-I", chain}, args[i]...)...); err != nil { return fmt.Errorf("unable to add inter-network communication rule: %v", err) } } } else { for i := 0; i < 2; i++ { if !iptables.Exists(table, chain, args[i]...) { continue } if err := iptables.RawCombinedOutput(append([]string{"-D", chain}, args[i]...)...); err != nil { return fmt.Errorf("unable to remove inter-network communication rule: %v", err) } } } return nil }
func setNetworkChain(cname string, remove bool) error { // Initialize the onetime global overlay chain filterOnce.Do(setupGlobalChain) exists := chainExists(cname) opt := "-N" // In case of remove, make sure to flush the rules in the chain if remove && exists { if err := iptables.RawCombinedOutput("-F", cname); err != nil { return fmt.Errorf("failed to flush overlay network chain %s rules: %v", cname, err) } opt = "-X" } if (!remove && !exists) || (remove && exists) { if err := iptables.RawCombinedOutput(opt, cname); err != nil { return fmt.Errorf("failed network chain operation %q for chain %s: %v", opt, cname, err) } } if !remove { if !iptables.Exists(iptables.Filter, cname, "-j", "DROP") { if err := iptables.RawCombinedOutput("-A", cname, "-j", "DROP"); err != nil { return fmt.Errorf("failed adding default drop rule to overlay network chain %s: %v", cname, err) } } } return nil }
func programMangle(vni uint32, add bool) (err error) { var ( p = strconv.FormatUint(uint64(vxlanPort), 10) c = fmt.Sprintf("0>>22&0x3C@12&0xFFFFFF00=%d", int(vni)<<8) m = strconv.FormatUint(uint64(mark), 10) chain = "OUTPUT" rule = []string{"-p", "udp", "--dport", p, "-m", "u32", "--u32", c, "-j", "MARK", "--set-mark", m} a = "-A" action = "install" ) if add == iptables.Exists(iptables.Mangle, chain, rule...) { return } if !add { a = "-D" action = "remove" } if err = iptables.RawCombinedOutput(append([]string{"-t", string(iptables.Mangle), a, chain}, rule...)...); err != nil { logrus.Warnf("could not %s mangle rule: %v", action, err) } return }
func programChainRule(rule iptRule, ruleDescr string, insert bool) error { var ( prefix []string operation string condition bool doesExist = iptables.Exists(rule.table, rule.chain, rule.args...) ) if insert { condition = !doesExist prefix = []string{"-I", rule.chain} operation = "enable" } else { condition = doesExist prefix = []string{"-D", rule.chain} operation = "disable" } if rule.preArgs != nil { prefix = append(rule.preArgs, prefix...) } if condition { if err := iptables.RawCombinedOutput(append(prefix, rule.args...)...); err != nil { return fmt.Errorf("Unable to %s %s rule: %s", operation, ruleDescr, err.Error()) } } return nil }
// Assert base function which pushes iptables chain rules on insertion and removal. func assertIPTableChainProgramming(rule iptRule, descr string, t *testing.T) { // Add if err := programChainRule(rule, descr, true); err != nil { t.Fatalf("Failed to program iptable rule %s: %s", descr, err.Error()) } if iptables.Exists(rule.table, rule.chain, rule.args...) == false { t.Fatalf("Failed to effectively program iptable rule: %s", descr) } // Remove if err := programChainRule(rule, descr, false); err != nil { t.Fatalf("Failed to remove iptable rule %s: %s", descr, err.Error()) } if iptables.Exists(rule.table, rule.chain, rule.args...) == true { t.Fatalf("Failed to effectively remove iptable rule: %s", descr) } }
func setIcc(bridgeIface string, iccEnable, insert bool) error { var ( table = iptables.Filter chain = "FORWARD" args = []string{"-i", bridgeIface, "-o", bridgeIface, "-j"} acceptArgs = append(args, "ACCEPT") dropArgs = append(args, "DROP") ) if insert { if !iccEnable { iptables.Raw(append([]string{"-D", chain}, acceptArgs...)...) if !iptables.Exists(table, chain, dropArgs...) { if output, err := iptables.Raw(append([]string{"-A", chain}, dropArgs...)...); err != nil { return fmt.Errorf("Unable to prevent intercontainer communication: %s", err.Error()) } else if len(output) != 0 { return fmt.Errorf("Error disabling intercontainer communication: %s", output) } } } else { iptables.Raw(append([]string{"-D", chain}, dropArgs...)...) if !iptables.Exists(table, chain, acceptArgs...) { if output, err := iptables.Raw(append([]string{"-A", chain}, acceptArgs...)...); err != nil { return fmt.Errorf("Unable to allow intercontainer communication: %s", err.Error()) } else if len(output) != 0 { return fmt.Errorf("Error enabling intercontainer communication: %s", output) } } } } else { // Remove any ICC rule. if !iccEnable { if iptables.Exists(table, chain, dropArgs...) { iptables.Raw(append([]string{"-D", chain}, dropArgs...)...) } } else { if iptables.Exists(table, chain, acceptArgs...) { iptables.Raw(append([]string{"-D", chain}, acceptArgs...)...) } } } return nil }
func setFilters(cname, brName string, remove bool) error { opt := "-I" if remove { opt = "-D" } // Every time we set filters for a new subnet make sure to move the global overlay hook to the top of the both the OUTPUT and forward chains if !remove { for _, chain := range []string{"OUTPUT", "FORWARD"} { exists := iptables.Exists(iptables.Filter, chain, "-j", globalChain) if exists { if err := iptables.RawCombinedOutput("-D", chain, "-j", globalChain); err != nil { return fmt.Errorf("failed to delete overlay hook in chain %s while moving the hook: %v", chain, err) } } if err := iptables.RawCombinedOutput("-I", chain, "-j", globalChain); err != nil { return fmt.Errorf("failed to insert overlay hook in chain %s: %v", chain, err) } } } // Insert/Delete the rule to jump to per-bridge chain exists := iptables.Exists(iptables.Filter, globalChain, "-o", brName, "-j", cname) if (!remove && !exists) || (remove && exists) { if err := iptables.RawCombinedOutput(opt, globalChain, "-o", brName, "-j", cname); err != nil { return fmt.Errorf("failed to add per-bridge filter rule for bridge %s, network chain %s: %v", brName, cname, err) } } exists = iptables.Exists(iptables.Filter, cname, "-i", brName, "-j", "ACCEPT") if (!remove && exists) || (remove && !exists) { return nil } if err := iptables.RawCombinedOutput(opt, cname, "-i", brName, "-j", "ACCEPT"); err != nil { return fmt.Errorf("failed to add overlay filter rile for network chain %s, bridge %s: %v", cname, brName, err) } return nil }
// In the filter table FORWARD chain first rule should be to jump to INGRESS-CHAIN // This chain has the rules to allow access to the published ports for swarm tasks // from local bridge networks and docker_gwbridge (ie:taks on other swarm netwroks) func arrangeIngressFilterRule() { if iptables.ExistChain(ingressChain, iptables.Filter) { if iptables.Exists(iptables.Filter, "FORWARD", "-j", ingressChain) { if err := iptables.RawCombinedOutput("-D", "FORWARD", "-j", ingressChain); err != nil { logrus.Warnf("failed to delete jump rule to ingressChain in filter table: %v", err) } } if err := iptables.RawCombinedOutput("-I", "FORWARD", "-j", ingressChain); err != nil { logrus.Warnf("failed to add jump rule to ingressChain in filter table: %v", err) } } }
func setupGlobalChain() { // Because of an ungraceful shutdown, chain could already be present if !chainExists(globalChain) { if err := iptables.RawCombinedOutput("-N", globalChain); err != nil { logrus.Errorf("could not create global overlay chain: %v", err) return } } if !iptables.Exists(iptables.Filter, globalChain, "-j", "RETURN") { if err := iptables.RawCombinedOutput("-A", globalChain, "-j", "RETURN"); err != nil { logrus.Errorf("could not install default return chain in the overlay global chain: %v", err) } } }
func addReturnRule(chain string) error { var ( table = iptables.Filter args = []string{"-j", "RETURN"} ) if iptables.Exists(table, chain, args...) { return nil } err := iptables.RawCombinedOutput(append([]string{"-I", chain}, args...)...) if err != nil { return fmt.Errorf("unable to add return rule in %s chain: %s", chain, err.Error()) } return nil }
// Ensure the jump rule is on top func ensureJumpRule(fromChain, toChain string) error { var ( table = iptables.Filter args = []string{"-j", toChain} ) if iptables.Exists(table, fromChain, args...) { err := iptables.RawCombinedOutput(append([]string{"-D", fromChain}, args...)...) if err != nil { return fmt.Errorf("unable to remove jump to %s rule in %s chain: %s", toChain, fromChain, err.Error()) } } err := iptables.RawCombinedOutput(append([]string{"-I", fromChain}, args...)...) if err != nil { return fmt.Errorf("unable to insert jump to %s rule in %s chain: %s", toChain, fromChain, err.Error()) } return nil }
// Firewall marker reexec function. func fwMarker() { runtime.LockOSThread() defer runtime.UnlockOSThread() if len(os.Args) < 7 { logrus.Error("invalid number of arguments..") os.Exit(1) } var ingressPorts []*PortConfig if os.Args[5] != "" { var err error ingressPorts, err = readPortsFromFile(os.Args[5]) if err != nil { logrus.Errorf("Failed reading ingress ports file: %v", err) os.Exit(6) } } vip := os.Args[2] fwMark, err := strconv.ParseUint(os.Args[3], 10, 32) if err != nil { logrus.Errorf("bad fwmark value(%s) passed: %v", os.Args[3], err) os.Exit(2) } addDelOpt := os.Args[4] rules := [][]string{} for _, iPort := range ingressPorts { rule := strings.Fields(fmt.Sprintf("-t mangle %s PREROUTING -p %s --dport %d -j MARK --set-mark %d", addDelOpt, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort, fwMark)) rules = append(rules, rule) } ns, err := netns.GetFromPath(os.Args[1]) if err != nil { logrus.Errorf("failed get network namespace %q: %v", os.Args[1], err) os.Exit(3) } defer ns.Close() if err := netns.Set(ns); err != nil { logrus.Errorf("setting into container net ns %v failed, %v", os.Args[1], err) os.Exit(4) } if addDelOpt == "-A" { eIP, subnet, err := net.ParseCIDR(os.Args[6]) if err != nil { logrus.Errorf("Failed to parse endpoint IP %s: %v", os.Args[6], err) os.Exit(9) } ruleParams := strings.Fields(fmt.Sprintf("-m ipvs --ipvs -d %s -j SNAT --to-source %s", subnet, eIP)) if !iptables.Exists("nat", "POSTROUTING", ruleParams...) { rule := append(strings.Fields("-t nat -A POSTROUTING"), ruleParams...) rules = append(rules, rule) err := ioutil.WriteFile("/proc/sys/net/ipv4/vs/conntrack", []byte{'1', '\n'}, 0644) if err != nil { logrus.Errorf("Failed to write to /proc/sys/net/ipv4/vs/conntrack: %v", err) os.Exit(8) } } } rule := strings.Fields(fmt.Sprintf("-t mangle %s OUTPUT -d %s/32 -j MARK --set-mark %d", addDelOpt, vip, fwMark)) rules = append(rules, rule) rule = strings.Fields(fmt.Sprintf("-t nat %s OUTPUT -p icmp --icmp echo-request -d %s -j DNAT --to 127.0.0.1", addDelOpt, vip)) rules = append(rules, rule) for _, rule := range rules { if err := iptables.RawCombinedOutputNative(rule...); err != nil { logrus.Errorf("setting up rule failed, %v: %v", rule, err) os.Exit(5) } } }
func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) error { addDelOpt := "-I" if isDelete { addDelOpt = "-D" } chainExists := iptables.ExistChain(ingressChain, iptables.Nat) filterChainExists := iptables.ExistChain(ingressChain, iptables.Filter) ingressOnce.Do(func() { // Flush nat table and filter table ingress chain rules during init if it // exists. It might contain stale rules from previous life. if chainExists { if err := iptables.RawCombinedOutput("-t", "nat", "-F", ingressChain); err != nil { logrus.Errorf("Could not flush nat table ingress chain rules during init: %v", err) } } if filterChainExists { if err := iptables.RawCombinedOutput("-F", ingressChain); err != nil { logrus.Errorf("Could not flush filter table ingress chain rules during init: %v", err) } } }) if !isDelete { if !chainExists { if err := iptables.RawCombinedOutput("-t", "nat", "-N", ingressChain); err != nil { return fmt.Errorf("failed to create ingress chain: %v", err) } } if !filterChainExists { if err := iptables.RawCombinedOutput("-N", ingressChain); err != nil { return fmt.Errorf("failed to create filter table ingress chain: %v", err) } } if !iptables.Exists(iptables.Nat, ingressChain, "-j", "RETURN") { if err := iptables.RawCombinedOutput("-t", "nat", "-A", ingressChain, "-j", "RETURN"); err != nil { return fmt.Errorf("failed to add return rule in nat table ingress chain: %v", err) } } if !iptables.Exists(iptables.Filter, ingressChain, "-j", "RETURN") { if err := iptables.RawCombinedOutput("-A", ingressChain, "-j", "RETURN"); err != nil { return fmt.Errorf("failed to add return rule to filter table ingress chain: %v", err) } } for _, chain := range []string{"OUTPUT", "PREROUTING"} { if !iptables.Exists(iptables.Nat, chain, "-m", "addrtype", "--dst-type", "LOCAL", "-j", ingressChain) { if err := iptables.RawCombinedOutput("-t", "nat", "-I", chain, "-m", "addrtype", "--dst-type", "LOCAL", "-j", ingressChain); err != nil { return fmt.Errorf("failed to add jump rule in %s to ingress chain: %v", chain, err) } } } if !iptables.Exists(iptables.Filter, "FORWARD", "-j", ingressChain) { if err := iptables.RawCombinedOutput("-I", "FORWARD", "-j", ingressChain); err != nil { return fmt.Errorf("failed to add jump rule to %s in filter table forward chain: %v", ingressChain, err) } } oifName, err := findOIFName(gwIP) if err != nil { return fmt.Errorf("failed to find gateway bridge interface name for %s: %v", gwIP, err) } path := filepath.Join("/proc/sys/net/ipv4/conf", oifName, "route_localnet") if err := ioutil.WriteFile(path, []byte{'1', '\n'}, 0644); err != nil { return fmt.Errorf("could not write to %s: %v", path, err) } ruleArgs := strings.Fields(fmt.Sprintf("-m addrtype --src-type LOCAL -o %s -j MASQUERADE", oifName)) if !iptables.Exists(iptables.Nat, "POSTROUTING", ruleArgs...) { if err := iptables.RawCombinedOutput(append([]string{"-t", "nat", "-I", "POSTROUTING"}, ruleArgs...)...); err != nil { return fmt.Errorf("failed to add ingress localhost POSTROUTING rule for %s: %v", oifName, err) } } } for _, iPort := range ingressPorts { if iptables.ExistChain(ingressChain, iptables.Nat) { rule := strings.Fields(fmt.Sprintf("-t nat %s %s -p %s --dport %d -j DNAT --to-destination %s:%d", addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort, gwIP, iPort.PublishedPort)) if err := iptables.RawCombinedOutput(rule...); err != nil { errStr := fmt.Sprintf("setting up rule failed, %v: %v", rule, err) if !isDelete { return fmt.Errorf("%s", errStr) } logrus.Infof("%s", errStr) } } // Filter table rules to allow a published service to be accessible in the local node from.. // 1) service tasks attached to other networks // 2) unmanaged containers on bridge networks rule := strings.Fields(fmt.Sprintf("%s %s -m state -p %s --sport %d --state ESTABLISHED,RELATED -j ACCEPT", addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort)) if err := iptables.RawCombinedOutput(rule...); err != nil { errStr := fmt.Sprintf("setting up rule failed, %v: %v", rule, err) if !isDelete { return fmt.Errorf("%s", errStr) } logrus.Warnf("%s", errStr) } rule = strings.Fields(fmt.Sprintf("%s %s -p %s --dport %d -j ACCEPT", addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort)) if err := iptables.RawCombinedOutput(rule...); err != nil { errStr := fmt.Sprintf("setting up rule failed, %v: %v", rule, err) if !isDelete { return fmt.Errorf("%s", errStr) } logrus.Warnf("%s", errStr) } if err := plumbProxy(iPort, isDelete); err != nil { logrus.Warnf("failed to create proxy for port %d: %v", iPort.PublishedPort, err) } } return nil }
// Firewall marker reexec function. func fwMarker() { runtime.LockOSThread() defer runtime.UnlockOSThread() if len(os.Args) < 7 { logrus.Error("invalid number of arguments..") os.Exit(1) } var ingressPorts []*PortConfig if os.Args[5] != "" { buf, err := ioutil.ReadFile(os.Args[5]) if err != nil { logrus.Errorf("Failed to read ports config file: %v", err) os.Exit(6) } var epRec EndpointRecord err = proto.Unmarshal(buf, &epRec) if err != nil { logrus.Errorf("Failed to unmarshal ports config data: %v", err) os.Exit(7) } ingressPorts = epRec.IngressPorts } vip := os.Args[2] fwMark, err := strconv.ParseUint(os.Args[3], 10, 32) if err != nil { logrus.Errorf("bad fwmark value(%s) passed: %v", os.Args[3], err) os.Exit(2) } addDelOpt := os.Args[4] rules := [][]string{} for _, iPort := range ingressPorts { rule := strings.Fields(fmt.Sprintf("-t nat %s PREROUTING -p %s --dport %d -j REDIRECT --to-port %d", addDelOpt, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort, iPort.TargetPort)) rules = append(rules, rule) rule = strings.Fields(fmt.Sprintf("-t mangle %s PREROUTING -p %s --dport %d -j MARK --set-mark %d", addDelOpt, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort, fwMark)) rules = append(rules, rule) } ns, err := netns.GetFromPath(os.Args[1]) if err != nil { logrus.Errorf("failed get network namespace %q: %v", os.Args[1], err) os.Exit(3) } defer ns.Close() if err := netns.Set(ns); err != nil { logrus.Errorf("setting into container net ns %v failed, %v", os.Args[1], err) os.Exit(4) } if len(ingressPorts) != 0 && addDelOpt == "-A" { ruleParams := strings.Fields(fmt.Sprintf("-m ipvs --ipvs -j SNAT --to-source %s", os.Args[6])) if !iptables.Exists("nat", "POSTROUTING", ruleParams...) { rule := append(strings.Fields("-t nat -A POSTROUTING"), ruleParams...) rules = append(rules, rule) err := ioutil.WriteFile("/proc/sys/net/ipv4/vs/conntrack", []byte{'1', '\n'}, 0644) if err != nil { logrus.Errorf("Failed to write to /proc/sys/net/ipv4/vs/conntrack: %v", err) os.Exit(8) } } } rule := strings.Fields(fmt.Sprintf("-t mangle %s OUTPUT -d %s/32 -j MARK --set-mark %d", addDelOpt, vip, fwMark)) rules = append(rules, rule) for _, rule := range rules { if err := iptables.RawCombinedOutputNative(rule...); err != nil { logrus.Errorf("setting up rule failed, %v: %v", rule, err) os.Exit(5) } } }
func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) error { addDelOpt := "-I" if isDelete { addDelOpt = "-D" } chainExists := iptables.ExistChain(ingressChain, iptables.Nat) ingressOnce.Do(func() { if chainExists { // Flush ingress chain rules during init if it // exists. It might contain stale rules from // previous life. if err := iptables.RawCombinedOutput("-t", "nat", "-F", ingressChain); err != nil { logrus.Errorf("Could not flush ingress chain rules during init: %v", err) } } }) if !isDelete { if !chainExists { if err := iptables.RawCombinedOutput("-t", "nat", "-N", ingressChain); err != nil { return fmt.Errorf("failed to create ingress chain: %v", err) } } if !iptables.Exists(iptables.Nat, ingressChain, "-j", "RETURN") { if err := iptables.RawCombinedOutput("-t", "nat", "-A", ingressChain, "-j", "RETURN"); err != nil { return fmt.Errorf("failed to add return rule in ingress chain: %v", err) } } for _, chain := range []string{"OUTPUT", "PREROUTING"} { if !iptables.Exists(iptables.Nat, chain, "-j", ingressChain) { if err := iptables.RawCombinedOutput("-t", "nat", "-I", chain, "-j", ingressChain); err != nil { return fmt.Errorf("failed to add jump rule in %s to ingress chain: %v", chain, err) } } } oifName, err := findOIFName(gwIP) if err != nil { return fmt.Errorf("failed to find gateway bridge interface name for %s: %v", gwIP, err) } path := filepath.Join("/proc/sys/net/ipv4/conf", oifName, "route_localnet") if err := ioutil.WriteFile(path, []byte{'1', '\n'}, 0644); err != nil { return fmt.Errorf("could not write to %s: %v", path, err) } ruleArgs := strings.Fields(fmt.Sprintf("-m addrtype --src-type LOCAL -o %s -j MASQUERADE", oifName)) if !iptables.Exists(iptables.Nat, "POSTROUTING", ruleArgs...) { if err := iptables.RawCombinedOutput(append([]string{"-t", "nat", "-I", "POSTROUTING"}, ruleArgs...)...); err != nil { return fmt.Errorf("failed to add ingress localhost POSTROUTING rule for %s: %v", oifName, err) } } } for _, iPort := range ingressPorts { if iptables.ExistChain(ingressChain, iptables.Nat) { rule := strings.Fields(fmt.Sprintf("-t nat %s %s -p %s --dport %d -j DNAT --to-destination %s:%d", addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort, gwIP, iPort.PublishedPort)) if err := iptables.RawCombinedOutput(rule...); err != nil { return fmt.Errorf("setting up rule failed, %v: %v", rule, err) } } if err := plumbProxy(iPort, isDelete); err != nil { return fmt.Errorf("failed to create proxy for port %d: %v", iPort.PublishedPort, err) } } return nil }