func (e *podEnv) unforwardPorts() error { ipt, err := iptables.New() if err != nil { return err } chain := e.portFwdChain() rule := e.portFwdRuleSpec(chain) // There's no clean way now to test if a chain exists or // even if a rule exists if the chain is not present. // So we swallow the errors for now :( // TODO(eyakubovich): move to using libiptc for iptable // manipulation // outside traffic hitting this hot ipt.Delete("nat", "PREROUTING", rule...) // traffic originating on this host ipt.Delete("nat", "OUTPUT", rule...) // there should be no references, delete the chain ipt.ClearChain("nat", chain) ipt.DeleteChain("nat", chain) return nil }
func UnBlockIP(ip string) bool { // Some default chain names sChain := "INPUT" dChain := "LOGGING" // Get a new iptables interface ipt, err := iptables.New() if err != nil { log(fmt.Sprintf("Failed to new up an IPtables intance. ERROR: %v", err)) return false } // Build out the ipstring(add /32 to the end) ipstr := fmt.Sprintf("%s%s", ip, "/32") // Use the appendUnique method to put this in iptables, but only once err = ipt.Delete("filter", sChain, "-s", ipstr, "-j", dChain) if err != nil { log(fmt.Sprintf("Failed to ban an ip(%v). ERROR: %v", ipstr, err)) return false } // Since we made it here, we won return true }
func (e *podEnv) unforwardPorts() error { ipt, err := iptables.New() if err != nil { return err } chainDNAT := e.portFwdChain("DNAT") chainSNAT := e.portFwdChain("SNAT") chainRuleDNAT := e.portFwdChainRuleSpec(chainDNAT, "DNAT") chainRuleSNAT := e.portFwdChainRuleSpec(chainSNAT, "SNAT") // There's no clean way now to test if a chain exists or // even if a rule exists if the chain is not present. // So we swallow the errors for now :( // TODO(eyakubovich): move to using libiptc for iptable // manipulation for _, entry := range []struct { chain string customChainRule []string }{ {"POSTROUTING", chainRuleSNAT}, // traffic originating on this host {"PREROUTING", chainRuleDNAT}, // outside traffic hitting this host {"OUTPUT", chainRuleDNAT}, // traffic originating on this host } { ipt.Delete("nat", entry.chain, entry.customChainRule...) } for _, entry := range []string{chainDNAT, chainSNAT} { ipt.ClearChain("nat", entry) ipt.DeleteChain("nat", entry) } return nil }
func init() { tunnels = make(map[string]*TunnelInfo) ip2tunnel = make(map[string]string) ipt, _ = iptables.New() pin = fastping.NewPinger() initConfig() readConfig() initLogger() }
func Init() error { if config.JustProxy { Balancer = nil return nil } // decide which balancer to use switch config.Balancer { case "lvs": Balancer = &Lvs{} case "nginx": Balancer = &Nginx{} default: Balancer = &Lvs{} // faster } var err error tab, err = iptables.New() if err != nil { tab = nil } // don't break if we can't use iptables if _, err = tab.List("filter", "INPUT"); err != nil { config.Log.Error("Could not use iptables, continuing without - %v", err) tab = nil } if tab != nil { tab.Delete("filter", "INPUT", "-j", "portal") tab.ClearChain("filter", "portal") tab.DeleteChain("filter", "portal") err = tab.NewChain("filter", "portal") if err != nil { return fmt.Errorf("Failed to create new chain - %v", err) } err = tab.AppendUnique("filter", "portal", "-j", "RETURN") if err != nil { return fmt.Errorf("Failed to append to portal chain - %v", err) } err = tab.AppendUnique("filter", "INPUT", "-j", "portal") if err != nil { return fmt.Errorf("Failed to append to INPUT chain - %v", err) } // Allow router through by default (ports 80/443) err = tab.Insert("filter", "portal", 1, "-p", "tcp", "--dport", "80", "-j", "ACCEPT") if err != nil { return err } err = tab.Insert("filter", "portal", 1, "-p", "tcp", "--dport", "443", "-j", "ACCEPT") if err != nil { return err } } return Balancer.Init() }
func DetachContainer(ns netns.NsHandle, id, ifName string, cidrs []*net.IPNet) error { ipt, err := iptables.New() if err != nil { return err } return WithNetNSLinkUnsafe(ns, ifName, func(veth netlink.Link) error { existingAddrs, err := netlink.AddrList(veth, netlink.FAMILY_V4) if err != nil { return fmt.Errorf("failed to get IP address for %q: %v", veth.Attrs().Name, err) } for _, ipnet := range cidrs { if !contains(existingAddrs, ipnet) { continue } if err := netlink.AddrDel(veth, &netlink.Addr{IPNet: ipnet}); err != nil { return fmt.Errorf("failed to remove IP address from %q: %v", veth.Attrs().Name, err) } } addrs, err := netlink.AddrList(veth, netlink.FAMILY_V4) if err != nil { return fmt.Errorf("failed to get IP address for %q: %v", veth.Attrs().Name, err) } // Remove multicast ACCEPT rules for subnets we no longer have addresses in subnets := subnets(addrs) rules, err := ipt.List("filter", "INPUT") if err != nil { return err } for _, rule := range rules { ps := strings.Split(rule, " ") if len(ps) == 10 && ps[0] == "-A" && ps[2] == "-s" && ps[4] == "-d" && ps[5] == "224.0.0.0/4" && ps[6] == "-i" && ps[7] == ifName && ps[8] == "-j" && ps[9] == "ACCEPT" { if _, found := subnets[ps[3]]; !found { if err := ipt.Delete("filter", "INPUT", ps[2:]...); err != nil { return err } } } } if len(addrs) == 0 { // all addresses gone: remove the interface if err := ipt.Delete("filter", "INPUT", "-i", ifName, "-d", "224.0.0.0/4", "-j", "DROP"); err != nil { return err } if err := netlink.LinkDel(veth); err != nil { return err } } return nil }) }
// Test the blocking of ips func TestBlockAndUnblock(t *testing.T) { // Make sure we are the root user. u, _ := user.Current() if u.Uid != "0" { log("You must be root to run this. Try again.") os.Exit(1) } // Block an ip ok := BlockIP("1.2.3.4") if ok == false { t.Error("Failed to block IP") } // make sure this block is in this chain sChain := "INPUT" //dChain := "LOGGING" // Get a new iptables interface ipt, err := iptables.New() if err != nil { t.Error("Failed to new up an IPtables intance:", err) } rules, err := ipt.List("filter", sChain) if err != nil { t.Fatalf("List failed: %v", err) } // Test to see if the ip we banned was in that slice found := false for _, rule := range rules { if strings.Contains(rule, "1.2.3.4") { found = true } } if found == false { t.Error("Didn't find the ip that we tried to block.") } // Now that we found it, lets delete it ok = UnBlockIP("1.2.3.4") if ok == false { t.Error("Failed to un block IP") } // Now that we are done testing, lets call the clean up method cleanIPTables() }
func teardownIPMasq(ipn ip.IP4Net) error { ipt, err := iptables.New() if err != nil { return fmt.Errorf("failed to teardown IP Masquerade. iptables was not found") } for _, rule := range rules(ipn) { log.Info("Deleting iptables rule: ", strings.Join(rule, " ")) err = ipt.Delete("nat", "POSTROUTING", rule...) if err != nil { return fmt.Errorf("failed to delete IP masquerade rule: %v", err) } } return nil }
func setupIPMasq(ipn ip.IP4Net) error { ipt, err := iptables.New() if err != nil { return fmt.Errorf("failed to set up IP Masquerade. iptables was not found") } for _, rule := range rules(ipn) { log.Info("Adding iptables rule: ", strings.Join(rule, " ")) err = ipt.AppendUnique("nat", "POSTROUTING", rule...) if err != nil { return fmt.Errorf("failed to insert IP masquerade rule: %v", err) } } return nil }
// Check for the existance of the LOGGING iptables base chain func checkIPTablesBaseConfig() bool { ipt, err := iptables.New() if err != nil { log("Some stuff is broken yo.") } chain := "LOGGING" _, err = ipt.List("filter", chain) if err != nil { log(fmt.Sprintf("%v doesn't exist. It needs to be created.", chain)) return false } else { return true } }
// TeardownIPMasq undoes the effects of SetupIPMasq func TeardownIPMasq(ipn *net.IPNet, chain string) error { ipt, err := iptables.New() if err != nil { return fmt.Errorf("failed to locate iptabes: %v", err) } if err = ipt.Delete("nat", "POSTROUTING", "-s", ipn.String(), "-j", chain); err != nil { return err } if err = ipt.ClearChain("nat", chain); err != nil { return err } return ipt.DeleteChain("nat", chain) }
func main() { accessToken := os.Getenv(`DO_KEY`) if accessToken == `` { log.Fatal(`Usage: DO_KEY environment variable must be set.`) } // setup dependencies oauthClient := oauth2.NewClient(oauth2.NoContext, oauth2.StaticTokenSource(&oauth2.Token{AccessToken: accessToken})) apiClient := godo.NewClient(oauthClient) metaClient := metadata.NewClient() ipt, err := iptables.New() failIfErr(err) // collect needed metadata from metadata service region, err := metaClient.Region() failIfErr(err) mData, err := metaClient.Metadata() failIfErr(err) // collect list of all droplets drops, err := DropletList(apiClient.Droplets) failIfErr(err) allowed, ok := SortDroplets(drops)[region] if !ok { log.Fatalf(`No droplets listed in region [%s]`, region) } // collect local network interface information local, err := LocalAddress(mData) failIfErr(err) ifaces, err := net.Interfaces() failIfErr(err) iface, err := PrivateInterface(ifaces, local) failIfErr(err) // setup dolan-peers chain for local interface err = Setup(ipt, iface) failIfErr(err) // update dolan-peers err = UpdatePeers(ipt, allowed) failIfErr(err) log.Printf(`Added %d peers to dolan-peers`, len(allowed)) }
func (e *podEnv) forwardPorts(fps []ForwardedPort, defIP net.IP) error { if len(fps) == 0 { return nil } ipt, err := iptables.New() if err != nil { return err } // Create a separate chain for this pod. This helps with debugging // and makes it easier to cleanup chain := e.portFwdChain() if err = ipt.NewChain("nat", chain); err != nil { return err } rule := e.portFwdRuleSpec(chain) for _, entry := range [][]string{ {"nat", "PREROUTING"}, // outside traffic hitting this host {"nat", "OUTPUT"}, // traffic originating on this host } { exists, err := ipt.Exists(entry[0], entry[1], rule...) if err != nil { return err } if !exists { err = ipt.Insert(entry[0], entry[1], 1, rule...) if err != nil { return err } } } for _, p := range fps { if err = forwardPort(ipt, chain, &p, defIP); err != nil { return err } } return nil }
// setupForwarding creates the iptables chains func (e *podEnv) setupForwarding() error { ipt, err := iptables.New() if err != nil { return err } // Create a separate chain for this pod. This helps with debugging // and makes it easier to cleanup chainDNAT := e.portFwdChain("DNAT") chainSNAT := e.portFwdChain("SNAT") if err = ipt.NewChain("nat", chainDNAT); err != nil { return err } if err = ipt.NewChain("nat", chainSNAT); err != nil { return err } chainRuleDNAT := e.portFwdChainRuleSpec(chainDNAT, "DNAT") chainRuleSNAT := e.portFwdChainRuleSpec(chainSNAT, "SNAT") for _, entry := range []struct { chain string customChainRule []string }{ {"POSTROUTING", chainRuleSNAT}, // traffic originating from this host from loopback {"PREROUTING", chainRuleDNAT}, // outside traffic hitting this host {"OUTPUT", chainRuleDNAT}, // traffic originating from this host on non-loopback } { exists, err := ipt.Exists("nat", entry.chain, entry.customChainRule...) if err != nil { return err } if !exists { err = ipt.Insert("nat", entry.chain, 1, entry.customChainRule...) if err != nil { return err } } } return nil }
func (e *podEnv) forwardPorts(fps []commonnet.ForwardedPort, podIP net.IP) error { if len(fps) == 0 { return nil } ipt, err := iptables.New() if err != nil { return err } chainDNAT := e.portFwdChain("DNAT") chainSNAT := e.portFwdChain("SNAT") for _, fp := range fps { for _, r := range portRules(fp, podIP, chainDNAT, chainSNAT) { if err := ipt.AppendUnique("nat", r.Chain, r.Rule...); err != nil { return err } } } return nil }
func cleanIPTables() { // Do an iptables flush to clean out all the rules. // chain now exists ipt, err := iptables.New() if err != nil { log(fmt.Sprintf("Failed to new up an IPtables intance: %v", err)) } err = ipt.ClearChain("filter", "LOGGING") if err != nil { log("ClearChain of LOGGING failed.") } err = ipt.ClearChain("filter", "INPUT") if err != nil { log("ClearChain of INPUT failed.") } err = ipt.DeleteChain("filter", "LOGGING") if err != nil { log("DeleteChain of LOGGING failed") } }
// SetupIPMasq installs iptables rules to masquerade traffic // coming from ipn and going outside of it func SetupIPMasq(ipn *net.IPNet, chain string) error { ipt, err := iptables.New() if err != nil { return fmt.Errorf("failed to locate iptabes: %v", err) } if err = ipt.NewChain("nat", chain); err != nil { if err.(*iptables.Error).ExitStatus() != 1 { // TODO(eyakubovich): assumes exit status 1 implies chain exists return err } } if err = ipt.AppendUnique("nat", chain, "-d", ipn.String(), "-j", "ACCEPT"); err != nil { return err } if err = ipt.AppendUnique("nat", chain, "!", "-d", "224.0.0.0/4", "-j", "MASQUERADE"); err != nil { return err } return ipt.AppendUnique("nat", "POSTROUTING", "-s", ipn.String(), "-j", chain) }
func setupBaseIPTables() { i, err := iptables.New() if err != nil { log("Some stuff is broken yo.") } // The table that we are going to use(the default is filter) table := "filter" // The rule that we will add first will be for the logging chain chain := "LOGGING" // Create the chain(We don't care about errors becuase it throws one if the // chain already exists) i.NewChain(table, chain) // Setup the logging rule so we can log the failed attempts err = i.AppendUnique(table, chain, "-m", "limit", "--limit", "5/min", "--limit-burst", "10", "-j", "LOG", "--log-prefix", "Drop it like its hot:", "--log-level", "7") if err != nil { fmt.Printf("ERROR YO:\n%v", err) } // Setup the drop rule. This will drop all packets that make it to this chain. err = i.AppendUnique(table, chain, "-j", "DROP") if err != nil { log(fmt.Sprintf("ERROR YO:\n%v", err)) } log("Done adding the logging chain.") // Add the icmp block to the input chain chain = "INPUT" err = i.AppendUnique(table, chain, "-p", "icmp", "-m", "icmp", "--icmp-type", "8", "-j", "LOGGING") if err != nil { log(fmt.Sprintf("ERROR YO:\n%v", err)) } }
func (e *podEnv) forwardPorts(fps []ForwardedPort, podIP net.IP) error { if len(fps) == 0 { return nil } ipt, err := iptables.New() if err != nil { return err } // Create a separate chain for this pod. This helps with debugging // and makes it easier to cleanup chainDNAT := e.portFwdChain("DNAT") chainSNAT := e.portFwdChain("SNAT") if err = ipt.NewChain("nat", chainDNAT); err != nil { return err } if err = ipt.NewChain("nat", chainSNAT); err != nil { return err } chainRuleDNAT := e.portFwdChainRuleSpec(chainDNAT, "DNAT") chainRuleSNAT := e.portFwdChainRuleSpec(chainSNAT, "SNAT") for _, entry := range []struct { chain string customChainRule []string }{ {"POSTROUTING", chainRuleSNAT}, // traffic originating from this host {"PREROUTING", chainRuleDNAT}, // outside traffic hitting this host {"OUTPUT", chainRuleDNAT}, // traffic originating from this host } { exists, err := ipt.Exists("nat", entry.chain, entry.customChainRule...) if err != nil { return err } if !exists { err = ipt.Insert("nat", entry.chain, 1, entry.customChainRule...) if err != nil { return err } } } for _, p := range fps { socketPod := fmt.Sprintf("%v:%v", podIP, p.PodPort) dstPortHost := strconv.Itoa(int(p.HostPort)) dstPortPod := strconv.Itoa(int(p.PodPort)) for _, r := range []struct { chain string rule []string }{ { // Rewrite the destination chainDNAT, []string{ "-p", p.Protocol, "--dport", dstPortHost, "-j", "DNAT", "--to-destination", socketPod, }, }, { // Rewrite the source for connections to localhost on the host chainSNAT, []string{ "-p", p.Protocol, "-s", "127.0.0.1", "-d", podIP.String(), "--dport", dstPortPod, "-j", "MASQUERADE", }, }, } { if err := ipt.AppendUnique("nat", r.chain, r.rule...); err != nil { return err } } } return nil }
func AttachContainer(ns netns.NsHandle, id, ifName, bridgeName string, mtu int, withMulticastRoute bool, cidrs []*net.IPNet, keepTXOn bool) error { ipt, err := iptables.New() if err != nil { return err } if !interfaceExistsInNamespace(ns, ifName) { maxIDLen := IFNAMSIZ - 1 - len(vethPrefix+"pl") if len(id) > maxIDLen { id = id[:maxIDLen] // trim passed ID if too long } name, peerName := vethPrefix+"pl"+id, vethPrefix+"pg"+id _, err := CreateAndAttachVeth(name, peerName, bridgeName, mtu, keepTXOn, func(veth netlink.Link) error { if err := netlink.LinkSetNsFd(veth, int(ns)); err != nil { return fmt.Errorf("failed to move veth to container netns: %s", err) } if err := WithNetNSUnsafe(ns, func() error { if err := netlink.LinkSetName(veth, ifName); err != nil { return err } if err := ConfigureARPCache(ifName); err != nil { return err } if err := ipt.Append("filter", "INPUT", "-i", ifName, "-d", "224.0.0.0/4", "-j", "DROP"); err != nil { return err } return nil }); err != nil { return fmt.Errorf("error setting up interface: %s", err) } return nil }) if err != nil { return err } } if err := WithNetNSLinkUnsafe(ns, ifName, func(veth netlink.Link) error { newAddresses, err := AddAddresses(veth, cidrs) if err != nil { return err } // Add multicast ACCEPT rules for new subnets for _, ipnet := range newAddresses { acceptRule := []string{"-i", ifName, "-s", subnet(ipnet), "-d", "224.0.0.0/4", "-j", "ACCEPT"} exists, err := ipt.Exists("filter", "INPUT", acceptRule...) if err != nil { return err } if !exists { if err := ipt.Insert("filter", "INPUT", 1, acceptRule...); err != nil { return err } } } if err := netlink.LinkSetUp(veth); err != nil { return err } for _, ipnet := range newAddresses { // If we don't wait for a bit here, we see the arp fail to reach the bridge. time.Sleep(1 * time.Millisecond) arping.GratuitousArpOverIfaceByName(ipnet.IP, ifName) } if withMulticastRoute { /* Route multicast packets across the weave network. This must come last in 'attach'. If you change this, change weavewait to match. TODO: Add the MTU lock to prevent PMTU discovery for multicast destinations. Without that, the kernel sets the DF flag on multicast packets. Since RFC1122 prohibits sending of ICMP errors for packets with multicast destinations, that causes packets larger than the PMTU to be dropped silently. */ _, multicast, _ := net.ParseCIDR("224.0.0.0/4") if err := AddRoute(veth, netlink.SCOPE_LINK, multicast, nil); err != nil { return err } } return nil }); err != nil { return err } return nil }