wgengine/netstack: handle multiple magicDNS queries per UDP socket (#4708)

Fixes: #4686

Signed-off-by: Tom DNetto <tom@tailscale.com>
pull/4734/head
Tom 3 years ago committed by GitHub
parent c81be7b899
commit fc5839864b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -386,7 +386,6 @@ func (ns *Impl) handleLocalPackets(p *packet.Parsed, t *tstun.Wrapper) filter.Re
} }
} }
var pn tcpip.NetworkProtocolNumber var pn tcpip.NetworkProtocolNumber
switch p.IPVersion { switch p.IPVersion {
case 4: case 4:
@ -900,12 +899,27 @@ func (ns *Impl) handleMagicDNSUDP(srcAddr netaddr.IPPort, c *gonet.UDPConn) {
// In practice, implementations are advised not to exceed 512 bytes // In practice, implementations are advised not to exceed 512 bytes
// due to fragmenting. Just to be sure, we bump all the way to the MTU. // due to fragmenting. Just to be sure, we bump all the way to the MTU.
const maxUDPReqSize = mtu const maxUDPReqSize = mtu
// Packets are being generated by the local host, so there should be
// very, very little latency. 150ms was chosen as something of an upper
// bound on resource usage, while hopefully still being long enough for
// a heavily loaded system.
const readDeadline = 150 * time.Millisecond
defer c.Close() defer c.Close()
q := make([]byte, maxUDPReqSize) q := make([]byte, maxUDPReqSize)
n, err := c.Read(q)
// libresolv from glibc is quite adamant that transmitting multiple DNS
// requests down the same UDP socket is valid. To support this, we read
// in a loop (with a tight deadline so we don't chew too many resources).
//
// See: https://github.com/bminor/glibc/blob/f7fbb99652eceb1b6b55e4be931649df5946497c/resolv/res_send.c#L995
for {
c.SetReadDeadline(time.Now().Add(readDeadline))
n, _, err := c.ReadFrom(q)
if err != nil { if err != nil {
ns.logf("dns udp read: %v", err) if oe, ok := err.(*net.OpError); !(ok && oe.Timeout()) {
ns.logf("dns udp read: %v", err) // log non-timeout errors
}
return return
} }
resp, err := ns.dns.Query(context.Background(), q[:n], srcAddr) resp, err := ns.dns.Query(context.Background(), q[:n], srcAddr)
@ -914,6 +928,7 @@ func (ns *Impl) handleMagicDNSUDP(srcAddr netaddr.IPPort, c *gonet.UDPConn) {
return return
} }
c.Write(resp) c.Write(resp)
}
} }
// forwardUDP proxies between client (with addr clientAddr) and dstAddr. // forwardUDP proxies between client (with addr clientAddr) and dstAddr.

Loading…
Cancel
Save