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 }