cmd/{containerboot,k8s-operator}: add 4via6 support in singleton egress (#19983)
Add support for configuring egress to destinations reachable via 4via6 subnet routes, using either the synthesized 4via6 address or the MagicDNS name (in the form <IPv4-with-hyphens>-via-<siteID>[.*]). Also update the Connector to validate and advertise 4via6 subnet routes. Export net/netutil.ValidateViaPrefix so it can be reused by the Connector validation logic. This change only affects standalone egress proxies — ProxyGroup egress requires IPv6 support before it can use 4via6. Updates #19334 Change-Id: I6faecd6eb61ab55fc0cd97fe417af6b6a12fe7fc Signed-off-by: Becky Pauley <becky@tailscale.com>
This commit is contained in:
@@ -10,8 +10,13 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/util/dnsname"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -53,6 +58,43 @@ func CapVerFromFileName(name string) (tailcfg.CapabilityVersion, error) {
|
||||
return cap, err
|
||||
}
|
||||
|
||||
// ResolveViaDomain parses an FQDN (with or without trailing dot) as a
|
||||
// 4via6 domain in the format "<ipv4-with-hyphens>-via-<siteID>[.domain]"
|
||||
// and returns the synthesized IPv6 via address.
|
||||
// This borrows heavily from net/dns/resolver.(*Resolver).resolveViaDomain.
|
||||
// TODO(beckypauley): consider a refactor of the above to remove duplication.
|
||||
func ResolveViaDomain(name string) (netip.Addr, bool) {
|
||||
// The minimum length of a valid 4via6 FQDN i.e. "0-0-0-0-via-X".
|
||||
const minFQDNLength = 13
|
||||
fqdn := strings.TrimSuffix(name, ".")
|
||||
if len(fqdn) < minFQDNLength {
|
||||
return netip.Addr{}, false // too short to be valid
|
||||
}
|
||||
if !strings.Contains(fqdn, "-via-") {
|
||||
return netip.Addr{}, false
|
||||
}
|
||||
firstLabel, domain, _ := strings.Cut(fqdn, ".")
|
||||
if !(domain == "" || dnsname.HasSuffix(domain, "ts.net") || dnsname.HasSuffix(domain, "tailscale.net")) {
|
||||
return netip.Addr{}, false
|
||||
}
|
||||
v4hyphens, siteIDStr, ok := strings.Cut(firstLabel, "-via-")
|
||||
if !ok {
|
||||
return netip.Addr{}, false
|
||||
}
|
||||
ip4Str := strings.ReplaceAll(v4hyphens, "-", ".")
|
||||
ip4, err := netip.ParseAddr(ip4Str)
|
||||
if err != nil || !ip4.Is4() {
|
||||
return netip.Addr{}, false
|
||||
}
|
||||
prefix, err := strconv.ParseUint(siteIDStr, 0, 32)
|
||||
if err != nil {
|
||||
return netip.Addr{}, false
|
||||
}
|
||||
// MapVia will never error when given an IPv4 netip.Prefix.
|
||||
out, _ := tsaddr.MapVia(uint32(prefix), netip.PrefixFrom(ip4, ip4.BitLen()))
|
||||
return out.Addr(), true
|
||||
}
|
||||
|
||||
// TruncateLabelValue truncates a Kubernetes label value to fit within the
|
||||
// 63-character limit. If the value exceeds the limit, it is truncated and a
|
||||
// short hash suffix is appended to preserve uniqueness.
|
||||
|
||||
Reference in New Issue
Block a user