github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/libnetwork/drivers/overlay/filter.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  package overlay
     5  
     6  import (
     7  	"fmt"
     8  	"sync"
     9  
    10  	"github.com/docker/docker/libnetwork/iptables"
    11  	"github.com/sirupsen/logrus"
    12  )
    13  
    14  const globalChain = "DOCKER-OVERLAY"
    15  
    16  var filterOnce sync.Once
    17  
    18  var filterChan = make(chan struct{}, 1)
    19  
    20  func filterWait() func() {
    21  	filterChan <- struct{}{}
    22  	return func() { <-filterChan }
    23  }
    24  
    25  func chainExists(cname string) bool {
    26  	// TODO IPv6 support
    27  	iptable := iptables.GetIptable(iptables.IPv4)
    28  	if _, err := iptable.Raw("-L", cname); err != nil {
    29  		return false
    30  	}
    31  
    32  	return true
    33  }
    34  
    35  func setupGlobalChain() {
    36  	// TODO IPv6 support
    37  	iptable := iptables.GetIptable(iptables.IPv4)
    38  	// Because of an ungraceful shutdown, chain could already be present
    39  	if !chainExists(globalChain) {
    40  		if err := iptable.RawCombinedOutput("-N", globalChain); err != nil {
    41  			logrus.Errorf("could not create global overlay chain: %v", err)
    42  			return
    43  		}
    44  	}
    45  
    46  	if !iptable.Exists(iptables.Filter, globalChain, "-j", "RETURN") {
    47  		if err := iptable.RawCombinedOutput("-A", globalChain, "-j", "RETURN"); err != nil {
    48  			logrus.Errorf("could not install default return chain in the overlay global chain: %v", err)
    49  		}
    50  	}
    51  }
    52  
    53  func setNetworkChain(cname string, remove bool) error {
    54  	// TODO IPv6 support
    55  	iptable := iptables.GetIptable(iptables.IPv4)
    56  	// Initialize the onetime global overlay chain
    57  	filterOnce.Do(setupGlobalChain)
    58  
    59  	exists := chainExists(cname)
    60  
    61  	opt := "-N"
    62  	// In case of remove, make sure to flush the rules in the chain
    63  	if remove && exists {
    64  		if err := iptable.RawCombinedOutput("-F", cname); err != nil {
    65  			return fmt.Errorf("failed to flush overlay network chain %s rules: %v", cname, err)
    66  		}
    67  		opt = "-X"
    68  	}
    69  
    70  	if (!remove && !exists) || (remove && exists) {
    71  		if err := iptable.RawCombinedOutput(opt, cname); err != nil {
    72  			return fmt.Errorf("failed network chain operation %q for chain %s: %v", opt, cname, err)
    73  		}
    74  	}
    75  
    76  	if !remove {
    77  		if !iptable.Exists(iptables.Filter, cname, "-j", "DROP") {
    78  			if err := iptable.RawCombinedOutput("-A", cname, "-j", "DROP"); err != nil {
    79  				return fmt.Errorf("failed adding default drop rule to overlay network chain %s: %v", cname, err)
    80  			}
    81  		}
    82  	}
    83  
    84  	return nil
    85  }
    86  
    87  func addNetworkChain(cname string) error {
    88  	defer filterWait()()
    89  
    90  	return setNetworkChain(cname, false)
    91  }
    92  
    93  func removeNetworkChain(cname string) error {
    94  	defer filterWait()()
    95  
    96  	return setNetworkChain(cname, true)
    97  }
    98  
    99  func setFilters(cname, brName string, remove bool) error {
   100  	opt := "-I"
   101  	if remove {
   102  		opt = "-D"
   103  	}
   104  	// TODO IPv6 support
   105  	iptable := iptables.GetIptable(iptables.IPv4)
   106  
   107  	// 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
   108  	if !remove {
   109  		for _, chain := range []string{"OUTPUT", "FORWARD"} {
   110  			exists := iptable.Exists(iptables.Filter, chain, "-j", globalChain)
   111  			if exists {
   112  				if err := iptable.RawCombinedOutput("-D", chain, "-j", globalChain); err != nil {
   113  					return fmt.Errorf("failed to delete overlay hook in chain %s while moving the hook: %v", chain, err)
   114  				}
   115  			}
   116  
   117  			if err := iptable.RawCombinedOutput("-I", chain, "-j", globalChain); err != nil {
   118  				return fmt.Errorf("failed to insert overlay hook in chain %s: %v", chain, err)
   119  			}
   120  		}
   121  	}
   122  
   123  	// Insert/Delete the rule to jump to per-bridge chain
   124  	exists := iptable.Exists(iptables.Filter, globalChain, "-o", brName, "-j", cname)
   125  	if (!remove && !exists) || (remove && exists) {
   126  		if err := iptable.RawCombinedOutput(opt, globalChain, "-o", brName, "-j", cname); err != nil {
   127  			return fmt.Errorf("failed to add per-bridge filter rule for bridge %s, network chain %s: %v", brName, cname, err)
   128  		}
   129  	}
   130  
   131  	exists = iptable.Exists(iptables.Filter, cname, "-i", brName, "-j", "ACCEPT")
   132  	if (!remove && exists) || (remove && !exists) {
   133  		return nil
   134  	}
   135  
   136  	if err := iptable.RawCombinedOutput(opt, cname, "-i", brName, "-j", "ACCEPT"); err != nil {
   137  		return fmt.Errorf("failed to add overlay filter rile for network chain %s, bridge %s: %v", cname, brName, err)
   138  	}
   139  
   140  	return nil
   141  }
   142  
   143  func addFilters(cname, brName string) error {
   144  	defer filterWait()()
   145  
   146  	return setFilters(cname, brName, false)
   147  }
   148  
   149  func removeFilters(cname, brName string) error {
   150  	defer filterWait()()
   151  
   152  	return setFilters(cname, brName, true)
   153  }