summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrew Dunham <andrew@tailscale.com>2022-11-08 16:38:49 -0500
committerAndrew Dunham <andrew@tailscale.com>2022-11-08 16:59:17 -0500
commit284809da138bd0b5746aed9f86c4adbb9f48b4d5 (patch)
tree6b01739e5963b91a092aff26efc7470823f215d6
parente85613aa2d9016bf50ab0192d528c6a9861cfea1 (diff)
downloadtailscale-andrew/net-tsaddr-mapviaaddr.tar.xz
tailscale-andrew/net-tsaddr-mapviaaddr.zip
net/tsaddr: add MapViaAddr functionandrew/net-tsaddr-mapviaaddr
Change-Id: I45122fd65c7133fb3d2cbc7eec6f1de89d768ef4 Signed-off-by: Andrew Dunham <andrew@tailscale.com>
-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")
+ }
+ })
+}