package bridge import ( "fmt" "net" "strconv" "testing" "github.com/docker/docker/daemon/networkdriver/portmapper" "github.com/docker/docker/engine" "github.com/docker/docker/pkg/iptables" ) func init() { // reset the new proxy command for mocking out the userland proxy in tests portmapper.NewProxy = portmapper.NewMockProxyCommand } func findFreePort(t *testing.T) int { l, err := net.Listen("tcp", ":0") if err != nil { t.Fatal("Failed to find a free port") } defer l.Close() result, err := net.ResolveTCPAddr("tcp", l.Addr().String()) if err != nil { t.Fatal("Failed to resolve address to identify free port") } return result.Port } func newPortAllocationJob(eng *engine.Engine, port int) (job *engine.Job) { strPort := strconv.Itoa(port) job = eng.Job("allocate_port", "container_id") job.Setenv("HostIP", "127.0.0.1") job.Setenv("HostPort", strPort) job.Setenv("Proto", "tcp") job.Setenv("ContainerPort", strPort) return } func newPortAllocationJobWithInvalidHostIP(eng *engine.Engine, port int) (job *engine.Job) { strPort := strconv.Itoa(port) job = eng.Job("allocate_port", "container_id") job.Setenv("HostIP", "localhost") job.Setenv("HostPort", strPort) job.Setenv("Proto", "tcp") job.Setenv("ContainerPort", strPort) return } func TestAllocatePortDetection(t *testing.T) { eng := engine.New() eng.Logging = false freePort := findFreePort(t) // Init driver job := eng.Job("initdriver") if res := InitDriver(job); res != nil { t.Fatal("Failed to initialize network driver") } // Allocate interface job = eng.Job("allocate_interface", "container_id") if res := Allocate(job); res != nil { t.Fatal("Failed to allocate network interface") } // Allocate same port twice, expect failure on second call job = newPortAllocationJob(eng, freePort) if res := AllocatePort(job); res != nil { t.Fatal("Failed to find a free port to allocate") } if res := AllocatePort(job); res == nil { t.Fatal("Duplicate port allocation granted by AllocatePort") } } func TestHostnameFormatChecking(t *testing.T) { eng := engine.New() eng.Logging = false freePort := findFreePort(t) // Init driver job := eng.Job("initdriver") if res := InitDriver(job); res != nil { t.Fatal("Failed to initialize network driver") } // Allocate interface job = eng.Job("allocate_interface", "container_id") if res := Allocate(job); res != nil { t.Fatal("Failed to allocate network interface") } // Allocate port with invalid HostIP, expect failure with Bad Request http status job = newPortAllocationJobWithInvalidHostIP(eng, freePort) if res := AllocatePort(job); res == nil { t.Fatal("Failed to check invalid HostIP") } } func newInterfaceAllocation(t *testing.T, input engine.Env) (output engine.Env) { eng := engine.New() eng.Logging = false done := make(chan bool) // set IPv6 global if given if input.Exists("globalIPv6Network") { _, globalIPv6Network, _ = net.ParseCIDR(input.Get("globalIPv6Network")) } job := eng.Job("allocate_interface", "container_id") job.Env().Init(&input) reader, _ := job.Stdout.AddPipe() go func() { output.Decode(reader) done <- true }() res := Allocate(job) job.Stdout.Close() <-done if input.Exists("expectFail") && input.GetBool("expectFail") { if res == nil { t.Fatal("Doesn't fail to allocate network interface") } } else { if res != nil { t.Fatal("Failed to allocate network interface") } } if input.Exists("globalIPv6Network") { // check for bug #11427 _, subnet, _ := net.ParseCIDR(input.Get("globalIPv6Network")) if globalIPv6Network.IP.String() != subnet.IP.String() { t.Fatal("globalIPv6Network was modified during allocation") } // clean up IPv6 global globalIPv6Network = nil } return } func TestIPv6InterfaceAllocationAutoNetmaskGt80(t *testing.T) { input := engine.Env{} _, subnet, _ := net.ParseCIDR("2001:db8:1234:1234:1234::/81") // set global ipv6 input.Set("globalIPv6Network", subnet.String()) output := newInterfaceAllocation(t, input) // ensure low manually assigend global ip ip := net.ParseIP(output.Get("GlobalIPv6")) _, subnet, _ = net.ParseCIDR(fmt.Sprintf("%s/%d", subnet.IP.String(), 120)) if !subnet.Contains(ip) { t.Fatalf("Error ip %s not in subnet %s", ip.String(), subnet.String()) } } func TestIPv6InterfaceAllocationAutoNetmaskLe80(t *testing.T) { input := engine.Env{} _, subnet, _ := net.ParseCIDR("2001:db8:1234:1234:1234::/80") // set global ipv6 input.Set("globalIPv6Network", subnet.String()) input.Set("RequestedMac", "ab:cd:ab:cd:ab:cd") output := newInterfaceAllocation(t, input) // ensure global ip with mac ip := net.ParseIP(output.Get("GlobalIPv6")) expected_ip := net.ParseIP("2001:db8:1234:1234:1234:abcd:abcd:abcd") if ip.String() != expected_ip.String() { t.Fatalf("Error ip %s should be %s", ip.String(), expected_ip.String()) } // ensure link local format ip = net.ParseIP(output.Get("LinkLocalIPv6")) expected_ip = net.ParseIP("fe80::a9cd:abff:fecd:abcd") if ip.String() != expected_ip.String() { t.Fatalf("Error ip %s should be %s", ip.String(), expected_ip.String()) } } func TestIPv6InterfaceAllocationRequest(t *testing.T) { input := engine.Env{} _, subnet, _ := net.ParseCIDR("2001:db8:1234:1234:1234::/80") expected_ip := net.ParseIP("2001:db8:1234:1234:1234::1328") // set global ipv6 input.Set("globalIPv6Network", subnet.String()) input.Set("RequestedIPv6", expected_ip.String()) output := newInterfaceAllocation(t, input) // ensure global ip with mac ip := net.ParseIP(output.Get("GlobalIPv6")) if ip.String() != expected_ip.String() { t.Fatalf("Error ip %s should be %s", ip.String(), expected_ip.String()) } // retry -> fails for duplicated address input.SetBool("expectFail", true) output = newInterfaceAllocation(t, input) } func TestMacAddrGeneration(t *testing.T) { ip := net.ParseIP("192.168.0.1") mac := generateMacAddr(ip).String() // Should be consistent. if generateMacAddr(ip).String() != mac { t.Fatal("Inconsistent MAC address") } // Should be unique. ip2 := net.ParseIP("192.168.0.2") if generateMacAddr(ip2).String() == mac { t.Fatal("Non-unique MAC address") } } func TestLinkContainers(t *testing.T) { eng := engine.New() eng.Logging = false // Init driver job := eng.Job("initdriver") if res := InitDriver(job); res != nil { t.Fatal("Failed to initialize network driver") } // Allocate interface job = eng.Job("allocate_interface", "container_id") if res := Allocate(job); res != nil { t.Fatal("Failed to allocate network interface") } job.Args[0] = "-I" job.Setenv("ChildIP", "172.17.0.2") job.Setenv("ParentIP", "172.17.0.1") job.SetenvBool("IgnoreErrors", false) job.SetenvList("Ports", []string{"1234"}) bridgeIface = "lo" _, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter) if err != nil { t.Fatal(err) } if res := LinkContainers(job); res != nil { t.Fatalf("LinkContainers failed") } // flush rules if _, err = iptables.Raw([]string{"-F", "DOCKER"}...); err != nil { t.Fatal(err) } }