Check subnet overlap when programming of sandbox interface

Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
Alessandro Boch 2016-10-13 11:14:39 -07:00
parent 734f4ec86d
commit 0d32a1924e
6 changed files with 161 additions and 41 deletions

View file

@ -495,10 +495,6 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
return err
}
if err = n.getController().updateToStore(ep); err != nil {
return err
}
// Current endpoint providing external connectivity for the sandbox
extEp := sb.getGatewayEndpoint()
@ -515,6 +511,10 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
return err
}
if err = n.getController().updateToStore(ep); err != nil {
return err
}
if sb.needDefaultGW() && sb.getEndpointInGWNetwork() == nil {
return sb.setupDefaultGW()
}

View file

@ -402,6 +402,20 @@ func externalKeyTest(t *testing.T, reexec bool) {
}
}()
n2, err := createTestNetwork(bridgeNetType, "testnetwork2", options.Generic{
netlabel.GenericData: options.Generic{
"BridgeName": "testnetwork2",
},
}, nil, nil)
if err != nil {
t.Fatal(err)
}
defer func() {
if err := n2.Delete(); err != nil {
t.Fatal(err)
}
}()
ep, err := n.CreateEndpoint("ep1")
if err != nil {
t.Fatal(err)
@ -413,7 +427,7 @@ func externalKeyTest(t *testing.T, reexec bool) {
}
}()
ep2, err := n.CreateEndpoint("ep2")
ep2, err := n2.CreateEndpoint("ep2")
if err != nil {
t.Fatal(err)
}

View file

@ -882,6 +882,20 @@ func TestEndpointDeleteWithActiveContainer(t *testing.T) {
}
}()
n2, err := createTestNetwork(bridgeNetType, "testnetwork2", options.Generic{
netlabel.GenericData: options.Generic{
"BridgeName": "testnetwork2",
},
}, nil, nil)
if err != nil {
t.Fatal(err)
}
defer func() {
if err := n2.Delete(); err != nil {
t.Fatal(err)
}
}()
ep, err := n.CreateEndpoint("ep1")
if err != nil {
t.Fatal(err)
@ -1012,12 +1026,26 @@ func TestLeaveAll(t *testing.T) {
}
}()
n2, err := createTestNetwork(bridgeNetType, "testnetwork2", options.Generic{
netlabel.GenericData: options.Generic{
"BridgeName": "testnetwork2",
},
}, nil, nil)
if err != nil {
t.Fatal(err)
}
defer func() {
if err := n2.Delete(); err != nil {
t.Fatal(err)
}
}()
ep1, err := n.CreateEndpoint("ep1")
if err != nil {
t.Fatal(err)
}
ep2, err := n.CreateEndpoint("ep2")
ep2, err := n2.CreateEndpoint("ep2")
if err != nil {
t.Fatal(err)
}

View file

@ -377,7 +377,9 @@ func setInterfaceIP(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
if i.Address() == nil {
return nil
}
if err := checkRouteConflict(nlh, i.Address(), netlink.FAMILY_V4); err != nil {
return err
}
ipAddr := &netlink.Addr{IPNet: i.Address(), Label: ""}
return nlh.AddrAdd(iface, ipAddr)
}
@ -386,6 +388,9 @@ func setInterfaceIPv6(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error
if i.AddressIPv6() == nil {
return nil
}
if err := checkRouteConflict(nlh, i.AddressIPv6(), netlink.FAMILY_V6); err != nil {
return err
}
ipAddr := &netlink.Addr{IPNet: i.AddressIPv6(), Label: "", Flags: syscall.IFA_F_NODAD}
return nlh.AddrAdd(iface, ipAddr)
}
@ -442,3 +447,19 @@ func scanInterfaceStats(data, ifName string, i *types.InterfaceStatistics) error
return err
}
func checkRouteConflict(nlh *netlink.Handle, address *net.IPNet, family int) error {
routes, err := nlh.RouteList(nil, family)
if err != nil {
return err
}
for _, route := range routes {
if route.Dst != nil {
if route.Dst.Contains(address.IP) || address.Contains(route.Dst.IP) {
return fmt.Errorf("cannot program address %v in sandbox interface because it conflicts with existing route %s",
address, route)
}
}
}
return nil
}

View file

