// CleanupLeftovers removes all iptables rules and chains created by the Proxier // It returns true if an error was encountered. Errors are logged. func CleanupLeftovers(ipt utiliptables.Interface) (encounteredError bool) { //TODO: actually tear down all rules and chains. args := []string{"-j", "KUBE-SERVICES"} if err := ipt.DeleteRule(utiliptables.TableNAT, utiliptables.ChainOutput, args...); err != nil { glog.Errorf("Error removing pure-iptables proxy rule: %v", err) encounteredError = true } if err := ipt.DeleteRule(utiliptables.TableNAT, utiliptables.ChainPrerouting, args...); err != nil { glog.Errorf("Error removing pure-iptables proxy rule: %v", err) encounteredError = true } return encounteredError }
// Flush all of our custom iptables rules. func iptablesFlush(ipt iptables.Interface) error { el := []error{} if err := ipt.FlushChain(iptables.TableNAT, iptablesContainerPortalChain); err != nil { el = append(el, err) } if err := ipt.FlushChain(iptables.TableNAT, iptablesHostPortalChain); err != nil { el = append(el, err) } if err := ipt.FlushChain(iptables.TableNAT, iptablesContainerNodePortChain); err != nil { el = append(el, err) } if err := ipt.FlushChain(iptables.TableNAT, iptablesHostNodePortChain); err != nil { el = append(el, err) } if len(el) != 0 { glog.Errorf("Some errors flushing old iptables portals: %v", el) } return errors.NewAggregate(el) }
// Ensure that the iptables infrastructure we use is set up. This can safely be called periodically. func iptablesInit(ipt iptables.Interface) error { // TODO: There is almost certainly room for optimization here. E.g. If // we knew the service-cluster-ip-range CIDR we could fast-track outbound packets not // destined for a service. There's probably more, help wanted. // Danger - order of these rules matters here: // // We match portal rules first, then NodePort rules. For NodePort rules, we filter primarily on --dst-type LOCAL, // because we want to listen on all local addresses, but don't match internet traffic with the same dst port number. // // There is one complication (per thockin): // -m addrtype --dst-type LOCAL is what we want except that it is broken (by intent without foresight to our usecase) // on at least GCE. Specifically, GCE machines have a daemon which learns what external IPs are forwarded to that // machine, and configure a local route for that IP, making a match for --dst-type LOCAL when we don't want it to. // Removing the route gives correct behavior until the daemon recreates it. // Killing the daemon is an option, but means that any non-kubernetes use of the machine with external IP will be broken. // // This applies to IPs on GCE that are actually from a load-balancer; they will be categorized as LOCAL. // _If_ the chains were in the wrong order, and the LB traffic had dst-port == a NodePort on some other service, // the NodePort would take priority (incorrectly). // This is unlikely (and would only affect outgoing traffic from the cluster to the load balancer, which seems // doubly-unlikely), but we need to be careful to keep the rules in the right order. args := []string{ /* service-cluster-ip-range matching could go here */ } args = append(args, "-m", "comment", "--comment", "handle ClusterIPs; NOTE: this must be before the NodePort rules") if _, err := ipt.EnsureChain(iptables.TableNAT, iptablesContainerPortalChain); err != nil { return err } if _, err := ipt.EnsureRule(iptables.Prepend, iptables.TableNAT, iptables.ChainPrerouting, append(args, "-j", string(iptablesContainerPortalChain))...); err != nil { return err } if _, err := ipt.EnsureChain(iptables.TableNAT, iptablesHostPortalChain); err != nil { return err } if _, err := ipt.EnsureRule(iptables.Prepend, iptables.TableNAT, iptables.ChainOutput, append(args, "-j", string(iptablesHostPortalChain))...); err != nil { return err } // This set of rules matches broadly (addrtype & destination port), and therefore must come after the portal rules args = []string{"-m", "addrtype", "--dst-type", "LOCAL"} args = append(args, "-m", "comment", "--comment", "handle service NodePorts; NOTE: this must be the last rule in the chain") if _, err := ipt.EnsureChain(iptables.TableNAT, iptablesContainerNodePortChain); err != nil { return err } if _, err := ipt.EnsureRule(iptables.Append, iptables.TableNAT, iptables.ChainPrerouting, append(args, "-j", string(iptablesContainerNodePortChain))...); err != nil { return err } if _, err := ipt.EnsureChain(iptables.TableNAT, iptablesHostNodePortChain); err != nil { return err } if _, err := ipt.EnsureRule(iptables.Append, iptables.TableNAT, iptables.ChainOutput, append(args, "-j", string(iptablesHostNodePortChain))...); err != nil { return err } // TODO: Verify order of rules. return nil }
// CleanupLeftovers removes all iptables rules and chains created by the Proxier // It returns true if an error was encountered. Errors are logged. func CleanupLeftovers(ipt iptables.Interface) (encounteredError bool) { // NOTE: Warning, this needs to be kept in sync with the userspace Proxier, // we want to ensure we remove all of the iptables rules it creates. // Currently they are all in iptablesInit() // Delete Rules first, then Flush and Delete Chains args := []string{"-m", "comment", "--comment", "handle ClusterIPs; NOTE: this must be before the NodePort rules"} if err := ipt.DeleteRule(iptables.TableNAT, iptables.ChainOutput, append(args, "-j", string(iptablesHostPortalChain))...); err != nil { glog.Errorf("Error removing userspace rule: %v", err) encounteredError = true } if err := ipt.DeleteRule(iptables.TableNAT, iptables.ChainPrerouting, append(args, "-j", string(iptablesContainerPortalChain))...); err != nil { glog.Errorf("Error removing userspace rule: %v", err) encounteredError = true } args = []string{"-m", "addrtype", "--dst-type", "LOCAL"} args = append(args, "-m", "comment", "--comment", "handle service NodePorts; NOTE: this must be the last rule in the chain") if err := ipt.DeleteRule(iptables.TableNAT, iptables.ChainOutput, append(args, "-j", string(iptablesHostNodePortChain))...); err != nil { glog.Errorf("Error removing userspace rule: %v", err) encounteredError = true } if err := ipt.DeleteRule(iptables.TableNAT, iptables.ChainPrerouting, append(args, "-j", string(iptablesContainerNodePortChain))...); err != nil { glog.Errorf("Error removing userspace rule: %v", err) encounteredError = true } // flush and delete chains. chains := []iptables.Chain{iptablesContainerPortalChain, iptablesHostPortalChain, iptablesHostNodePortChain, iptablesContainerNodePortChain} for _, c := range chains { // flush chain, then if sucessful delete, delete will fail if flush fails. if err := ipt.FlushChain(iptables.TableNAT, c); err != nil { glog.Errorf("Error flushing userspace chain: %v", err) encounteredError = true } else { if err = ipt.DeleteChain(iptables.TableNAT, c); err != nil { glog.Errorf("Error deleting userspace chain: %v", err) encounteredError = true } } } return encounteredError }