MCPcopy Index your code
hub / github.com/tailscale/tailscale / forwardUDP

Method forwardUDP

wgengine/netstack/netstack.go:2017–2103  ·  view source on GitHub ↗

forwardUDP proxies between client (with addr clientAddr) and dstAddr. dstAddr may be either a local Tailscale IP, in which we case we proxy to 127.0.0.1, or any other IP (from an advertised subnet), in which case we proxy to it directly.

(client *gonet.UDPConn, clientAddr, dstAddr netip.AddrPort)

Source from the content-addressed store, hash-verified

2015// 127.0.0.1, or any other IP (from an advertised subnet), in which case we
2016// proxy to it directly.
2017func (ns *Impl) forwardUDP(client *gonet.UDPConn, clientAddr, dstAddr netip.AddrPort) {
2018 port, srcPort := dstAddr.Port(), clientAddr.Port()
2019 if debugNetstack() {
2020 ns.logf("[v2] netstack: forwarding incoming UDP connection on port %v", port)
2021 }
2022
2023 var backendListenAddr *net.UDPAddr
2024 var backendRemoteAddr *net.UDPAddr
2025 isLocal := ns.isLocalIP(dstAddr.Addr())
2026 isLoopback := dstAddr.Addr() == ipv4Loopback || dstAddr.Addr() == ipv6Loopback
2027 if isLocal {
2028 backendRemoteAddr = &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: int(port)}
2029 backendListenAddr = &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: int(srcPort)}
2030 } else if isLoopback {
2031 ip := net.IP(ipv4Loopback.AsSlice())
2032 if dstAddr.Addr() == ipv6Loopback {
2033 ip = ipv6Loopback.AsSlice()
2034 }
2035 backendRemoteAddr = &net.UDPAddr{IP: ip, Port: int(port)}
2036 backendListenAddr = &net.UDPAddr{IP: ip, Port: int(srcPort)}
2037 } else {
2038 if dstIP := dstAddr.Addr(); viaRange.Contains(dstIP) {
2039 dstAddr = netip.AddrPortFrom(tsaddr.UnmapVia(dstIP), dstAddr.Port())
2040 }
2041 backendRemoteAddr = net.UDPAddrFromAddrPort(dstAddr)
2042 if dstAddr.Addr().Is4() {
2043 backendListenAddr = &net.UDPAddr{IP: net.ParseIP("0.0.0.0"), Port: int(srcPort)}
2044 } else {
2045 backendListenAddr = &net.UDPAddr{IP: net.ParseIP("::"), Port: int(srcPort)}
2046 }
2047 }
2048
2049 backendConn, err := net.ListenUDP("udp", backendListenAddr)
2050 if err != nil {
2051 ns.logf("netstack: could not bind local port %v: %v, trying again with random port", backendListenAddr.Port, err)
2052 backendListenAddr.Port = 0
2053 backendConn, err = net.ListenUDP("udp", backendListenAddr)
2054 if err != nil {
2055 ns.logf("netstack: could not create UDP socket, preventing forwarding to %v: %v", dstAddr, err)
2056 return
2057 }
2058 }
2059 backendLocalAddr := backendConn.LocalAddr().(*net.UDPAddr)
2060
2061 backendLocalIPPort := netip.AddrPortFrom(backendListenAddr.AddrPort().Addr().Unmap().WithZone(backendLocalAddr.Zone), backendLocalAddr.AddrPort().Port())
2062 if !backendLocalIPPort.IsValid() {
2063 ns.logf("could not get backend local IP:port from %v:%v", backendLocalAddr.IP, backendLocalAddr.Port)
2064 }
2065 if isLocal {
2066 if err := ns.pm.RegisterIPPortIdentity("udp", backendLocalIPPort, clientAddr.Addr()); err != nil {
2067 ns.logf("netstack: could not register UDP mapping %s: %v", backendLocalIPPort, err)
2068 return
2069 }
2070 }
2071 ctx, cancel := context.WithCancel(context.Background())
2072
2073 idleTimeout := 2 * time.Minute
2074 if port == 53 {

Callers 1

acceptUDPMethod · 0.95

Calls 15

isLocalIPMethod · 0.95
removeSubnetAddressMethod · 0.95
UnmapViaFunction · 0.92
startPacketCopyFunction · 0.85
IPMethod · 0.80
LocalAddrMethod · 0.65
AfterFuncMethod · 0.65
CloseMethod · 0.65
ResetMethod · 0.65
DoneMethod · 0.65

Tested by

no test coverage detected