diff --git a/wgengine/netstack/netstack.go b/wgengine/netstack/netstack.go index e2f930b4c..b73ffae00 100644 --- a/wgengine/netstack/netstack.go +++ b/wgengine/netstack/netstack.go @@ -1059,10 +1059,15 @@ func (ns *Impl) acceptUDP(r *udp.ForwarderRequest) { go ns.forwardUDP(c, srcAddr, dstAddr) } +// Buffer pool for forwarding UDP packets. +var udpBufPool = &sync.Pool{ + New: func() any { + b := make([]byte, maxUDPPacketSize) + return &b + }, +} + func (ns *Impl) handleMagicDNSUDP(srcAddr netip.AddrPort, c *gonet.UDPConn) { - // 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. - var maxUDPReqSize = tstun.DefaultMTU() // 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 @@ -1070,7 +1075,10 @@ func (ns *Impl) handleMagicDNSUDP(srcAddr netip.AddrPort, c *gonet.UDPConn) { const readDeadline = 150 * time.Millisecond defer c.Close() - q := make([]byte, maxUDPReqSize) + + bufp := udpBufPool.Get().(*[]byte) + defer udpBufPool.Put(bufp) + q := *bufp // libresolv from glibc is quite adamant that transmitting multiple DNS // requests down the same UDP socket is valid. To support this, we read @@ -1183,7 +1191,11 @@ func startPacketCopy(ctx context.Context, cancel context.CancelFunc, dst net.Pac } go func() { defer cancel() // tear down the other direction's copy - pkt := make([]byte, maxUDPPacketSize) + + bufp := udpBufPool.Get().(*[]byte) + defer udpBufPool.Put(bufp) + pkt := *bufp + for { select { case <-ctx.Done():