summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--net/tsaddr/tsaddr.go14
-rw-r--r--net/tsaddr/tsaddr_test.go33
2 files changed, 47 insertions, 0 deletions
diff --git a/net/tsaddr/tsaddr.go b/net/tsaddr/tsaddr.go
index 9cd3ba752..29238eb06 100644
--- a/net/tsaddr/tsaddr.go
+++ b/net/tsaddr/tsaddr.go
@@ -309,3 +309,17 @@ func MapVia(siteID uint32, v4 netip.Prefix) (via netip.Prefix, err error) {
copy(a[12:], ip4a[:])
return netip.PrefixFrom(netip.AddrFrom16(a), v4.Bits()+64+32), nil
}
+
+// MapViaAddr returns an IPv6 "via" address for an IPv4 address in a given siteID.
+func MapViaAddr(siteID uint32, v4 netip.Addr) (netip.Addr, error) {
+ if !v4.Is4() {
+ return netip.Addr{}, errors.New("want IPv4 address with a site ID")
+ }
+ viaRange16 := TailscaleViaRange().Addr().As16()
+ var a [16]byte
+ copy(a[:], viaRange16[:8])
+ binary.BigEndian.PutUint32(a[8:], siteID)
+ ip4a := v4.As4()
+ copy(a[12:], ip4a[:])
+ return netip.AddrFrom16(a), nil
+}
diff --git a/net/tsaddr/tsaddr_test.go b/net/tsaddr/tsaddr_test.go
index 812475ac1..36c3cae3e 100644
--- a/net/tsaddr/tsaddr_test.go
+++ b/net/tsaddr/tsaddr_test.go
@@ -105,3 +105,36 @@ func TestUnmapVia(t *testing.T) {
}
}
}
+
+func TestMapViaAddr(t *testing.T) {
+ tests := []struct {
+ ip string
+ site uint32
+ want string
+ }{
+ {"1.2.3.4", 0, "fd7a:115c:a1e0:b1a::102:304"},
+ {"1.2.3.4", 7, "fd7a:115c:a1e0:b1a:0:7:102:304"},
+ }
+ for _, tt := range tests {
+ got, err := MapViaAddr(tt.site, netip.MustParseAddr(tt.ip))
+ if err != nil {
+ t.Errorf("for %q @ %d: error: %v", tt.ip, tt.site, err)
+ continue
+ }
+
+ if got.String() != tt.want {
+ t.Errorf("for %q @ %d: got %q, want %q", tt.ip, tt.site, got.String(), tt.want)
+ }
+ }
+
+ t.Run("Error", func(t *testing.T) {
+ addr, err := MapViaAddr(9, netip.MustParseAddr("::1"))
+ want := "want IPv4 address with a site ID"
+ if err == nil || err.Error() != want {
+ t.Errorf("got err=%v; want %q", err, want)
+ }
+ if addr.IsValid() {
+ t.Errorf("expected invalid Addr")
+ }
+ })
+}