From 052eb9d88ff3a59177d182c618c5720a718d5814 Mon Sep 17 00:00:00 2001 From: James Tucker Date: Thu, 13 Feb 2025 13:35:28 -0800 Subject: [PATCH] net/stunserver: reply from the address at which STUN was received Updates #15014 Signed-off-by: James Tucker --- cmd/derper/depaware.txt | 6 ++++- cmd/stund/depaware.txt | 7 ++++- net/stunserver/stunserver.go | 51 ++++++++++++++++++++++++++++++------ 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/cmd/derper/depaware.txt b/cmd/derper/depaware.txt index 1812a1a8d..1323d2237 100644 --- a/cmd/derper/depaware.txt +++ b/cmd/derper/depaware.txt @@ -198,13 +198,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 1d0a093c4..2850b2fb3 100644 --- a/cmd/stund/depaware.txt +++ b/cmd/stund/depaware.txt @@ -93,15 +93,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 {