github.com/pwn-term/docker@v0.0.0-20210616085119-6e977cce2565/libnetwork/drivers/overlay/filter.go (about)

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