ipn/ipnlocal: Support TCP and Web VIP services

This commit intend to provide support for TCP and Web VIP services and also allow user to use Tun
for VIP services if they want to.
The commit includes:
1.Setting TCP intercept function for VIP Services.
2.Update netstack to send packet written from WG to netStack handler for VIP service.
3.Return correct TCP hander for VIP services when netstack acceptTCP.

This commit also includes unit tests for if the local backend setServeConfig would set correct TCP intercept
function and test if a hander gets returned when getting TCPHandlerForDst. The shouldProcessInbound
check is not unit tested since the test result just depends on mocked functions. There should be an integration
test to cover  shouldProcessInbound and if the returned TCP handler actually does what the serveConfig says.

Updates tailscale/corp#24604

Signed-off-by: KevinLiang10 <37811973+KevinLiang10@users.noreply.github.com>
This commit is contained in:
KevinLiang10
2025-01-20 12:02:53 -05:00
parent cb3b1a1dcf
commit 8c8750f1b3
9 changed files with 783 additions and 21 deletions

View File

@@ -0,0 +1,19 @@
package netmap
import "net/netip"
// IPServiceMappings maps IP addresses to service names. This is the inverse of
// [ServiceIPMappings], and is used to inform clients which services is an VIP
// address associated with. This is set to b.ipVIPServiceMap every time the
// netmap is updated. This is used to reduce the cost for looking up the service
// name for the dst IP address in the netStack packet processing workflow.
//
// This is of the form:
//
// {
// "100.65.32.1": "svc:samba",
// "fd7a:115c:a1e0::1234": "svc:samba",
// "100.102.42.3": "svc:web",
// "fd7a:115c:a1e0::abcd": "svc:web",
// }
type IPServiceMappings map[netip.Addr]string

View File

@@ -101,6 +101,54 @@ func (nm *NetworkMap) GetAddresses() views.Slice[netip.Prefix] {
return nm.SelfNode.Addresses()
}
// GetVIPServiceIPMap returns a map of service names to the slice of
// VIP addresses that correspond to the service. The service names are
// with the prefix "svc:".
//
// TODO(corp##25997): cache the result of decoding the capmap so that
// we don't have to decode it multiple times after each netmap update.
func (nm *NetworkMap) GetVIPServiceIPMap() tailcfg.ServiceIPMappings {
if nm == nil {
return nil
}
if !nm.SelfNode.Valid() {
return nil
}
ipMaps, err := tailcfg.UnmarshalNodeCapJSON[tailcfg.ServiceIPMappings](nm.SelfNode.CapMap().AsMap(), tailcfg.NodeAttrServiceHost)
if len(ipMaps) != 1 || err != nil {
return nil
}
return ipMaps[0]
}
// GetIPVIPServiceMap returns a map of VIP addresses to the service
// names that has the VIP address. The service names are with the
// prefix "svc:".
func (nm *NetworkMap) GetIPVIPServiceMap() IPServiceMappings {
var res IPServiceMappings
if nm == nil {
return res
}
if !nm.SelfNode.Valid() {
return res
}
serviceIPMap := nm.GetVIPServiceIPMap()
if serviceIPMap == nil {
return res
}
res = make(IPServiceMappings)
for svc, addrs := range serviceIPMap {
for _, addr := range addrs {
res[addr] = svc
}
}
return res
}
// AnyPeersAdvertiseRoutes reports whether any peer is advertising non-exit node routes.
func (nm *NetworkMap) AnyPeersAdvertiseRoutes() bool {
for _, p := range nm.Peers {