diff --git a/cmd/derper/depaware.txt b/cmd/derper/depaware.txt
index 5d375a515..0941ea06e 100644
--- a/cmd/derper/depaware.txt
+++ b/cmd/derper/depaware.txt
@@ -199,13 +199,17 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
         golang.org/x/crypto/salsa20/salsa                            from golang.org/x/crypto/nacl/box+
    W    golang.org/x/exp/constraints                                 from tailscale.com/util/winutil
         golang.org/x/exp/maps                                        from tailscale.com/util/syspolicy/setting+
-   L    golang.org/x/net/bpf                                         from github.com/mdlayher/netlink+
+        golang.org/x/net/bpf                                         from github.com/mdlayher/netlink+
         golang.org/x/net/dns/dnsmessage                              from net+
         golang.org/x/net/http/httpguts                               from net/http
         golang.org/x/net/http/httpproxy                              from net/http+
         golang.org/x/net/http2/hpack                                 from net/http
         golang.org/x/net/idna                                        from golang.org/x/crypto/acme/autocert+
+        golang.org/x/net/internal/iana                               from golang.org/x/net/ipv4+
+        golang.org/x/net/internal/socket                             from golang.org/x/net/ipv4+
         golang.org/x/net/internal/socks                              from golang.org/x/net/proxy
+        golang.org/x/net/ipv4                                        from tailscale.com/net/stunserver
+        golang.org/x/net/ipv6                                        from tailscale.com/net/stunserver
         golang.org/x/net/proxy                                       from tailscale.com/net/netns
    D    golang.org/x/net/route                                       from net+
         golang.org/x/sync/errgroup                                   from github.com/mdlayher/socket+
diff --git a/cmd/stund/depaware.txt b/cmd/stund/depaware.txt
index 2326e3a24..d9c79b158 100644
--- a/cmd/stund/depaware.txt
+++ b/cmd/stund/depaware.txt
@@ -94,15 +94,20 @@ tailscale.com/cmd/stund dependencies: (generated by github.com/tailscale/depawar
         golang.org/x/crypto/nacl/box                                 from tailscale.com/types/key
         golang.org/x/crypto/nacl/secretbox                           from golang.org/x/crypto/nacl/box
         golang.org/x/crypto/salsa20/salsa                            from golang.org/x/crypto/nacl/box+
+        golang.org/x/net/bpf                                         from golang.org/x/net/ipv4+
         golang.org/x/net/dns/dnsmessage                              from net+
         golang.org/x/net/http/httpguts                               from net/http
         golang.org/x/net/http/httpproxy                              from net/http
         golang.org/x/net/http2/hpack                                 from net/http
         golang.org/x/net/idna                                        from golang.org/x/net/http/httpguts+
+        golang.org/x/net/internal/iana                               from golang.org/x/net/ipv4+
+        golang.org/x/net/internal/socket                             from golang.org/x/net/ipv4+
+        golang.org/x/net/ipv4                                        from tailscale.com/net/stunserver
+        golang.org/x/net/ipv6                                        from tailscale.com/net/stunserver
    D    golang.org/x/net/route                                       from net
         golang.org/x/sys/cpu                                         from golang.org/x/crypto/blake2b+
   LD    golang.org/x/sys/unix                                        from github.com/prometheus/procfs+
-   W    golang.org/x/sys/windows                                     from github.com/prometheus/client_golang/prometheus
+   W    golang.org/x/sys/windows                                     from github.com/prometheus/client_golang/prometheus+
         golang.org/x/text/secure/bidirule                            from golang.org/x/net/idna
         golang.org/x/text/transform                                  from golang.org/x/text/secure/bidirule+
         golang.org/x/text/unicode/bidi                               from golang.org/x/net/idna+
diff --git a/net/stunserver/stunserver.go b/net/stunserver/stunserver.go
index b45bb6331..c7068e116 100644
--- a/net/stunserver/stunserver.go
+++ b/net/stunserver/stunserver.go
@@ -15,6 +15,8 @@ import (
 	"net/netip"
 	"time"
 
+	"golang.org/x/net/ipv4"
+	"golang.org/x/net/ipv6"
 	"tailscale.com/metrics"
 	"tailscale.com/net/stun"
 )
@@ -70,13 +72,17 @@ func (s *STUNServer) Listen(listenAddr string) error {
 // Serve starts serving responses to STUN requests. Listen must be called before Serve.
 func (s *STUNServer) Serve() error {
 	var buf [64 << 10]byte
+	var oob [4096]byte
 	var (
-		n   int
-		ua  *net.UDPAddr
-		err error
+		n, oobn int
+		remote  netip.AddrPort
+		local   net.IP
+		err     error
+		cm4     ipv4.ControlMessage
+		cm6     ipv6.ControlMessage
 	)
 	for {
-		n, ua, err = s.pc.ReadFromUDP(buf[:])
+		n, oobn, _, remote, err = s.pc.ReadMsgUDPAddrPort(buf[:], oob[:])
 		if err != nil {
 			if errors.Is(err, io.EOF) || errors.Is(err, net.ErrClosed) {
 				return nil
@@ -86,6 +92,22 @@ func (s *STUNServer) Serve() error {
 			stunReadError.Add(1)
 			continue
 		}
+
+		if remote.Addr().Is4() {
+			err = cm4.Parse(oob[:oobn])
+		} else {
+			err = cm6.Parse(oob[:oobn])
+		}
+		if err != nil {
+			log.Printf("parse control msg error: %v", err)
+			continue
+		}
+		if remote.Addr().Is4() {
+			local = cm4.Dst
+		} else {
+			local = cm6.Dst
+		}
+
 		pkt := buf[:n]
 		if !stun.Is(pkt) {
 			stunNotSTUN.Add(1)
@@ -96,14 +118,27 @@ func (s *STUNServer) Serve() error {
 			stunNotSTUN.Add(1)
 			continue
 		}
-		if ua.IP.To4() != nil {
+		if remote.Addr().Is4() {
 			stunIPv4.Add(1)
 		} else {
 			stunIPv6.Add(1)
 		}
-		addr, _ := netip.AddrFromSlice(ua.IP)
-		res := stun.Response(txid, netip.AddrPortFrom(addr, uint16(ua.Port)))
-		_, err = s.pc.WriteTo(res, ua)
+		res := stun.Response(txid, remote)
+
+		// TODO(raggi): send upstream patch to provide a way to serialize a
+		// control message into an existng buffer.
+		if remote.Addr().Is4() {
+			cm4 = ipv4.ControlMessage{
+				Src: local,
+			}
+			oobn = copy(oob[:], cm4.Marshal())
+		} else {
+			cm6 = ipv6.ControlMessage{
+				Src: local,
+			}
+			oobn = copy(oob[:], cm6.Marshal())
+		}
+		_, _, err = s.pc.WriteMsgUDPAddrPort(res, oob[:oobn], remote)
 		if err != nil {
 			stunWriteError.Add(1)
 		} else {