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  }