github.com/moby/docker@v26.1.3+incompatible/integration/networking/resolvconf_test.go (about) 1 package networking 2 3 import ( 4 "context" 5 "os" 6 "path" 7 "strings" 8 "testing" 9 "time" 10 11 containertypes "github.com/docker/docker/api/types/container" 12 "github.com/docker/docker/api/types/mount" 13 "github.com/docker/docker/integration/internal/container" 14 "github.com/docker/docker/integration/internal/network" 15 "github.com/docker/docker/testutil/daemon" 16 "gotest.tools/v3/assert" 17 is "gotest.tools/v3/assert/cmp" 18 "gotest.tools/v3/skip" 19 ) 20 21 // Regression test for https://github.com/moby/moby/issues/46968 22 func TestResolvConfLocalhostIPv6(t *testing.T) { 23 // No "/etc/resolv.conf" on Windows. 24 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 25 26 ctx := setupTest(t) 27 28 tmpFileName := network.WriteTempResolvConf(t, "127.0.0.53") 29 30 d := daemon.New(t, daemon.WithEnvVars("DOCKER_TEST_RESOLV_CONF_PATH="+tmpFileName)) 31 d.StartWithBusybox(ctx, t, "--experimental", "--ip6tables") 32 defer d.Stop(t) 33 34 c := d.NewClientT(t) 35 defer c.Close() 36 37 netName := "nnn" 38 network.CreateNoError(ctx, t, c, netName, 39 network.WithDriver("bridge"), 40 network.WithIPv6(), 41 network.WithIPAM("fd49:b5ef:36d9::/64", "fd49:b5ef:36d9::1"), 42 ) 43 defer network.RemoveNoError(ctx, t, c, netName) 44 45 result := container.RunAttach(ctx, t, c, 46 container.WithImage("busybox:latest"), 47 container.WithNetworkMode(netName), 48 container.WithCmd("cat", "/etc/resolv.conf"), 49 ) 50 defer c.ContainerRemove(ctx, result.ContainerID, containertypes.RemoveOptions{ 51 Force: true, 52 }) 53 54 output := strings.ReplaceAll(result.Stdout.String(), tmpFileName, "RESOLV.CONF") 55 assert.Check(t, is.Equal(output, `# Generated by Docker Engine. 56 # This file can be edited; Docker Engine will not make further changes once it 57 # has been modified. 58 59 nameserver 127.0.0.11 60 options ndots:0 61 62 # Based on host file: 'RESOLV.CONF' (internal resolver) 63 # ExtServers: [host(127.0.0.53)] 64 # Overrides: [] 65 # Option ndots from: internal 66 `)) 67 } 68 69 // Check that when a container is connected to an internal network, DNS 70 // requests sent to daemon's internal DNS resolver are not forwarded to 71 // an upstream resolver listening on a localhost address. 72 // (Assumes the host does not already have a DNS server on 127.0.0.1.) 73 func TestInternalNetworkDNS(t *testing.T) { 74 skip.If(t, testEnv.DaemonInfo.OSType == "windows", "No resolv.conf on Windows") 75 skip.If(t, testEnv.IsRootless, "Can't use resolver on host in rootless mode") 76 ctx := setupTest(t) 77 78 // Start a DNS server on the loopback interface. 79 network.StartDaftDNS(t, "127.0.0.1") 80 81 // Set up a temp resolv.conf pointing at that DNS server, and a daemon using it. 82 tmpFileName := network.WriteTempResolvConf(t, "127.0.0.1") 83 d := daemon.New(t, daemon.WithEnvVars("DOCKER_TEST_RESOLV_CONF_PATH="+tmpFileName)) 84 d.StartWithBusybox(ctx, t, "--experimental", "--ip6tables") 85 defer d.Stop(t) 86 87 c := d.NewClientT(t) 88 defer c.Close() 89 90 intNetName := "intnet" 91 network.CreateNoError(ctx, t, c, intNetName, 92 network.WithDriver("bridge"), 93 network.WithInternal(), 94 ) 95 defer network.RemoveNoError(ctx, t, c, intNetName) 96 97 extNetName := "extnet" 98 network.CreateNoError(ctx, t, c, extNetName, 99 network.WithDriver("bridge"), 100 ) 101 defer network.RemoveNoError(ctx, t, c, extNetName) 102 103 // Create a container, initially with external connectivity. 104 // Expect the external DNS server to respond to a request from the container. 105 ctrId := container.Run(ctx, t, c, container.WithNetworkMode(extNetName)) 106 defer c.ContainerRemove(ctx, ctrId, containertypes.RemoveOptions{Force: true}) 107 res, err := container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"}) 108 assert.NilError(t, err) 109 assert.Check(t, is.Equal(res.ExitCode, 0)) 110 assert.Check(t, is.Contains(res.Stdout(), network.DNSRespAddr)) 111 112 // Connect the container to the internal network as well. 113 // External DNS should still be used. 114 err = c.NetworkConnect(ctx, intNetName, ctrId, nil) 115 assert.NilError(t, err) 116 res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"}) 117 assert.NilError(t, err) 118 assert.Check(t, is.Equal(res.ExitCode, 0)) 119 assert.Check(t, is.Contains(res.Stdout(), network.DNSRespAddr)) 120 121 // Disconnect from the external network. 122 // Expect no access to the external DNS. 123 err = c.NetworkDisconnect(ctx, extNetName, ctrId, true) 124 assert.NilError(t, err) 125 res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"}) 126 assert.NilError(t, err) 127 assert.Check(t, is.Equal(res.ExitCode, 1)) 128 assert.Check(t, is.Contains(res.Stdout(), "SERVFAIL")) 129 130 // Reconnect the external network. 131 // Check that the external DNS server is used again. 132 err = c.NetworkConnect(ctx, extNetName, ctrId, nil) 133 assert.NilError(t, err) 134 res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"}) 135 assert.NilError(t, err) 136 assert.Check(t, is.Equal(res.ExitCode, 0)) 137 assert.Check(t, is.Contains(res.Stdout(), network.DNSRespAddr)) 138 } 139 140 // Check that '--dns' can be used to name a server inside a '--internal' network. 141 // Regression test for https://github.com/moby/moby/issues/47822 142 func TestInternalNetworkLocalDNS(t *testing.T) { 143 skip.If(t, testEnv.DaemonInfo.OSType == "windows", "No internal networks on Windows") 144 skip.If(t, testEnv.IsRootless, "Can't write an accessible dnsd.conf in rootless mode") 145 ctx := setupTest(t) 146 147 d := daemon.New(t) 148 d.StartWithBusybox(ctx, t) 149 defer d.Stop(t) 150 151 c := d.NewClientT(t) 152 defer c.Close() 153 154 intNetName := "intnet" 155 network.CreateNoError(ctx, t, c, intNetName, 156 network.WithDriver("bridge"), 157 network.WithInternal(), 158 ) 159 defer network.RemoveNoError(ctx, t, c, intNetName) 160 161 // Write a config file for busybox's dnsd. 162 td := t.TempDir() 163 fname := path.Join(td, "dnsd.conf") 164 err := os.WriteFile(fname, []byte("foo.example 192.0.2.42\n"), 0644) 165 assert.NilError(t, err) 166 167 // Start a DNS server on the internal network. 168 serverId := container.Run(ctx, t, c, 169 container.WithNetworkMode(intNetName), 170 container.WithMount(mount.Mount{ 171 Type: mount.TypeBind, 172 Source: fname, 173 Target: "/etc/dnsd.conf", 174 }), 175 container.WithCmd("dnsd"), 176 ) 177 defer c.ContainerRemove(ctx, serverId, containertypes.RemoveOptions{Force: true}) 178 179 // Get the DNS server's address. 180 inspect := container.Inspect(ctx, t, c, serverId) 181 serverIP := inspect.NetworkSettings.Networks[intNetName].IPAddress 182 183 // Query the internal network's DNS server (via the daemon's internal DNS server). 184 res := container.RunAttach(ctx, t, c, 185 container.WithNetworkMode(intNetName), 186 container.WithDNS([]string{serverIP}), 187 container.WithCmd("nslookup", "-type=A", "foo.example"), 188 ) 189 defer c.ContainerRemove(ctx, res.ContainerID, containertypes.RemoveOptions{Force: true}) 190 assert.Check(t, is.Contains(res.Stdout.String(), "192.0.2.42")) 191 } 192 193 // TestNslookupWindows checks that nslookup gets results from external DNS. 194 // Regression test for https://github.com/moby/moby/issues/46792 195 func TestNslookupWindows(t *testing.T) { 196 skip.If(t, testEnv.DaemonInfo.OSType != "windows") 197 198 ctx := setupTest(t) 199 c := testEnv.APIClient() 200 201 attachCtx, cancel := context.WithTimeout(ctx, 5*time.Second) 202 defer cancel() 203 res := container.RunAttach(attachCtx, t, c, 204 container.WithCmd("nslookup", "docker.com"), 205 ) 206 defer c.ContainerRemove(ctx, res.ContainerID, containertypes.RemoveOptions{Force: true}) 207 208 assert.Check(t, is.Equal(res.ExitCode, 0)) 209 // Current default is to not-forward requests to external servers, which 210 // can only be changed in daemon.json using feature flag "windows-dns-proxy". 211 // So, expect the lookup to fail... 212 assert.Check(t, is.Contains(res.Stderr.String(), "Server failed")) 213 // When the default behaviour is changed, nslookup should succeed... 214 //assert.Check(t, is.Contains(res.Stdout.String(), "Addresses:")) 215 }