Larger downstream capacity.

This commit is contained in:
David Fifield
2020-04-18 14:33:39 -06:00
parent 0022cdd16c
commit f2abcbf4de
+38 -33
View File
@@ -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