From 2e5d3e8fb34ba3ab42d53da9ba39b71e1f53bb75 Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Mon, 15 Nov 2021 10:43:42 +0100 Subject: Introduce Address type to be used in secondary IPv4 and IPv6 inspect data structure. Resolves a discrepancy between the types used in inspect for docker and podman. This causes a panic when using the docker client against podman when the secondary IP fields in the `NetworkSettings` inspect field are populated. Fixes containers#12165 Signed-off-by: Federico Gimenez --- libpod/define/container_inspect.go | 10 +- libpod/networking_linux.go | 4 +- libpod/networking_linux_test.go | 217 ++++++++++++++++++++++++++++++++++++- 3 files changed, 226 insertions(+), 5 deletions(-) (limited to 'libpod') diff --git a/libpod/define/container_inspect.go b/libpod/define/container_inspect.go index 7decb18a8..9b73dbded 100644 --- a/libpod/define/container_inspect.go +++ b/libpod/define/container_inspect.go @@ -542,6 +542,12 @@ type InspectContainerHostConfig struct { CgroupConf map[string]string `json:"CgroupConf"` } +// Address represents an IP address. +type Address struct { + Addr string + PrefixLength int +} + // InspectBasicNetworkConfig holds basic configuration information (e.g. IP // addresses, MAC address, subnet masks, etc) that are common for all networks // (both additional and main). @@ -556,7 +562,7 @@ type InspectBasicNetworkConfig struct { IPPrefixLen int `json:"IPPrefixLen"` // SecondaryIPAddresses is a list of extra IP Addresses that the // container has been assigned in this network. - SecondaryIPAddresses []string `json:"SecondaryIPAddresses,omitempty"` + SecondaryIPAddresses []Address `json:"SecondaryIPAddresses,omitempty"` // IPv6Gateway is the IPv6 gateway this network will use. IPv6Gateway string `json:"IPv6Gateway"` // GlobalIPv6Address is the global-scope IPv6 Address for this network. @@ -565,7 +571,7 @@ type InspectBasicNetworkConfig struct { GlobalIPv6PrefixLen int `json:"GlobalIPv6PrefixLen"` // SecondaryIPv6Addresses is a list of extra IPv6 Addresses that the // container has been assigned in this network. - SecondaryIPv6Addresses []string `json:"SecondaryIPv6Addresses,omitempty"` + SecondaryIPv6Addresses []Address `json:"SecondaryIPv6Addresses,omitempty"` // MacAddress is the MAC address for the interface in this network. MacAddress string `json:"MacAddress"` // AdditionalMacAddresses is a set of additional MAC Addresses beyond diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index 9be600bb4..4150509d7 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -1133,7 +1133,7 @@ func resultToBasicNetworkConfig(result types.StatusBlock) (define.InspectBasicNe config.IPPrefixLen = size config.Gateway = netAddress.Gateway.String() } else { - config.SecondaryIPAddresses = append(config.SecondaryIPAddresses, netAddress.IPNet.IP.String()) + config.SecondaryIPAddresses = append(config.SecondaryIPAddresses, define.Address{Addr: netAddress.IPNet.IP.String(), PrefixLength: size}) } } else { //ipv6 @@ -1142,7 +1142,7 @@ func resultToBasicNetworkConfig(result types.StatusBlock) (define.InspectBasicNe config.GlobalIPv6PrefixLen = size config.IPv6Gateway = netAddress.Gateway.String() } else { - config.SecondaryIPv6Addresses = append(config.SecondaryIPv6Addresses, netAddress.IPNet.IP.String()) + config.SecondaryIPv6Addresses = append(config.SecondaryIPv6Addresses, define.Address{Addr: netAddress.IPNet.IP.String(), PrefixLength: size}) } } } diff --git a/libpod/networking_linux_test.go b/libpod/networking_linux_test.go index 06bf05723..d925b69f7 100644 --- a/libpod/networking_linux_test.go +++ b/libpod/networking_linux_test.go @@ -2,10 +2,14 @@ package libpod import ( "fmt" + "net" + "reflect" "testing" - "github.com/containers/podman/v3/libpod/network/types" "github.com/stretchr/testify/assert" + + "github.com/containers/podman/v3/libpod/define" + "github.com/containers/podman/v3/libpod/network/types" ) func Test_ocicniPortsToNetTypesPorts(t *testing.T) { @@ -234,6 +238,217 @@ func Test_ocicniPortsToNetTypesPorts(t *testing.T) { } } +func Test_resultToBasicNetworkConfig(t *testing.T) { + testCases := []struct { + description string + expectError bool + inputResult types.StatusBlock + expectedNetworkConfig define.InspectBasicNetworkConfig + }{ + { + description: "single secondary IPv4 address is shown as define.Address", + inputResult: types.StatusBlock{ + Interfaces: map[string]types.NetInterface{ + "eth1": { + Subnets: []types.NetAddress{ + { + Gateway: net.ParseIP("172.26.0.1"), + IPNet: types.IPNet{ + IPNet: net.IPNet{ + IP: net.ParseIP("172.26.0.2"), + Mask: net.CIDRMask(20, 32), + }, + }, + }, + { + IPNet: types.IPNet{ + IPNet: net.IPNet{ + IP: net.ParseIP("172.26.0.3"), + Mask: net.CIDRMask(10, 32), + }, + }, + }, + }, + }, + }, + }, + expectedNetworkConfig: define.InspectBasicNetworkConfig{ + IPAddress: "172.26.0.2", + IPPrefixLen: 20, + Gateway: "172.26.0.1", + SecondaryIPAddresses: []define.Address{ + { + Addr: "172.26.0.3", + PrefixLength: 10, + }, + }, + }, + }, + { + description: "multiple secondary IPv4 addresses are shown as define.Address", + inputResult: types.StatusBlock{ + Interfaces: map[string]types.NetInterface{ + "eth1": { + Subnets: []types.NetAddress{ + { + Gateway: net.ParseIP("172.26.0.1"), + IPNet: types.IPNet{ + IPNet: net.IPNet{ + IP: net.ParseIP("172.26.0.2"), + Mask: net.CIDRMask(20, 32), + }, + }, + }, + { + IPNet: types.IPNet{ + IPNet: net.IPNet{ + IP: net.ParseIP("172.26.0.3"), + Mask: net.CIDRMask(10, 32), + }, + }, + }, + { + IPNet: types.IPNet{ + IPNet: net.IPNet{ + IP: net.ParseIP("172.26.0.4"), + Mask: net.CIDRMask(24, 32), + }, + }, + }, + }, + }, + }, + }, + expectedNetworkConfig: define.InspectBasicNetworkConfig{ + IPAddress: "172.26.0.2", + IPPrefixLen: 20, + Gateway: "172.26.0.1", + SecondaryIPAddresses: []define.Address{ + { + Addr: "172.26.0.3", + PrefixLength: 10, + }, + { + Addr: "172.26.0.4", + PrefixLength: 24, + }, + }, + }, + }, + { + description: "single secondary IPv6 address is shown as define.Address", + inputResult: types.StatusBlock{ + Interfaces: map[string]types.NetInterface{ + "eth1": { + Subnets: []types.NetAddress{ + { + Gateway: net.ParseIP("ff02::fb"), + IPNet: types.IPNet{ + IPNet: net.IPNet{ + IP: net.ParseIP("ff02::fc"), + Mask: net.CIDRMask(20, 128), + }, + }, + }, + { + IPNet: types.IPNet{ + IPNet: net.IPNet{ + IP: net.ParseIP("ff02::fd"), + Mask: net.CIDRMask(10, 128), + }, + }, + }, + }, + }, + }, + }, + expectedNetworkConfig: define.InspectBasicNetworkConfig{ + GlobalIPv6Address: "ff02::fc", + GlobalIPv6PrefixLen: 20, + IPv6Gateway: "ff02::fb", + SecondaryIPv6Addresses: []define.Address{ + { + Addr: "ff02::fd", + PrefixLength: 10, + }, + }, + }, + }, + { + description: "multiple secondary IPv6 addresses are shown as define.Address", + inputResult: types.StatusBlock{ + Interfaces: map[string]types.NetInterface{ + "eth1": { + Subnets: []types.NetAddress{ + { + Gateway: net.ParseIP("ff02::fb"), + IPNet: types.IPNet{ + IPNet: net.IPNet{ + IP: net.ParseIP("ff02::fc"), + Mask: net.CIDRMask(20, 128), + }, + }, + }, + { + IPNet: types.IPNet{ + IPNet: net.IPNet{ + IP: net.ParseIP("ff02::fd"), + Mask: net.CIDRMask(10, 128), + }, + }, + }, + { + IPNet: types.IPNet{ + IPNet: net.IPNet{ + IP: net.ParseIP("ff02::fe"), + Mask: net.CIDRMask(24, 128), + }, + }, + }, + }, + }, + }, + }, + expectedNetworkConfig: define.InspectBasicNetworkConfig{ + GlobalIPv6Address: "ff02::fc", + GlobalIPv6PrefixLen: 20, + IPv6Gateway: "ff02::fb", + SecondaryIPv6Addresses: []define.Address{ + { + Addr: "ff02::fd", + PrefixLength: 10, + }, + { + Addr: "ff02::fe", + PrefixLength: 24, + }, + }, + }, + }, + } + + for _, tcl := range testCases { + tc := tcl + t.Run(tc.description, func(t *testing.T) { + t.Parallel() + actualNetworkConfig, err := resultToBasicNetworkConfig(tc.inputResult) + + if tc.expectError && err == nil { + t.Fatalf("Expected error didn't happen") + } + + if !tc.expectError && err != nil { + t.Fatalf("Unexpected error happened: %v", err) + } + + if !reflect.DeepEqual(tc.expectedNetworkConfig, actualNetworkConfig) { + t.Fatalf( + "Expected networkConfig %+v didn't match actual value %+v", tc.expectedNetworkConfig, actualNetworkConfig) + } + }) + } +} + func benchmarkOCICNIPortsToNetTypesPorts(b *testing.B, ports []types.OCICNIPortMapping) { for n := 0; n < b.N; n++ { ocicniPortsToNetTypesPorts(ports) -- cgit v1.2.3-54-g00ecf