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 }