Explorar o código

libnetwork: add regression test for issue 44575

Signed-off-by: Cory Snider <csnider@mirantis.com>
Cory Snider %!s(int64=2) %!d(string=hai) anos
pai
achega
78792eae68
Modificáronse 2 ficheiros con 131 adicións e 3 borrados
  1. 6 1
      libnetwork/resolver.go
  2. 125 2
      libnetwork/resolver_test.go

+ 6 - 1
libnetwork/resolver.go

@@ -73,6 +73,7 @@ const (
 
 
 type extDNSEntry struct {
 type extDNSEntry struct {
 	IPStr        string
 	IPStr        string
+	port         uint16 // for testing
 	HostLoopback bool
 	HostLoopback bool
 }
 }
 
 
@@ -451,7 +452,11 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
 				break
 				break
 			}
 			}
 			extConnect := func() {
 			extConnect := func() {
-				addr := fmt.Sprintf("%s:%d", extDNS.IPStr, 53)
+				port := extDNS.port
+				if port == 0 {
+					port = 53
+				}
+				addr := fmt.Sprintf("%s:%d", extDNS.IPStr, port)
 				extConn, err = net.DialTimeout(proto, addr, extIOTimeout)
 				extConn, err = net.DialTimeout(proto, addr, extIOTimeout)
 			}
 			}
 
 

+ 125 - 2
libnetwork/resolver_test.go

