David Fifield 6 лет назад
Родитель
Сommit
f2abcbf4de
1 измененных файлов с 38 добавлено и 33 удалено
  1. 38 33
      dnstt-server/main.go

+ 38 - 33
dnstt-server/main.go

@@ -23,6 +23,28 @@ import (
 const (
 	idleTimeout = 10 * time.Minute
 	responseTTL = 60
+
+	// We don't send UDP payloads larger than this, in an attempt to avoid
+	// network-layer fragmentation. 40 bytes is the size of an IPv6 header
+	// (though without any extension headers). 8 bytes is the size of a UDP
+	// header.
+	maxUDPPayload = 1500 - 40 - 8
+
+	// We may have a variable amount of room in which to encode downstream
+	// packets in each response, because we must echo the query's Question
+	// section, which is of variable length. But we cannot give dynamic
+	// packet size limits to KCP; the best we can do is set a global maximum
+	// which no packet will exceed. We choose that maximum to keep the UDP
+	// payload size under maxUDPPayload, even in the worst case of a
+	// maximum-length name in the Question section. The precise limit is
+	// 1153 = (maxUDPPayload - 294) * 255/256, where 294 is the size of a
+	// DNS message containing a Question section with a name that is 255
+	// bytes long, an Answer section with a single TXT RR whose name is a
+	// compressed pointer to the name in the Question section and no data,
+	// and an Additional section with an OPT RR for EDNS(0); and 255/256
+	// reflects the overhead of encoding data into a TXT RR. We leave some
+	// slack in case of IPv6 extension headers or non-Ethernet links.
+	maxEncodedPayload = 1100
 )
 
 // A base32 encoding without padding.
@@ -110,23 +132,11 @@ func acceptSessions(ln *kcp.Listener, upstream *net.TCPAddr) error {
 			0, // default resend
 			1, // nc=1 => congestion window off
 		)
-		// Set the maximum transmission unit.
-		longName, err := dns.NewName([][]byte{
-			bytes.Repeat([]byte{'a'}, 63),
-			bytes.Repeat([]byte{'b'}, 63),
-			bytes.Repeat([]byte{'c'}, 63),
-			bytes.Repeat([]byte{'d'}, 61),
-		})
-		if err != nil {
-			panic(err)
+		// Set the maximum transmission unit. 2 bytes accounts for a
+		// packet length prefix.
+		if rc := conn.SetMtu(maxEncodedPayload - 2); !rc {
+			panic(rc)
 		}
-		mtu := dnsMessageCapacity(longName)
-		if mtu < 80 {
-			// This value doesn't depend on any configuration values, so it
-			// should never be too small.
-			panic("too little space for downstream payload")
-		}
-		conn.SetMtu(mtu)
 		go func() {
 			defer conn.Close()
 			err := acceptStreams(conn, upstream)
@@ -137,22 +147,6 @@ func acceptSessions(ln *kcp.Listener, upstream *net.TCPAddr) error {
 	}
 }
 
-func dnsMessageCapacity(name dns.Name) int {
-	message := dns.Message{
-		Question: []dns.Question{
-			dns.Question{Name: name},
-		},
-		Answer: []dns.RR{
-			dns.RR{Name: name},
-		},
-	}
-	builder, err := message.WireFormat()
-	if err != nil {
-		panic(err)
-	}
-	return (512 - len(builder)) * 255 / 256
-}
-
 func nextPacket(r *bytes.Reader) ([]byte, error) {
 	eof := func(err error) error {
 		if err == io.EOF {
@@ -240,6 +234,17 @@ func responseFor(query *dns.Message, domain dns.Name) (*dns.Message, turbotunnel
 			payloadSize = 512
 		}
 	}
+	if payloadSize < maxUDPPayload {
+		// We require clients to support EDNS(0) with a minimum payload
+		// size; otherwise we would have to set a small KCP MTU (only
+		// around 200 bytes).
+		// https://tools.ietf.org/html/rfc6891#section-7
+		// "If there is a problem with processing the OPT record itself,
+		// such as an option value that is badly formatted or that
+		// includes out-of-range values, a FORMERR MUST be returned."
+		resp.Flags |= dns.RcodeFormatError
+		return resp, clientID, nil
+	}
 
 	if query.Flags&0x7800 != 0 {
 		// We don't support OPCODE != QUERY.
@@ -381,7 +386,7 @@ func sendLoop(dnsConn net.PacketConn, ttConn *turbotunnel.QueuePacketConn, ch <-
 
 			var payload bytes.Buffer
 
-			limit := dnsMessageCapacity(rec.Resp.Question[0].Name)
+			limit := maxEncodedPayload
 			if len(nextP) > 0 {
 				// No length check on any packet left over from
 				// the previous bundle -- if it's too large, we