@ -7,6 +7,7 @@ import (
"net"
"os"
"path/filepath"
"strings"
"syscall"
"testing"
"time"
@ -74,8 +75,7 @@ func newInfo(hnd *netlink.Handle, t *testing.T) (Sandbox, error) {
intf1.address = addr
intf1.address.IP = ip4
// ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48")
ip6, addrv6, err := net.ParseCIDR("fe80::2/64")
ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48")
if err != nil {
return nil, err
}
@ -225,3 +225,65 @@ func TestDisableIPv6DAD(t *testing.T) {
t.Fatalf("Unexpected interface flags: 0x%x. Expected to contain 0x%x", addrList[0].Flags, syscall.IFA_F_NODAD)
}
}
func TestSetInterfaceIP(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
ipv4, _ := types.ParseCIDR("172.30.0.33/24")
ipv6, _ := types.ParseCIDR("2001:db8::44/64")
iface := &nwIface{address: ipv4, addressIPv6: ipv6}
nlh, err := netlink.NewHandle(syscall.NETLINK_ROUTE)
if err != nil {
t.Fatal(err)
}
if err := nlh.LinkAdd(&netlink.Veth{
LinkAttrs: netlink.LinkAttrs{Name: "sideA"},
PeerName: "sideB",
}); err != nil {
t.Fatal(err)
}
linkA, err := nlh.LinkByName("sideA")
if err != nil {
t.Fatal(err)
}
linkB, err := nlh.LinkByName("sideB")
if err != nil {
t.Fatal(err)
}
if err := nlh.LinkSetUp(linkA); err != nil {
t.Fatal(err)
}
if err := nlh.LinkSetUp(linkB); err != nil {
t.Fatal(err)
}
if err := setInterfaceIP(nlh, linkA, iface); err != nil {
t.Fatal(err)
}
if err := setInterfaceIPv6(nlh, linkA, iface); err != nil {
t.Fatal(err)
}
err = setInterfaceIP(nlh, linkB, iface)
if err == nil {
t.Fatalf("Expected route conflict error, but succeeded")
}
if !strings.Contains(err.Error(), "conflicts with existing route") {
t.Fatalf("Unexpected error: %v", err)
}
err = setInterfaceIPv6(nlh, linkB, iface)
if err == nil {
t.Fatalf("Expected route conflict error, but succeeded")
}
if !strings.Contains(err.Error(), "conflicts with existing route") {
t.Fatalf("Unexpected error: %v", err)
}
}

View file

@ -1,6 +1,7 @@
package libnetwork
import (
"fmt"
"testing"
"github.com/docker/libnetwork/config"
@ -10,7 +11,7 @@ import (
"github.com/docker/libnetwork/testutils"
)
func getTestEnv(t *testing.T, empty bool) (NetworkController, Network, Network) {
func getTestEnv(t *testing.T, numNetworks int) (NetworkController, []Network) {
netType := "bridge"
option := options.Generic{
@ -28,37 +29,31 @@ func getTestEnv(t *testing.T, empty bool) (NetworkController, Network, Network)
t.Fatal(err)
}
if empty {
return c, nil, nil
if numNetworks == 0 {
return c, nil
}
name1 := "test_nw_1"
netOption1 := options.Generic{
netlabel.GenericData: options.Generic{
"BridgeName": name1,
},
}
n1, err := c.NewNetwork(netType, name1, "", NetworkOptionGeneric(netOption1))
if err != nil {
t.Fatal(err)
nwList := make([]Network, 0, numNetworks)
for i := 0; i < numNetworks; i++ {
name := fmt.Sprintf("test_nw_%d", i)
netOption := options.Generic{
netlabel.GenericData: options.Generic{
"BridgeName": name,
},
}
n, err := c.NewNetwork(netType, name, "", NetworkOptionGeneric(netOption))
if err != nil {
t.Fatal(err)
}
nwList = append(nwList, n)
}
name2 := "test_nw_2"
netOption2 := options.Generic{
netlabel.GenericData: options.Generic{
"BridgeName": name2,
},
}
n2, err := c.NewNetwork(netType, name2, "", NetworkOptionGeneric(netOption2))
if err != nil {
t.Fatal(err)
}
return c, n1, n2
return c, nwList
}
func TestSandboxAddEmpty(t *testing.T) {
c, _, _ := getTestEnv(t, true)
c, _ := getTestEnv(t, 0)
ctrlr := c.(*controller)
sbx, err := ctrlr.NewSandbox("sandbox0")
@ -82,7 +77,7 @@ func TestSandboxAddMultiPrio(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
}
c, nw, _ := getTestEnv(t, false)
c, nws := getTestEnv(t, 3)
ctrlr := c.(*controller)
sbx, err := ctrlr.NewSandbox("sandbox1")
@ -91,15 +86,15 @@ func TestSandboxAddMultiPrio(t *testing.T) {
}
sid := sbx.ID()
ep1, err := nw.CreateEndpoint("ep1")
ep1, err := nws[0].CreateEndpoint("ep1")
if err != nil {
t.Fatal(err)
}
ep2, err := nw.CreateEndpoint("ep2")
ep2, err := nws[1].CreateEndpoint("ep2")
if err != nil {
t.Fatal(err)
}
ep3, err := nw.CreateEndpoint("ep3")
ep3, err := nws[2].CreateEndpoint("ep3")
if err != nil {
t.Fatal(err)
}
@ -163,7 +158,7 @@ func TestSandboxAddSamePrio(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
}
c, nw1, nw2 := getTestEnv(t, false)
c, nws := getTestEnv(t, 2)
ctrlr := c.(*controller)
@ -173,11 +168,11 @@ func TestSandboxAddSamePrio(t *testing.T) {
}
sid := sbx.ID()
ep1, err := nw1.CreateEndpoint("ep1")
ep1, err := nws[0].CreateEndpoint("ep1")
if err != nil {
t.Fatal(err)
}
ep2, err := nw2.CreateEndpoint("ep2")
ep2, err := nws[1].CreateEndpoint("ep2")
if err != nil {
t.Fatal(err)
}