|
|
|
@ -127,8 +127,10 @@ import (
|
|
|
|
"tailscale.com/kube/services"
|
|
|
|
"tailscale.com/kube/services"
|
|
|
|
"tailscale.com/tailcfg"
|
|
|
|
"tailscale.com/tailcfg"
|
|
|
|
"tailscale.com/types/logger"
|
|
|
|
"tailscale.com/types/logger"
|
|
|
|
|
|
|
|
"tailscale.com/types/netmap"
|
|
|
|
"tailscale.com/types/ptr"
|
|
|
|
"tailscale.com/types/ptr"
|
|
|
|
"tailscale.com/util/deephash"
|
|
|
|
"tailscale.com/util/deephash"
|
|
|
|
|
|
|
|
"tailscale.com/util/dnsname"
|
|
|
|
"tailscale.com/util/linuxfw"
|
|
|
|
"tailscale.com/util/linuxfw"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@ -526,27 +528,14 @@ runLoop:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if cfg.TailnetTargetFQDN != "" {
|
|
|
|
if cfg.TailnetTargetFQDN != "" {
|
|
|
|
var (
|
|
|
|
egressAddrs, err := resolveTailnetFQDN(n.NetMap, cfg.TailnetTargetFQDN)
|
|
|
|
egressAddrs []netip.Prefix
|
|
|
|
if err != nil {
|
|
|
|
newCurentEgressIPs deephash.Sum
|
|
|
|
log.Print(err.Error())
|
|
|
|
egressIPsHaveChanged bool
|
|
|
|
|
|
|
|
node tailcfg.NodeView
|
|
|
|
|
|
|
|
nodeFound bool
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
for _, n := range n.NetMap.Peers {
|
|
|
|
|
|
|
|
if strings.EqualFold(n.Name(), cfg.TailnetTargetFQDN) {
|
|
|
|
|
|
|
|
node = n
|
|
|
|
|
|
|
|
nodeFound = true
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if !nodeFound {
|
|
|
|
|
|
|
|
log.Printf("Tailscale node %q not found; it either does not exist, or not reachable because of ACLs", cfg.TailnetTargetFQDN)
|
|
|
|
|
|
|
|
break
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
egressAddrs = node.Addresses().AsSlice()
|
|
|
|
|
|
|
|
newCurentEgressIPs = deephash.Hash(&egressAddrs)
|
|
|
|
newCurentEgressIPs := deephash.Hash(&egressAddrs)
|
|
|
|
egressIPsHaveChanged = newCurentEgressIPs != currentEgressIPs
|
|
|
|
egressIPsHaveChanged := newCurentEgressIPs != currentEgressIPs
|
|
|
|
// The firewall rules get (re-)installed:
|
|
|
|
// The firewall rules get (re-)installed:
|
|
|
|
// - on startup
|
|
|
|
// - on startup
|
|
|
|
// - when the tailnet IPs of the tailnet target have changed
|
|
|
|
// - when the tailnet IPs of the tailnet target have changed
|
|
|
|
@ -892,3 +881,64 @@ func runHTTPServer(mux *http.ServeMux, addr string) (close func() error) {
|
|
|
|
return errors.Join(err, ln.Close())
|
|
|
|
return errors.Join(err, ln.Close())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// resolveTailnetFQDN resolves a tailnet FQDN to a list of IP prefixes, which
|
|
|
|
|
|
|
|
// can be either a peer device or a Tailscale Service.
|
|
|
|
|
|
|
|
func resolveTailnetFQDN(nm *netmap.NetworkMap, fqdn string) ([]netip.Prefix, error) {
|
|
|
|
|
|
|
|
// Check all peer devices first.
|
|
|
|
|
|
|
|
for _, p := range nm.Peers {
|
|
|
|
|
|
|
|
if strings.EqualFold(p.Name(), fqdn) {
|
|
|
|
|
|
|
|
return p.Addresses().AsSlice(), nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If not found yet, check for a matching Tailscale Service.
|
|
|
|
|
|
|
|
dnsFQDN, err := dnsname.ToFQDN(fqdn)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, fmt.Errorf("error parsing %q as FQDN: %w", fqdn, err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if svcIPs := serviceIPsFromNetMap(nm, dnsFQDN); len(svcIPs) != 0 {
|
|
|
|
|
|
|
|
return svcIPs, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return nil, fmt.Errorf("could not find Tailscale node or service %q; it either does not exist, or not reachable because of ACLs", fqdn)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// serviceIPsFromNetMap returns all IPs of a Tailscale Service if its FQDN is
|
|
|
|
|
|
|
|
// found in the netmap. Note that Tailscale Services are not a first-class
|
|
|
|
|
|
|
|
// object in the netmap, so we guess based on DNS ExtraRecords and AllowedIPs.
|
|
|
|
|
|
|
|
func serviceIPsFromNetMap(nm *netmap.NetworkMap, fqdn dnsname.FQDN) []netip.Prefix {
|
|
|
|
|
|
|
|
var extraRecords []tailcfg.DNSRecord
|
|
|
|
|
|
|
|
for _, rec := range nm.DNS.ExtraRecords {
|
|
|
|
|
|
|
|
recFQDN, err := dnsname.ToFQDN(rec.Name)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.EqualFold(fqdn.WithTrailingDot(), recFQDN.WithTrailingDot()) {
|
|
|
|
|
|
|
|
extraRecords = append(extraRecords, rec)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if len(extraRecords) == 0 {
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Validate we can see a peer advertising the Tailscale Service.
|
|
|
|
|
|
|
|
var prefixes []netip.Prefix
|
|
|
|
|
|
|
|
for _, extraRecord := range extraRecords {
|
|
|
|
|
|
|
|
ip, err := netip.ParseAddr(extraRecord.Value)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ipPrefix := netip.PrefixFrom(ip, ip.BitLen())
|
|
|
|
|
|
|
|
for _, ps := range nm.Peers {
|
|
|
|
|
|
|
|
for _, allowedIP := range ps.AllowedIPs().All() {
|
|
|
|
|
|
|
|
if allowedIP == ipPrefix {
|
|
|
|
|
|
|
|
prefixes = append(prefixes, ipPrefix)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return prefixes
|
|
|
|
|
|
|
|
}
|
|
|
|
|