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