net/tsaddr, wgengine/netstack: add IPv6 range that forwards to site-relative IPv4

This defines a new magic IPv6 prefix, fd7a:115c:a1e0:b1a::/64, a
subset of our existing /48, where the final 32 bits are an IPv4
address, and the middle 32 bits are a user-chosen "site ID". (which
must currently be 0000:00xx; the top 3 bytes must be zero for now)

e.g., I can say my home LAN's "site ID" is "0000:00bb" and then
advertise its 10.2.0.0/16 IPv4 range via IPv6, like:

    tailscale up --advertise-routes=fd7a:115c:a1e0:b1a::bb:10.2.0.0/112

(112 being /128 minuse the /96 v6 prefix length)

Then people in my tailnet can:

     $ curl '[fd7a:115c:a1e0:b1a::bb:10.2.0.230]'
     <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ....

Updates #3616, etc

RELNOTE=initial support for TS IPv6 addresses to route v4 "via" specific nodes

Change-Id: I9b49b6ad10410a24b5866b9fbc69d3cae1f600ef
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2022-03-30 08:47:16 -07:00
committed by Brad Fitzpatrick
parent f992749b98
commit 3ae701f0eb
6 changed files with 156 additions and 4 deletions

View File

@@ -431,6 +431,8 @@ func (ns *Impl) peerAPIPortAtomic(ip netaddr.IP) *uint32 {
}
}
var viaRange = tsaddr.TailscaleViaRange()
// shouldProcessInbound reports whether an inbound packet should be
// handled by netstack.
func (ns *Impl) shouldProcessInbound(p *packet.Parsed, t *tstun.Wrapper) bool {
@@ -453,6 +455,9 @@ func (ns *Impl) shouldProcessInbound(p *packet.Parsed, t *tstun.Wrapper) bool {
if ns.isInboundTSSH(p) && ns.processSSH() {
return true
}
if p.IPVersion == 6 && viaRange.Contains(p.Dst.IP()) {
return ns.lb != nil && ns.lb.ShouldHandleViaIP(p.Dst.IP())
}
if !ns.ProcessLocalIPs && !ns.ProcessSubnets {
// Fast path for common case (e.g. Linux server in TUN mode) where
// netstack isn't used at all; don't even do an isLocalIP lookup.
@@ -624,6 +629,12 @@ func (ns *Impl) acceptTCP(r *tcp.ForwarderRequest) {
dialIP := netaddrIPFromNetstackIP(reqDetails.LocalAddress)
isTailscaleIP := tsaddr.IsTailscaleIP(dialIP)
if viaRange.Contains(dialIP) {
isTailscaleIP = false
dialIP = tsaddr.UnmapVia(dialIP)
}
defer func() {
if !isTailscaleIP {
// if this is a subnet IP, we added this in before the TCP handshake
@@ -775,6 +786,9 @@ func (ns *Impl) forwardUDP(client *gonet.UDPConn, wq *waiter.Queue, clientAddr,
backendRemoteAddr = &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: int(port)}
backendListenAddr = &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: int(srcPort)}
} else {
if dstIP := dstAddr.IP(); viaRange.Contains(dstIP) {
dstAddr = netaddr.IPPortFrom(tsaddr.UnmapVia(dstIP), dstAddr.Port())
}
backendRemoteAddr = dstAddr.UDPAddr()
if dstAddr.IP().Is4() {
backendListenAddr = &net.UDPAddr{IP: net.ParseIP("0.0.0.0"), Port: int(srcPort)}