@@ -1,6 +1,8 @@
 package libnetwork
 package libnetwork
 
 
 import (
 import (
+	"encoding/hex"
+	"errors"
 	"net"
 	"net"
 	"runtime"
 	"runtime"
 	"syscall"
 	"syscall"
@@ -10,6 +12,7 @@ import (
 	"github.com/docker/docker/libnetwork/testutils"
 	"github.com/docker/docker/libnetwork/testutils"
 	"github.com/miekg/dns"
 	"github.com/miekg/dns"
 	"github.com/sirupsen/logrus"
 	"github.com/sirupsen/logrus"
+	"gotest.tools/v3/assert"
 	"gotest.tools/v3/skip"
 	"gotest.tools/v3/skip"
 )
 )
 
 
@@ -23,7 +26,8 @@ func (a *tstaddr) String() string { return "127.0.0.1" }
 
 
 // a simple writer that implements dns.ResponseWriter for unit testing purposes
 // a simple writer that implements dns.ResponseWriter for unit testing purposes
 type tstwriter struct {
 type tstwriter struct {
-	msg *dns.Msg
+	localAddr net.Addr
+	msg       *dns.Msg
 }
 }
 
 
 func (w *tstwriter) WriteMsg(m *dns.Msg) (err error) {
 func (w *tstwriter) WriteMsg(m *dns.Msg) (err error) {
@@ -33,7 +37,12 @@ func (w *tstwriter) WriteMsg(m *dns.Msg) (err error) {
 
 
 func (w *tstwriter) Write(m []byte) (int, error) { return 0, nil }
 func (w *tstwriter) Write(m []byte) (int, error) { return 0, nil }
 
 
-func (w *tstwriter) LocalAddr() net.Addr { return new(tstaddr) }
+func (w *tstwriter) LocalAddr() net.Addr {
+	if w.localAddr != nil {
+		return w.localAddr
+	}
+	return new(tstaddr)
+}
 
 
 func (w *tstwriter) RemoteAddr() net.Addr { return new(tstaddr) }
 func (w *tstwriter) RemoteAddr() net.Addr { return new(tstaddr) }
 
 
@@ -285,3 +294,117 @@ func TestDNSProxyServFail(t *testing.T) {
 	}
 	}
 	t.Logf("Expected number of DNS requests generated")
 	t.Logf("Expected number of DNS requests generated")
 }
 }
+
+// Packet 24 extracted from
+// https://gist.github.com/vojtad/3bac63b8c91b1ec50e8d8b36047317fa/raw/7d75eb3d3448381bf252ae55ea5123a132c46658/host.pcap
+// (https://github.com/moby/moby/issues/44575)
+// which is a non-compliant DNS reply > 512B (w/o EDNS(0)) to the query
+//
+//	s3.amazonaws.com. IN A
+const oversizedDNSReplyMsg = "\xf5\x11\x81\x80\x00\x01\x00\x20\x00\x00\x00\x00\x02\x73\x33\x09" +
+	"\x61\x6d\x61\x7a\x6f\x6e\x61\x77\x73\x03\x63\x6f\x6d\x00\x00\x01" +
+	"\x00\x01\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd9" +
+	"\x11\x9e\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd8" +
+	"\x4c\x66\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd8" +
+	"\xda\x10\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd9" +
+	"\x01\x3e\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd9" +
+	"\x88\x68\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd9" +
+	"\x66\x9e\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd9" +
+	"\x5f\x28\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd8" +
+	"\x8e\x4e\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x36\xe7" +
+	"\x84\xf0\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x34\xd8" +
+	"\x92\x45\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd8" +
+	"\x8f\xa6\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x36\xe7" +
+	"\xc0\xd0\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd9" +
+	"\xfe\x28\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd8" +
+	"\xaa\x3d\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd8" +
+	"\x4e\x56\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd9" +
+	"\xea\xb0\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd8" +
+	"\x6d\xed\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x04\x00\x04\x34\xd8" +
+	"\x28\x00\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x34\xd9" +
+	"\xe9\x78\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x34\xd9" +
+	"\x6e\x9e\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x34\xd9" +
+	"\x45\x86\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x34\xd8" +
+	"\x30\x38\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x36\xe7" +
+	"\xc6\xa8\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x03\x05" +
+	"\x01\x9d\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\x34\xd9" +
+	"\xa8\xe8\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\x34\xd9" +
+	"\x64\xa6\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\x34\xd8" +
+	"\x3c\x48\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\x34\xd8" +
+	"\x35\x20\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\x34\xd9" +
+	"\x54\xf6\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\x34\xd9" +
+	"\x5d\x36\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\x34\xd9" +
+	"\x30\x36\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\x36\xe7" +
+	"\x83\x90"
+
+// Regression test for https://github.com/moby/moby/issues/44575
+func TestOversizedDNSReply(t *testing.T) {
+	srv, err := net.ListenPacket("udp", "127.0.0.1:0")
+	assert.NilError(t, err)
+	defer srv.Close()
+	go func() {
+		buf := make([]byte, 65536)
+		for {
+			n, src, err := srv.ReadFrom(buf)
+			if errors.Is(err, net.ErrClosed) {
+				return
+			}
+			t.Logf("[<-%v]\n%s", src, hex.Dump(buf[:n]))
+			if n < 2 {
+				continue
+			}
+			resp := []byte(oversizedDNSReplyMsg)
+			resp[0], resp[1] = buf[0], buf[1] // Copy query ID into response.
+			_, err = srv.WriteTo(resp, src)
+			if errors.Is(err, net.ErrClosed) {
+				return
+			}
+			if err != nil {
+				t.Log(err)
+			}
+		}
+	}()
+
+	srvAddr := srv.LocalAddr().(*net.UDPAddr)
+	rsv := NewResolver("", true, noopDNSBackend{}).(*resolver)
+	rsv.SetExtServers([]extDNSEntry{
+		{IPStr: srvAddr.IP.String(), port: uint16(srvAddr.Port), HostLoopback: true},
+	})
+
+	// The resolver logs lots of valuable info at level debug. Redirect it
+	// to t.Log() so the log spew is emitted only if the test fails.
+	oldLevel, oldOut := logrus.StandardLogger().Level, logrus.StandardLogger().Out
+	defer func() {
+		logrus.StandardLogger().SetLevel(oldLevel)
+		logrus.StandardLogger().SetOutput(oldOut)
+	}()
+	logrus.StandardLogger().SetLevel(logrus.DebugLevel)
+	logrus.SetOutput(tlogWriter{t})
+
+	w := &tstwriter{localAddr: srv.LocalAddr()}
+	q := new(dns.Msg).SetQuestion("s3.amazonaws.com.", dns.TypeA)
+	rsv.ServeDNS(w, q)
+	resp := w.GetResponse()
+	checkNonNullResponse(t, resp)
+	t.Log("Response: ", resp.String())
+	checkDNSResponseCode(t, resp, dns.RcodeSuccess)
+	assert.Assert(t, len(resp.Answer) >= 1)
+	checkDNSRRType(t, resp.Answer[0].Header().Rrtype, dns.TypeA)
+}
+
+type tlogWriter struct{ t *testing.T }
+
+func (w tlogWriter) Write(p []byte) (n int, err error) {
+	w.t.Logf("%s", p)
+	return len(p), nil
+}
+
+type noopDNSBackend struct{ DNSBackend }
+
+func (noopDNSBackend) ResolveName(name string, iplen int) ([]net.IP, bool) { return nil, false }
+
+func (noopDNSBackend) ExecFunc(f func()) error { f(); return nil }
+
+func (noopDNSBackend) NdotsSet() bool { return false }
+
+func (noopDNSBackend) HandleQueryResp(name string, ip net.IP) {}