package daemon import ( "net/netip" "testing" "github.com/moby/moby/api/types/network" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" ) func TestValidateIPAM(t *testing.T) { tests := []struct { name string ipam []network.IPAMConfig ipv6 bool expectedErrors []string }{ { name: "IP version mismatch", ipam: []network.IPAMConfig{{ Subnet: netip.MustParsePrefix("10.10.10.0/24"), IPRange: netip.MustParsePrefix("2001:db8::/32"), Gateway: netip.MustParseAddr("2001:db8::1"), AuxAddress: map[string]netip.Addr{"DefaultGatewayIPv4": netip.MustParseAddr("2001:db8::1")}, }}, expectedErrors: []string{ "invalid ip-range 2001:db8::/32: parent subnet is an IPv4 block", "invalid gateway 2001:db8::1: parent subnet is an IPv4 block", "invalid auxiliary address DefaultGatewayIPv4: parent subnet is an IPv4 block", }, }, { // Regression test for https://github.com/moby/moby/issues/47202 name: "IPv6 subnet is discarded with no error when IPv6 is disabled", ipam: []network.IPAMConfig{{Subnet: netip.MustParsePrefix("2001:db8::/32")}}, ipv6: false, }, { name: "IPRange bigger than its subnet", ipam: []network.IPAMConfig{ {Subnet: netip.MustParsePrefix("10.10.10.0/24"), IPRange: netip.MustParsePrefix("10.0.0.0/8")}, }, expectedErrors: []string{ "invalid ip-range 10.0.0.0/8: CIDR block is bigger than its parent subnet 10.10.10.0/24", }, }, { name: "Out of range prefix & addresses", ipam: []network.IPAMConfig{{ Subnet: netip.MustParsePrefix("10.0.0.0/8"), IPRange: netip.MustParsePrefix("192.168.0.1/24"), Gateway: netip.MustParseAddr("192.168.0.1"), AuxAddress: map[string]netip.Addr{"DefaultGatewayIPv4": netip.MustParseAddr("192.168.0.1")}, }}, expectedErrors: []string{ "invalid ip-range 192.168.0.1/24: it should be 192.168.0.0/24", "invalid ip-range 192.168.0.1/24: parent subnet 10.0.0.0/8 doesn't contain ip-range", "invalid gateway 192.168.0.1: parent subnet 10.0.0.0/8 doesn't contain this address", "invalid auxiliary address DefaultGatewayIPv4: parent subnet 10.0.0.0/8 doesn't contain this address", }, }, { name: "Subnet with host fragment set", ipam: []network.IPAMConfig{{ Subnet: netip.MustParsePrefix("10.10.10.0/8"), }}, expectedErrors: []string{"invalid subnet 10.10.10.0/8: it should be 10.0.0.0/8"}, }, { name: "IPRange with host fragment set", ipam: []network.IPAMConfig{{ Subnet: netip.MustParsePrefix("10.0.0.0/8"), IPRange: netip.MustParsePrefix("10.10.10.0/16"), }}, expectedErrors: []string{"invalid ip-range 10.10.10.0/16: it should be 10.10.0.0/16"}, }, { name: "Empty IPAM is valid", }, { name: "Valid IPAM", ipam: []network.IPAMConfig{{ Subnet: netip.MustParsePrefix("10.0.0.0/8"), IPRange: netip.MustParsePrefix("10.10.0.0/16"), Gateway: netip.MustParseAddr("10.10.0.1"), AuxAddress: map[string]netip.Addr{"DefaultGatewayIPv4": netip.MustParseAddr("10.10.0.1")}, }}, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { t.Parallel() errs := validateIpamConfig(tc.ipam, tc.ipv6) if tc.expectedErrors == nil { assert.NilError(t, errs) return } assert.Check(t, is.ErrorContains(errs, "invalid network config")) for _, expected := range tc.expectedErrors { assert.Check(t, is.ErrorContains(errs, expected)) } }) } }