From 366e1686a0ee4c6d71aeaf60d84a8cef284f7d8b Mon Sep 17 00:00:00 2001 From: Aditya R Date: Sun, 20 Nov 2022 07:33:19 +0530 Subject: [PATCH 1/4] podman: relay custom DNS servers to network stack Aardvark-dns and netavark now accepts custom DNS servers for containers via new config field `dns_servers`. New field allows containers to use custom resolvers instead of host's default resolvers. Following commit instruments libpod to pass these custom DNS servers set via `--dns` or central config to the network stack. Depends-on: * Common: containers/common#1189 * Netavark: containers/netavark#452 * Aardvark-dns: containers/aardvark-dns#240 Signed-off-by: Aditya R --- libpod/networking_common.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libpod/networking_common.go b/libpod/networking_common.go index ac914493b2..816e1d1c08 100644 --- a/libpod/networking_common.go +++ b/libpod/networking_common.go @@ -39,9 +39,15 @@ func (c *Container) convertPortMappings() []types.PortMapping { } func (c *Container) getNetworkOptions(networkOpts map[string]types.PerNetworkOptions) types.NetworkOptions { + nameservers := make([]string, 0, len(c.runtime.config.Containers.DNSServers)+len(c.config.DNSServer)) + nameservers = append(nameservers, c.runtime.config.Containers.DNSServers...) + for _, ip := range c.config.DNSServer { + nameservers = append(nameservers, ip.String()) + } opts := types.NetworkOptions{ ContainerID: c.config.ID, ContainerName: getNetworkPodName(c), + DNSServers: nameservers, } opts.PortMappings = c.convertPortMappings() From 06241077ccf32fc82724ee4442e9b2ccdfa74ffe Mon Sep 17 00:00:00 2001 From: Aditya R Date: Sun, 20 Nov 2022 07:33:33 +0530 Subject: [PATCH 2/4] libpod,netavark: correctly populate /etc/resolv.conf with custom dns server After https://github.com/containers/netavark/pull/452 `netavark` is incharge of deciding `custom_dns_servers` if any so lets honor that and libpod should not set these manually. This also ensures docker parity Podman populates container's `/etc/resolv.conf` with custom DNS servers ( specified via `--dns` or `dns_server` in containers.conf ) even when container is connected to a network where `dns_enabled` is `true`. Current behavior does not matches with docker, hence following commit ensures that podman only populates custom DNS server when container is not connected to any network where DNS is enabled and for the cases where `dns_enabled` is `true` the resolution for custom DNS server will happen via ( `aardvark-dns` or `dnsname` ). Reference: https://docs.docker.com/config/containers/container-networking/#dns-services Closes: containers#16172 Signed-off-by: Aditya R --- libpod/container_internal_common.go | 17 +++++++++++++--- test/e2e/run_networking_test.go | 31 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/libpod/container_internal_common.go b/libpod/container_internal_common.go index 05a36e49b8..9e93188fd3 100644 --- a/libpod/container_internal_common.go +++ b/libpod/container_internal_common.go @@ -1993,10 +1993,21 @@ func (c *Container) generateResolvConf() error { return err } + networkBackend := c.runtime.config.Network.NetworkBackend nameservers := make([]string, 0, len(c.runtime.config.Containers.DNSServers)+len(c.config.DNSServer)) - nameservers = append(nameservers, c.runtime.config.Containers.DNSServers...) - for _, ip := range c.config.DNSServer { - nameservers = append(nameservers, ip.String()) + + // If NetworkBackend is `netavark` do not populate `/etc/resolv.conf` + // with custom dns server since after https://github.com/containers/netavark/pull/452 + // netavark will always set required `nameservers` in statsBlock and libpod + // will correctly populate `networkNameServers`. Also see https://github.com/containers/podman/issues/16172 + + // Exception: Populate `/etc/resolv.conf` if container is not connected to any network + // ( i.e len(netStatus)==0 ) since in such case netavark is not invoked at all. + if networkBackend != string(types.Netavark) || len(netStatus) == 0 { + nameservers = append(nameservers, c.runtime.config.Containers.DNSServers...) + for _, ip := range c.config.DNSServer { + nameservers = append(nameservers, ip.String()) + } } // If the user provided dns, it trumps all; then dns masq; then resolv.conf var search []string diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index 3880fbc5b5..9bb2eac3c7 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -126,6 +126,37 @@ var _ = Describe("Podman run networking", func() { Expect(session).Should(Exit(0)) }) + It("podman verify resolv.conf with --dns + --network", func() { + // Following test is only functional with netavark and aardvark + // since new behaviour depends upon output from of statusBlock + SkipIfCNI(podmanTest) + net := createNetworkName("IntTest") + session := podmanTest.Podman([]string{"network", "create", net}) + session.WaitWithDefaultTimeout() + defer podmanTest.removeNetwork(net) + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"run", "--name", "con1", "--dns", "1.1.1.1", "--network", net, ALPINE, "cat", "/etc/resolv.conf"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + // Must not contain custom dns server in containers + // `/etc/resolv.conf` since custom dns-server is + // already expected to be present and processed by + // Podman's DNS resolver i.e ( aarvark-dns or dnsname ). + Expect(session.OutputToString()).ToNot(ContainSubstring("nameserver 1.1.1.1")) + // But /etc/resolve.conf must contain othe nameserver + // i.e dns server configured for network. + Expect(session.OutputToString()).To(ContainSubstring("nameserver")) + + session = podmanTest.Podman([]string{"run", "--name", "con2", "--dns", "1.1.1.1", ALPINE, "cat", "/etc/resolv.conf"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + // All the networks being used by following container + // don't have dns_enabled in such scenario `/etc/resolv.conf` + // must contain nameserver which were specified via `--dns`. + Expect(session.OutputToString()).To(ContainSubstring("nameserver 1.1.1.1")) + }) + It("podman run network expose port 222", func() { SkipIfRootless("iptables is not supported for rootless users") session := podmanTest.Podman([]string{"run", "-dt", "--expose", "222-223", "-P", ALPINE, "/bin/sh"}) From e2c44c3d4958947f2b5331f240bfb163e798bf24 Mon Sep 17 00:00:00 2001 From: Aditya R Date: Sun, 20 Nov 2022 07:33:37 +0530 Subject: [PATCH 3/4] libpod: set search domain independently of nameservers Set search domain irrespective of nameservers. Signed-off-by: Aditya R --- libpod/container_internal_common.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libpod/container_internal_common.go b/libpod/container_internal_common.go index 9e93188fd3..b26b4c95cc 100644 --- a/libpod/container_internal_common.go +++ b/libpod/container_internal_common.go @@ -2010,18 +2010,18 @@ func (c *Container) generateResolvConf() error { } } // If the user provided dns, it trumps all; then dns masq; then resolv.conf - var search []string keepHostServers := false if len(nameservers) == 0 { keepHostServers = true // first add the nameservers from the networks status nameservers = networkNameServers - // when we add network dns server we also have to add the search domains - search = networkSearchDomains // slirp4netns has a built in DNS forwarder. nameservers = c.addSlirp4netnsDNS(nameservers) } + // Set DNS search domains + search := networkSearchDomains + if len(c.config.DNSSearch) > 0 || len(c.runtime.config.Containers.DNSSearches) > 0 { customSearch := make([]string, 0, len(c.config.DNSSearch)+len(c.runtime.config.Containers.DNSSearches)) customSearch = append(customSearch, c.runtime.config.Containers.DNSSearches...) From b7ab889a7efcd71eed78c55f7619ae29bab774ad Mon Sep 17 00:00:00 2001 From: Aditya R Date: Mon, 23 Jan 2023 10:52:33 +0530 Subject: [PATCH 4/4] systems: retrofit dns options test to honor other search domains Signed-off-by: Aditya R --- test/system/500-networking.bats | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats index 20f25728a6..3b797be089 100644 --- a/test/system/500-networking.bats +++ b/test/system/500-networking.bats @@ -651,7 +651,7 @@ EOF " CONTAINERS_CONF=$containersconf run_podman run --rm $IMAGE cat /etc/resolv.conf - is "$output" "search example.com$nl.*" "correct search domain" + is "$output" "search example.com.*" "correct search domain" is "$output" ".*nameserver 1.1.1.1${nl}nameserver $searchIP${nl}nameserver 1.0.0.1${nl}nameserver 8.8.8.8" "nameserver order is correct" # create network with dns @@ -660,9 +660,13 @@ EOF run_podman network create --subnet "$subnet.0/24" $netname # custom server overwrites the network dns server CONTAINERS_CONF=$containersconf run_podman run --network $netname --rm $IMAGE cat /etc/resolv.conf - is "$output" "search example.com$nl.*" "correct search domain" - is "$output" ".*nameserver 1.1.1.1${nl}nameserver $searchIP${nl}nameserver 1.0.0.1${nl}nameserver 8.8.8.8" "nameserver order is correct" - + is "$output" "search example.com.*" "correct search domain" + local store=$output + if is_netavark; then + is "$store" ".*nameserver $subnet.1.*" "integrated dns nameserver is set" + else + is "$store" ".*nameserver 1.1.1.1${nl}nameserver $searchIP${nl}nameserver 1.0.0.1${nl}nameserver 8.8.8.8" "nameserver order is correct" + fi # we should use the integrated dns server run_podman run --network $netname --rm $IMAGE cat /etc/resolv.conf is "$output" "search dns.podman.*" "correct search domain"