github.com/jfrazelle/docker@v1.1.2-0.20210712172922-bf78e25fe508/libnetwork/drivers/overlay/filter.go (about)

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