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)
| 2015 | // 127.0.0.1, or any other IP (from an advertised subnet), in which case we |
| 2016 | // proxy to it directly. |
| 2017 | func (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 { |
no test coverage detected