Merge pull request #2386 from weaveworks/issues/354-multicast-isolation

Provide multicast isolation with in-container-netns iptables rules

Fixes #354.
This commit is contained in:
Matthias Radestock authored and GitHub committed 2016-07-12 09:46:14 +01:00
commit d9c998b5c4
1 file changed
+67
+67
View File
@@ -3,8 +3,10 @@ package net
import (
"fmt"
"net"
"strings"
"time"
"github.com/coreos/go-iptables/iptables"
"github.com/j-keck/arping"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
@@ -112,6 +114,11 @@ func interfaceExistsInNamespace(ns netns.NsHandle, ifName string) bool {
}
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 {
@@ -129,6 +136,9 @@ func AttachContainer(ns netns.NsHandle, id, ifName, bridgeName string, mtu int,
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)
@@ -145,6 +155,21 @@ func AttachContainer(ns netns.NsHandle, id, ifName, bridgeName string, mtu int,
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
}
@@ -177,6 +202,11 @@ func AttachContainer(ns netns.NsHandle, id, ifName, bridgeName string, mtu int,
}
func DetachContainer(ns netns.NsHandle, id, ifName string, cidrs []*net.IPNet) error {
ipt, err := iptables.New()
if err != nil {
return err
}
return WithNetNSLink(ns, ifName, func(veth netlink.Link) error {
existingAddrs, err := netlink.AddrList(veth, netlink.FAMILY_V4)
if err != nil {
@@ -194,7 +224,31 @@ func DetachContainer(ns netns.NsHandle, id, ifName string, cidrs []*net.IPNet) e
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
}
@@ -202,3 +256,16 @@ func DetachContainer(ns netns.NsHandle, id, ifName string, cidrs []*net.IPNet) e
return nil
})
}
func subnet(ipn *net.IPNet) string {
ones, _ := ipn.Mask.Size()
return fmt.Sprintf("%s/%d", ipn.IP.Mask(ipn.Mask).String(), ones)
}
func subnets(addrs []netlink.Addr) map[string]struct{} {
subnets := make(map[string]struct{})
for _, addr := range addrs {
subnets[subnet(addr.IPNet)] = struct{}{}
}
return subnets
}