Skip to content

Commit

Permalink
Merge pull request weaveworks#2386 from weaveworks/issues/354-multica…
Browse files Browse the repository at this point in the history
…st-isolation

Provide multicast isolation with in-container-netns iptables rules

Fixes weaveworks#354.
  • Loading branch information
rade authored Jul 12, 2016
2 parents 170e19c + f386548 commit d9c998b
Showing 1 changed file with 67 additions and 0 deletions.
67 changes: 67 additions & 0 deletions net/veth.go
Original file line number Diff line number Diff line change
@@ -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,11 +224,48 @@ 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
}
}
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
}

0 comments on commit d9c998b

Please sign in to comment.