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 }