Move dummy DNS server to integration/internal/network
Signed-off-by: Rob Murray <rob.murray@docker.com>
This commit is contained in:
parent
6d30487d2e
commit
d8b768149b
2 changed files with 72 additions and 64 deletions
66
integration/internal/network/dns.go
Normal file
66
integration/internal/network/dns.go
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
package network
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
const DNSRespAddr = "10.11.12.13"
|
||||||
|
|
||||||
|
// WriteTempResolvConf writes a resolv.conf that only contains a single
|
||||||
|
// nameserver line, with address addr.
|
||||||
|
// It returns the name of the temp file. The temp file will be deleted
|
||||||
|
// automatically by a t.Cleanup().
|
||||||
|
func WriteTempResolvConf(t *testing.T, addr string) string {
|
||||||
|
t.Helper()
|
||||||
|
// Not using t.TempDir() here because in rootless mode, while the temporary
|
||||||
|
// directory gets mode 0777, it's a subdir of an 0700 directory owned by root.
|
||||||
|
// So, it's not accessible by the daemon.
|
||||||
|
f, err := os.CreateTemp("", "resolv.conf")
|
||||||
|
assert.NilError(t, err)
|
||||||
|
t.Cleanup(func() { os.Remove(f.Name()) })
|
||||||
|
err = f.Chmod(0644)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
f.Write([]byte("nameserver " + addr + "\n"))
|
||||||
|
return f.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartDaftDNS starts and returns a really, really daft DNS server that only
|
||||||
|
// responds to type-A requests, and always with address dnsRespAddr.
|
||||||
|
// The DNS server will be stopped automatically by a t.Cleanup().
|
||||||
|
func StartDaftDNS(t *testing.T, addr string) {
|
||||||
|
serveDNS := func(w dns.ResponseWriter, query *dns.Msg) {
|
||||||
|
if query.Question[0].Qtype == dns.TypeA {
|
||||||
|
resp := &dns.Msg{}
|
||||||
|
resp.SetReply(query)
|
||||||
|
answer := &dns.A{
|
||||||
|
Hdr: dns.RR_Header{
|
||||||
|
Name: query.Question[0].Name,
|
||||||
|
Rrtype: dns.TypeA,
|
||||||
|
Class: dns.ClassINET,
|
||||||
|
Ttl: 600,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
answer.A = net.ParseIP(DNSRespAddr)
|
||||||
|
resp.Answer = append(resp.Answer, answer)
|
||||||
|
_ = w.WriteMsg(resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := net.ListenUDP("udp", &net.UDPAddr{
|
||||||
|
IP: net.ParseIP(addr),
|
||||||
|
Port: 53,
|
||||||
|
})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
server := &dns.Server{Handler: dns.HandlerFunc(serveDNS), PacketConn: conn}
|
||||||
|
go func() {
|
||||||
|
_ = server.ActivateAndServe()
|
||||||
|
}()
|
||||||
|
|
||||||
|
t.Cleanup(func() { server.Shutdown() })
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
package networking
|
package networking
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -10,29 +8,11 @@ import (
|
||||||
"github.com/docker/docker/integration/internal/container"
|
"github.com/docker/docker/integration/internal/container"
|
||||||
"github.com/docker/docker/integration/internal/network"
|
"github.com/docker/docker/integration/internal/network"
|
||||||
"github.com/docker/docker/testutil/daemon"
|
"github.com/docker/docker/testutil/daemon"
|
||||||
"github.com/miekg/dns"
|
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
is "gotest.tools/v3/assert/cmp"
|
||||||
"gotest.tools/v3/skip"
|
"gotest.tools/v3/skip"
|
||||||
)
|
)
|
||||||
|
|
||||||
// writeTempResolvConf writes a resolv.conf that only contains a single
|
|
||||||
// nameserver line, with address addr.
|
|
||||||
// It returns the name of the temp file.
|
|
||||||
func writeTempResolvConf(t *testing.T, addr string) string {
|
|
||||||
t.Helper()
|
|
||||||
// Not using t.TempDir() here because in rootless mode, while the temporary
|
|
||||||
// directory gets mode 0777, it's a subdir of an 0700 directory owned by root.
|
|
||||||
// So, it's not accessible by the daemon.
|
|
||||||
f, err := os.CreateTemp("", "resolv.conf")
|
|
||||||
assert.NilError(t, err)
|
|
||||||
t.Cleanup(func() { os.Remove(f.Name()) })
|
|
||||||
err = f.Chmod(0644)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
f.Write([]byte("nameserver " + addr + "\n"))
|
|
||||||
return f.Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regression test for https://github.com/moby/moby/issues/46968
|
// Regression test for https://github.com/moby/moby/issues/46968
|
||||||
func TestResolvConfLocalhostIPv6(t *testing.T) {
|
func TestResolvConfLocalhostIPv6(t *testing.T) {
|
||||||
// No "/etc/resolv.conf" on Windows.
|
// No "/etc/resolv.conf" on Windows.
|
||||||
|
@ -40,7 +20,7 @@ func TestResolvConfLocalhostIPv6(t *testing.T) {
|
||||||
|
|
||||||
ctx := setupTest(t)
|
ctx := setupTest(t)
|
||||||
|
|
||||||
tmpFileName := writeTempResolvConf(t, "127.0.0.53")
|
tmpFileName := network.WriteTempResolvConf(t, "127.0.0.53")
|
||||||
|
|
||||||
d := daemon.New(t, daemon.WithEnvVars("DOCKER_TEST_RESOLV_CONF_PATH="+tmpFileName))
|
d := daemon.New(t, daemon.WithEnvVars("DOCKER_TEST_RESOLV_CONF_PATH="+tmpFileName))
|
||||||
d.StartWithBusybox(ctx, t, "--experimental", "--ip6tables")
|
d.StartWithBusybox(ctx, t, "--experimental", "--ip6tables")
|
||||||
|
@ -81,43 +61,6 @@ options ndots:0
|
||||||
`))
|
`))
|
||||||
}
|
}
|
||||||
|
|
||||||
const dnsRespAddr = "10.11.12.13"
|
|
||||||
|
|
||||||
// startDaftDNS starts and returns a really, really daft DNS server that only
|
|
||||||
// responds to type-A requests, and always with address dnsRespAddr.
|
|
||||||
func startDaftDNS(t *testing.T, addr string) *dns.Server {
|
|
||||||
serveDNS := func(w dns.ResponseWriter, query *dns.Msg) {
|
|
||||||
if query.Question[0].Qtype == dns.TypeA {
|
|
||||||
resp := &dns.Msg{}
|
|
||||||
resp.SetReply(query)
|
|
||||||
answer := &dns.A{
|
|
||||||
Hdr: dns.RR_Header{
|
|
||||||
Name: query.Question[0].Name,
|
|
||||||
Rrtype: dns.TypeA,
|
|
||||||
Class: dns.ClassINET,
|
|
||||||
Ttl: 600,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
answer.A = net.ParseIP(dnsRespAddr)
|
|
||||||
resp.Answer = append(resp.Answer, answer)
|
|
||||||
_ = w.WriteMsg(resp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
conn, err := net.ListenUDP("udp", &net.UDPAddr{
|
|
||||||
IP: net.ParseIP(addr),
|
|
||||||
Port: 53,
|
|
||||||
})
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
server := &dns.Server{Handler: dns.HandlerFunc(serveDNS), PacketConn: conn}
|
|
||||||
go func() {
|
|
||||||
_ = server.ActivateAndServe()
|
|
||||||
}()
|
|
||||||
|
|
||||||
return server
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that when a container is connected to an internal network, DNS
|
// Check that when a container is connected to an internal network, DNS
|
||||||
// requests sent to daemon's internal DNS resolver are not forwarded to
|
// requests sent to daemon's internal DNS resolver are not forwarded to
|
||||||
// an upstream resolver listening on a localhost address.
|
// an upstream resolver listening on a localhost address.
|
||||||
|
@ -128,11 +71,10 @@ func TestInternalNetworkDNS(t *testing.T) {
|
||||||
ctx := setupTest(t)
|
ctx := setupTest(t)
|
||||||
|
|
||||||
// Start a DNS server on the loopback interface.
|
// Start a DNS server on the loopback interface.
|
||||||
server := startDaftDNS(t, "127.0.0.1")
|
network.StartDaftDNS(t, "127.0.0.1")
|
||||||
defer server.Shutdown()
|
|
||||||
|
|
||||||
// Set up a temp resolv.conf pointing at that DNS server, and a daemon using it.
|
// Set up a temp resolv.conf pointing at that DNS server, and a daemon using it.
|
||||||
tmpFileName := writeTempResolvConf(t, "127.0.0.1")
|
tmpFileName := network.WriteTempResolvConf(t, "127.0.0.1")
|
||||||
d := daemon.New(t, daemon.WithEnvVars("DOCKER_TEST_RESOLV_CONF_PATH="+tmpFileName))
|
d := daemon.New(t, daemon.WithEnvVars("DOCKER_TEST_RESOLV_CONF_PATH="+tmpFileName))
|
||||||
d.StartWithBusybox(ctx, t, "--experimental", "--ip6tables")
|
d.StartWithBusybox(ctx, t, "--experimental", "--ip6tables")
|
||||||
defer d.Stop(t)
|
defer d.Stop(t)
|
||||||
|
@ -160,7 +102,7 @@ func TestInternalNetworkDNS(t *testing.T) {
|
||||||
res, err := container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
|
res, err := container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Check(t, is.Equal(res.ExitCode, 0))
|
assert.Check(t, is.Equal(res.ExitCode, 0))
|
||||||
assert.Check(t, is.Contains(res.Stdout(), dnsRespAddr))
|
assert.Check(t, is.Contains(res.Stdout(), network.DNSRespAddr))
|
||||||
|
|
||||||
// Connect the container to the internal network as well.
|
// Connect the container to the internal network as well.
|
||||||
// External DNS should still be used.
|
// External DNS should still be used.
|
||||||
|
@ -169,7 +111,7 @@ func TestInternalNetworkDNS(t *testing.T) {
|
||||||
res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
|
res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Check(t, is.Equal(res.ExitCode, 0))
|
assert.Check(t, is.Equal(res.ExitCode, 0))
|
||||||
assert.Check(t, is.Contains(res.Stdout(), dnsRespAddr))
|
assert.Check(t, is.Contains(res.Stdout(), network.DNSRespAddr))
|
||||||
|
|
||||||
// Disconnect from the external network.
|
// Disconnect from the external network.
|
||||||
// Expect no access to the external DNS.
|
// Expect no access to the external DNS.
|
||||||
|
@ -187,5 +129,5 @@ func TestInternalNetworkDNS(t *testing.T) {
|
||||||
res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
|
res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Check(t, is.Equal(res.ExitCode, 0))
|
assert.Check(t, is.Equal(res.ExitCode, 0))
|
||||||
assert.Check(t, is.Contains(res.Stdout(), dnsRespAddr))
|
assert.Check(t, is.Contains(res.Stdout(), network.DNSRespAddr))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue