all: convert more code to use net/netip directly

perl -i -npe 's,netaddr.IPPrefixFrom,netip.PrefixFrom,' $(git grep -l -F netaddr.)
    perl -i -npe 's,netaddr.IPPortFrom,netip.AddrPortFrom,' $(git grep -l -F netaddr. )
    perl -i -npe 's,netaddr.IPPrefix,netip.Prefix,g' $(git grep -l -F netaddr. )
    perl -i -npe 's,netaddr.IPPort,netip.AddrPort,g' $(git grep -l -F netaddr. )
    perl -i -npe 's,netaddr.IP\b,netip.Addr,g' $(git grep -l -F netaddr. )
    perl -i -npe 's,netaddr.IPv6Raw\b,netip.AddrFrom16,g' $(git grep -l -F netaddr. )
    goimports -w .

Then delete some stuff from the net/netaddr shim package which is no
longer neeed.

Updates #5162

Change-Id: Ia7a86893fe21c7e3ee1ec823e8aba288d4566cd8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2022-07-25 21:14:09 -07:00 committed by Brad Fitzpatrick
parent 6a396731eb
commit a12aad6b47
148 changed files with 1117 additions and 1200 deletions

View File

@ -13,8 +13,7 @@
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http" "net/http"
"net/netip"
"tailscale.com/net/netaddr"
) )
// ACLRow defines a rule that grants access by a set of users or groups to a set // ACLRow defines a rule that grants access by a set of users or groups to a set
@ -354,7 +353,7 @@ func (c *Client) PreviewACLForUser(ctx context.Context, acl ACL, user string) (r
// Returns ACLPreview on success with matches in a slice. If there are no matches, // Returns ACLPreview on success with matches in a slice. If there are no matches,
// the call is still successful but Matches will be an empty slice. // the call is still successful but Matches will be an empty slice.
// Returns error if the provided ACL is invalid. // Returns error if the provided ACL is invalid.
func (c *Client) PreviewACLForIPPort(ctx context.Context, acl ACL, ipport netaddr.IPPort) (res *ACLPreview, err error) { func (c *Client) PreviewACLForIPPort(ctx context.Context, acl ACL, ipport netip.AddrPort) (res *ACLPreview, err error) {
// Format return errors to be descriptive. // Format return errors to be descriptive.
defer func() { defer func() {
if err != nil { if err != nil {

View File

@ -19,6 +19,7 @@
"net" "net"
"net/http" "net/http"
"net/http/httptrace" "net/http/httptrace"
"net/netip"
"net/url" "net/url"
"os/exec" "os/exec"
"runtime" "runtime"
@ -31,7 +32,6 @@
"tailscale.com/client/tailscale/apitype" "tailscale.com/client/tailscale/apitype"
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/net/netaddr"
"tailscale.com/net/netutil" "tailscale.com/net/netutil"
"tailscale.com/paths" "tailscale.com/paths"
"tailscale.com/safesocket" "tailscale.com/safesocket"
@ -665,7 +665,7 @@ func (lc *LocalClient) ExpandSNIName(ctx context.Context, name string) (fqdn str
// Ping sends a ping of the provided type to the provided IP and waits // Ping sends a ping of the provided type to the provided IP and waits
// for its response. // for its response.
func (lc *LocalClient) Ping(ctx context.Context, ip netaddr.IP, pingtype tailcfg.PingType) (*ipnstate.PingResult, error) { func (lc *LocalClient) Ping(ctx context.Context, ip netip.Addr, pingtype tailcfg.PingType) (*ipnstate.PingResult, error) {
v := url.Values{} v := url.Values{}
v.Set("ip", ip.String()) v.Set("ip", ip.String())
v.Set("type", string(pingtype)) v.Set("type", string(pingtype))

View File

@ -13,15 +13,14 @@
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http" "net/http"
"net/netip"
"tailscale.com/net/netaddr"
) )
// Routes contains the lists of subnet routes that are currently advertised by a device, // Routes contains the lists of subnet routes that are currently advertised by a device,
// as well as the subnets that are enabled to be routed by the device. // as well as the subnets that are enabled to be routed by the device.
type Routes struct { type Routes struct {
AdvertisedRoutes []netaddr.IPPrefix `json:"advertisedRoutes"` AdvertisedRoutes []netip.Prefix `json:"advertisedRoutes"`
EnabledRoutes []netaddr.IPPrefix `json:"enabledRoutes"` EnabledRoutes []netip.Prefix `json:"enabledRoutes"`
} }
// Routes retrieves the list of subnet routes that have been enabled for a device. // Routes retrieves the list of subnet routes that have been enabled for a device.
@ -56,14 +55,14 @@ func (c *Client) Routes(ctx context.Context, deviceID string) (routes *Routes, e
} }
type postRoutesParams struct { type postRoutesParams struct {
Routes []netaddr.IPPrefix `json:"routes"` Routes []netip.Prefix `json:"routes"`
} }
// SetRoutes updates the list of subnets that are enabled for a device. // SetRoutes updates the list of subnets that are enabled for a device.
// Subnets must be parsable by net/netip.ParsePrefix. // Subnets must be parsable by net/netip.ParsePrefix.
// Subnets do not have to be currently advertised by a device, they may be pre-enabled. // Subnets do not have to be currently advertised by a device, they may be pre-enabled.
// Returns the updated list of enabled and advertised subnet routes in a *Routes object. // Returns the updated list of enabled and advertised subnet routes in a *Routes object.
func (c *Client) SetRoutes(ctx context.Context, deviceID string, subnets []netaddr.IPPrefix) (routes *Routes, err error) { func (c *Client) SetRoutes(ctx context.Context, deviceID string, subnets []netip.Prefix) (routes *Routes, err error) {
defer func() { defer func() {
if err != nil { if err != nil {
err = fmt.Errorf("tailscale.SetRoutes: %w", err) err = fmt.Errorf("tailscale.SetRoutes: %w", err)

View File

@ -18,7 +18,6 @@
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/net/netaddr"
"tailscale.com/tstest" "tailscale.com/tstest"
"tailscale.com/types/persist" "tailscale.com/types/persist"
"tailscale.com/types/preftype" "tailscale.com/types/preftype"
@ -57,7 +56,7 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
flags []string // argv to be parsed by FlagSet flags []string // argv to be parsed by FlagSet
curPrefs *ipn.Prefs curPrefs *ipn.Prefs
curExitNodeIP netaddr.IP curExitNodeIP netip.Addr
curUser string // os.Getenv("USER") on the client side curUser string // os.Getenv("USER") on the client side
goos string // empty means "linux" goos string // empty means "linux"
distro distro.Distro distro distro.Distro
@ -153,7 +152,7 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
AllowSingleHosts: true, AllowSingleHosts: true,
CorpDNS: true, CorpDNS: true,
NetfilterMode: preftype.NetfilterOn, NetfilterMode: preftype.NetfilterOn,
AdvertiseRoutes: []netaddr.IPPrefix{ AdvertiseRoutes: []netip.Prefix{
netip.MustParsePrefix("10.0.42.0/24"), netip.MustParsePrefix("10.0.42.0/24"),
netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("0.0.0.0/0"),
netip.MustParsePrefix("::/0"), netip.MustParsePrefix("::/0"),
@ -169,7 +168,7 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
AllowSingleHosts: true, AllowSingleHosts: true,
CorpDNS: true, CorpDNS: true,
NetfilterMode: preftype.NetfilterOn, NetfilterMode: preftype.NetfilterOn,
AdvertiseRoutes: []netaddr.IPPrefix{ AdvertiseRoutes: []netip.Prefix{
netip.MustParsePrefix("10.0.42.0/24"), netip.MustParsePrefix("10.0.42.0/24"),
netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("0.0.0.0/0"),
netip.MustParsePrefix("::/0"), netip.MustParsePrefix("::/0"),
@ -185,7 +184,7 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
AllowSingleHosts: true, AllowSingleHosts: true,
CorpDNS: true, CorpDNS: true,
NetfilterMode: preftype.NetfilterOn, NetfilterMode: preftype.NetfilterOn,
AdvertiseRoutes: []netaddr.IPPrefix{ AdvertiseRoutes: []netip.Prefix{
netip.MustParsePrefix("10.0.42.0/24"), netip.MustParsePrefix("10.0.42.0/24"),
netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("0.0.0.0/0"),
netip.MustParsePrefix("::/0"), netip.MustParsePrefix("::/0"),
@ -213,7 +212,7 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
CorpDNS: true, CorpDNS: true,
NetfilterMode: preftype.NetfilterOn, NetfilterMode: preftype.NetfilterOn,
AdvertiseRoutes: []netaddr.IPPrefix{ AdvertiseRoutes: []netip.Prefix{
netip.MustParsePrefix("1.2.0.0/16"), netip.MustParsePrefix("1.2.0.0/16"),
}, },
}, },
@ -227,7 +226,7 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
AllowSingleHosts: true, AllowSingleHosts: true,
CorpDNS: true, CorpDNS: true,
NetfilterMode: preftype.NetfilterOn, NetfilterMode: preftype.NetfilterOn,
AdvertiseRoutes: []netaddr.IPPrefix{ AdvertiseRoutes: []netip.Prefix{
netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("0.0.0.0/0"),
netip.MustParsePrefix("::/0"), netip.MustParsePrefix("::/0"),
netip.MustParsePrefix("1.2.0.0/16"), netip.MustParsePrefix("1.2.0.0/16"),
@ -262,7 +261,7 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
AdvertiseTags: []string{"tag:foo", "tag:bar"}, AdvertiseTags: []string{"tag:foo", "tag:bar"},
Hostname: "myhostname", Hostname: "myhostname",
ForceDaemon: true, ForceDaemon: true,
AdvertiseRoutes: []netaddr.IPPrefix{ AdvertiseRoutes: []netip.Prefix{
netip.MustParsePrefix("10.0.0.0/16"), netip.MustParsePrefix("10.0.0.0/16"),
netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("0.0.0.0/0"),
netip.MustParsePrefix("::/0"), netip.MustParsePrefix("::/0"),
@ -287,7 +286,7 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
AdvertiseTags: []string{"tag:foo", "tag:bar"}, AdvertiseTags: []string{"tag:foo", "tag:bar"},
Hostname: "myhostname", Hostname: "myhostname",
ForceDaemon: true, ForceDaemon: true,
AdvertiseRoutes: []netaddr.IPPrefix{ AdvertiseRoutes: []netip.Prefix{
netip.MustParsePrefix("10.0.0.0/16"), netip.MustParsePrefix("10.0.0.0/16"),
}, },
NetfilterMode: preftype.NetfilterNoDivert, NetfilterMode: preftype.NetfilterNoDivert,
@ -345,7 +344,7 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
AllowSingleHosts: true, AllowSingleHosts: true,
CorpDNS: true, CorpDNS: true,
NetfilterMode: preftype.NetfilterOn, NetfilterMode: preftype.NetfilterOn,
AdvertiseRoutes: []netaddr.IPPrefix{ AdvertiseRoutes: []netip.Prefix{
netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("0.0.0.0/0"),
netip.MustParsePrefix("::/0"), netip.MustParsePrefix("::/0"),
netip.MustParsePrefix("1.2.0.0/16"), netip.MustParsePrefix("1.2.0.0/16"),
@ -361,7 +360,7 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
AllowSingleHosts: true, AllowSingleHosts: true,
CorpDNS: true, CorpDNS: true,
NetfilterMode: preftype.NetfilterOn, NetfilterMode: preftype.NetfilterOn,
AdvertiseRoutes: []netaddr.IPPrefix{ AdvertiseRoutes: []netip.Prefix{
netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("0.0.0.0/0"),
netip.MustParsePrefix("::/0"), netip.MustParsePrefix("::/0"),
netip.MustParsePrefix("1.2.0.0/16"), netip.MustParsePrefix("1.2.0.0/16"),
@ -563,7 +562,7 @@ func TestPrefsFromUpArgs(t *testing.T) {
WantRunning: true, WantRunning: true,
AllowSingleHosts: true, AllowSingleHosts: true,
CorpDNS: true, CorpDNS: true,
AdvertiseRoutes: []netaddr.IPPrefix{ AdvertiseRoutes: []netip.Prefix{
netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("0.0.0.0/0"),
netip.MustParsePrefix("::/0"), netip.MustParsePrefix("::/0"),
}, },
@ -632,7 +631,7 @@ func TestPrefsFromUpArgs(t *testing.T) {
exitNodeIP: "100.105.106.107", exitNodeIP: "100.105.106.107",
}, },
st: &ipnstate.Status{ st: &ipnstate.Status{
TailscaleIPs: []netaddr.IP{netip.MustParseAddr("100.105.106.107")}, TailscaleIPs: []netip.Addr{netip.MustParseAddr("100.105.106.107")},
}, },
wantErr: `cannot use 100.105.106.107 as an exit node as it is a local IP address to this machine; did you mean --advertise-exit-node?`, wantErr: `cannot use 100.105.106.107 as an exit node as it is a local IP address to this machine; did you mean --advertise-exit-node?`,
}, },
@ -672,7 +671,7 @@ func TestPrefsFromUpArgs(t *testing.T) {
want: &ipn.Prefs{ want: &ipn.Prefs{
WantRunning: true, WantRunning: true,
NoSNAT: true, NoSNAT: true,
AdvertiseRoutes: []netaddr.IPPrefix{ AdvertiseRoutes: []netip.Prefix{
netip.MustParsePrefix("fd7a:115c:a1e0:b1a::bb:10.0.0.0/112"), netip.MustParsePrefix("fd7a:115c:a1e0:b1a::bb:10.0.0.0/112"),
}, },
}, },
@ -957,7 +956,7 @@ func TestUpdatePrefs(t *testing.T) {
} }
} }
var cmpIP = cmp.Comparer(func(a, b netaddr.IP) bool { var cmpIP = cmp.Comparer(func(a, b netip.Addr) bool {
return a == b return a == b
}) })

View File

@ -27,7 +27,6 @@
"tailscale.com/client/tailscale/apitype" "tailscale.com/client/tailscale/apitype"
"tailscale.com/envknob" "tailscale.com/envknob"
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/version" "tailscale.com/version"
@ -192,7 +191,7 @@ func getTargetStableID(ctx context.Context, ipStr string) (id tailcfg.StableNode
// fileTargetErrorDetail returns a non-nil error saying why ip is an // fileTargetErrorDetail returns a non-nil error saying why ip is an
// invalid file sharing target. // invalid file sharing target.
func fileTargetErrorDetail(ctx context.Context, ip netaddr.IP) error { func fileTargetErrorDetail(ctx context.Context, ip netip.Addr) error {
found := false found := false
if st, err := localClient.Status(ctx); err == nil && st.Self != nil { if st, err := localClient.Status(ctx); err == nil && st.Self != nil {
for _, peer := range st.Peer { for _, peer := range st.Peer {

View File

@ -13,6 +13,7 @@
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
"net/netip"
"os" "os"
"strings" "strings"
@ -21,7 +22,6 @@
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
) )
@ -260,7 +260,7 @@ func ownerLogin(st *ipnstate.Status, ps *ipnstate.PeerStatus) string {
return u.LoginName return u.LoginName
} }
func firstIPString(v []netaddr.IP) string { func firstIPString(v []netip.Addr) string {
if len(v) == 0 { if len(v) == 0 {
return "" return ""
} }

View File

@ -27,7 +27,6 @@
qrcode "github.com/skip2/go-qrcode" qrcode "github.com/skip2/go-qrcode"
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
"tailscale.com/safesocket" "tailscale.com/safesocket"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
@ -204,7 +203,7 @@ func warnf(format string, args ...any) {
ipv6default = netip.MustParsePrefix("::/0") ipv6default = netip.MustParsePrefix("::/0")
) )
func validateViaPrefix(ipp netaddr.IPPrefix) error { func validateViaPrefix(ipp netip.Prefix) error {
if !tsaddr.IsViaPrefix(ipp) { if !tsaddr.IsViaPrefix(ipp) {
return fmt.Errorf("%v is not a 4-in-6 prefix", ipp) return fmt.Errorf("%v is not a 4-in-6 prefix", ipp)
} }
@ -224,8 +223,8 @@ func validateViaPrefix(ipp netaddr.IPPrefix) error {
return nil return nil
} }
func calcAdvertiseRoutes(advertiseRoutes string, advertiseDefaultRoute bool) ([]netaddr.IPPrefix, error) { func calcAdvertiseRoutes(advertiseRoutes string, advertiseDefaultRoute bool) ([]netip.Prefix, error) {
routeMap := map[netaddr.IPPrefix]bool{} routeMap := map[netip.Prefix]bool{}
if advertiseRoutes != "" { if advertiseRoutes != "" {
var default4, default6 bool var default4, default6 bool
advroutes := strings.Split(advertiseRoutes, ",") advroutes := strings.Split(advertiseRoutes, ",")
@ -259,7 +258,7 @@ func calcAdvertiseRoutes(advertiseRoutes string, advertiseDefaultRoute bool) ([]
routeMap[netip.MustParsePrefix("0.0.0.0/0")] = true routeMap[netip.MustParsePrefix("0.0.0.0/0")] = true
routeMap[netip.MustParsePrefix("::/0")] = true routeMap[netip.MustParsePrefix("::/0")] = true
} }
routes := make([]netaddr.IPPrefix, 0, len(routeMap)) routes := make([]netip.Prefix, 0, len(routeMap))
for r := range routeMap { for r := range routeMap {
routes = append(routes, r) routes = append(routes, r)
} }
@ -791,7 +790,7 @@ type upCheckEnv struct {
flagSet *flag.FlagSet flagSet *flag.FlagSet
upArgs upArgsT upArgs upArgsT
backendState string backendState string
curExitNodeIP netaddr.IP curExitNodeIP netip.Addr
distro distro.Distro distro distro.Distro
} }
@ -992,7 +991,7 @@ func fmtFlagValueArg(flagName string, val any) string {
return fmt.Sprintf("--%s=%v", flagName, shellquote.Join(fmt.Sprint(val))) return fmt.Sprintf("--%s=%v", flagName, shellquote.Join(fmt.Sprint(val)))
} }
func hasExitNodeRoutes(rr []netaddr.IPPrefix) bool { func hasExitNodeRoutes(rr []netip.Prefix) bool {
var v4, v6 bool var v4, v6 bool
for _, r := range rr { for _, r := range rr {
if r.Bits() == 0 { if r.Bits() == 0 {
@ -1009,11 +1008,11 @@ func hasExitNodeRoutes(rr []netaddr.IPPrefix) bool {
// withoutExitNodes returns rr unchanged if it has only 1 or 0 /0 // withoutExitNodes returns rr unchanged if it has only 1 or 0 /0
// routes. If it has both IPv4 and IPv6 /0 routes, then it returns // routes. If it has both IPv4 and IPv6 /0 routes, then it returns
// a copy with all /0 routes removed. // a copy with all /0 routes removed.
func withoutExitNodes(rr []netaddr.IPPrefix) []netaddr.IPPrefix { func withoutExitNodes(rr []netip.Prefix) []netip.Prefix {
if !hasExitNodeRoutes(rr) { if !hasExitNodeRoutes(rr) {
return rr return rr
} }
var out []netaddr.IPPrefix var out []netip.Prefix
for _, r := range rr { for _, r := range rr {
if r.Bits() > 0 { if r.Bits() > 0 {
out = append(out, r) out = append(out, r)
@ -1024,7 +1023,7 @@ func withoutExitNodes(rr []netaddr.IPPrefix) []netaddr.IPPrefix {
// exitNodeIP returns the exit node IP from p, using st to map // exitNodeIP returns the exit node IP from p, using st to map
// it from its ID form to an IP address if needed. // it from its ID form to an IP address if needed.
func exitNodeIP(p *ipn.Prefs, st *ipnstate.Status) (ip netaddr.IP) { func exitNodeIP(p *ipn.Prefs, st *ipnstate.Status) (ip netip.Addr) {
if p == nil { if p == nil {
return return
} }

View File

@ -52,7 +52,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
tailscale.com/net/dnsfallback from tailscale.com/control/controlhttp tailscale.com/net/dnsfallback from tailscale.com/control/controlhttp
tailscale.com/net/flowtrack from tailscale.com/wgengine/filter+ tailscale.com/net/flowtrack from tailscale.com/wgengine/filter+
💣 tailscale.com/net/interfaces from tailscale.com/cmd/tailscale/cli+ 💣 tailscale.com/net/interfaces from tailscale.com/cmd/tailscale/cli+
tailscale.com/net/netaddr from tailscale.com/client/tailscale+ tailscale.com/net/netaddr from tailscale.com/disco+
tailscale.com/net/netcheck from tailscale.com/cmd/tailscale/cli tailscale.com/net/netcheck from tailscale.com/cmd/tailscale/cli
tailscale.com/net/neterror from tailscale.com/net/netcheck+ tailscale.com/net/neterror from tailscale.com/net/netcheck+
tailscale.com/net/netknob from tailscale.com/net/netns tailscale.com/net/netknob from tailscale.com/net/netns

View File

@ -30,7 +30,6 @@
"tailscale.com/envknob" "tailscale.com/envknob"
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
"tailscale.com/net/portmapper" "tailscale.com/net/portmapper"
"tailscale.com/net/tshttpproxy" "tailscale.com/net/tshttpproxy"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
@ -267,7 +266,7 @@ func debugPortmap(ctx context.Context) error {
return err return err
} }
gatewayAndSelfIP := func() (gw, self netaddr.IP, ok bool) { gatewayAndSelfIP := func() (gw, self netip.Addr, ok bool) {
if v := os.Getenv("TS_DEBUG_GW_SELF"); strings.Contains(v, "/") { if v := os.Getenv("TS_DEBUG_GW_SELF"); strings.Contains(v, "/") {
i := strings.Index(v, "/") i := strings.Index(v, "/")
gw = netip.MustParseAddr(v[:i]) gw = netip.MustParseAddr(v[:i])

View File

@ -217,7 +217,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/net/dnsfallback from tailscale.com/control/controlclient+ tailscale.com/net/dnsfallback from tailscale.com/control/controlclient+
tailscale.com/net/flowtrack from tailscale.com/net/packet+ tailscale.com/net/flowtrack from tailscale.com/net/packet+
💣 tailscale.com/net/interfaces from tailscale.com/control/controlclient+ 💣 tailscale.com/net/interfaces from tailscale.com/control/controlclient+
tailscale.com/net/netaddr from tailscale.com/client/tailscale+ tailscale.com/net/netaddr from tailscale.com/disco+
tailscale.com/net/netcheck from tailscale.com/wgengine/magicsock tailscale.com/net/netcheck from tailscale.com/wgengine/magicsock
tailscale.com/net/neterror from tailscale.com/net/dns/resolver+ tailscale.com/net/neterror from tailscale.com/net/dns/resolver+
tailscale.com/net/netknob from tailscale.com/net/netns+ tailscale.com/net/netknob from tailscale.com/net/netns+

View File

@ -21,6 +21,7 @@
"net" "net"
"net/http" "net/http"
"net/http/pprof" "net/http/pprof"
"net/netip"
"os" "os"
"os/signal" "os/signal"
"path/filepath" "path/filepath"
@ -38,7 +39,6 @@
"tailscale.com/logpolicy" "tailscale.com/logpolicy"
"tailscale.com/logtail" "tailscale.com/logtail"
"tailscale.com/net/dns" "tailscale.com/net/dns"
"tailscale.com/net/netaddr"
"tailscale.com/net/netns" "tailscale.com/net/netns"
"tailscale.com/net/proxymux" "tailscale.com/net/proxymux"
"tailscale.com/net/socks5" "tailscale.com/net/socks5"
@ -366,11 +366,11 @@ func run() error {
ns.ProcessSubnets = useNetstack || wrapNetstack ns.ProcessSubnets = useNetstack || wrapNetstack
if useNetstack { if useNetstack {
dialer.UseNetstackForIP = func(ip netaddr.IP) bool { dialer.UseNetstackForIP = func(ip netip.Addr) bool {
_, ok := e.PeerForIP(ip) _, ok := e.PeerForIP(ip)
return ok return ok
} }
dialer.NetstackDialTCP = func(ctx context.Context, dst netaddr.IPPort) (net.Conn, error) { dialer.NetstackDialTCP = func(ctx context.Context, dst netip.AddrPort) (net.Conn, error) {
return ns.DialContextTCP(ctx, dst) return ns.DialContextTCP(ctx, dst)
} }
} }

View File

@ -25,6 +25,7 @@
"encoding/json" "encoding/json"
"fmt" "fmt"
"log" "log"
"net/netip"
"os" "os"
"time" "time"
@ -37,7 +38,6 @@
"tailscale.com/ipn/store" "tailscale.com/ipn/store"
"tailscale.com/logpolicy" "tailscale.com/logpolicy"
"tailscale.com/net/dns" "tailscale.com/net/dns"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
"tailscale.com/net/tstun" "tailscale.com/net/tstun"
"tailscale.com/safesocket" "tailscale.com/safesocket"
@ -245,7 +245,7 @@ func beFirewallKillswitch() bool {
// is passed in via stdin encoded in json. // is passed in via stdin encoded in json.
dcd := json.NewDecoder(os.Stdin) dcd := json.NewDecoder(os.Stdin)
for { for {
var routes []netaddr.IPPrefix var routes []netip.Prefix
if err := dcd.Decode(&routes); err != nil { if err := dcd.Decode(&routes); err != nil {
log.Fatalf("parent process died or requested exit, exiting (%v)", err) log.Fatalf("parent process died or requested exit, exiting (%v)", err)
} }

View File

@ -19,6 +19,7 @@
"log" "log"
"math/rand" "math/rand"
"net" "net"
"net/netip"
"strings" "strings"
"syscall/js" "syscall/js"
"time" "time"
@ -29,7 +30,6 @@
"tailscale.com/ipn/ipnlocal" "tailscale.com/ipn/ipnlocal"
"tailscale.com/ipn/ipnserver" "tailscale.com/ipn/ipnserver"
"tailscale.com/ipn/store/mem" "tailscale.com/ipn/store/mem"
"tailscale.com/net/netaddr"
"tailscale.com/net/netns" "tailscale.com/net/netns"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
"tailscale.com/safesocket" "tailscale.com/safesocket"
@ -78,10 +78,10 @@ func newIPN(jsConfig js.Value) map[string]any {
if err := ns.Start(); err != nil { if err := ns.Start(); err != nil {
log.Fatalf("failed to start netstack: %v", err) log.Fatalf("failed to start netstack: %v", err)
} }
dialer.UseNetstackForIP = func(ip netaddr.IP) bool { dialer.UseNetstackForIP = func(ip netip.Addr) bool {
return true return true
} }
dialer.NetstackDialTCP = func(ctx context.Context, dst netaddr.IPPort) (net.Conn, error) { dialer.NetstackDialTCP = func(ctx context.Context, dst netip.AddrPort) (net.Conn, error) {
return ns.DialContextTCP(ctx, dst) return ns.DialContextTCP(ctx, dst)
} }
@ -175,7 +175,7 @@ func (i *jsIPN) run(jsCallbacks js.Value) {
Self: jsNetMapSelfNode{ Self: jsNetMapSelfNode{
jsNetMapNode: jsNetMapNode{ jsNetMapNode: jsNetMapNode{
Name: nm.Name, Name: nm.Name,
Addresses: mapSlice(nm.Addresses, func(a netaddr.IPPrefix) string { return a.Addr().String() }), Addresses: mapSlice(nm.Addresses, func(a netip.Prefix) string { return a.Addr().String() }),
NodeKey: nm.NodeKey.String(), NodeKey: nm.NodeKey.String(),
MachineKey: nm.MachineKey.String(), MachineKey: nm.MachineKey.String(),
}, },
@ -185,7 +185,7 @@ func (i *jsIPN) run(jsCallbacks js.Value) {
return jsNetMapPeerNode{ return jsNetMapPeerNode{
jsNetMapNode: jsNetMapNode{ jsNetMapNode: jsNetMapNode{
Name: p.Name, Name: p.Name,
Addresses: mapSlice(p.Addresses, func(a netaddr.IPPrefix) string { return a.Addr().String() }), Addresses: mapSlice(p.Addresses, func(a netip.Prefix) string { return a.Addr().String() }),
MachineKey: p.Machine.String(), MachineKey: p.Machine.String(),
NodeKey: p.Key.String(), NodeKey: p.Key.String(),
}, },

View File

@ -7,15 +7,14 @@
import ( import (
"fmt" "fmt"
"net/netip"
"tailscale.com/net/netaddr"
) )
//go:generate go run tailscale.com/cmd/viewer --type=StructWithPtrs,StructWithoutPtrs,Map,StructWithSlices //go:generate go run tailscale.com/cmd/viewer --type=StructWithPtrs,StructWithoutPtrs,Map,StructWithSlices
type StructWithoutPtrs struct { type StructWithoutPtrs struct {
Int int Int int
Pfx netaddr.IPPrefix Pfx netip.Prefix
} }
type Map struct { type Map struct {
@ -54,6 +53,6 @@ type StructWithSlices struct {
Ints []*int Ints []*int
Slice []string Slice []string
Prefixes []netaddr.IPPrefix Prefixes []netip.Prefix
Data []byte Data []byte
} }

View File

@ -177,7 +177,7 @@ func genView(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named, thi
case "byte": case "byte":
it.Import("go4.org/mem") it.Import("go4.org/mem")
writeTemplate("byteSliceField") writeTemplate("byteSliceField")
case "inet.af/netaddr.IPPrefix", "net/netip.Prefix": case "inet.af/netip.Prefix", "net/netip.Prefix":
it.Import("tailscale.com/types/views") it.Import("tailscale.com/types/views")
writeTemplate("ipPrefixSliceField") writeTemplate("ipPrefixSliceField")
default: default:

View File

@ -16,6 +16,7 @@
"io/ioutil" "io/ioutil"
"log" "log"
"net/http" "net/http"
"net/netip"
"net/url" "net/url"
"os" "os"
"reflect" "reflect"
@ -36,7 +37,6 @@
"tailscale.com/net/dnscache" "tailscale.com/net/dnscache"
"tailscale.com/net/dnsfallback" "tailscale.com/net/dnsfallback"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
"tailscale.com/net/netutil" "tailscale.com/net/netutil"
"tailscale.com/net/tlsdial" "tailscale.com/net/tlsdial"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
@ -129,7 +129,7 @@ type Options struct {
// Pinger is the LocalBackend.Ping method. // Pinger is the LocalBackend.Ping method.
type Pinger interface { type Pinger interface {
// Ping is a request to do a ping with the peer handling the given IP. // Ping is a request to do a ping with the peer handling the given IP.
Ping(ctx context.Context, ip netaddr.IP, pingType tailcfg.PingType) (*ipnstate.PingResult, error) Ping(ctx context.Context, ip netip.Addr, pingType tailcfg.PingType) (*ipnstate.PingResult, error)
} }
type Decompressor interface { type Decompressor interface {
@ -1167,8 +1167,8 @@ func TrimWGConfig() opt.Bool {
// It should not return false positives. // It should not return false positives.
// //
// TODO(bradfitz): Change controlclient.Options.SkipIPForwardingCheck into a // TODO(bradfitz): Change controlclient.Options.SkipIPForwardingCheck into a
// func([]netaddr.IPPrefix) error signature instead. // func([]netip.Prefix) error signature instead.
func ipForwardingBroken(routes []netaddr.IPPrefix, state *interfaces.State) bool { func ipForwardingBroken(routes []netip.Prefix, state *interfaces.State) bool {
warn, err := netutil.CheckIPForwarding(routes, state) warn, err := netutil.CheckIPForwarding(routes, state)
if err != nil { if err != nil {
// Oh well, we tried. This is just for debugging. // Oh well, we tried. This is just for debugging.

View File

@ -8,12 +8,12 @@
"encoding/json" "encoding/json"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"net/netip"
"testing" "testing"
"time" "time"
"tailscale.com/hostinfo" "tailscale.com/hostinfo"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/key" "tailscale.com/types/key"
@ -86,7 +86,7 @@ func TestNewDirect(t *testing.T) {
func fakeEndpoints(ports ...uint16) (ret []tailcfg.Endpoint) { func fakeEndpoints(ports ...uint16) (ret []tailcfg.Endpoint) {
for _, port := range ports { for _, port := range ports {
ret = append(ret, tailcfg.Endpoint{ ret = append(ret, tailcfg.Endpoint{
Addr: netaddr.IPPortFrom(netaddr.IP{}, port), Addr: netip.AddrPortFrom(netip.Addr{}, port),
}) })
} }
return return

View File

@ -7,10 +7,10 @@
import ( import (
"fmt" "fmt"
"log" "log"
"net/netip"
"sort" "sort"
"tailscale.com/envknob" "tailscale.com/envknob"
"tailscale.com/net/netaddr"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/key" "tailscale.com/types/key"
"tailscale.com/types/logger" "tailscale.com/types/logger"
@ -303,7 +303,7 @@ func cloneNodes(v1 []*tailcfg.Node) []*tailcfg.Node {
var debugSelfIPv6Only = envknob.Bool("TS_DEBUG_SELF_V6_ONLY") var debugSelfIPv6Only = envknob.Bool("TS_DEBUG_SELF_V6_ONLY")
func filterSelfAddresses(in []netaddr.IPPrefix) (ret []netaddr.IPPrefix) { func filterSelfAddresses(in []netip.Prefix) (ret []netip.Prefix) {
switch { switch {
default: default:
return in return in

View File

@ -18,7 +18,6 @@
"go4.org/mem" "go4.org/mem"
"golang.org/x/time/rate" "golang.org/x/time/rate"
"tailscale.com/net/netaddr"
"tailscale.com/types/key" "tailscale.com/types/key"
"tailscale.com/types/logger" "tailscale.com/types/logger"
) )
@ -598,17 +597,17 @@ func (c *Client) setSendRateLimiter(sm ServerInfoMessage) {
// //
// If the client is broken in some previously detectable way, it // If the client is broken in some previously detectable way, it
// returns an error. // returns an error.
func (c *Client) LocalAddr() (netaddr.IPPort, error) { func (c *Client) LocalAddr() (netip.AddrPort, error) {
readErr, _ := c.readErr.Load().(error) readErr, _ := c.readErr.Load().(error)
if readErr != nil { if readErr != nil {
return netaddr.IPPort{}, readErr return netip.AddrPort{}, readErr
} }
if c.nc == nil { if c.nc == nil {
return netaddr.IPPort{}, errors.New("nil conn") return netip.AddrPort{}, errors.New("nil conn")
} }
a := c.nc.LocalAddr() a := c.nc.LocalAddr()
if a == nil { if a == nil {
return netaddr.IPPort{}, errors.New("nil addr") return netip.AddrPort{}, errors.New("nil addr")
} }
return netip.ParseAddrPort(a.String()) return netip.ParseAddrPort(a.String())
} }

View File

@ -41,7 +41,6 @@
"tailscale.com/disco" "tailscale.com/disco"
"tailscale.com/envknob" "tailscale.com/envknob"
"tailscale.com/metrics" "tailscale.com/metrics"
"tailscale.com/net/netaddr"
"tailscale.com/syncs" "tailscale.com/syncs"
"tailscale.com/types/key" "tailscale.com/types/key"
"tailscale.com/types/logger" "tailscale.com/types/logger"
@ -163,8 +162,8 @@ type Server struct {
// src. // src.
sentTo map[key.NodePublic]map[key.NodePublic]int64 // src => dst => dst's latest sclient.connNum sentTo map[key.NodePublic]map[key.NodePublic]int64 // src => dst => dst's latest sclient.connNum
// maps from netaddr.IPPort to a client's public key // maps from netip.AddrPort to a client's public key
keyOfAddr map[netaddr.IPPort]key.NodePublic keyOfAddr map[netip.AddrPort]key.NodePublic
} }
// clientSet represents 1 or more *sclients. // clientSet represents 1 or more *sclients.
@ -315,7 +314,7 @@ func NewServer(privateKey key.NodePrivate, logf logger.Logf) *Server {
watchers: map[*sclient]bool{}, watchers: map[*sclient]bool{},
sentTo: map[key.NodePublic]map[key.NodePublic]int64{}, sentTo: map[key.NodePublic]map[key.NodePublic]int64{},
avgQueueDuration: new(uint64), avgQueueDuration: new(uint64),
keyOfAddr: map[netaddr.IPPort]key.NodePublic{}, keyOfAddr: map[netip.AddrPort]key.NodePublic{},
} }
s.initMetacert() s.initMetacert()
s.packetsRecvDisco = s.packetsRecvByKind.Get("disco") s.packetsRecvDisco = s.packetsRecvByKind.Get("disco")
@ -1247,7 +1246,7 @@ type sclient struct {
logf logger.Logf logf logger.Logf
done <-chan struct{} // closed when connection closes done <-chan struct{} // closed when connection closes
remoteAddr string // usually ip:port from net.Conn.RemoteAddr().String() remoteAddr string // usually ip:port from net.Conn.RemoteAddr().String()
remoteIPPort netaddr.IPPort // zero if remoteAddr is not ip:port. remoteIPPort netip.AddrPort // zero if remoteAddr is not ip:port.
sendQueue chan pkt // packets queued to this client; never closed sendQueue chan pkt // packets queued to this client; never closed
discoSendQueue chan pkt // important packets queued to this client; never closed discoSendQueue chan pkt // important packets queued to this client; never closed
sendPongCh chan [8]byte // pong replies to send to the client; never closed sendPongCh chan [8]byte // pong replies to send to the client; never closed
@ -1760,8 +1759,8 @@ type BytesSentRecv struct {
// parseSSOutput parses the output from the specific call to ss in ServeDebugTraffic. // parseSSOutput parses the output from the specific call to ss in ServeDebugTraffic.
// Separated out for ease of testing. // Separated out for ease of testing.
func parseSSOutput(raw string) map[netaddr.IPPort]BytesSentRecv { func parseSSOutput(raw string) map[netip.AddrPort]BytesSentRecv {
newState := map[netaddr.IPPort]BytesSentRecv{} newState := map[netip.AddrPort]BytesSentRecv{}
// parse every 2 lines and get src and dst ips, and kv pairs // parse every 2 lines and get src and dst ips, and kv pairs
lines := strings.Split(raw, "\n") lines := strings.Split(raw, "\n")
for i := 0; i < len(lines); i += 2 { for i := 0; i < len(lines); i += 2 {
@ -1794,7 +1793,7 @@ func parseSSOutput(raw string) map[netaddr.IPPort]BytesSentRecv {
} }
func (s *Server) ServeDebugTraffic(w http.ResponseWriter, r *http.Request) { func (s *Server) ServeDebugTraffic(w http.ResponseWriter, r *http.Request) {
prevState := map[netaddr.IPPort]BytesSentRecv{} prevState := map[netip.AddrPort]BytesSentRecv{}
enc := json.NewEncoder(w) enc := json.NewEncoder(w)
for r.Context().Err() == nil { for r.Context().Err() == nil {
output, err := exec.Command("ss", "-i", "-H", "-t").Output() output, err := exec.Command("ss", "-i", "-H", "-t").Output()

View File

@ -34,7 +34,6 @@
"tailscale.com/derp" "tailscale.com/derp"
"tailscale.com/envknob" "tailscale.com/envknob"
"tailscale.com/net/dnscache" "tailscale.com/net/dnscache"
"tailscale.com/net/netaddr"
"tailscale.com/net/netns" "tailscale.com/net/netns"
"tailscale.com/net/tlsdial" "tailscale.com/net/tlsdial"
"tailscale.com/net/tshttpproxy" "tailscale.com/net/tshttpproxy"
@ -580,7 +579,7 @@ func (c *Client) dialContext(ctx context.Context, proto, addr string) (net.Conn,
// address (given in s) is valid. An empty value means to dial, but to // address (given in s) is valid. An empty value means to dial, but to
// use DNS. The predicate function reports whether the non-empty // use DNS. The predicate function reports whether the non-empty
// string s contained a valid IP address of the right family. // string s contained a valid IP address of the right family.
func shouldDialProto(s string, pred func(netaddr.IP) bool) bool { func shouldDialProto(s string, pred func(netip.Addr) bool) bool {
if s == "" { if s == "" {
return true return true
} }
@ -652,10 +651,10 @@ type res struct {
} }
}() }()
} }
if shouldDialProto(n.IPv4, netaddr.IP.Is4) { if shouldDialProto(n.IPv4, netip.Addr.Is4) {
startDial(n.IPv4, "tcp4") startDial(n.IPv4, "tcp4")
} }
if shouldDialProto(n.IPv6, netaddr.IP.Is6) { if shouldDialProto(n.IPv6, netip.Addr.Is6) {
startDial(n.IPv6, "tcp6") startDial(n.IPv6, "tcp6")
} }
if nwait == 0 { if nwait == 0 {
@ -840,15 +839,15 @@ func (c *Client) SendPing(data [8]byte) error {
// LocalAddr reports c's local TCP address, without any implicit // LocalAddr reports c's local TCP address, without any implicit
// connect or reconnect. // connect or reconnect.
func (c *Client) LocalAddr() (netaddr.IPPort, error) { func (c *Client) LocalAddr() (netip.AddrPort, error) {
c.mu.Lock() c.mu.Lock()
closed, client := c.closed, c.client closed, client := c.closed, c.client
c.mu.Unlock() c.mu.Unlock()
if closed { if closed {
return netaddr.IPPort{}, ErrClientClosed return netip.AddrPort{}, ErrClientClosed
} }
if client == nil { if client == nil {
return netaddr.IPPort{}, errors.New("client not connected") return netip.AddrPort{}, errors.New("client not connected")
} }
return client.LocalAddr() return client.LocalAddr()
} }

View File

@ -24,6 +24,7 @@
"errors" "errors"
"fmt" "fmt"
"net" "net"
"net/netip"
"go4.org/mem" "go4.org/mem"
"tailscale.com/net/netaddr" "tailscale.com/net/netaddr"
@ -172,7 +173,7 @@ type CallMeMaybe struct {
// in this field, but might not yet be in control's endpoints. // in this field, but might not yet be in control's endpoints.
// (And in the future, control will stop distributing endpoints // (And in the future, control will stop distributing endpoints
// when clients are suitably new.) // when clients are suitably new.)
MyNumber []netaddr.IPPort MyNumber []netip.AddrPort
} }
const epLength = 16 + 2 // 16 byte IP address + 2 byte port const epLength = 16 + 2 // 16 byte IP address + 2 byte port
@ -193,11 +194,11 @@ func parseCallMeMaybe(ver uint8, p []byte) (m *CallMeMaybe, err error) {
if len(p)%epLength != 0 || ver != 0 || len(p) == 0 { if len(p)%epLength != 0 || ver != 0 || len(p) == 0 {
return m, nil return m, nil
} }
m.MyNumber = make([]netaddr.IPPort, 0, len(p)/epLength) m.MyNumber = make([]netip.AddrPort, 0, len(p)/epLength)
for len(p) > 0 { for len(p) > 0 {
var a [16]byte var a [16]byte
copy(a[:], p) copy(a[:], p)
m.MyNumber = append(m.MyNumber, netaddr.IPPortFrom( m.MyNumber = append(m.MyNumber, netip.AddrPortFrom(
netaddr.IPFrom16(a), netaddr.IPFrom16(a),
binary.BigEndian.Uint16(p[16:18]))) binary.BigEndian.Uint16(p[16:18])))
p = p[epLength:] p = p[epLength:]
@ -211,7 +212,7 @@ func parseCallMeMaybe(ver uint8, p []byte) (m *CallMeMaybe, err error) {
// STUN response. // STUN response.
type Pong struct { type Pong struct {
TxID [12]byte TxID [12]byte
Src netaddr.IPPort // 18 bytes (16+2) on the wire; v4-mapped ipv6 for IPv4 Src netip.AddrPort // 18 bytes (16+2) on the wire; v4-mapped ipv6 for IPv4
} }
const pongLen = 12 + 16 + 2 const pongLen = 12 + 16 + 2
@ -236,7 +237,7 @@ func parsePong(ver uint8, p []byte) (m *Pong, err error) {
srcIP, _ := netaddr.FromStdIP(net.IP(p[:16])) srcIP, _ := netaddr.FromStdIP(net.IP(p[:16]))
p = p[16:] p = p[16:]
port := binary.BigEndian.Uint16(p) port := binary.BigEndian.Uint16(p)
m.Src = netaddr.IPPortFrom(srcIP, port) m.Src = netip.AddrPortFrom(srcIP, port)
return m, nil return m, nil
} }

View File

@ -12,7 +12,6 @@
"testing" "testing"
"go4.org/mem" "go4.org/mem"
"tailscale.com/net/netaddr"
"tailscale.com/types/key" "tailscale.com/types/key"
) )
@ -61,7 +60,7 @@ func TestMarshalAndParse(t *testing.T) {
{ {
name: "call_me_maybe_endpoints", name: "call_me_maybe_endpoints",
m: &CallMeMaybe{ m: &CallMeMaybe{
MyNumber: []netaddr.IPPort{ MyNumber: []netip.AddrPort{
netip.MustParseAddrPort("1.2.3.4:567"), netip.MustParseAddrPort("1.2.3.4:567"),
netip.MustParseAddrPort("[2001::3456]:789"), netip.MustParseAddrPort("[2001::3456]:789"),
}, },
@ -94,7 +93,7 @@ func TestMarshalAndParse(t *testing.T) {
} }
} }
func mustIPPort(s string) netaddr.IPPort { func mustIPPort(s string) netip.AddrPort {
ipp, err := netip.ParseAddrPort(s) ipp, err := netip.ParseAddrPort(s)
if err != nil { if err != nil {
panic(err) panic(err)

View File

@ -5,10 +5,10 @@
package ipn package ipn
import ( import (
"net/netip"
"sync" "sync"
"time" "time"
"tailscale.com/net/netaddr"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/types/netmap" "tailscale.com/types/netmap"
@ -126,7 +126,7 @@ func (h *Handle) EngineStatus() EngineStatus {
return h.engineStatusCache return h.engineStatusCache
} }
func (h *Handle) LocalAddrs() []netaddr.IPPrefix { func (h *Handle) LocalAddrs() []netip.Prefix {
h.mu.Lock() h.mu.Lock()
defer h.mu.Unlock() defer h.mu.Unlock()
@ -134,7 +134,7 @@ func (h *Handle) LocalAddrs() []netaddr.IPPrefix {
if nm != nil { if nm != nil {
return nm.Addresses return nm.Addresses
} }
return []netaddr.IPPrefix{} return []netip.Prefix{}
} }
func (h *Handle) NetMap() *netmap.NetworkMap { func (h *Handle) NetMap() *netmap.NetworkMap {

View File

@ -12,7 +12,6 @@
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/net/dns" "tailscale.com/net/dns"
"tailscale.com/net/netaddr"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/tstest" "tailscale.com/tstest"
"tailscale.com/types/dnstype" "tailscale.com/types/dnstype"
@ -21,7 +20,7 @@
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
) )
func ipps(ippStrs ...string) (ipps []netaddr.IPPrefix) { func ipps(ippStrs ...string) (ipps []netip.Prefix) {
for _, s := range ippStrs { for _, s := range ippStrs {
if ip, err := netip.ParseAddr(s); err == nil { if ip, err := netip.ParseAddr(s); err == nil {
ipps = append(ipps, netip.PrefixFrom(ip, ip.BitLen())) ipps = append(ipps, netip.PrefixFrom(ip, ip.BitLen()))
@ -32,7 +31,7 @@ func ipps(ippStrs ...string) (ipps []netaddr.IPPrefix) {
return return
} }
func ips(ss ...string) (ips []netaddr.IP) { func ips(ss ...string) (ips []netip.Addr) {
for _, s := range ss { for _, s := range ss {
ips = append(ips, netip.MustParseAddr(s)) ips = append(ips, netip.MustParseAddr(s))
} }
@ -55,7 +54,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
prefs: &ipn.Prefs{}, prefs: &ipn.Prefs{},
want: &dns.Config{ want: &dns.Config{
Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
Hosts: map[dnsname.FQDN][]netaddr.IP{}, Hosts: map[dnsname.FQDN][]netip.Addr{},
}, },
}, },
{ {
@ -81,7 +80,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
prefs: &ipn.Prefs{}, prefs: &ipn.Prefs{},
want: &dns.Config{ want: &dns.Config{
Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
Hosts: map[dnsname.FQDN][]netaddr.IP{ Hosts: map[dnsname.FQDN][]netip.Addr{
"b.net.": ips("100.102.0.1", "100.102.0.2"), "b.net.": ips("100.102.0.1", "100.102.0.2"),
"myname.net.": ips("100.101.101.101"), "myname.net.": ips("100.101.101.101"),
"peera.net.": ips("100.102.0.1", "100.102.0.2"), "peera.net.": ips("100.102.0.1", "100.102.0.2"),
@ -116,7 +115,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
want: &dns.Config{ want: &dns.Config{
OnlyIPv6: true, OnlyIPv6: true,
Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
Hosts: map[dnsname.FQDN][]netaddr.IP{ Hosts: map[dnsname.FQDN][]netip.Addr{
"b.net.": ips("fe75::2"), "b.net.": ips("fe75::2"),
"myname.net.": ips("fe75::1"), "myname.net.": ips("fe75::1"),
"peera.net.": ips("fe75::1001"), "peera.net.": ips("fe75::1001"),
@ -140,7 +139,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
prefs: &ipn.Prefs{}, prefs: &ipn.Prefs{},
want: &dns.Config{ want: &dns.Config{
Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
Hosts: map[dnsname.FQDN][]netaddr.IP{ Hosts: map[dnsname.FQDN][]netip.Addr{
"myname.net.": ips("100.101.101.101"), "myname.net.": ips("100.101.101.101"),
"foo.com.": ips("1.2.3.4"), "foo.com.": ips("1.2.3.4"),
"bar.com.": ips("1::6"), "bar.com.": ips("1::6"),
@ -160,7 +159,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
CorpDNS: true, CorpDNS: true,
}, },
want: &dns.Config{ want: &dns.Config{
Hosts: map[dnsname.FQDN][]netaddr.IP{}, Hosts: map[dnsname.FQDN][]netip.Addr{},
Routes: map[dnsname.FQDN][]*dnstype.Resolver{ Routes: map[dnsname.FQDN][]*dnstype.Resolver{
"0.e.1.a.c.5.1.1.a.7.d.f.ip6.arpa.": nil, "0.e.1.a.c.5.1.1.a.7.d.f.ip6.arpa.": nil,
"100.100.in-addr.arpa.": nil, "100.100.in-addr.arpa.": nil,
@ -260,7 +259,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
CorpDNS: true, CorpDNS: true,
}, },
want: &dns.Config{ want: &dns.Config{
Hosts: map[dnsname.FQDN][]netaddr.IP{}, Hosts: map[dnsname.FQDN][]netip.Addr{},
DefaultResolvers: []*dnstype.Resolver{ DefaultResolvers: []*dnstype.Resolver{
{Addr: "8.8.8.8"}, {Addr: "8.8.8.8"},
}, },
@ -283,7 +282,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
ExitNodeID: "some-id", ExitNodeID: "some-id",
}, },
want: &dns.Config{ want: &dns.Config{
Hosts: map[dnsname.FQDN][]netaddr.IP{}, Hosts: map[dnsname.FQDN][]netip.Addr{},
Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
DefaultResolvers: []*dnstype.Resolver{ DefaultResolvers: []*dnstype.Resolver{
{Addr: "8.8.4.4"}, {Addr: "8.8.4.4"},
@ -303,7 +302,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
CorpDNS: true, CorpDNS: true,
}, },
want: &dns.Config{ want: &dns.Config{
Hosts: map[dnsname.FQDN][]netaddr.IP{}, Hosts: map[dnsname.FQDN][]netip.Addr{},
Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
}, },
}, },

View File

@ -34,7 +34,6 @@
"tailscale.com/ipn/policy" "tailscale.com/ipn/policy"
"tailscale.com/net/dns" "tailscale.com/net/dns"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
"tailscale.com/net/netutil" "tailscale.com/net/netutil"
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
@ -130,7 +129,7 @@ type LocalBackend struct {
shutdownCalled bool // if Shutdown has been called shutdownCalled bool // if Shutdown has been called
filterAtomic atomic.Value // of *filter.Filter filterAtomic atomic.Value // of *filter.Filter
containsViaIPFuncAtomic atomic.Value // of func(netaddr.IP) bool containsViaIPFuncAtomic atomic.Value // of func(netip.Addr) bool
// The mutex protects the following elements. // The mutex protects the following elements.
mu sync.Mutex mu sync.Mutex
@ -152,7 +151,7 @@ type LocalBackend struct {
hostinfo *tailcfg.Hostinfo hostinfo *tailcfg.Hostinfo
// netMap is not mutated in-place once set. // netMap is not mutated in-place once set.
netMap *netmap.NetworkMap netMap *netmap.NetworkMap
nodeByAddr map[netaddr.IP]*tailcfg.Node nodeByAddr map[netip.Addr]*tailcfg.Node
activeLogin string // last logged LoginName from netMap activeLogin string // last logged LoginName from netMap
engineStatus ipn.EngineStatus engineStatus ipn.EngineStatus
endpoints []tailcfg.Endpoint endpoints []tailcfg.Endpoint
@ -498,13 +497,13 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
if p.LastSeen != nil { if p.LastSeen != nil {
lastSeen = *p.LastSeen lastSeen = *p.LastSeen
} }
var tailscaleIPs = make([]netaddr.IP, 0, len(p.Addresses)) var tailscaleIPs = make([]netip.Addr, 0, len(p.Addresses))
for _, addr := range p.Addresses { for _, addr := range p.Addresses {
if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.Addr()) { if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.Addr()) {
tailscaleIPs = append(tailscaleIPs, addr.Addr()) tailscaleIPs = append(tailscaleIPs, addr.Addr())
} }
} }
exitNodeOption := tsaddr.PrefixesContainsFunc(p.AllowedIPs, func(r netaddr.IPPrefix) bool { exitNodeOption := tsaddr.PrefixesContainsFunc(p.AllowedIPs, func(r netip.Prefix) bool {
return r.Bits() == 0 return r.Bits() == 0
}) })
var tags *views.Slice[string] var tags *views.Slice[string]
@ -542,12 +541,12 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
// WhoIs reports the node and user who owns the node with the given IP:port. // WhoIs reports the node and user who owns the node with the given IP:port.
// If the IP address is a Tailscale IP, the provided port may be 0. // If the IP address is a Tailscale IP, the provided port may be 0.
// If ok == true, n and u are valid. // If ok == true, n and u are valid.
func (b *LocalBackend) WhoIs(ipp netaddr.IPPort) (n *tailcfg.Node, u tailcfg.UserProfile, ok bool) { func (b *LocalBackend) WhoIs(ipp netip.AddrPort) (n *tailcfg.Node, u tailcfg.UserProfile, ok bool) {
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()
n, ok = b.nodeByAddr[ipp.Addr()] n, ok = b.nodeByAddr[ipp.Addr()]
if !ok { if !ok {
var ip netaddr.IP var ip netip.Addr
if ipp.Port() != 0 { if ipp.Port() != 0 {
ip, ok = b.e.WhoIsIPPort(ipp) ip, ok = b.e.WhoIsIPPort(ipp)
} }
@ -568,7 +567,7 @@ func (b *LocalBackend) WhoIs(ipp netaddr.IPPort) (n *tailcfg.Node, u tailcfg.Use
// PeerCaps returns the capabilities that remote src IP has to // PeerCaps returns the capabilities that remote src IP has to
// ths current node. // ths current node.
func (b *LocalBackend) PeerCaps(src netaddr.IP) []string { func (b *LocalBackend) PeerCaps(src netip.Addr) []string {
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()
if b.netMap == nil { if b.netMap == nil {
@ -770,7 +769,7 @@ func (b *LocalBackend) findExitNodeIDLocked(nm *netmap.NetworkMap) (prefsChanged
// Found the node being referenced, upgrade prefs to // Found the node being referenced, upgrade prefs to
// reference it directly for next time. // reference it directly for next time.
b.prefs.ExitNodeID = peer.StableID b.prefs.ExitNodeID = peer.StableID
b.prefs.ExitNodeIP = netaddr.IP{} b.prefs.ExitNodeIP = netip.Addr{}
return true return true
} }
} }
@ -1123,7 +1122,7 @@ func (b *LocalBackend) updateFilterLocked(netMap *netmap.NetworkMap, prefs *ipn.
// quite hard to debug, so save yourself the trouble. // quite hard to debug, so save yourself the trouble.
var ( var (
haveNetmap = netMap != nil haveNetmap = netMap != nil
addrs []netaddr.IPPrefix addrs []netip.Prefix
packetFilter []filter.Match packetFilter []filter.Match
localNetsB netipx.IPSetBuilder localNetsB netipx.IPSetBuilder
logNetsB netipx.IPSetBuilder logNetsB netipx.IPSetBuilder
@ -1206,7 +1205,7 @@ func (b *LocalBackend) setFilter(f *filter.Filter) {
b.e.SetFilter(f) b.e.SetFilter(f)
} }
var removeFromDefaultRoute = []netaddr.IPPrefix{ var removeFromDefaultRoute = []netip.Prefix{
// RFC1918 LAN ranges // RFC1918 LAN ranges
netip.MustParsePrefix("192.168.0.0/16"), netip.MustParsePrefix("192.168.0.0/16"),
netip.MustParsePrefix("172.16.0.0/12"), netip.MustParsePrefix("172.16.0.0/12"),
@ -1232,7 +1231,7 @@ func (b *LocalBackend) setFilter(f *filter.Filter) {
// //
// Given that "internal" routes don't leave the device, we choose to // Given that "internal" routes don't leave the device, we choose to
// trust them more, allowing access to them when an Exit Node is enabled. // trust them more, allowing access to them when an Exit Node is enabled.
func internalAndExternalInterfaces() (internal, external []netaddr.IPPrefix, err error) { func internalAndExternalInterfaces() (internal, external []netip.Prefix, err error) {
il, err := interfaces.GetList() il, err := interfaces.GetList()
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -1240,11 +1239,11 @@ func internalAndExternalInterfaces() (internal, external []netaddr.IPPrefix, err
return internalAndExternalInterfacesFrom(il, runtime.GOOS) return internalAndExternalInterfacesFrom(il, runtime.GOOS)
} }
func internalAndExternalInterfacesFrom(il interfaces.List, goos string) (internal, external []netaddr.IPPrefix, err error) { func internalAndExternalInterfacesFrom(il interfaces.List, goos string) (internal, external []netip.Prefix, err error) {
// We use an IPSetBuilder here to canonicalize the prefixes // We use an IPSetBuilder here to canonicalize the prefixes
// and to remove any duplicate entries. // and to remove any duplicate entries.
var internalBuilder, externalBuilder netipx.IPSetBuilder var internalBuilder, externalBuilder netipx.IPSetBuilder
if err := il.ForeachInterfaceAddress(func(iface interfaces.Interface, pfx netaddr.IPPrefix) { if err := il.ForeachInterfaceAddress(func(iface interfaces.Interface, pfx netip.Prefix) {
if tsaddr.IsTailscaleIP(pfx.Addr()) { if tsaddr.IsTailscaleIP(pfx.Addr()) {
return return
} }
@ -1286,9 +1285,9 @@ func internalAndExternalInterfacesFrom(il interfaces.List, goos string) (interna
return iSet.Prefixes(), eSet.Prefixes(), nil return iSet.Prefixes(), eSet.Prefixes(), nil
} }
func interfaceRoutes() (ips *netipx.IPSet, hostIPs []netaddr.IP, err error) { func interfaceRoutes() (ips *netipx.IPSet, hostIPs []netip.Addr, err error) {
var b netipx.IPSetBuilder var b netipx.IPSetBuilder
if err := interfaces.ForeachInterfaceAddress(func(_ interfaces.Interface, pfx netaddr.IPPrefix) { if err := interfaces.ForeachInterfaceAddress(func(_ interfaces.Interface, pfx netip.Prefix) {
if tsaddr.IsTailscaleIP(pfx.Addr()) { if tsaddr.IsTailscaleIP(pfx.Addr()) {
return return
} }
@ -1308,7 +1307,7 @@ func interfaceRoutes() (ips *netipx.IPSet, hostIPs []netaddr.IP, err error) {
// shrinkDefaultRoute returns an IPSet representing the IPs in route, // shrinkDefaultRoute returns an IPSet representing the IPs in route,
// minus those in removeFromDefaultRoute and localInterfaceRoutes, // minus those in removeFromDefaultRoute and localInterfaceRoutes,
// plus the IPs in hostIPs. // plus the IPs in hostIPs.
func shrinkDefaultRoute(route netaddr.IPPrefix, localInterfaceRoutes *netipx.IPSet, hostIPs []netaddr.IP) (*netipx.IPSet, error) { func shrinkDefaultRoute(route netip.Prefix, localInterfaceRoutes *netipx.IPSet, hostIPs []netip.Addr) (*netipx.IPSet, error) {
var b netipx.IPSetBuilder var b netipx.IPSetBuilder
// Add the default route. // Add the default route.
b.AddPrefix(route) b.AddPrefix(route)
@ -1335,7 +1334,7 @@ func shrinkDefaultRoute(route netaddr.IPPrefix, localInterfaceRoutes *netipx.IPS
// dnsCIDRsEqual determines whether two CIDR lists are equal // dnsCIDRsEqual determines whether two CIDR lists are equal
// for DNS map construction purposes (that is, only the first entry counts). // for DNS map construction purposes (that is, only the first entry counts).
func dnsCIDRsEqual(newAddr, oldAddr []netaddr.IPPrefix) bool { func dnsCIDRsEqual(newAddr, oldAddr []netip.Prefix) bool {
if len(newAddr) != len(oldAddr) { if len(newAddr) != len(oldAddr) {
return false return false
} }
@ -1733,7 +1732,7 @@ func (b *LocalBackend) StartLoginInteractive() {
} }
} }
func (b *LocalBackend) Ping(ctx context.Context, ip netaddr.IP, pingType tailcfg.PingType) (*ipnstate.PingResult, error) { func (b *LocalBackend) Ping(ctx context.Context, ip netip.Addr, pingType tailcfg.PingType) (*ipnstate.PingResult, error) {
if pingType == tailcfg.PingPeerAPI { if pingType == tailcfg.PingPeerAPI {
t0 := time.Now() t0 := time.Now()
node, base, err := b.pingPeerAPI(ctx, ip) node, base, err := b.pingPeerAPI(ctx, ip)
@ -1770,7 +1769,7 @@ func (b *LocalBackend) Ping(ctx context.Context, ip netaddr.IP, pingType tailcfg
} }
} }
func (b *LocalBackend) pingPeerAPI(ctx context.Context, ip netaddr.IP) (peer *tailcfg.Node, peerBase string, err error) { func (b *LocalBackend) pingPeerAPI(ctx context.Context, ip netip.Addr) (peer *tailcfg.Node, peerBase string, err error) {
ctx, cancel := context.WithTimeout(ctx, 10*time.Second) ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel() defer cancel()
nm := b.NetMap() nm := b.NetMap()
@ -2069,7 +2068,7 @@ func (b *LocalBackend) setPrefsLockedOnEntry(caller string, newp *ipn.Prefs) {
// GetPeerAPIPort returns the port number for the peerapi server // GetPeerAPIPort returns the port number for the peerapi server
// running on the provided IP. // running on the provided IP.
func (b *LocalBackend) GetPeerAPIPort(ip netaddr.IP) (port uint16, ok bool) { func (b *LocalBackend) GetPeerAPIPort(ip netip.Addr) (port uint16, ok bool) {
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()
for _, pln := range b.peerAPIListeners { for _, pln := range b.peerAPIListeners {
@ -2087,7 +2086,7 @@ func (b *LocalBackend) GetPeerAPIPort(ip netaddr.IP) (port uint16, ok bool) {
// or IPv6 IP and the peerapi port for that address). // or IPv6 IP and the peerapi port for that address).
// //
// The connection will be closed by ServePeerAPIConnection. // The connection will be closed by ServePeerAPIConnection.
func (b *LocalBackend) ServePeerAPIConnection(remote, local netaddr.IPPort, c net.Conn) { func (b *LocalBackend) ServePeerAPIConnection(remote, local netip.AddrPort, c net.Conn) {
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()
for _, pln := range b.peerAPIListeners { for _, pln := range b.peerAPIListeners {
@ -2289,7 +2288,7 @@ func shouldUseOneCGNATRoute(nm *netmap.NetworkMap, logf logger.Logf, versionOS s
func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Logf, versionOS string) *dns.Config { func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Logf, versionOS string) *dns.Config {
dcfg := &dns.Config{ dcfg := &dns.Config{
Routes: map[dnsname.FQDN][]*dnstype.Resolver{}, Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
Hosts: map[dnsname.FQDN][]netaddr.IP{}, Hosts: map[dnsname.FQDN][]netip.Addr{},
} }
// selfV6Only is whether we only have IPv6 addresses ourselves. // selfV6Only is whether we only have IPv6 addresses ourselves.
@ -2302,7 +2301,7 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Log
// isn't configured to make MagicDNS resolution truly // isn't configured to make MagicDNS resolution truly
// magic. Details in // magic. Details in
// https://github.com/tailscale/tailscale/issues/1886. // https://github.com/tailscale/tailscale/issues/1886.
set := func(name string, addrs []netaddr.IPPrefix) { set := func(name string, addrs []netip.Prefix) {
if len(addrs) == 0 || name == "" { if len(addrs) == 0 || name == "" {
return return
} }
@ -2311,7 +2310,7 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Log
return // TODO: propagate error? return // TODO: propagate error?
} }
have4 := tsaddr.PrefixesContainsFunc(addrs, tsaddr.PrefixIs4) have4 := tsaddr.PrefixesContainsFunc(addrs, tsaddr.PrefixIs4)
var ips []netaddr.IP var ips []netip.Addr
for _, addr := range addrs { for _, addr := range addrs {
if selfV6Only { if selfV6Only {
if addr.Addr().Is6() { if addr.Addr().Is6() {
@ -2629,11 +2628,11 @@ func magicDNSRootDomains(nm *netmap.NetworkMap) []dnsname.FQDN {
// peerRoutes returns the routerConfig.Routes to access peers. // peerRoutes returns the routerConfig.Routes to access peers.
// If there are over cgnatThreshold CGNAT routes, one big CGNAT route // If there are over cgnatThreshold CGNAT routes, one big CGNAT route
// is used instead. // is used instead.
func peerRoutes(peers []wgcfg.Peer, cgnatThreshold int) (routes []netaddr.IPPrefix) { func peerRoutes(peers []wgcfg.Peer, cgnatThreshold int) (routes []netip.Prefix) {
tsULA := tsaddr.TailscaleULARange() tsULA := tsaddr.TailscaleULARange()
cgNAT := tsaddr.CGNATRange() cgNAT := tsaddr.CGNATRange()
var didULA bool var didULA bool
var cgNATIPs []netaddr.IPPrefix var cgNATIPs []netip.Prefix
for _, peer := range peers { for _, peer := range peers {
for _, aip := range peer.AllowedIPs { for _, aip := range peer.AllowedIPs {
aip = unmapIPPrefix(aip) aip = unmapIPPrefix(aip)
@ -2665,7 +2664,7 @@ func peerRoutes(peers []wgcfg.Peer, cgnatThreshold int) (routes []netaddr.IPPref
return routes return routes
} }
func ipPrefixLess(ri, rj netaddr.IPPrefix) bool { func ipPrefixLess(ri, rj netip.Prefix) bool {
if ri.Addr() == rj.Addr() { if ri.Addr() == rj.Addr() {
return ri.Bits() < rj.Bits() return ri.Bits() < rj.Bits()
} }
@ -2736,17 +2735,17 @@ func (b *LocalBackend) routerConfig(cfg *wgcfg.Config, prefs *ipn.Prefs, oneCGNA
} }
if tsaddr.PrefixesContainsFunc(rs.LocalAddrs, tsaddr.PrefixIs4) { if tsaddr.PrefixesContainsFunc(rs.LocalAddrs, tsaddr.PrefixIs4) {
rs.Routes = append(rs.Routes, netaddr.IPPrefixFrom(tsaddr.TailscaleServiceIP(), 32)) rs.Routes = append(rs.Routes, netip.PrefixFrom(tsaddr.TailscaleServiceIP(), 32))
} }
return rs return rs
} }
func unmapIPPrefix(ipp netaddr.IPPrefix) netaddr.IPPrefix { func unmapIPPrefix(ipp netip.Prefix) netip.Prefix {
return netip.PrefixFrom(ipp.Addr().Unmap(), ipp.Bits()) return netip.PrefixFrom(ipp.Addr().Unmap(), ipp.Bits())
} }
func unmapIPPrefixes(ippsList ...[]netaddr.IPPrefix) (ret []netaddr.IPPrefix) { func unmapIPPrefixes(ippsList ...[]netip.Prefix) (ret []netip.Prefix) {
for _, ipps := range ippsList { for _, ipps := range ippsList {
for _, ipp := range ipps { for _, ipp := range ipps {
ret = append(ret, unmapIPPrefix(ipp)) ret = append(ret, unmapIPPrefix(ipp))
@ -2989,8 +2988,8 @@ func (b *LocalBackend) ShouldRunSSH() bool { return b.sshAtomicBool.Get() && can
// ShouldHandleViaIP reports whether whether ip is an IPv6 address in the // ShouldHandleViaIP reports whether whether ip is an IPv6 address in the
// Tailscale ULA's v6 "via" range embedding an IPv4 address to be forwarded to // Tailscale ULA's v6 "via" range embedding an IPv4 address to be forwarded to
// by Tailscale. // by Tailscale.
func (b *LocalBackend) ShouldHandleViaIP(ip netaddr.IP) bool { func (b *LocalBackend) ShouldHandleViaIP(ip netip.Addr) bool {
if f, ok := b.containsViaIPFuncAtomic.Load().(func(netaddr.IP) bool); ok { if f, ok := b.containsViaIPFuncAtomic.Load().(func(netip.Addr) bool); ok {
return f(ip) return f(ip)
} }
return false return false
@ -3107,7 +3106,7 @@ func (b *LocalBackend) setNetMapLocked(nm *netmap.NetworkMap) {
// Update the nodeByAddr index. // Update the nodeByAddr index.
if b.nodeByAddr == nil { if b.nodeByAddr == nil {
b.nodeByAddr = map[netaddr.IP]*tailcfg.Node{} b.nodeByAddr = map[netip.Addr]*tailcfg.Node{}
} }
// First pass, mark everything unwanted. // First pass, mark everything unwanted.
for k := range b.nodeByAddr { for k := range b.nodeByAddr {
@ -3313,12 +3312,12 @@ func peerAPIBase(nm *netmap.NetworkMap, peer *tailcfg.Node) string {
p6 = s.Port p6 = s.Port
} }
} }
var ipp netaddr.IPPort var ipp netip.AddrPort
switch { switch {
case have4 && p4 != 0: case have4 && p4 != 0:
ipp = netaddr.IPPortFrom(nodeIP(peer, netaddr.IP.Is4), p4) ipp = netip.AddrPortFrom(nodeIP(peer, netip.Addr.Is4), p4)
case have6 && p6 != 0: case have6 && p6 != 0:
ipp = netaddr.IPPortFrom(nodeIP(peer, netaddr.IP.Is6), p6) ipp = netip.AddrPortFrom(nodeIP(peer, netip.Addr.Is6), p6)
} }
if !ipp.Addr().IsValid() { if !ipp.Addr().IsValid() {
return "" return ""
@ -3326,13 +3325,13 @@ func peerAPIBase(nm *netmap.NetworkMap, peer *tailcfg.Node) string {
return fmt.Sprintf("http://%v", ipp) return fmt.Sprintf("http://%v", ipp)
} }
func nodeIP(n *tailcfg.Node, pred func(netaddr.IP) bool) netaddr.IP { func nodeIP(n *tailcfg.Node, pred func(netip.Addr) bool) netip.Addr {
for _, a := range n.Addresses { for _, a := range n.Addresses {
if a.IsSingleIP() && pred(a.Addr()) { if a.IsSingleIP() && pred(a.Addr()) {
return a.Addr() return a.Addr()
} }
} }
return netaddr.IP{} return netip.Addr{}
} }
func (b *LocalBackend) CheckIPForwarding() error { func (b *LocalBackend) CheckIPForwarding() error {

View File

@ -17,7 +17,6 @@
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/ipn/store/mem" "tailscale.com/ipn/store/mem"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/logger" "tailscale.com/types/logger"
@ -31,13 +30,13 @@ func TestNetworkMapCompare(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
node1 := &tailcfg.Node{Addresses: []netaddr.IPPrefix{prefix1}} node1 := &tailcfg.Node{Addresses: []netip.Prefix{prefix1}}
prefix2, err := netip.ParsePrefix("10.0.0.0/8") prefix2, err := netip.ParsePrefix("10.0.0.0/8")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
node2 := &tailcfg.Node{Addresses: []netaddr.IPPrefix{prefix2}} node2 := &tailcfg.Node{Addresses: []netip.Prefix{prefix2}}
tests := []struct { tests := []struct {
name string name string
@ -133,7 +132,7 @@ func TestNetworkMapCompare(t *testing.T) {
} }
} }
func inRemove(ip netaddr.IP) bool { func inRemove(ip netip.Addr) bool {
for _, pfx := range removeFromDefaultRoute { for _, pfx := range removeFromDefaultRoute {
if pfx.Contains(ip) { if pfx.Contains(ip) {
return true return true
@ -147,7 +146,7 @@ func TestShrinkDefaultRoute(t *testing.T) {
route string route string
in []string in []string
out []string out []string
localIPFn func(netaddr.IP) bool // true if this machine's local IP address should be "in" after shrinking. localIPFn func(netip.Addr) bool // true if this machine's local IP address should be "in" after shrinking.
}{ }{
{ {
route: "0.0.0.0/0", route: "0.0.0.0/0",
@ -167,7 +166,7 @@ func TestShrinkDefaultRoute(t *testing.T) {
"fe80::", "fe80::",
"2601::1", "2601::1",
}, },
localIPFn: func(ip netaddr.IP) bool { return !inRemove(ip) && ip.Is4() }, localIPFn: func(ip netip.Addr) bool { return !inRemove(ip) && ip.Is4() },
}, },
{ {
route: "::/0", route: "::/0",
@ -177,7 +176,7 @@ func TestShrinkDefaultRoute(t *testing.T) {
"ff00::1", "ff00::1",
tsaddr.TailscaleULARange().Addr().String(), tsaddr.TailscaleULARange().Addr().String(),
}, },
localIPFn: func(ip netaddr.IP) bool { return !inRemove(ip) && ip.Is6() }, localIPFn: func(ip netip.Addr) bool { return !inRemove(ip) && ip.Is6() },
}, },
} }
@ -193,13 +192,13 @@ func TestShrinkDefaultRoute(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
hostIPs := []netaddr.IP{ hostIPs := []netip.Addr{
netip.MustParseAddr("127.0.0.1"), netip.MustParseAddr("127.0.0.1"),
netip.MustParseAddr("192.168.9.39"), netip.MustParseAddr("192.168.9.39"),
netip.MustParseAddr("fe80::1"), netip.MustParseAddr("fe80::1"),
netip.MustParseAddr("fe80::437d:feff:feca:49a7"), netip.MustParseAddr("fe80::437d:feff:feca:49a7"),
} }
localAddresses := []netaddr.IP{ localAddresses := []netip.Addr{
netip.MustParseAddr("192.168.9.39"), netip.MustParseAddr("192.168.9.39"),
} }
@ -233,18 +232,18 @@ func TestPeerRoutes(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
peers []wgcfg.Peer peers []wgcfg.Peer
want []netaddr.IPPrefix want []netip.Prefix
}{ }{
{ {
name: "small_v4", name: "small_v4",
peers: []wgcfg.Peer{ peers: []wgcfg.Peer{
{ {
AllowedIPs: []netaddr.IPPrefix{ AllowedIPs: []netip.Prefix{
pp("100.101.102.103/32"), pp("100.101.102.103/32"),
}, },
}, },
}, },
want: []netaddr.IPPrefix{ want: []netip.Prefix{
pp("100.101.102.103/32"), pp("100.101.102.103/32"),
}, },
}, },
@ -252,14 +251,14 @@ func TestPeerRoutes(t *testing.T) {
name: "big_v4", name: "big_v4",
peers: []wgcfg.Peer{ peers: []wgcfg.Peer{
{ {
AllowedIPs: []netaddr.IPPrefix{ AllowedIPs: []netip.Prefix{
pp("100.101.102.103/32"), pp("100.101.102.103/32"),
pp("100.101.102.104/32"), pp("100.101.102.104/32"),
pp("100.101.102.105/32"), pp("100.101.102.105/32"),
}, },
}, },
}, },
want: []netaddr.IPPrefix{ want: []netip.Prefix{
pp("100.64.0.0/10"), pp("100.64.0.0/10"),
}, },
}, },
@ -267,12 +266,12 @@ func TestPeerRoutes(t *testing.T) {
name: "has_1_v6", name: "has_1_v6",
peers: []wgcfg.Peer{ peers: []wgcfg.Peer{
{ {
AllowedIPs: []netaddr.IPPrefix{ AllowedIPs: []netip.Prefix{
pp("fd7a:115c:a1e0:ab12:4843:cd96:6258:b240/128"), pp("fd7a:115c:a1e0:ab12:4843:cd96:6258:b240/128"),
}, },
}, },
}, },
want: []netaddr.IPPrefix{ want: []netip.Prefix{
pp("fd7a:115c:a1e0::/48"), pp("fd7a:115c:a1e0::/48"),
}, },
}, },
@ -280,13 +279,13 @@ func TestPeerRoutes(t *testing.T) {
name: "has_2_v6", name: "has_2_v6",
peers: []wgcfg.Peer{ peers: []wgcfg.Peer{
{ {
AllowedIPs: []netaddr.IPPrefix{ AllowedIPs: []netip.Prefix{
pp("fd7a:115c:a1e0:ab12:4843:cd96:6258:b240/128"), pp("fd7a:115c:a1e0:ab12:4843:cd96:6258:b240/128"),
pp("fd7a:115c:a1e0:ab12:4843:cd96:6258:b241/128"), pp("fd7a:115c:a1e0:ab12:4843:cd96:6258:b241/128"),
}, },
}, },
}, },
want: []netaddr.IPPrefix{ want: []netip.Prefix{
pp("fd7a:115c:a1e0::/48"), pp("fd7a:115c:a1e0::/48"),
}, },
}, },
@ -294,7 +293,7 @@ func TestPeerRoutes(t *testing.T) {
name: "big_v4_big_v6", name: "big_v4_big_v6",
peers: []wgcfg.Peer{ peers: []wgcfg.Peer{
{ {
AllowedIPs: []netaddr.IPPrefix{ AllowedIPs: []netip.Prefix{
pp("100.101.102.103/32"), pp("100.101.102.103/32"),
pp("100.101.102.104/32"), pp("100.101.102.104/32"),
pp("100.101.102.105/32"), pp("100.101.102.105/32"),
@ -303,7 +302,7 @@ func TestPeerRoutes(t *testing.T) {
}, },
}, },
}, },
want: []netaddr.IPPrefix{ want: []netip.Prefix{
pp("100.64.0.0/10"), pp("100.64.0.0/10"),
pp("fd7a:115c:a1e0::/48"), pp("fd7a:115c:a1e0::/48"),
}, },
@ -312,19 +311,19 @@ func TestPeerRoutes(t *testing.T) {
name: "output-should-be-sorted", name: "output-should-be-sorted",
peers: []wgcfg.Peer{ peers: []wgcfg.Peer{
{ {
AllowedIPs: []netaddr.IPPrefix{ AllowedIPs: []netip.Prefix{
pp("100.64.0.2/32"), pp("100.64.0.2/32"),
pp("10.0.0.0/16"), pp("10.0.0.0/16"),
}, },
}, },
{ {
AllowedIPs: []netaddr.IPPrefix{ AllowedIPs: []netip.Prefix{
pp("100.64.0.1/32"), pp("100.64.0.1/32"),
pp("10.0.0.0/8"), pp("10.0.0.0/8"),
}, },
}, },
}, },
want: []netaddr.IPPrefix{ want: []netip.Prefix{
pp("10.0.0.0/8"), pp("10.0.0.0/8"),
pp("10.0.0.0/16"), pp("10.0.0.0/16"),
pp("100.64.0.1/32"), pp("100.64.0.1/32"),
@ -363,12 +362,12 @@ func TestPeerAPIBase(t *testing.T) {
{ {
name: "self_only_4_them_both", name: "self_only_4_them_both",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
netip.MustParsePrefix("100.64.1.1/32"), netip.MustParsePrefix("100.64.1.1/32"),
}, },
}, },
peer: &tailcfg.Node{ peer: &tailcfg.Node{
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
netip.MustParsePrefix("100.64.1.2/32"), netip.MustParsePrefix("100.64.1.2/32"),
netip.MustParsePrefix("fe70::2/128"), netip.MustParsePrefix("fe70::2/128"),
}, },
@ -384,12 +383,12 @@ func TestPeerAPIBase(t *testing.T) {
{ {
name: "self_only_6_them_both", name: "self_only_6_them_both",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
netip.MustParsePrefix("fe70::1/128"), netip.MustParsePrefix("fe70::1/128"),
}, },
}, },
peer: &tailcfg.Node{ peer: &tailcfg.Node{
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
netip.MustParsePrefix("100.64.1.2/32"), netip.MustParsePrefix("100.64.1.2/32"),
netip.MustParsePrefix("fe70::2/128"), netip.MustParsePrefix("fe70::2/128"),
}, },
@ -405,13 +404,13 @@ func TestPeerAPIBase(t *testing.T) {
{ {
name: "self_both_them_only_4", name: "self_both_them_only_4",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
netip.MustParsePrefix("100.64.1.1/32"), netip.MustParsePrefix("100.64.1.1/32"),
netip.MustParsePrefix("fe70::1/128"), netip.MustParsePrefix("fe70::1/128"),
}, },
}, },
peer: &tailcfg.Node{ peer: &tailcfg.Node{
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
netip.MustParsePrefix("100.64.1.2/32"), netip.MustParsePrefix("100.64.1.2/32"),
netip.MustParsePrefix("fe70::2/128"), netip.MustParsePrefix("fe70::2/128"),
}, },
@ -426,13 +425,13 @@ func TestPeerAPIBase(t *testing.T) {
{ {
name: "self_both_them_only_6", name: "self_both_them_only_6",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
netip.MustParsePrefix("100.64.1.1/32"), netip.MustParsePrefix("100.64.1.1/32"),
netip.MustParsePrefix("fe70::1/128"), netip.MustParsePrefix("fe70::1/128"),
}, },
}, },
peer: &tailcfg.Node{ peer: &tailcfg.Node{
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
netip.MustParsePrefix("100.64.1.2/32"), netip.MustParsePrefix("100.64.1.2/32"),
netip.MustParsePrefix("fe70::2/128"), netip.MustParsePrefix("fe70::2/128"),
}, },
@ -447,13 +446,13 @@ func TestPeerAPIBase(t *testing.T) {
{ {
name: "self_both_them_no_peerapi_service", name: "self_both_them_no_peerapi_service",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
netip.MustParsePrefix("100.64.1.1/32"), netip.MustParsePrefix("100.64.1.1/32"),
netip.MustParsePrefix("fe70::1/128"), netip.MustParsePrefix("fe70::1/128"),
}, },
}, },
peer: &tailcfg.Node{ peer: &tailcfg.Node{
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
netip.MustParsePrefix("100.64.1.2/32"), netip.MustParsePrefix("100.64.1.2/32"),
netip.MustParsePrefix("fe70::2/128"), netip.MustParsePrefix("fe70::2/128"),
}, },
@ -543,10 +542,10 @@ func TestFileTargets(t *testing.T) {
func TestInternalAndExternalInterfaces(t *testing.T) { func TestInternalAndExternalInterfaces(t *testing.T) {
type interfacePrefix struct { type interfacePrefix struct {
i interfaces.Interface i interfaces.Interface
pfx netaddr.IPPrefix pfx netip.Prefix
} }
masked := func(ips ...interfacePrefix) (pfxs []netaddr.IPPrefix) { masked := func(ips ...interfacePrefix) (pfxs []netip.Prefix) {
for _, ip := range ips { for _, ip := range ips {
pfxs = append(pfxs, ip.pfx.Masked()) pfxs = append(pfxs, ip.pfx.Masked())
} }
@ -585,8 +584,8 @@ type interfacePrefix struct {
name string name string
goos string goos string
il interfaces.List il interfaces.List
wantInt []netaddr.IPPrefix wantInt []netip.Prefix
wantExt []netaddr.IPPrefix wantExt []netip.Prefix
}{ }{
{ {
name: "single-interface", name: "single-interface",

View File

@ -48,7 +48,7 @@
"tailscale.com/wgengine/filter" "tailscale.com/wgengine/filter"
) )
var initListenConfig func(*net.ListenConfig, netaddr.IP, *interfaces.State, string) error var initListenConfig func(*net.ListenConfig, netip.Addr, *interfaces.State, string) error
// addH2C is non-nil on platforms where we want to add H2C // addH2C is non-nil on platforms where we want to add H2C
// ("cleartext" HTTP/2) support to the peerAPI. // ("cleartext" HTTP/2) support to the peerAPI.
@ -387,7 +387,7 @@ func (s *peerAPIServer) OpenFile(baseName string) (rc io.ReadCloser, size int64,
return f, fi.Size(), nil return f, fi.Size(), nil
} }
func (s *peerAPIServer) listen(ip netaddr.IP, ifState *interfaces.State) (ln net.Listener, err error) { func (s *peerAPIServer) listen(ip netip.Addr, ifState *interfaces.State) (ln net.Listener, err error) {
// Android for whatever reason often has problems creating the peerapi listener. // Android for whatever reason often has problems creating the peerapi listener.
// But since we started intercepting it with netstack, it's not even important that // But since we started intercepting it with netstack, it's not even important that
// we have a real kernel-level listener. So just create a dummy listener on Android // we have a real kernel-level listener. So just create a dummy listener on Android
@ -451,7 +451,7 @@ func (s *peerAPIServer) listen(ip netaddr.IP, ifState *interfaces.State) (ln net
type peerAPIListener struct { type peerAPIListener struct {
ps *peerAPIServer ps *peerAPIServer
ip netaddr.IP ip netip.Addr
lb *LocalBackend lb *LocalBackend
// ln is the Listener. It can be nil in netstack mode if there are more than // ln is the Listener. It can be nil in netstack mode if there are more than
@ -503,7 +503,7 @@ func (pln *peerAPIListener) serve() {
} }
} }
func (pln *peerAPIListener) ServeConn(src netaddr.IPPort, c net.Conn) { func (pln *peerAPIListener) ServeConn(src netip.AddrPort, c net.Conn) {
logf := pln.lb.logf logf := pln.lb.logf
peerNode, peerUser, ok := pln.lb.WhoIs(src) peerNode, peerUser, ok := pln.lb.WhoIs(src)
if !ok { if !ok {
@ -530,7 +530,7 @@ func (pln *peerAPIListener) ServeConn(src netaddr.IPPort, c net.Conn) {
// peerAPIHandler serves the Peer API for a source specific client. // peerAPIHandler serves the Peer API for a source specific client.
type peerAPIHandler struct { type peerAPIHandler struct {
ps *peerAPIServer ps *peerAPIServer
remoteAddr netaddr.IPPort remoteAddr netip.AddrPort
isSelf bool // whether peerNode is owned by same user as this node isSelf bool // whether peerNode is owned by same user as this node
peerNode *tailcfg.Node // peerNode is who's making the request peerNode *tailcfg.Node // peerNode is who's making the request
peerUser tailcfg.UserProfile // profile of peerNode peerUser tailcfg.UserProfile // profile of peerNode
@ -609,7 +609,7 @@ func (h *peerAPIHandler) handleServeInterfaces(w http.ResponseWriter, r *http.Re
fmt.Fprintf(w, "<th>%v</th> ", v) fmt.Fprintf(w, "<th>%v</th> ", v)
} }
fmt.Fprint(w, "</tr>\n") fmt.Fprint(w, "</tr>\n")
i.ForeachInterface(func(iface interfaces.Interface, ipps []netaddr.IPPrefix) { i.ForeachInterface(func(iface interfaces.Interface, ipps []netip.Prefix) {
fmt.Fprint(w, "<tr>") fmt.Fprint(w, "<tr>")
for _, v := range []any{iface.Index, iface.Name, iface.MTU, iface.Flags, ipps} { for _, v := range []any{iface.Index, iface.Name, iface.MTU, iface.Flags, ipps} {
fmt.Fprintf(w, "<td>%v</td> ", v) fmt.Fprintf(w, "<td>%v</td> ", v)
@ -1169,9 +1169,9 @@ func writePrettyDNSReply(w io.Writer, res []byte) (err error) {
// it's listening on the provided IP address and on TCP port 1. // it's listening on the provided IP address and on TCP port 1.
// //
// See docs on fakePeerAPIListener. // See docs on fakePeerAPIListener.
func newFakePeerAPIListener(ip netaddr.IP) net.Listener { func newFakePeerAPIListener(ip netip.Addr) net.Listener {
return &fakePeerAPIListener{ return &fakePeerAPIListener{
addr: net.TCPAddrFromAddrPort(netaddr.IPPortFrom(ip, 1)), addr: net.TCPAddrFromAddrPort(netip.AddrPortFrom(ip, 1)),
closed: make(chan struct{}), closed: make(chan struct{}),
} }
} }

View File

@ -11,9 +11,9 @@
import ( import (
"fmt" "fmt"
"net" "net"
"net/netip"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
"tailscale.com/net/netns" "tailscale.com/net/netns"
) )
@ -24,7 +24,7 @@ func init() {
// initListenConfigNetworkExtension configures nc for listening on IP // initListenConfigNetworkExtension configures nc for listening on IP
// through the iOS/macOS Network/System Extension (Packet Tunnel // through the iOS/macOS Network/System Extension (Packet Tunnel
// Provider) sandbox. // Provider) sandbox.
func initListenConfigNetworkExtension(nc *net.ListenConfig, ip netaddr.IP, st *interfaces.State, tunIfName string) error { func initListenConfigNetworkExtension(nc *net.ListenConfig, ip netip.Addr, st *interfaces.State, tunIfName string) error {
tunIf, ok := st.Interface[tunIfName] tunIf, ok := st.Interface[tunIfName]
if !ok { if !ok {
return fmt.Errorf("no interface with name %q", tunIfName) return fmt.Errorf("no interface with name %q", tunIfName)

View File

@ -22,7 +22,6 @@
"go4.org/netipx" "go4.org/netipx"
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/net/netaddr"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/tstest" "tailscale.com/tstest"
"tailscale.com/types/logger" "tailscale.com/types/logger"
@ -596,7 +595,7 @@ func TestPeerAPIReplyToDNSQueries(t *testing.T) {
t.Fatal("unexpectedly offering exit node") t.Fatal("unexpectedly offering exit node")
} }
h.ps.b.prefs = &ipn.Prefs{ h.ps.b.prefs = &ipn.Prefs{
AdvertiseRoutes: []netaddr.IPPrefix{ AdvertiseRoutes: []netip.Prefix{
netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("0.0.0.0/0"),
netip.MustParsePrefix("::/0"), netip.MustParsePrefix("::/0"),
}, },

View File

@ -37,7 +37,6 @@
"tailscale.com/ipn/ipnlocal" "tailscale.com/ipn/ipnlocal"
"tailscale.com/ipn/localapi" "tailscale.com/ipn/localapi"
"tailscale.com/logtail/backoff" "tailscale.com/logtail/backoff"
"tailscale.com/net/netaddr"
"tailscale.com/net/netstat" "tailscale.com/net/netstat"
"tailscale.com/net/netutil" "tailscale.com/net/netutil"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
@ -1066,7 +1065,7 @@ func (s *Server) ServeHTMLStatus(w http.ResponseWriter, r *http.Request) {
st.WriteHTML(w) st.WriteHTML(w)
} }
func peerPid(entries []netstat.Entry, la, ra netaddr.IPPort) int { func peerPid(entries []netstat.Entry, la, ra netip.AddrPort) int {
for _, e := range entries { for _, e := range entries {
if e.Local == ra && e.Remote == la { if e.Local == ra && e.Remote == la {
return e.Pid return e.Pid

View File

@ -12,12 +12,12 @@
"html" "html"
"io" "io"
"log" "log"
"net/netip"
"sort" "sort"
"strings" "strings"
"sync" "sync"
"time" "time"
"tailscale.com/net/netaddr"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/key" "tailscale.com/types/key"
"tailscale.com/types/views" "tailscale.com/types/views"
@ -35,7 +35,7 @@ type Status struct {
BackendState string BackendState string
AuthURL string // current URL provided by control to authorize client AuthURL string // current URL provided by control to authorize client
TailscaleIPs []netaddr.IP // Tailscale IP(s) assigned to this node TailscaleIPs []netip.Addr // Tailscale IP(s) assigned to this node
Self *PeerStatus Self *PeerStatus
// ExitNodeStatus describes the current exit node. // ExitNodeStatus describes the current exit node.
@ -94,7 +94,7 @@ type ExitNodeStatus struct {
Online bool Online bool
// TailscaleIPs are the exit node's IP addresses assigned to the node. // TailscaleIPs are the exit node's IP addresses assigned to the node.
TailscaleIPs []netaddr.IPPrefix TailscaleIPs []netip.Prefix
} }
func (s *Status) Peers() []key.NodePublic { func (s *Status) Peers() []key.NodePublic {
@ -124,7 +124,7 @@ type PeerStatus struct {
DNSName string DNSName string
OS string // HostInfo.OS OS string // HostInfo.OS
UserID tailcfg.UserID UserID tailcfg.UserID
TailscaleIPs []netaddr.IP // Tailscale IP(s) assigned to this node TailscaleIPs []netip.Addr // Tailscale IP(s) assigned to this node
// Tags are the list of ACL tags applied to this node. // Tags are the list of ACL tags applied to this node.
// See tailscale.com/tailcfg#Node.Tags for more information. // See tailscale.com/tailcfg#Node.Tags for more information.
@ -240,7 +240,7 @@ func (sb *StatusBuilder) AddUser(id tailcfg.UserID, up tailcfg.UserProfile) {
} }
// AddIP adds a Tailscale IP address to the status. // AddIP adds a Tailscale IP address to the status.
func (sb *StatusBuilder) AddTailscaleIP(ip netaddr.IP) { func (sb *StatusBuilder) AddTailscaleIP(ip netip.Addr) {
sb.mu.Lock() sb.mu.Lock()
defer sb.mu.Unlock() defer sb.mu.Unlock()
if sb.locked { if sb.locked {

View File

@ -29,7 +29,6 @@
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/ipn/ipnlocal" "tailscale.com/ipn/ipnlocal"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/net/netaddr"
"tailscale.com/net/netutil" "tailscale.com/net/netutil"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/logger" "tailscale.com/types/logger"
@ -223,7 +222,7 @@ func (h *Handler) serveWhoIs(w http.ResponseWriter, r *http.Request) {
return return
} }
b := h.b b := h.b
var ipp netaddr.IPPort var ipp netip.AddrPort
if v := r.FormValue("addr"); v != "" { if v := r.FormValue("addr"); v != "" {
var err error var err error
ipp, err = netip.ParseAddrPort(v) ipp, err = netip.ParseAddrPort(v)

View File

@ -99,7 +99,7 @@ type Prefs struct {
// blackhole route will be installed on the local system to // blackhole route will be installed on the local system to
// prevent any traffic escaping to the local network. // prevent any traffic escaping to the local network.
ExitNodeID tailcfg.StableNodeID ExitNodeID tailcfg.StableNodeID
ExitNodeIP netaddr.IP ExitNodeIP netip.Addr
// ExitNodeAllowLANAccess indicates whether locally accessible subnets should be // ExitNodeAllowLANAccess indicates whether locally accessible subnets should be
// routed directly or via the exit node. // routed directly or via the exit node.
@ -168,7 +168,7 @@ type Prefs struct {
// AdvertiseRoutes specifies CIDR prefixes to advertise into the // AdvertiseRoutes specifies CIDR prefixes to advertise into the
// Tailscale network as reachable through the current // Tailscale network as reachable through the current
// node. // node.
AdvertiseRoutes []netaddr.IPPrefix AdvertiseRoutes []netip.Prefix
// NoSNAT specifies whether to source NAT traffic going to // NoSNAT specifies whether to source NAT traffic going to
// destinations in AdvertiseRoutes. The default is to apply source // destinations in AdvertiseRoutes. The default is to apply source
@ -383,7 +383,7 @@ func (p *Prefs) Equals(p2 *Prefs) bool {
p.Persist.Equals(p2.Persist) p.Persist.Equals(p2.Persist)
} }
func compareIPNets(a, b []netaddr.IPPrefix) bool { func compareIPNets(a, b []netip.Prefix) bool {
if len(a) != len(b) { if len(a) != len(b) {
return false return false
} }
@ -478,13 +478,13 @@ func (p *Prefs) SetAdvertiseExitNode(runExit bool) {
return return
} }
p.AdvertiseRoutes = append(p.AdvertiseRoutes, p.AdvertiseRoutes = append(p.AdvertiseRoutes,
netaddr.IPPrefixFrom(netaddr.IPv4(0, 0, 0, 0), 0), netip.PrefixFrom(netaddr.IPv4(0, 0, 0, 0), 0),
netaddr.IPPrefixFrom(netip.IPv6Unspecified(), 0)) netip.PrefixFrom(netip.IPv6Unspecified(), 0))
} }
// peerWithTailscaleIP returns the peer in st with the provided // peerWithTailscaleIP returns the peer in st with the provided
// Tailscale IP. // Tailscale IP.
func peerWithTailscaleIP(st *ipnstate.Status, ip netaddr.IP) (ps *ipnstate.PeerStatus, ok bool) { func peerWithTailscaleIP(st *ipnstate.Status, ip netip.Addr) (ps *ipnstate.PeerStatus, ok bool) {
for _, ps := range st.Peer { for _, ps := range st.Peer {
for _, ip2 := range ps.TailscaleIPs { for _, ip2 := range ps.TailscaleIPs {
if ip == ip2 { if ip == ip2 {
@ -495,7 +495,7 @@ func peerWithTailscaleIP(st *ipnstate.Status, ip netaddr.IP) (ps *ipnstate.PeerS
return nil, false return nil, false
} }
func isRemoteIP(st *ipnstate.Status, ip netaddr.IP) bool { func isRemoteIP(st *ipnstate.Status, ip netip.Addr) bool {
for _, selfIP := range st.TailscaleIPs { for _, selfIP := range st.TailscaleIPs {
if ip == selfIP { if ip == selfIP {
return false return false
@ -507,7 +507,7 @@ func isRemoteIP(st *ipnstate.Status, ip netaddr.IP) bool {
// ClearExitNode sets the ExitNodeID and ExitNodeIP to their zero values. // ClearExitNode sets the ExitNodeID and ExitNodeIP to their zero values.
func (p *Prefs) ClearExitNode() { func (p *Prefs) ClearExitNode() {
p.ExitNodeID = "" p.ExitNodeID = ""
p.ExitNodeIP = netaddr.IP{} p.ExitNodeIP = netip.Addr{}
} }
// ExitNodeLocalIPError is returned when the requested IP address for an exit // ExitNodeLocalIPError is returned when the requested IP address for an exit
@ -520,7 +520,7 @@ func (e ExitNodeLocalIPError) Error() string {
return fmt.Sprintf("cannot use %s as an exit node as it is a local IP address to this machine", e.hostOrIP) return fmt.Sprintf("cannot use %s as an exit node as it is a local IP address to this machine", e.hostOrIP)
} }
func exitNodeIPOfArg(s string, st *ipnstate.Status) (ip netaddr.IP, err error) { func exitNodeIPOfArg(s string, st *ipnstate.Status) (ip netip.Addr, err error) {
if s == "" { if s == "" {
return ip, os.ErrInvalid return ip, os.ErrInvalid
} }

View File

@ -63,7 +63,7 @@ func TestPrefsEqual(t *testing.T) {
have, prefsHandles) have, prefsHandles)
} }
nets := func(strs ...string) (ns []netaddr.IPPrefix) { nets := func(strs ...string) (ns []netip.Prefix) {
for _, s := range strs { for _, s := range strs {
n, err := netip.ParsePrefix(s) n, err := netip.ParsePrefix(s)
if err != nil { if err != nil {
@ -227,12 +227,12 @@ func TestPrefsEqual(t *testing.T) {
{ {
&Prefs{AdvertiseRoutes: nil}, &Prefs{AdvertiseRoutes: nil},
&Prefs{AdvertiseRoutes: []netaddr.IPPrefix{}}, &Prefs{AdvertiseRoutes: []netip.Prefix{}},
true, true,
}, },
{ {
&Prefs{AdvertiseRoutes: []netaddr.IPPrefix{}}, &Prefs{AdvertiseRoutes: []netip.Prefix{}},
&Prefs{AdvertiseRoutes: []netaddr.IPPrefix{}}, &Prefs{AdvertiseRoutes: []netip.Prefix{}},
true, true,
}, },
{ {
@ -659,7 +659,7 @@ func TestPrefsExitNode(t *testing.T) {
if p.AdvertisesExitNode() { if p.AdvertisesExitNode() {
t.Errorf("default shouldn't advertise exit node") t.Errorf("default shouldn't advertise exit node")
} }
p.AdvertiseRoutes = []netaddr.IPPrefix{ p.AdvertiseRoutes = []netip.Prefix{
netip.MustParsePrefix("10.0.0.0/16"), netip.MustParsePrefix("10.0.0.0/16"),
} }
p.SetAdvertiseExitNode(true) p.SetAdvertiseExitNode(true)
@ -688,7 +688,7 @@ func TestExitNodeIPOfArg(t *testing.T) {
name string name string
arg string arg string
st *ipnstate.Status st *ipnstate.Status
want netaddr.IP want netip.Addr
wantErr string wantErr string
}{ }{
{ {
@ -714,7 +714,7 @@ func TestExitNodeIPOfArg(t *testing.T) {
BackendState: "Running", BackendState: "Running",
Peer: map[key.NodePublic]*ipnstate.PeerStatus{ Peer: map[key.NodePublic]*ipnstate.PeerStatus{
key.NewNode().Public(): { key.NewNode().Public(): {
TailscaleIPs: []netaddr.IP{mustIP("1.2.3.4")}, TailscaleIPs: []netip.Addr{mustIP("1.2.3.4")},
}, },
}, },
}, },
@ -727,7 +727,7 @@ func TestExitNodeIPOfArg(t *testing.T) {
BackendState: "Running", BackendState: "Running",
Peer: map[key.NodePublic]*ipnstate.PeerStatus{ Peer: map[key.NodePublic]*ipnstate.PeerStatus{
key.NewNode().Public(): { key.NewNode().Public(): {
TailscaleIPs: []netaddr.IP{mustIP("1.2.3.4")}, TailscaleIPs: []netip.Addr{mustIP("1.2.3.4")},
ExitNodeOption: true, ExitNodeOption: true,
}, },
}, },
@ -748,7 +748,7 @@ func TestExitNodeIPOfArg(t *testing.T) {
Peer: map[key.NodePublic]*ipnstate.PeerStatus{ Peer: map[key.NodePublic]*ipnstate.PeerStatus{
key.NewNode().Public(): { key.NewNode().Public(): {
DNSName: "skippy.foo.", DNSName: "skippy.foo.",
TailscaleIPs: []netaddr.IP{mustIP("1.0.0.2")}, TailscaleIPs: []netip.Addr{mustIP("1.0.0.2")},
ExitNodeOption: true, ExitNodeOption: true,
}, },
}, },
@ -763,7 +763,7 @@ func TestExitNodeIPOfArg(t *testing.T) {
Peer: map[key.NodePublic]*ipnstate.PeerStatus{ Peer: map[key.NodePublic]*ipnstate.PeerStatus{
key.NewNode().Public(): { key.NewNode().Public(): {
DNSName: "skippy.foo.", DNSName: "skippy.foo.",
TailscaleIPs: []netaddr.IP{mustIP("1.0.0.2")}, TailscaleIPs: []netip.Addr{mustIP("1.0.0.2")},
}, },
}, },
}, },
@ -777,12 +777,12 @@ func TestExitNodeIPOfArg(t *testing.T) {
Peer: map[key.NodePublic]*ipnstate.PeerStatus{ Peer: map[key.NodePublic]*ipnstate.PeerStatus{
key.NewNode().Public(): { key.NewNode().Public(): {
DNSName: "skippy.foo.", DNSName: "skippy.foo.",
TailscaleIPs: []netaddr.IP{mustIP("1.0.0.2")}, TailscaleIPs: []netip.Addr{mustIP("1.0.0.2")},
ExitNodeOption: true, ExitNodeOption: true,
}, },
key.NewNode().Public(): { key.NewNode().Public(): {
DNSName: "SKIPPY.foo.", DNSName: "SKIPPY.foo.",
TailscaleIPs: []netaddr.IP{mustIP("1.0.0.2")}, TailscaleIPs: []netip.Addr{mustIP("1.0.0.2")},
ExitNodeOption: true, ExitNodeOption: true,
}, },
}, },

View File

@ -7,10 +7,10 @@
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"net/netip"
"sort" "sort"
"tailscale.com/net/dns/resolver" "tailscale.com/net/dns/resolver"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
"tailscale.com/types/dnstype" "tailscale.com/types/dnstype"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
@ -40,13 +40,13 @@ type Config struct {
// Adding an entry to Hosts merely creates the record. If you want // Adding an entry to Hosts merely creates the record. If you want
// it to resolve, you also need to add appropriate routes to // it to resolve, you also need to add appropriate routes to
// Routes. // Routes.
Hosts map[dnsname.FQDN][]netaddr.IP Hosts map[dnsname.FQDN][]netip.Addr
// OnlyIPv6, if true, uses the IPv6 service IP (for MagicDNS) // OnlyIPv6, if true, uses the IPv6 service IP (for MagicDNS)
// instead of the IPv4 version (100.100.100.100). // instead of the IPv4 version (100.100.100.100).
OnlyIPv6 bool OnlyIPv6 bool
} }
func (c *Config) serviceIP() netaddr.IP { func (c *Config) serviceIP() netip.Addr {
if c.OnlyIPv6 { if c.OnlyIPv6 {
return tsaddr.TailscaleServiceIPv6() return tsaddr.TailscaleServiceIPv6()
} }
@ -143,7 +143,7 @@ func sameResolverNames(a, b []*dnstype.Resolver) bool {
return true return true
} }
func sameIPs(a, b []netaddr.IP) bool { func sameIPs(a, b []netip.Addr) bool {
if len(a) != len(b) { if len(a) != len(b) {
return false return false
} }

View File

@ -13,6 +13,7 @@
"io" "io"
"io/fs" "io/fs"
"io/ioutil" "io/ioutil"
"net/netip"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@ -21,7 +22,6 @@
"time" "time"
"tailscale.com/net/dns/resolvconffile" "tailscale.com/net/dns/resolvconffile"
"tailscale.com/net/netaddr"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
"tailscale.com/version/distro" "tailscale.com/version/distro"
@ -33,7 +33,7 @@
) )
// writeResolvConf writes DNS configuration in resolv.conf format to the given writer. // writeResolvConf writes DNS configuration in resolv.conf format to the given writer.
func writeResolvConf(w io.Writer, servers []netaddr.IP, domains []dnsname.FQDN) error { func writeResolvConf(w io.Writer, servers []netip.Addr, domains []dnsname.FQDN) error {
c := &resolvconffile.Config{ c := &resolvconffile.Config{
Nameservers: servers, Nameservers: servers,
SearchDomains: domains, SearchDomains: domains,

View File

@ -16,7 +16,6 @@
"testing" "testing"
qt "github.com/frankban/quicktest" qt "github.com/frankban/quicktest"
"tailscale.com/net/netaddr"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
) )
@ -82,7 +81,7 @@ func testDirect(t *testing.T, fs wholeFileFS) {
m := directManager{logf: t.Logf, fs: fs} m := directManager{logf: t.Logf, fs: fs}
if err := m.SetDNS(OSConfig{ if err := m.SetDNS(OSConfig{
Nameservers: []netaddr.IP{netip.MustParseAddr("8.8.8.8"), netip.MustParseAddr("8.8.4.4")}, Nameservers: []netip.Addr{netip.MustParseAddr("8.8.8.8"), netip.MustParseAddr("8.8.4.4")},
SearchDomains: []dnsname.FQDN{"ts.net.", "ts-dns.test."}, SearchDomains: []dnsname.FQDN{"ts.net.", "ts-dns.test."},
MatchDomains: []dnsname.FQDN{"ignored."}, MatchDomains: []dnsname.FQDN{"ignored."},
}); err != nil { }); err != nil {
@ -109,7 +108,7 @@ func testDirect(t *testing.T, fs wholeFileFS) {
assertBaseState(t) assertBaseState(t)
// Test that Close cleans up resolv.conf. // Test that Close cleans up resolv.conf.
if err := m.SetDNS(OSConfig{Nameservers: []netaddr.IP{netip.MustParseAddr("8.8.8.8")}}); err != nil { if err := m.SetDNS(OSConfig{Nameservers: []netip.Addr{netip.MustParseAddr("8.8.8.8")}}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := m.Close(); err != nil { if err := m.Close(); err != nil {
@ -150,21 +149,21 @@ func TestReadResolve(t *testing.T) {
}{ }{
{in: `nameserver 192.168.0.100`, {in: `nameserver 192.168.0.100`,
want: OSConfig{ want: OSConfig{
Nameservers: []netaddr.IP{ Nameservers: []netip.Addr{
netip.MustParseAddr("192.168.0.100"), netip.MustParseAddr("192.168.0.100"),
}, },
}, },
}, },
{in: `nameserver 192.168.0.100 # comment`, {in: `nameserver 192.168.0.100 # comment`,
want: OSConfig{ want: OSConfig{
Nameservers: []netaddr.IP{ Nameservers: []netip.Addr{
netip.MustParseAddr("192.168.0.100"), netip.MustParseAddr("192.168.0.100"),
}, },
}, },
}, },
{in: `nameserver 192.168.0.100#`, {in: `nameserver 192.168.0.100#`,
want: OSConfig{ want: OSConfig{
Nameservers: []netaddr.IP{ Nameservers: []netip.Addr{
netip.MustParseAddr("192.168.0.100"), netip.MustParseAddr("192.168.0.100"),
}, },
}, },

View File

@ -11,13 +11,13 @@
"errors" "errors"
"io" "io"
"net" "net"
"net/netip"
"runtime" "runtime"
"sync/atomic" "sync/atomic"
"time" "time"
"tailscale.com/health" "tailscale.com/health"
"tailscale.com/net/dns/resolver" "tailscale.com/net/dns/resolver"
"tailscale.com/net/netaddr"
"tailscale.com/net/packet" "tailscale.com/net/packet"
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
@ -67,7 +67,7 @@ func maxActiveQueries() int32 {
type response struct { type response struct {
pkt []byte pkt []byte
to netaddr.IPPort // response destination (request source) to netip.AddrPort // response destination (request source)
} }
// Manager manages system DNS settings. // Manager manages system DNS settings.
@ -175,7 +175,7 @@ func (m *Manager) compileConfig(cfg Config) (rcfg resolver.Config, ocfg OSConfig
// through quad-100. // through quad-100.
rcfg.Routes = routes rcfg.Routes = routes
rcfg.Routes["."] = cfg.DefaultResolvers rcfg.Routes["."] = cfg.DefaultResolvers
ocfg.Nameservers = []netaddr.IP{cfg.serviceIP()} ocfg.Nameservers = []netip.Addr{cfg.serviceIP()}
return rcfg, ocfg, nil return rcfg, ocfg, nil
} }
@ -212,7 +212,7 @@ func (m *Manager) compileConfig(cfg Config) (rcfg resolver.Config, ocfg OSConfig
// or routes + MagicDNS, or just MagicDNS, or on an OS that cannot // or routes + MagicDNS, or just MagicDNS, or on an OS that cannot
// split-DNS. Install a split config pointing at quad-100. // split-DNS. Install a split config pointing at quad-100.
rcfg.Routes = routes rcfg.Routes = routes
ocfg.Nameservers = []netaddr.IP{cfg.serviceIP()} ocfg.Nameservers = []netip.Addr{cfg.serviceIP()}
// If the OS can't do native split-dns, read out the underlying // If the OS can't do native split-dns, read out the underlying
// resolver config and blend it into our config. // resolver config and blend it into our config.
@ -239,7 +239,7 @@ func (m *Manager) compileConfig(cfg Config) (rcfg resolver.Config, ocfg OSConfig
// toIPsOnly returns only the IP portion of dnstype.Resolver. // toIPsOnly returns only the IP portion of dnstype.Resolver.
// Only safe to use if the resolvers slice has been cleared of // Only safe to use if the resolvers slice has been cleared of
// DoH or custom-port entries with something like hasDefaultIPResolversOnly. // DoH or custom-port entries with something like hasDefaultIPResolversOnly.
func toIPsOnly(resolvers []*dnstype.Resolver) (ret []netaddr.IP) { func toIPsOnly(resolvers []*dnstype.Resolver) (ret []netip.Addr) {
for _, r := range resolvers { for _, r := range resolvers {
if ipp, ok := r.IPPort(); ok && ipp.Port() == 53 { if ipp, ok := r.IPPort(); ok && ipp.Port() == 53 {
ret = append(ret, ipp.Addr()) ret = append(ret, ipp.Addr())
@ -252,7 +252,7 @@ func toIPsOnly(resolvers []*dnstype.Resolver) (ret []netaddr.IP) {
// called with a DNS request payload. // called with a DNS request payload.
// //
// TODO(tom): Rip out once all platforms use netstack. // TODO(tom): Rip out once all platforms use netstack.
func (m *Manager) EnqueuePacket(bs []byte, proto ipproto.Proto, from, to netaddr.IPPort) error { func (m *Manager) EnqueuePacket(bs []byte, proto ipproto.Proto, from, to netip.AddrPort) error {
if to.Port() != 53 || proto != ipproto.UDP { if to.Port() != 53 || proto != ipproto.UDP {
return nil return nil
} }
@ -334,7 +334,7 @@ func (m *Manager) NextPacket() ([]byte, error) {
// Query executes a DNS query recieved from the given address. The query is // Query executes a DNS query recieved from the given address. The query is
// provided in bs as a wire-encoded DNS query without any transport header. // provided in bs as a wire-encoded DNS query without any transport header.
// This method is called for requests arriving over UDP and TCP. // This method is called for requests arriving over UDP and TCP.
func (m *Manager) Query(ctx context.Context, bs []byte, from netaddr.IPPort) ([]byte, error) { func (m *Manager) Query(ctx context.Context, bs []byte, from netip.AddrPort) ([]byte, error) {
select { select {
case <-m.ctx.Done(): case <-m.ctx.Done():
return nil, net.ErrClosed return nil, net.ErrClosed
@ -368,7 +368,7 @@ type dnsTCPSession struct {
m *Manager m *Manager
conn net.Conn conn net.Conn
srcAddr netaddr.IPPort srcAddr netip.AddrPort
readClosing chan struct{} readClosing chan struct{}
responses chan []byte // DNS replies pending writing responses chan []byte // DNS replies pending writing
@ -455,7 +455,7 @@ func (s *dnsTCPSession) handleReads() {
// HandleTCPConn implements magicDNS over TCP, taking a connection and // HandleTCPConn implements magicDNS over TCP, taking a connection and
// servicing DNS requests sent down it. // servicing DNS requests sent down it.
func (m *Manager) HandleTCPConn(conn net.Conn, srcAddr netaddr.IPPort) { func (m *Manager) HandleTCPConn(conn net.Conn, srcAddr netip.AddrPort) {
s := dnsTCPSession{ s := dnsTCPSession{
m: m, m: m,
conn: conn, conn: conn,

View File

@ -8,11 +8,11 @@
"encoding/binary" "encoding/binary"
"io" "io"
"net" "net"
"net/netip"
"testing" "testing"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
dns "golang.org/x/net/dns/dnsmessage" dns "golang.org/x/net/dns/dnsmessage"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
) )
@ -73,7 +73,7 @@ func TestDNSOverTCP(t *testing.T) {
c, s := net.Pipe() c, s := net.Pipe()
defer s.Close() defer s.Close()
go m.HandleTCPConn(s, netaddr.IPPort{}) go m.HandleTCPConn(s, netip.AddrPort{})
defer c.Close() defer c.Close()
wantResults := map[dnsname.FQDN]string{ wantResults := map[dnsname.FQDN]string{

View File

@ -13,7 +13,6 @@
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts" "github.com/google/go-cmp/cmp/cmpopts"
"tailscale.com/net/dns/resolver" "tailscale.com/net/dns/resolver"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
"tailscale.com/types/dnstype" "tailscale.com/types/dnstype"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
@ -394,8 +393,8 @@ func TestManager(t *testing.T) {
}, },
} }
trIP := cmp.Transformer("ipStr", func(ip netaddr.IP) string { return ip.String() }) trIP := cmp.Transformer("ipStr", func(ip netip.Addr) string { return ip.String() })
trIPPort := cmp.Transformer("ippStr", func(ipp netaddr.IPPort) string { trIPPort := cmp.Transformer("ippStr", func(ipp netip.AddrPort) string {
if ipp.Port() == 53 { if ipp.Port() == 53 {
return ipp.Addr().String() return ipp.Addr().String()
} }
@ -424,14 +423,14 @@ func TestManager(t *testing.T) {
} }
} }
func mustIPs(strs ...string) (ret []netaddr.IP) { func mustIPs(strs ...string) (ret []netip.Addr) {
for _, s := range strs { for _, s := range strs {
ret = append(ret, netip.MustParseAddr(s)) ret = append(ret, netip.MustParseAddr(s))
} }
return ret return ret
} }
func mustIPPs(strs ...string) (ret []netaddr.IPPort) { func mustIPPs(strs ...string) (ret []netip.AddrPort) {
for _, s := range strs { for _, s := range strs {
ret = append(ret, netip.MustParseAddrPort(s)) ret = append(ret, netip.MustParseAddrPort(s))
} }
@ -456,9 +455,9 @@ func fqdns(strs ...string) (ret []dnsname.FQDN) {
return ret return ret
} }
func hosts(strs ...string) (ret map[dnsname.FQDN][]netaddr.IP) { func hosts(strs ...string) (ret map[dnsname.FQDN][]netip.Addr) {
var key dnsname.FQDN var key dnsname.FQDN
ret = map[dnsname.FQDN][]netaddr.IP{} ret = map[dnsname.FQDN][]netip.Addr{}
for _, s := range strs { for _, s := range strs {
if ip, err := netip.ParseAddr(s); err == nil { if ip, err := netip.ParseAddr(s); err == nil {
if key == "" { if key == "" {

View File

@ -90,7 +90,7 @@ func delValue(key registry.Key, name string) error {
// system's "primary" resolver. // system's "primary" resolver.
// //
// If no resolvers are provided, the Tailscale NRPT rules are deleted. // If no resolvers are provided, the Tailscale NRPT rules are deleted.
func (m windowsManager) setSplitDNS(resolvers []netaddr.IP, domains []dnsname.FQDN) error { func (m windowsManager) setSplitDNS(resolvers []netip.Addr, domains []dnsname.FQDN) error {
if m.nrptDB == nil { if m.nrptDB == nil {
if resolvers == nil { if resolvers == nil {
// Just a no-op in this case. // Just a no-op in this case.
@ -118,7 +118,7 @@ func (m windowsManager) setSplitDNS(resolvers []netaddr.IP, domains []dnsname.FQ
// "primary" resolvers. // "primary" resolvers.
// domains can be set without resolvers, which just contributes new // domains can be set without resolvers, which just contributes new
// paths to the global DNS search list. // paths to the global DNS search list.
func (m windowsManager) setPrimaryDNS(resolvers []netaddr.IP, domains []dnsname.FQDN) error { func (m windowsManager) setPrimaryDNS(resolvers []netip.Addr, domains []dnsname.FQDN) error {
var ipsv4 []string var ipsv4 []string
var ipsv6 []string var ipsv6 []string
@ -347,7 +347,7 @@ func (m windowsManager) GetBaseConfig() (OSConfig, error) {
// It's used on Windows 7 to emulate split DNS by trying to figure out // It's used on Windows 7 to emulate split DNS by trying to figure out
// what the "previous" primary resolver was. It might be wrong, or // what the "previous" primary resolver was. It might be wrong, or
// incomplete. // incomplete.
func (m windowsManager) getBasePrimaryResolver() (resolvers []netaddr.IP, err error) { func (m windowsManager) getBasePrimaryResolver() (resolvers []netip.Addr, err error) {
tsGUID, err := windows.GUIDFromString(m.guid) tsGUID, err := windows.GUIDFromString(m.guid)
if err != nil { if err != nil {
return nil, err return nil, err
@ -422,7 +422,7 @@ type candidate struct {
return resolvers, nil return resolvers, nil
} }
var siteLocalResolvers = []netaddr.IP{ var siteLocalResolvers = []netip.Addr{
netip.MustParseAddr("fec0:0:0:ffff::1"), netip.MustParseAddr("fec0:0:0:ffff::1"),
netip.MustParseAddr("fec0:0:0:ffff::2"), netip.MustParseAddr("fec0:0:0:ffff::2"),
netip.MustParseAddr("fec0:0:0:ffff::3"), netip.MustParseAddr("fec0:0:0:ffff::3"),

View File

@ -15,7 +15,6 @@
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"golang.org/x/sys/windows/registry" "golang.org/x/sys/windows/registry"
"tailscale.com/net/netaddr"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
"tailscale.com/util/winutil" "tailscale.com/util/winutil"
) )
@ -92,7 +91,7 @@ func TestManagerWindowsGPMove(t *testing.T) {
// Upon initialization of cfg, we should not have any NRPT rules // Upon initialization of cfg, we should not have any NRPT rules
ensureNoRules(t) ensureNoRules(t)
resolvers := []netaddr.IP{netip.MustParseAddr("1.1.1.1")} resolvers := []netip.Addr{netip.MustParseAddr("1.1.1.1")}
domains := genRandomSubdomains(t, 1) domains := genRandomSubdomains(t, 1)
// 1. Populate local NRPT // 1. Populate local NRPT
@ -216,7 +215,7 @@ func runTest(t *testing.T, isLocal bool) {
// Upon initialization of cfg, we should not have any NRPT rules // Upon initialization of cfg, we should not have any NRPT rules
ensureNoRules(t) ensureNoRules(t)
resolvers := []netaddr.IP{netip.MustParseAddr("1.1.1.1")} resolvers := []netip.Addr{netip.MustParseAddr("1.1.1.1")}
domains := genRandomSubdomains(t, 2*nrptMaxDomainsPerRule+1) domains := genRandomSubdomains(t, 2*nrptMaxDomainsPerRule+1)

View File

@ -16,7 +16,6 @@
"github.com/godbus/dbus/v5" "github.com/godbus/dbus/v5"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
"tailscale.com/util/endian" "tailscale.com/util/endian"
) )
@ -294,7 +293,7 @@ func (m *nmManager) GetBaseConfig() (OSConfig, error) {
} }
type dnsPrio struct { type dnsPrio struct {
resolvers []netaddr.IP resolvers []netip.Addr
domains []string domains []string
priority int32 priority int32
} }
@ -342,7 +341,7 @@ type dnsPrio struct {
var ( var (
ret OSConfig ret OSConfig
seenResolvers = map[netaddr.IP]bool{} seenResolvers = map[netip.Addr]bool{}
seenSearch = map[string]bool{} seenSearch = map[string]bool{}
) )

View File

@ -6,8 +6,8 @@
import ( import (
"errors" "errors"
"net/netip"
"tailscale.com/net/netaddr"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
) )
@ -40,7 +40,7 @@ type OSConfigurator interface {
// OSConfig is an OS DNS configuration. // OSConfig is an OS DNS configuration.
type OSConfig struct { type OSConfig struct {
// Nameservers are the IP addresses of the nameservers to use. // Nameservers are the IP addresses of the nameservers to use.
Nameservers []netaddr.IP Nameservers []netip.Addr
// SearchDomains are the domain suffixes to use when expanding // SearchDomains are the domain suffixes to use when expanding
// single-label name queries. SearchDomains is additive to // single-label name queries. SearchDomains is additive to
// whatever non-Tailscale search domains the OS has. // whatever non-Tailscale search domains the OS has.

View File

@ -9,31 +9,29 @@
import ( import (
"net/netip" "net/netip"
"sync" "sync"
"tailscale.com/net/netaddr"
) )
var knownDoH = map[netaddr.IP]string{} // 8.8.8.8 => "https://..." var knownDoH = map[netip.Addr]string{} // 8.8.8.8 => "https://..."
var dohIPsOfBase = map[string][]netaddr.IP{} var dohIPsOfBase = map[string][]netip.Addr{}
var populateOnce sync.Once var populateOnce sync.Once
// KnownDoH returns a map of well-known public DNS IPs to their DoH URL. // KnownDoH returns a map of well-known public DNS IPs to their DoH URL.
// The returned map should not be modified. // The returned map should not be modified.
func KnownDoH() map[netaddr.IP]string { func KnownDoH() map[netip.Addr]string {
populateOnce.Do(populate) populateOnce.Do(populate)
return knownDoH return knownDoH
} }
// DoHIPsOfBase returns a map of DNS server IP addresses keyed // DoHIPsOfBase returns a map of DNS server IP addresses keyed
// by their DoH URL. It is the inverse of KnownDoH. // by their DoH URL. It is the inverse of KnownDoH.
func DoHIPsOfBase() map[string][]netaddr.IP { func DoHIPsOfBase() map[string][]netip.Addr {
populateOnce.Do(populate) populateOnce.Do(populate)
return dohIPsOfBase return dohIPsOfBase
} }
// DoHV6 returns the first IPv6 DNS address from a given public DNS provider // DoHV6 returns the first IPv6 DNS address from a given public DNS provider
// if found, along with a boolean indicating success. // if found, along with a boolean indicating success.
func DoHV6(base string) (ip netaddr.IP, ok bool) { func DoHV6(base string) (ip netip.Addr, ok bool) {
populateOnce.Do(populate) populateOnce.Do(populate)
for _, ip := range dohIPsOfBase[base] { for _, ip := range dohIPsOfBase[base] {
if ip.Is6() { if ip.Is6() {
@ -43,7 +41,7 @@ func DoHV6(base string) (ip netaddr.IP, ok bool) {
return ip, false return ip, false
} }
// addDoH parses a given well-formed ip string into a netaddr.IP type and // addDoH parses a given well-formed ip string into a netip.Addr type and
// adds it to both knownDoH and dohIPsOFBase maps. // adds it to both knownDoH and dohIPsOFBase maps.
func addDoH(ipStr, base string) { func addDoH(ipStr, base string) {
ip := netip.MustParseAddr(ipStr) ip := netip.MustParseAddr(ipStr)

View File

@ -7,8 +7,6 @@
import ( import (
"net/netip" "net/netip"
"testing" "testing"
"tailscale.com/net/netaddr"
) )
func TestInit(t *testing.T) { func TestInit(t *testing.T) {
@ -24,12 +22,12 @@ func TestInit(t *testing.T) {
func TestDohV6(t *testing.T) { func TestDohV6(t *testing.T) {
tests := []struct { tests := []struct {
in string in string
firstIP netaddr.IP firstIP netip.Addr
want bool want bool
}{ }{
{"https://cloudflare-dns.com/dns-query", netip.MustParseAddr("2606:4700:4700::1111"), true}, {"https://cloudflare-dns.com/dns-query", netip.MustParseAddr("2606:4700:4700::1111"), true},
{"https://dns.google/dns-query", netip.MustParseAddr("2001:4860:4860::8888"), true}, {"https://dns.google/dns-query", netip.MustParseAddr("2001:4860:4860::8888"), true},
{"bogus", netaddr.IP{}, false}, {"bogus", netip.Addr{}, false},
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.in, func(t *testing.T) { t.Run(test.in, func(t *testing.T) {

View File

@ -20,7 +20,6 @@
"os" "os"
"strings" "strings"
"tailscale.com/net/netaddr"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
) )
@ -30,7 +29,7 @@
// Config represents a resolv.conf(5) file. // Config represents a resolv.conf(5) file.
type Config struct { type Config struct {
// Nameservers are the IP addresses of the nameservers to use. // Nameservers are the IP addresses of the nameservers to use.
Nameservers []netaddr.IP Nameservers []netip.Addr
// SearchDomains are the domain suffixes to use when expanding // SearchDomains are the domain suffixes to use when expanding
// single-label name queries. SearchDomains is additive to // single-label name queries. SearchDomains is additive to

View File

@ -10,7 +10,6 @@
"strings" "strings"
"testing" "testing"
"tailscale.com/net/netaddr"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
) )
@ -22,21 +21,21 @@ func TestParse(t *testing.T) {
}{ }{
{in: `nameserver 192.168.0.100`, {in: `nameserver 192.168.0.100`,
want: &Config{ want: &Config{
Nameservers: []netaddr.IP{ Nameservers: []netip.Addr{
netip.MustParseAddr("192.168.0.100"), netip.MustParseAddr("192.168.0.100"),
}, },
}, },
}, },
{in: `nameserver 192.168.0.100 # comment`, {in: `nameserver 192.168.0.100 # comment`,
want: &Config{ want: &Config{
Nameservers: []netaddr.IP{ Nameservers: []netip.Addr{
netip.MustParseAddr("192.168.0.100"), netip.MustParseAddr("192.168.0.100"),
}, },
}, },
}, },
{in: `nameserver 192.168.0.100#`, {in: `nameserver 192.168.0.100#`,
want: &Config{ want: &Config{
Nameservers: []netaddr.IP{ Nameservers: []netip.Addr{
netip.MustParseAddr("192.168.0.100"), netip.MustParseAddr("192.168.0.100"),
}, },
}, },

View File

@ -15,6 +15,7 @@
"math/rand" "math/rand"
"net" "net"
"net/http" "net/http"
"net/netip"
"net/url" "net/url"
"runtime" "runtime"
"sort" "sort"
@ -28,7 +29,6 @@
"tailscale.com/hostinfo" "tailscale.com/hostinfo"
"tailscale.com/net/dns/publicdns" "tailscale.com/net/dns/publicdns"
"tailscale.com/net/dnscache" "tailscale.com/net/dnscache"
"tailscale.com/net/netaddr"
"tailscale.com/net/neterror" "tailscale.com/net/neterror"
"tailscale.com/net/netns" "tailscale.com/net/netns"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
@ -367,7 +367,7 @@ func (f *forwarder) setRoutes(routesBySuffix map[dnsname.FQDN][]*dnstype.Resolve
var stdNetPacketListener nettype.PacketListenerWithNetIP = nettype.MakePacketListenerWithNetIP(new(net.ListenConfig)) var stdNetPacketListener nettype.PacketListenerWithNetIP = nettype.MakePacketListenerWithNetIP(new(net.ListenConfig))
func (f *forwarder) packetListener(ip netaddr.IP) (nettype.PacketListenerWithNetIP, error) { func (f *forwarder) packetListener(ip netip.Addr) (nettype.PacketListenerWithNetIP, error) {
if f.linkSel == nil || initListenConfig == nil { if f.linkSel == nil || initListenConfig == nil {
return stdNetPacketListener, nil return stdNetPacketListener, nil
} }

View File

@ -54,7 +54,7 @@
type packet struct { type packet struct {
bs []byte bs []byte
addr netaddr.IPPort // src for a request, dst for a response addr netip.AddrPort // src for a request, dst for a response
} }
// Config is a resolver configuration. // Config is a resolver configuration.
@ -70,7 +70,7 @@ type Config struct {
// To register a "default route", add an entry for ".". // To register a "default route", add an entry for ".".
Routes map[dnsname.FQDN][]*dnstype.Resolver Routes map[dnsname.FQDN][]*dnstype.Resolver
// LocalHosts is a map of FQDNs to corresponding IPs. // LocalHosts is a map of FQDNs to corresponding IPs.
Hosts map[dnsname.FQDN][]netaddr.IP Hosts map[dnsname.FQDN][]netip.Addr
// LocalDomains is a list of DNS name suffixes that should not be // LocalDomains is a list of DNS name suffixes that should not be
// routed to upstream resolvers. // routed to upstream resolvers.
LocalDomains []dnsname.FQDN LocalDomains []dnsname.FQDN
@ -106,7 +106,7 @@ func (c *Config) WriteToBufioWriter(w *bufio.Writer) {
} }
// WriteIPPorts writes vv to w. // WriteIPPorts writes vv to w.
func WriteIPPorts(w *bufio.Writer, vv []netaddr.IPPort) { func WriteIPPorts(w *bufio.Writer, vv []netip.AddrPort) {
w.WriteByte('[') w.WriteByte('[')
var b []byte var b []byte
for i, v := range vv { for i, v := range vv {
@ -193,15 +193,15 @@ type Resolver struct {
// mu guards the following fields from being updated while used. // mu guards the following fields from being updated while used.
mu sync.Mutex mu sync.Mutex
localDomains []dnsname.FQDN localDomains []dnsname.FQDN
hostToIP map[dnsname.FQDN][]netaddr.IP hostToIP map[dnsname.FQDN][]netip.Addr
ipToHost map[netaddr.IP]dnsname.FQDN ipToHost map[netip.Addr]dnsname.FQDN
} }
type ForwardLinkSelector interface { type ForwardLinkSelector interface {
// PickLink returns which network device should be used to query // PickLink returns which network device should be used to query
// the DNS server at the given IP. // the DNS server at the given IP.
// The empty string means to use an unspecified default. // The empty string means to use an unspecified default.
PickLink(netaddr.IP) (linkName string) PickLink(netip.Addr) (linkName string)
} }
// New returns a new resolver. // New returns a new resolver.
@ -214,8 +214,8 @@ func New(logf logger.Logf, linkMon *monitor.Mon, linkSel ForwardLinkSelector, di
logf: logger.WithPrefix(logf, "resolver: "), logf: logger.WithPrefix(logf, "resolver: "),
linkMon: linkMon, linkMon: linkMon,
closed: make(chan struct{}), closed: make(chan struct{}),
hostToIP: map[dnsname.FQDN][]netaddr.IP{}, hostToIP: map[dnsname.FQDN][]netip.Addr{},
ipToHost: map[netaddr.IP]dnsname.FQDN{}, ipToHost: map[netip.Addr]dnsname.FQDN{},
dialer: dialer, dialer: dialer,
} }
r.forwarder = newForwarder(r.logf, linkMon, linkSel, dialer) r.forwarder = newForwarder(r.logf, linkMon, linkSel, dialer)
@ -229,7 +229,7 @@ func (r *Resolver) SetConfig(cfg Config) error {
r.saveConfigForTests(cfg) r.saveConfigForTests(cfg)
} }
reverse := make(map[netaddr.IP]dnsname.FQDN, len(cfg.Hosts)) reverse := make(map[netip.Addr]dnsname.FQDN, len(cfg.Hosts))
for host, ips := range cfg.Hosts { for host, ips := range cfg.Hosts {
for _, ip := range ips { for _, ip := range ips {
@ -266,7 +266,7 @@ func (r *Resolver) Close() {
// bound on per-query resource usage. // bound on per-query resource usage.
const dnsQueryTimeout = 10 * time.Second const dnsQueryTimeout = 10 * time.Second
func (r *Resolver) Query(ctx context.Context, bs []byte, from netaddr.IPPort) ([]byte, error) { func (r *Resolver) Query(ctx context.Context, bs []byte, from netip.AddrPort) ([]byte, error) {
metricDNSQueryLocal.Add(1) metricDNSQueryLocal.Add(1)
select { select {
case <-r.closed: case <-r.closed:
@ -323,7 +323,7 @@ func parseExitNodeQuery(q []byte) *response {
// still result in a response DNS packet (saying there's a failure) // still result in a response DNS packet (saying there's a failure)
// and a nil error. // and a nil error.
// TODO: figure out if we even need an error result. // TODO: figure out if we even need an error result.
func (r *Resolver) HandleExitNodeDNSQuery(ctx context.Context, q []byte, from netaddr.IPPort, allowName func(name string) bool) (res []byte, err error) { func (r *Resolver) HandleExitNodeDNSQuery(ctx context.Context, q []byte, from netip.AddrPort, allowName func(name string) bool) (res []byte, err error) {
metricDNSExitProxyQuery.Add(1) metricDNSExitProxyQuery.Add(1)
ch := make(chan packet, 1) ch := make(chan packet, 1)
@ -489,7 +489,7 @@ func isGoNoSuchHostError(err error) bool {
type resolvConfCache struct { type resolvConfCache struct {
mod time.Time mod time.Time
size int64 size int64
ip netaddr.IP ip netip.Addr
// TODO: inode/dev? // TODO: inode/dev?
} }
@ -501,10 +501,10 @@ type resolvConfCache struct {
// stubResolverForOS returns the IP address of the first nameserver in // stubResolverForOS returns the IP address of the first nameserver in
// /etc/resolv.conf. // /etc/resolv.conf.
func stubResolverForOS() (ip netaddr.IP, err error) { func stubResolverForOS() (ip netip.Addr, err error) {
fi, err := os.Stat(resolvconffile.Path) fi, err := os.Stat(resolvconffile.Path)
if err != nil { if err != nil {
return netaddr.IP{}, err return netip.Addr{}, err
} }
cur := resolvConfCache{ cur := resolvConfCache{
mod: fi.ModTime(), mod: fi.ModTime(),
@ -515,10 +515,10 @@ func stubResolverForOS() (ip netaddr.IP, err error) {
} }
conf, err := resolvconffile.ParseFile(resolvconffile.Path) conf, err := resolvconffile.ParseFile(resolvconffile.Path)
if err != nil { if err != nil {
return netaddr.IP{}, err return netip.Addr{}, err
} }
if len(conf.Nameservers) == 0 { if len(conf.Nameservers) == 0 {
return netaddr.IP{}, errEmptyResolvConf return netip.Addr{}, errEmptyResolvConf
} }
ip = conf.Nameservers[0] ip = conf.Nameservers[0]
cur.ip = ip cur.ip = ip
@ -531,12 +531,12 @@ func stubResolverForOS() (ip netaddr.IP, err error) {
// typ (A, AAAA, ALL). // typ (A, AAAA, ALL).
// Returns dns.RCodeRefused to indicate that the local map is not // Returns dns.RCodeRefused to indicate that the local map is not
// authoritative for domain. // authoritative for domain.
func (r *Resolver) resolveLocal(domain dnsname.FQDN, typ dns.Type) (netaddr.IP, dns.RCode) { func (r *Resolver) resolveLocal(domain dnsname.FQDN, typ dns.Type) (netip.Addr, dns.RCode) {
metricDNSResolveLocal.Add(1) metricDNSResolveLocal.Add(1)
// Reject .onion domains per RFC 7686. // Reject .onion domains per RFC 7686.
if dnsname.HasSuffix(domain.WithoutTrailingDot(), ".onion") { if dnsname.HasSuffix(domain.WithoutTrailingDot(), ".onion") {
metricDNSResolveLocalErrorOnion.Add(1) metricDNSResolveLocalErrorOnion.Add(1)
return netaddr.IP{}, dns.RCodeNameError return netip.Addr{}, dns.RCodeNameError
} }
// We return a symbolic domain if someone does a reverse lookup on the // We return a symbolic domain if someone does a reverse lookup on the
@ -566,11 +566,11 @@ func (r *Resolver) resolveLocal(domain dnsname.FQDN, typ dns.Type) (netaddr.IP,
if suffix.Contains(domain) { if suffix.Contains(domain) {
// We are authoritative for the queried domain. // We are authoritative for the queried domain.
metricDNSResolveLocalErrorMissing.Add(1) metricDNSResolveLocalErrorMissing.Add(1)
return netaddr.IP{}, dns.RCodeNameError return netip.Addr{}, dns.RCodeNameError
} }
} }
// Not authoritative, signal that forwarding is advisable. // Not authoritative, signal that forwarding is advisable.
return netaddr.IP{}, dns.RCodeRefused return netip.Addr{}, dns.RCodeRefused
} }
// Refactoring note: this must happen after we check suffixes, // Refactoring note: this must happen after we check suffixes,
@ -588,7 +588,7 @@ func (r *Resolver) resolveLocal(domain dnsname.FQDN, typ dns.Type) (netaddr.IP,
} }
} }
metricDNSResolveLocalNoA.Add(1) metricDNSResolveLocalNoA.Add(1)
return netaddr.IP{}, dns.RCodeSuccess return netip.Addr{}, dns.RCodeSuccess
case dns.TypeAAAA: case dns.TypeAAAA:
for _, ip := range addrs { for _, ip := range addrs {
if ip.Is6() { if ip.Is6() {
@ -597,14 +597,14 @@ func (r *Resolver) resolveLocal(domain dnsname.FQDN, typ dns.Type) (netaddr.IP,
} }
} }
metricDNSResolveLocalNoAAAA.Add(1) metricDNSResolveLocalNoAAAA.Add(1)
return netaddr.IP{}, dns.RCodeSuccess return netip.Addr{}, dns.RCodeSuccess
case dns.TypeALL: case dns.TypeALL:
// Answer with whatever we've got. // Answer with whatever we've got.
// It could be IPv4, IPv6, or a zero addr. // It could be IPv4, IPv6, or a zero addr.
// TODO: Return all available resolutions (A and AAAA, if we have them). // TODO: Return all available resolutions (A and AAAA, if we have them).
if len(addrs) == 0 { if len(addrs) == 0 {
metricDNSResolveLocalNoAll.Add(1) metricDNSResolveLocalNoAll.Add(1)
return netaddr.IP{}, dns.RCodeSuccess return netip.Addr{}, dns.RCodeSuccess
} }
metricDNSResolveLocalOKAll.Add(1) metricDNSResolveLocalOKAll.Add(1)
return addrs[0], dns.RCodeSuccess return addrs[0], dns.RCodeSuccess
@ -614,7 +614,7 @@ func (r *Resolver) resolveLocal(domain dnsname.FQDN, typ dns.Type) (netaddr.IP,
// DNS semantics and might be implemented in the future. // DNS semantics and might be implemented in the future.
case dns.TypeNS, dns.TypeSOA, dns.TypeAXFR, dns.TypeHINFO: case dns.TypeNS, dns.TypeSOA, dns.TypeAXFR, dns.TypeHINFO:
metricDNSResolveNotImplType.Add(1) metricDNSResolveNotImplType.Add(1)
return netaddr.IP{}, dns.RCodeNotImplemented return netip.Addr{}, dns.RCodeNotImplemented
// For everything except for the few types above that are explicitly not implemented, return no records. // For everything except for the few types above that are explicitly not implemented, return no records.
// This is what other DNS systems do: always return NOERROR // This is what other DNS systems do: always return NOERROR
@ -625,7 +625,7 @@ func (r *Resolver) resolveLocal(domain dnsname.FQDN, typ dns.Type) (netaddr.IP,
default: default:
metricDNSResolveNoRecordType.Add(1) metricDNSResolveNoRecordType.Add(1)
// The name exists, but no records exist of the requested type. // The name exists, but no records exist of the requested type.
return netaddr.IP{}, dns.RCodeSuccess return netip.Addr{}, dns.RCodeSuccess
} }
} }
@ -639,13 +639,13 @@ func (r *Resolver) resolveLocal(domain dnsname.FQDN, typ dns.Type) (netaddr.IP,
// (2022-06-02) to work around an issue in Chrome where it would treat // (2022-06-02) to work around an issue in Chrome where it would treat
// "http://via-1.1.2.3.4" as a search string instead of a URL. We should rip out // "http://via-1.1.2.3.4" as a search string instead of a URL. We should rip out
// the old format in early 2023. // the old format in early 2023.
func (r *Resolver) parseViaDomain(domain dnsname.FQDN, typ dns.Type) (netaddr.IP, bool) { func (r *Resolver) parseViaDomain(domain dnsname.FQDN, typ dns.Type) (netip.Addr, bool) {
fqdn := string(domain.WithoutTrailingDot()) fqdn := string(domain.WithoutTrailingDot())
if typ != dns.TypeAAAA { if typ != dns.TypeAAAA {
return netaddr.IP{}, false return netip.Addr{}, false
} }
if len(fqdn) < len("via-X.0.0.0.0") { if len(fqdn) < len("via-X.0.0.0.0") {
return netaddr.IP{}, false // too short to be valid return netip.Addr{}, false // too short to be valid
} }
var siteID string var siteID string
@ -653,18 +653,18 @@ func (r *Resolver) parseViaDomain(domain dnsname.FQDN, typ dns.Type) (netaddr.IP
if strings.HasPrefix(fqdn, "via-") { if strings.HasPrefix(fqdn, "via-") {
firstDot := strings.Index(fqdn, ".") firstDot := strings.Index(fqdn, ".")
if firstDot < 0 { if firstDot < 0 {
return netaddr.IP{}, false // missing dot delimiters return netip.Addr{}, false // missing dot delimiters
} }
siteID = fqdn[len("via-"):firstDot] siteID = fqdn[len("via-"):firstDot]
ip4Str = fqdn[firstDot+1:] ip4Str = fqdn[firstDot+1:]
} else { } else {
lastDot := strings.LastIndex(fqdn, ".") lastDot := strings.LastIndex(fqdn, ".")
if lastDot < 0 { if lastDot < 0 {
return netaddr.IP{}, false // missing dot delimiters return netip.Addr{}, false // missing dot delimiters
} }
suffix := fqdn[lastDot+1:] suffix := fqdn[lastDot+1:]
if !strings.HasPrefix(suffix, "via-") { if !strings.HasPrefix(suffix, "via-") {
return netaddr.IP{}, false return netip.Addr{}, false
} }
siteID = suffix[len("via-"):] siteID = suffix[len("via-"):]
ip4Str = fqdn[:lastDot] ip4Str = fqdn[:lastDot]
@ -672,22 +672,22 @@ func (r *Resolver) parseViaDomain(domain dnsname.FQDN, typ dns.Type) (netaddr.IP
ip4, err := netip.ParseAddr(ip4Str) ip4, err := netip.ParseAddr(ip4Str)
if err != nil { if err != nil {
return netaddr.IP{}, false // badly formed, dont respond return netip.Addr{}, false // badly formed, dont respond
} }
prefix, err := strconv.ParseUint(siteID, 0, 32) prefix, err := strconv.ParseUint(siteID, 0, 32)
if err != nil { if err != nil {
return netaddr.IP{}, false // badly formed, dont respond return netip.Addr{}, false // badly formed, dont respond
} }
// MapVia will never error when given an ipv4 netaddr.IPPrefix. // MapVia will never error when given an ipv4 netip.Prefix.
out, _ := tsaddr.MapVia(uint32(prefix), netip.PrefixFrom(ip4, ip4.BitLen())) out, _ := tsaddr.MapVia(uint32(prefix), netip.PrefixFrom(ip4, ip4.BitLen()))
return out.Addr(), true return out.Addr(), true
} }
// resolveReverse returns the unique domain name that maps to the given address. // resolveReverse returns the unique domain name that maps to the given address.
func (r *Resolver) resolveLocalReverse(name dnsname.FQDN) (dnsname.FQDN, dns.RCode) { func (r *Resolver) resolveLocalReverse(name dnsname.FQDN) (dnsname.FQDN, dns.RCode) {
var ip netaddr.IP var ip netip.Addr
var ok bool var ok bool
switch { switch {
case strings.HasSuffix(name.WithTrailingDot(), rdnsv4Suffix): case strings.HasSuffix(name.WithTrailingDot(), rdnsv4Suffix):
@ -717,7 +717,7 @@ func (r *Resolver) resolveLocalReverse(name dnsname.FQDN) (dnsname.FQDN, dns.RCo
} }
// r.mu must be held. // r.mu must be held.
func (r *Resolver) fqdnForIPLocked(ip netaddr.IP, name dnsname.FQDN) (dnsname.FQDN, dns.RCode) { func (r *Resolver) fqdnForIPLocked(ip netip.Addr, name dnsname.FQDN) (dnsname.FQDN, dns.RCode) {
// If someone curiously does a reverse lookup on the DNS IP, we // If someone curiously does a reverse lookup on the DNS IP, we
// return a domain that helps indicate that Tailscale is using // return a domain that helps indicate that Tailscale is using
// this IP for a special purpose and it is not a node on their // this IP for a special purpose and it is not a node on their
@ -749,8 +749,8 @@ type response struct {
// IP and IPs are the responses to an A, AAAA, or ALL query. // IP and IPs are the responses to an A, AAAA, or ALL query.
// Either/both/neither can be populated. // Either/both/neither can be populated.
IP netaddr.IP IP netip.Addr
IPs []netaddr.IP IPs []netip.Addr
// TXT is the response to a TXT query. // TXT is the response to a TXT query.
// Each one is its own RR with one string. // Each one is its own RR with one string.
@ -809,7 +809,7 @@ func (p *dnsParser) parseQuery(query []byte) error {
// marshalARecord serializes an A record into an active builder. // marshalARecord serializes an A record into an active builder.
// The caller may continue using the builder following the call. // The caller may continue using the builder following the call.
func marshalARecord(name dns.Name, ip netaddr.IP, builder *dns.Builder) error { func marshalARecord(name dns.Name, ip netip.Addr, builder *dns.Builder) error {
var answer dns.AResource var answer dns.AResource
answerHeader := dns.ResourceHeader{ answerHeader := dns.ResourceHeader{
@ -825,7 +825,7 @@ func marshalARecord(name dns.Name, ip netaddr.IP, builder *dns.Builder) error {
// marshalAAAARecord serializes an AAAA record into an active builder. // marshalAAAARecord serializes an AAAA record into an active builder.
// The caller may continue using the builder following the call. // The caller may continue using the builder following the call.
func marshalAAAARecord(name dns.Name, ip netaddr.IP, builder *dns.Builder) error { func marshalAAAARecord(name dns.Name, ip netip.Addr, builder *dns.Builder) error {
var answer dns.AAAAResource var answer dns.AAAAResource
answerHeader := dns.ResourceHeader{ answerHeader := dns.ResourceHeader{
@ -839,7 +839,7 @@ func marshalAAAARecord(name dns.Name, ip netaddr.IP, builder *dns.Builder) error
return builder.AAAAResource(answerHeader, answer) return builder.AAAAResource(answerHeader, answer)
} }
func marshalIP(name dns.Name, ip netaddr.IP, builder *dns.Builder) error { func marshalIP(name dns.Name, ip netip.Addr, builder *dns.Builder) error {
if ip.Is4() { if ip.Is4() {
return marshalARecord(name, ip, builder) return marshalARecord(name, ip, builder)
} }
@ -1066,14 +1066,14 @@ func rawNameToLower(name []byte) string {
// 4.3.2.1.in-addr.arpa // 4.3.2.1.in-addr.arpa
// is transformed to // is transformed to
// 1.2.3.4 // 1.2.3.4
func rdnsNameToIPv4(name dnsname.FQDN) (ip netaddr.IP, ok bool) { func rdnsNameToIPv4(name dnsname.FQDN) (ip netip.Addr, ok bool) {
s := strings.TrimSuffix(name.WithTrailingDot(), rdnsv4Suffix) s := strings.TrimSuffix(name.WithTrailingDot(), rdnsv4Suffix)
ip, err := netip.ParseAddr(s) ip, err := netip.ParseAddr(s)
if err != nil { if err != nil {
return netaddr.IP{}, false return netip.Addr{}, false
} }
if !ip.Is4() { if !ip.Is4() {
return netaddr.IP{}, false return netip.Addr{}, false
} }
b := ip.As4() b := ip.As4()
return netaddr.IPv4(b[3], b[2], b[1], b[0]), true return netaddr.IPv4(b[3], b[2], b[1], b[0]), true
@ -1085,14 +1085,14 @@ func rdnsNameToIPv4(name dnsname.FQDN) (ip netaddr.IP, ok bool) {
// b.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. // b.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
// is transformed to // is transformed to
// 2001:db8::567:89ab // 2001:db8::567:89ab
func rdnsNameToIPv6(name dnsname.FQDN) (ip netaddr.IP, ok bool) { func rdnsNameToIPv6(name dnsname.FQDN) (ip netip.Addr, ok bool) {
var b [32]byte var b [32]byte
var ipb [16]byte var ipb [16]byte
s := strings.TrimSuffix(name.WithTrailingDot(), rdnsv6Suffix) s := strings.TrimSuffix(name.WithTrailingDot(), rdnsv6Suffix)
// 32 nibbles and 31 dots between them. // 32 nibbles and 31 dots between them.
if len(s) != 63 { if len(s) != 63 {
return netaddr.IP{}, false return netip.Addr{}, false
} }
// Dots and hex digits alternate. // Dots and hex digits alternate.
@ -1101,7 +1101,7 @@ func rdnsNameToIPv6(name dnsname.FQDN) (ip netaddr.IP, ok bool) {
for i, j := len(s)-1, 0; i >= 0; i-- { for i, j := len(s)-1, 0; i >= 0; i-- {
thisDot := (s[i] == '.') thisDot := (s[i] == '.')
if prevDot == thisDot { if prevDot == thisDot {
return netaddr.IP{}, false return netip.Addr{}, false
} }
prevDot = thisDot prevDot = thisDot
@ -1115,7 +1115,7 @@ func rdnsNameToIPv6(name dnsname.FQDN) (ip netaddr.IP, ok bool) {
_, err := hex.Decode(ipb[:], b[:]) _, err := hex.Decode(ipb[:], b[:])
if err != nil { if err != nil {
return netaddr.IP{}, false return netip.Addr{}, false
} }
return netaddr.IPFrom16(ipb), true return netaddr.IPFrom16(ipb), true

View File

@ -7,11 +7,11 @@
import ( import (
"fmt" "fmt"
"net" "net"
"net/netip"
"strings" "strings"
"testing" "testing"
"github.com/miekg/dns" "github.com/miekg/dns"
"tailscale.com/net/netaddr"
) )
// This file exists to isolate the test infrastructure // This file exists to isolate the test infrastructure
@ -22,7 +22,7 @@
// to queries of type A it receives with an A record containing ipv4, // to queries of type A it receives with an A record containing ipv4,
// to queries of type AAAA with an AAAA record containing ipv6, // to queries of type AAAA with an AAAA record containing ipv6,
// to queries of type NS with an NS record containing name. // to queries of type NS with an NS record containing name.
func resolveToIP(ipv4, ipv6 netaddr.IP, ns string) dns.HandlerFunc { func resolveToIP(ipv4, ipv6 netip.Addr, ns string) dns.HandlerFunc {
return func(w dns.ResponseWriter, req *dns.Msg) { return func(w dns.ResponseWriter, req *dns.Msg) {
m := new(dns.Msg) m := new(dns.Msg)
m.SetReply(req) m.SetReply(req)
@ -73,7 +73,7 @@ func resolveToIP(ipv4, ipv6 netaddr.IP, ns string) dns.HandlerFunc {
// to queries of type A it receives with an A record containing ipv4, // to queries of type A it receives with an A record containing ipv4,
// to queries of type AAAA with an AAAA record containing ipv6, // to queries of type AAAA with an AAAA record containing ipv6,
// to queries of type NS with an NS record containing name. // to queries of type NS with an NS record containing name.
func resolveToIPLowercase(ipv4, ipv6 netaddr.IP, ns string) dns.HandlerFunc { func resolveToIPLowercase(ipv4, ipv6 netip.Addr, ns string) dns.HandlerFunc {
return func(w dns.ResponseWriter, req *dns.Msg) { return func(w dns.ResponseWriter, req *dns.Msg) {
m := new(dns.Msg) m := new(dns.Msg)
m.SetReply(req) m.SetReply(req)
@ -220,7 +220,7 @@ func weirdoGoCNAMEHandler(target string) dns.HandlerFunc {
// dnsHandler returns a handler that replies with the answers/options // dnsHandler returns a handler that replies with the answers/options
// provided. // provided.
// //
// Types supported: netaddr.IP. // Types supported: netip.Addr.
func dnsHandler(answers ...any) dns.HandlerFunc { func dnsHandler(answers ...any) dns.HandlerFunc {
return func(w dns.ResponseWriter, req *dns.Msg) { return func(w dns.ResponseWriter, req *dns.Msg) {
m := new(dns.Msg) m := new(dns.Msg)
@ -235,7 +235,7 @@ func dnsHandler(answers ...any) dns.HandlerFunc {
switch a := a.(type) { switch a := a.(type) {
default: default:
panic(fmt.Sprintf("unsupported dnsHandler arg %T", a)) panic(fmt.Sprintf("unsupported dnsHandler arg %T", a))
case netaddr.IP: case netip.Addr:
ip := a ip := a
if ip.Is4() { if ip.Is4() {
m.Answer = append(m.Answer, &dns.A{ m.Answer = append(m.Answer, &dns.A{

View File

@ -43,7 +43,7 @@
) )
var dnsCfg = Config{ var dnsCfg = Config{
Hosts: map[dnsname.FQDN][]netaddr.IP{ Hosts: map[dnsname.FQDN][]netip.Addr{
"test1.ipn.dev.": {testipv4}, "test1.ipn.dev.": {testipv4},
"test2.ipn.dev.": {testipv6}, "test2.ipn.dev.": {testipv6},
}, },
@ -92,7 +92,7 @@ func dnspacket(domain dnsname.FQDN, tp dns.Type, ednsSize uint16) []byte {
} }
type dnsResponse struct { type dnsResponse struct {
ip netaddr.IP ip netip.Addr
txt []string txt []string
name dnsname.FQDN name dnsname.FQDN
rcode dns.RCode rcode dns.RCode
@ -157,7 +157,7 @@ func unpackResponse(payload []byte) (dnsResponse, error) {
if err != nil { if err != nil {
return response, err return response, err
} }
response.ip = netaddr.IPv6Raw(res.AAAA) response.ip = netip.AddrFrom16(res.AAAA)
case dns.TypeTXT: case dns.TypeTXT:
res, err := parser.TXTResource() res, err := parser.TXTResource()
if err != nil { if err != nil {
@ -234,10 +234,10 @@ func unpackResponse(payload []byte) (dnsResponse, error) {
} }
func syncRespond(r *Resolver, query []byte) ([]byte, error) { func syncRespond(r *Resolver, query []byte) ([]byte, error) {
return r.Query(context.Background(), query, netaddr.IPPort{}) return r.Query(context.Background(), query, netip.AddrPort{})
} }
func mustIP(str string) netaddr.IP { func mustIP(str string) netip.Addr {
ip, err := netip.ParseAddr(str) ip, err := netip.ParseAddr(str)
if err != nil { if err != nil {
panic(err) panic(err)
@ -249,13 +249,13 @@ func TestRDNSNameToIPv4(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
input dnsname.FQDN input dnsname.FQDN
wantIP netaddr.IP wantIP netip.Addr
wantOK bool wantOK bool
}{ }{
{"valid", "4.123.24.1.in-addr.arpa.", netaddr.IPv4(1, 24, 123, 4), true}, {"valid", "4.123.24.1.in-addr.arpa.", netaddr.IPv4(1, 24, 123, 4), true},
{"double_dot", "1..2.3.in-addr.arpa.", netaddr.IP{}, false}, {"double_dot", "1..2.3.in-addr.arpa.", netip.Addr{}, false},
{"overflow", "1.256.3.4.in-addr.arpa.", netaddr.IP{}, false}, {"overflow", "1.256.3.4.in-addr.arpa.", netip.Addr{}, false},
{"not_ip", "sub.do.ma.in.in-addr.arpa.", netaddr.IP{}, false}, {"not_ip", "sub.do.ma.in.in-addr.arpa.", netip.Addr{}, false},
} }
for _, tt := range tests { for _, tt := range tests {
@ -274,7 +274,7 @@ func TestRDNSNameToIPv6(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
input dnsname.FQDN input dnsname.FQDN
wantIP netaddr.IP wantIP netip.Addr
wantOK bool wantOK bool
}{ }{
{ {
@ -286,19 +286,19 @@ func TestRDNSNameToIPv6(t *testing.T) {
{ {
"double_dot", "double_dot",
"b..9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.", "b..9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.",
netaddr.IP{}, netip.Addr{},
false, false,
}, },
{ {
"double_hex", "double_hex",
"b.a.98.0.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.", "b.a.98.0.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.",
netaddr.IP{}, netip.Addr{},
false, false,
}, },
{ {
"not_hex", "not_hex",
"b.a.g.0.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.", "b.a.g.0.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.",
netaddr.IP{}, netip.Addr{},
false, false,
}, },
} }
@ -329,27 +329,27 @@ func TestResolveLocal(t *testing.T) {
name string name string
qname dnsname.FQDN qname dnsname.FQDN
qtype dns.Type qtype dns.Type
ip netaddr.IP ip netip.Addr
code dns.RCode code dns.RCode
}{ }{
{"ipv4", "test1.ipn.dev.", dns.TypeA, testipv4, dns.RCodeSuccess}, {"ipv4", "test1.ipn.dev.", dns.TypeA, testipv4, dns.RCodeSuccess},
{"ipv6", "test2.ipn.dev.", dns.TypeAAAA, testipv6, dns.RCodeSuccess}, {"ipv6", "test2.ipn.dev.", dns.TypeAAAA, testipv6, dns.RCodeSuccess},
{"no-ipv6", "test1.ipn.dev.", dns.TypeAAAA, netaddr.IP{}, dns.RCodeSuccess}, {"no-ipv6", "test1.ipn.dev.", dns.TypeAAAA, netip.Addr{}, dns.RCodeSuccess},
{"nxdomain", "test3.ipn.dev.", dns.TypeA, netaddr.IP{}, dns.RCodeNameError}, {"nxdomain", "test3.ipn.dev.", dns.TypeA, netip.Addr{}, dns.RCodeNameError},
{"foreign domain", "google.com.", dns.TypeA, netaddr.IP{}, dns.RCodeRefused}, {"foreign domain", "google.com.", dns.TypeA, netip.Addr{}, dns.RCodeRefused},
{"all", "test1.ipn.dev.", dns.TypeA, testipv4, dns.RCodeSuccess}, {"all", "test1.ipn.dev.", dns.TypeA, testipv4, dns.RCodeSuccess},
{"mx-ipv4", "test1.ipn.dev.", dns.TypeMX, netaddr.IP{}, dns.RCodeSuccess}, {"mx-ipv4", "test1.ipn.dev.", dns.TypeMX, netip.Addr{}, dns.RCodeSuccess},
{"mx-ipv6", "test2.ipn.dev.", dns.TypeMX, netaddr.IP{}, dns.RCodeSuccess}, {"mx-ipv6", "test2.ipn.dev.", dns.TypeMX, netip.Addr{}, dns.RCodeSuccess},
{"mx-nxdomain", "test3.ipn.dev.", dns.TypeMX, netaddr.IP{}, dns.RCodeNameError}, {"mx-nxdomain", "test3.ipn.dev.", dns.TypeMX, netip.Addr{}, dns.RCodeNameError},
{"ns-nxdomain", "test3.ipn.dev.", dns.TypeNS, netaddr.IP{}, dns.RCodeNameError}, {"ns-nxdomain", "test3.ipn.dev.", dns.TypeNS, netip.Addr{}, dns.RCodeNameError},
{"onion-domain", "footest.onion.", dns.TypeA, netaddr.IP{}, dns.RCodeNameError}, {"onion-domain", "footest.onion.", dns.TypeA, netip.Addr{}, dns.RCodeNameError},
{"magicdns", dnsSymbolicFQDN, dns.TypeA, netip.MustParseAddr("100.100.100.100"), dns.RCodeSuccess}, {"magicdns", dnsSymbolicFQDN, dns.TypeA, netip.MustParseAddr("100.100.100.100"), dns.RCodeSuccess},
{"via_hex", dnsname.FQDN("via-0xff.1.2.3.4."), dns.TypeAAAA, netip.MustParseAddr("fd7a:115c:a1e0:b1a:0:ff:1.2.3.4"), dns.RCodeSuccess}, {"via_hex", dnsname.FQDN("via-0xff.1.2.3.4."), dns.TypeAAAA, netip.MustParseAddr("fd7a:115c:a1e0:b1a:0:ff:1.2.3.4"), dns.RCodeSuccess},
{"via_dec", dnsname.FQDN("via-1.10.0.0.1."), dns.TypeAAAA, netip.MustParseAddr("fd7a:115c:a1e0:b1a:0:1:10.0.0.1"), dns.RCodeSuccess}, {"via_dec", dnsname.FQDN("via-1.10.0.0.1."), dns.TypeAAAA, netip.MustParseAddr("fd7a:115c:a1e0:b1a:0:1:10.0.0.1"), dns.RCodeSuccess},
{"x_via_hex", dnsname.FQDN("4.3.2.1.via-0xff."), dns.TypeAAAA, netip.MustParseAddr("fd7a:115c:a1e0:b1a:0:ff:4.3.2.1"), dns.RCodeSuccess}, {"x_via_hex", dnsname.FQDN("4.3.2.1.via-0xff."), dns.TypeAAAA, netip.MustParseAddr("fd7a:115c:a1e0:b1a:0:ff:4.3.2.1"), dns.RCodeSuccess},
{"x_via_dec", dnsname.FQDN("1.0.0.10.via-1."), dns.TypeAAAA, netip.MustParseAddr("fd7a:115c:a1e0:b1a:0:1:1.0.0.10"), dns.RCodeSuccess}, {"x_via_dec", dnsname.FQDN("1.0.0.10.via-1."), dns.TypeAAAA, netip.MustParseAddr("fd7a:115c:a1e0:b1a:0:1:1.0.0.10"), dns.RCodeSuccess},
{"via_invalid", dnsname.FQDN("via-."), dns.TypeAAAA, netaddr.IP{}, dns.RCodeRefused}, {"via_invalid", dnsname.FQDN("via-."), dns.TypeAAAA, netip.Addr{}, dns.RCodeRefused},
{"via_invalid_2", dnsname.FQDN("2.3.4.5.via-."), dns.TypeAAAA, netaddr.IP{}, dns.RCodeRefused}, {"via_invalid_2", dnsname.FQDN("2.3.4.5.via-."), dns.TypeAAAA, netip.Addr{}, dns.RCodeRefused},
} }
for _, tt := range tests { for _, tt := range tests {
@ -1003,7 +1003,7 @@ func TestForwardLinkSelection(t *testing.T) {
// routes differently. // routes differently.
specialIP := netaddr.IPv4(1, 2, 3, 4) specialIP := netaddr.IPv4(1, 2, 3, 4)
fwd := newForwarder(t.Logf, nil, linkSelFunc(func(ip netaddr.IP) string { fwd := newForwarder(t.Logf, nil, linkSelFunc(func(ip netip.Addr) string {
if ip == netaddr.IPv4(1, 2, 3, 4) { if ip == netaddr.IPv4(1, 2, 3, 4) {
return "special" return "special"
} }
@ -1011,7 +1011,7 @@ func TestForwardLinkSelection(t *testing.T) {
}), new(tsdial.Dialer)) }), new(tsdial.Dialer))
// Test non-special IP. // Test non-special IP.
if got, err := fwd.packetListener(netaddr.IP{}); err != nil { if got, err := fwd.packetListener(netip.Addr{}); err != nil {
t.Fatal(err) t.Fatal(err)
} else if got != stdNetPacketListener { } else if got != stdNetPacketListener {
t.Errorf("for IP zero value, didn't get expected packet listener") t.Errorf("for IP zero value, didn't get expected packet listener")
@ -1035,9 +1035,9 @@ func TestForwardLinkSelection(t *testing.T) {
} }
} }
type linkSelFunc func(ip netaddr.IP) string type linkSelFunc func(ip netip.Addr) string
func (f linkSelFunc) PickLink(ip netaddr.IP) string { return f(ip) } func (f linkSelFunc) PickLink(ip netip.Addr) string { return f(ip) }
func TestHandleExitNodeDNSQueryWithNetPkg(t *testing.T) { func TestHandleExitNodeDNSQueryWithNetPkg(t *testing.T) {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {

View File

@ -15,6 +15,7 @@
"fmt" "fmt"
"log" "log"
"net" "net"
"net/netip"
"runtime" "runtime"
"sync" "sync"
"time" "time"
@ -62,7 +63,7 @@ type Resolver struct {
// LookupIPFallback optionally provides a backup DNS mechanism // LookupIPFallback optionally provides a backup DNS mechanism
// to use if Forward returns an error or no results. // to use if Forward returns an error or no results.
LookupIPFallback func(ctx context.Context, host string) ([]netaddr.IP, error) LookupIPFallback func(ctx context.Context, host string) ([]netip.Addr, error)
// TTL is how long to keep entries cached // TTL is how long to keep entries cached
// //
@ -76,7 +77,7 @@ type Resolver struct {
// SingleHostStaticResult, if non-nil, is the static result of IPs that is returned // SingleHostStaticResult, if non-nil, is the static result of IPs that is returned
// by Resolver.LookupIP for any hostname. When non-nil, SingleHost must also be // by Resolver.LookupIP for any hostname. When non-nil, SingleHost must also be
// set with the expected name. // set with the expected name.
SingleHostStaticResult []netaddr.IP SingleHostStaticResult []netip.Addr
// SingleHost is the hostname that SingleHostStaticResult is for. // SingleHost is the hostname that SingleHostStaticResult is for.
// It is required when SingleHostStaticResult is present. // It is required when SingleHostStaticResult is present.
@ -271,7 +272,7 @@ func (r *Resolver) lookupIP(host string) (ip, ip6 net.IP, allIPs []net.IPAddr, e
if (err != nil || len(ips) == 0) && r.LookupIPFallback != nil { if (err != nil || len(ips) == 0) && r.LookupIPFallback != nil {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel() defer cancel()
var fips []netaddr.IP var fips []netip.Addr
fips, err = r.LookupIPFallback(ctx, host) fips, err = r.LookupIPFallback(ctx, host)
if err == nil { if err == nil {
ips = nil ips = nil
@ -344,7 +345,7 @@ func Dialer(fwd DialContextFunc, dnsCache *Resolver) DialContextFunc {
d := &dialer{ d := &dialer{
fwd: fwd, fwd: fwd,
dnsCache: dnsCache, dnsCache: dnsCache,
pastConnect: map[netaddr.IP]time.Time{}, pastConnect: map[netip.Addr]time.Time{},
} }
return d.DialContext return d.DialContext
} }
@ -355,7 +356,7 @@ type dialer struct {
dnsCache *Resolver dnsCache *Resolver
mu sync.Mutex mu sync.Mutex
pastConnect map[netaddr.IP]time.Time pastConnect map[netip.Addr]time.Time
} }
func (d *dialer) DialContext(ctx context.Context, network, address string) (retConn net.Conn, ret error) { func (d *dialer) DialContext(ctx context.Context, network, address string) (retConn net.Conn, ret error) {
@ -426,7 +427,7 @@ type dialCall struct {
network, address, host, port string network, address, host, port string
mu sync.Mutex // lock ordering: dialer.mu, then dialCall.mu mu sync.Mutex // lock ordering: dialer.mu, then dialCall.mu
fails map[netaddr.IP]error // set of IPs that failed to dial thus far fails map[netip.Addr]error // set of IPs that failed to dial thus far
} }
// dnsWasTrustworthy reports whether we think the IP address(es) we // dnsWasTrustworthy reports whether we think the IP address(es) we
@ -453,7 +454,7 @@ func (dc *dialCall) dnsWasTrustworthy() bool {
return false return false
} }
func (dc *dialCall) dialOne(ctx context.Context, ip netaddr.IP) (net.Conn, error) { func (dc *dialCall) dialOne(ctx context.Context, ip netip.Addr) (net.Conn, error) {
c, err := dc.d.fwd(ctx, dc.network, net.JoinHostPort(ip.String(), dc.port)) c, err := dc.d.fwd(ctx, dc.network, net.JoinHostPort(ip.String(), dc.port))
dc.noteDialResult(ip, err) dc.noteDialResult(ip, err)
return c, err return c, err
@ -461,7 +462,7 @@ func (dc *dialCall) dialOne(ctx context.Context, ip netaddr.IP) (net.Conn, error
// noteDialResult records that a dial to ip either succeeded or // noteDialResult records that a dial to ip either succeeded or
// failed. // failed.
func (dc *dialCall) noteDialResult(ip netaddr.IP, err error) { func (dc *dialCall) noteDialResult(ip netip.Addr, err error) {
if err == nil { if err == nil {
d := dc.d d := dc.d
d.mu.Lock() d.mu.Lock()
@ -472,17 +473,17 @@ func (dc *dialCall) noteDialResult(ip netaddr.IP, err error) {
dc.mu.Lock() dc.mu.Lock()
defer dc.mu.Unlock() defer dc.mu.Unlock()
if dc.fails == nil { if dc.fails == nil {
dc.fails = map[netaddr.IP]error{} dc.fails = map[netip.Addr]error{}
} }
dc.fails[ip] = err dc.fails[ip] = err
} }
// uniqueIPs returns a possibly-mutated subslice of ips, filtering out // uniqueIPs returns a possibly-mutated subslice of ips, filtering out
// dups and ones that have already failed previously. // dups and ones that have already failed previously.
func (dc *dialCall) uniqueIPs(ips []netaddr.IP) (ret []netaddr.IP) { func (dc *dialCall) uniqueIPs(ips []netip.Addr) (ret []netip.Addr) {
dc.mu.Lock() dc.mu.Lock()
defer dc.mu.Unlock() defer dc.mu.Unlock()
seen := map[netaddr.IP]bool{} seen := map[netip.Addr]bool{}
ret = ips[:0] ret = ips[:0]
for _, ip := range ips { for _, ip := range ips {
if seen[ip] { if seen[ip] {
@ -504,7 +505,7 @@ func (dc *dialCall) uniqueIPs(ips []netaddr.IP) (ret []netaddr.IP) {
// raceDial tries to dial port on each ip in ips, starting a new race // raceDial tries to dial port on each ip in ips, starting a new race
// dial every fallbackDelay apart, returning whichever completes first. // dial every fallbackDelay apart, returning whichever completes first.
func (dc *dialCall) raceDial(ctx context.Context, ips []netaddr.IP) (net.Conn, error) { func (dc *dialCall) raceDial(ctx context.Context, ips []netip.Addr) (net.Conn, error) {
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
defer cancel() defer cancel()
@ -536,7 +537,7 @@ type res struct {
return return
} }
} }
go func(ip netaddr.IP) { go func(ip netip.Addr) {
c, err := dc.dialOne(ctx, ip) c, err := dc.dialOne(ctx, ip)
if err != nil { if err != nil {
// Best effort wake-up a pending dial. // Best effort wake-up a pending dial.
@ -580,7 +581,7 @@ type res struct {
} }
} }
func v4addrs(aa []net.IPAddr) (ret []netaddr.IP) { func v4addrs(aa []net.IPAddr) (ret []netip.Addr) {
for _, a := range aa { for _, a := range aa {
if ip, ok := netaddr.FromStdIP(a.IP); ok && ip.Is4() { if ip, ok := netaddr.FromStdIP(a.IP); ok && ip.Is4() {
ret = append(ret, ip) ret = append(ret, ip)
@ -589,7 +590,7 @@ func v4addrs(aa []net.IPAddr) (ret []netaddr.IP) {
return ret return ret
} }
func v6addrs(aa []net.IPAddr) (ret []netaddr.IP) { func v6addrs(aa []net.IPAddr) (ret []netip.Addr) {
for _, a := range aa { for _, a := range aa {
if ip, ok := netaddr.FromStdIP(a.IP); ok && ip.Is6() { if ip, ok := netaddr.FromStdIP(a.IP); ok && ip.Is6() {
ret = append(ret, ip) ret = append(ret, ip)

View File

@ -14,8 +14,6 @@
"reflect" "reflect"
"testing" "testing"
"time" "time"
"tailscale.com/net/netaddr"
) )
var dialTest = flag.String("dial-test", "", "if non-empty, addr:port to test dial") var dialTest = flag.String("dial-test", "", "if non-empty, addr:port to test dial")
@ -40,7 +38,7 @@ func TestDialer(t *testing.T) {
func TestDialCall_DNSWasTrustworthy(t *testing.T) { func TestDialCall_DNSWasTrustworthy(t *testing.T) {
type step struct { type step struct {
ip netaddr.IP // IP we pretended to dial ip netip.Addr // IP we pretended to dial
err error // the dial error or nil for success err error // the dial error or nil for success
} }
mustIP := netip.MustParseAddr mustIP := netip.MustParseAddr
@ -73,7 +71,7 @@ type step struct {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
d := &dialer{ d := &dialer{
pastConnect: map[netaddr.IP]time.Time{}, pastConnect: map[netip.Addr]time.Time{},
} }
dc := &dialCall{ dc := &dialCall{
d: d, d: d,
@ -95,7 +93,7 @@ func TestDialCall_uniqueIPs(t *testing.T) {
errFail := errors.New("some connect failure") errFail := errors.New("some connect failure")
dc.noteDialResult(mustIP("2003::1"), errFail) dc.noteDialResult(mustIP("2003::1"), errFail)
dc.noteDialResult(mustIP("2003::2"), errFail) dc.noteDialResult(mustIP("2003::2"), errFail)
got := dc.uniqueIPs([]netaddr.IP{ got := dc.uniqueIPs([]netip.Addr{
mustIP("2003::1"), mustIP("2003::1"),
mustIP("2003::2"), mustIP("2003::2"),
mustIP("2003::2"), mustIP("2003::2"),
@ -104,7 +102,7 @@ func TestDialCall_uniqueIPs(t *testing.T) {
mustIP("2003::4"), mustIP("2003::4"),
mustIP("2003::4"), mustIP("2003::4"),
}) })
want := []netaddr.IP{ want := []netip.Addr{
mustIP("2003::3"), mustIP("2003::3"),
mustIP("2003::4"), mustIP("2003::4"),
} }
@ -116,7 +114,7 @@ func TestDialCall_uniqueIPs(t *testing.T) {
func TestResolverAllHostStaticResult(t *testing.T) { func TestResolverAllHostStaticResult(t *testing.T) {
r := &Resolver{ r := &Resolver{
SingleHost: "foo.bar", SingleHost: "foo.bar",
SingleHostStaticResult: []netaddr.IP{ SingleHostStaticResult: []netip.Addr{
netip.MustParseAddr("2001:4860:4860::8888"), netip.MustParseAddr("2001:4860:4860::8888"),
netip.MustParseAddr("2001:4860:4860::8844"), netip.MustParseAddr("2001:4860:4860::8844"),
netip.MustParseAddr("8.8.8.8"), netip.MustParseAddr("8.8.8.8"),

View File

@ -22,21 +22,20 @@
"net/url" "net/url"
"time" "time"
"tailscale.com/net/netaddr"
"tailscale.com/net/netns" "tailscale.com/net/netns"
"tailscale.com/net/tlsdial" "tailscale.com/net/tlsdial"
"tailscale.com/net/tshttpproxy" "tailscale.com/net/tshttpproxy"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
) )
func Lookup(ctx context.Context, host string) ([]netaddr.IP, error) { func Lookup(ctx context.Context, host string) ([]netip.Addr, error) {
if ip, err := netip.ParseAddr(host); err == nil && ip.IsValid() { if ip, err := netip.ParseAddr(host); err == nil && ip.IsValid() {
return []netaddr.IP{ip}, nil return []netip.Addr{ip}, nil
} }
type nameIP struct { type nameIP struct {
dnsName string dnsName string
ip netaddr.IP ip netip.Addr
} }
dm := getDERPMap() dm := getDERPMap()
@ -94,7 +93,7 @@ type nameIP struct {
// serverName and serverIP of are, say, "derpN.tailscale.com". // serverName and serverIP of are, say, "derpN.tailscale.com".
// queryName is the name being sought (e.g. "controlplane.tailscale.com"), passed as hint. // queryName is the name being sought (e.g. "controlplane.tailscale.com"), passed as hint.
func bootstrapDNSMap(ctx context.Context, serverName string, serverIP netaddr.IP, queryName string) (dnsMap, error) { func bootstrapDNSMap(ctx context.Context, serverName string, serverIP netip.Addr, queryName string) (dnsMap, error) {
dialer := netns.NewDialer(log.Printf) dialer := netns.NewDialer(log.Printf)
tr := http.DefaultTransport.(*http.Transport).Clone() tr := http.DefaultTransport.(*http.Transport).Clone()
tr.Proxy = tshttpproxy.ProxyFromEnvironment tr.Proxy = tshttpproxy.ProxyFromEnvironment
@ -124,7 +123,7 @@ func bootstrapDNSMap(ctx context.Context, serverName string, serverIP netaddr.IP
// dnsMap is the JSON type returned by the DERP /bootstrap-dns handler: // dnsMap is the JSON type returned by the DERP /bootstrap-dns handler:
// https://derp10.tailscale.com/bootstrap-dns // https://derp10.tailscale.com/bootstrap-dns
type dnsMap map[string][]netaddr.IP type dnsMap map[string][]netip.Addr
// getDERPMap returns some DERP map. The DERP servers also run a fallback // getDERPMap returns some DERP map. The DERP servers also run a fallback
// DNS server. // DNS server.

View File

@ -13,16 +13,16 @@
import ( import (
"container/list" "container/list"
"fmt" "fmt"
"net/netip"
"tailscale.com/net/netaddr"
"tailscale.com/types/ipproto" "tailscale.com/types/ipproto"
) )
// Tuple is a 5-tuple of proto, source and destination IP and port. // Tuple is a 5-tuple of proto, source and destination IP and port.
type Tuple struct { type Tuple struct {
Proto ipproto.Proto Proto ipproto.Proto
Src netaddr.IPPort Src netip.AddrPort
Dst netaddr.IPPort Dst netip.AddrPort
} }
func (t Tuple) String() string { func (t Tuple) String() string {

View File

@ -28,7 +28,7 @@
// Tailscale returns the current machine's Tailscale interface, if any. // Tailscale returns the current machine's Tailscale interface, if any.
// If none is found, all zero values are returned. // If none is found, all zero values are returned.
// A non-nil error is only returned on a problem listing the system interfaces. // A non-nil error is only returned on a problem listing the system interfaces.
func Tailscale() ([]netaddr.IP, *net.Interface, error) { func Tailscale() ([]netip.Addr, *net.Interface, error) {
ifs, err := netInterfaces() ifs, err := netInterfaces()
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -41,7 +41,7 @@ func Tailscale() ([]netaddr.IP, *net.Interface, error) {
if err != nil { if err != nil {
continue continue
} }
var tsIPs []netaddr.IP var tsIPs []netip.Addr
for _, a := range addrs { for _, a := range addrs {
if ipnet, ok := a.(*net.IPNet); ok { if ipnet, ok := a.(*net.IPNet); ok {
nip, ok := netaddr.FromStdIP(ipnet.IP) nip, ok := netaddr.FromStdIP(ipnet.IP)
@ -86,13 +86,13 @@ func isProblematicInterface(nif *net.Interface) bool {
// whether they're loopback addresses. If there are no regular addresses // whether they're loopback addresses. If there are no regular addresses
// it will return any IPv4 linklocal or IPv6 unique local addresses because we // it will return any IPv4 linklocal or IPv6 unique local addresses because we
// know of environments where these are used with NAT to provide connectivity. // know of environments where these are used with NAT to provide connectivity.
func LocalAddresses() (regular, loopback []netaddr.IP, err error) { func LocalAddresses() (regular, loopback []netip.Addr, err error) {
// TODO(crawshaw): don't serve interface addresses that we are routing // TODO(crawshaw): don't serve interface addresses that we are routing
ifaces, err := netInterfaces() ifaces, err := netInterfaces()
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
var regular4, regular6, linklocal4, ula6 []netaddr.IP var regular4, regular6, linklocal4, ula6 []netip.Addr
for _, iface := range ifaces { for _, iface := range ifaces {
stdIf := iface.Interface stdIf := iface.Interface
if !isUp(stdIf) || isProblematicInterface(stdIf) { if !isUp(stdIf) || isProblematicInterface(stdIf) {
@ -165,7 +165,7 @@ func LocalAddresses() (regular, loopback []netaddr.IP, err error) {
return regular, loopback, nil return regular, loopback, nil
} }
func sortIPs(s []netaddr.IP) { func sortIPs(s []netip.Addr) {
sort.Slice(s, func(i, j int) bool { return s[i].Less(s[j]) }) sort.Slice(s, func(i, j int) bool { return s[i].Less(s[j]) })
} }
@ -187,7 +187,7 @@ func (i Interface) Addrs() ([]net.Addr, error) {
// ForeachInterfaceAddress is a wrapper for GetList, then // ForeachInterfaceAddress is a wrapper for GetList, then
// List.ForeachInterfaceAddress. // List.ForeachInterfaceAddress.
func ForeachInterfaceAddress(fn func(Interface, netaddr.IPPrefix)) error { func ForeachInterfaceAddress(fn func(Interface, netip.Prefix)) error {
ifaces, err := GetList() ifaces, err := GetList()
if err != nil { if err != nil {
return err return err
@ -198,7 +198,7 @@ func ForeachInterfaceAddress(fn func(Interface, netaddr.IPPrefix)) error {
// ForeachInterfaceAddress calls fn for each interface in ifaces, with // ForeachInterfaceAddress calls fn for each interface in ifaces, with
// all its addresses. The IPPrefix's IP is the IP address assigned to // all its addresses. The IPPrefix's IP is the IP address assigned to
// the interface, and Bits are the subnet mask. // the interface, and Bits are the subnet mask.
func (ifaces List) ForeachInterfaceAddress(fn func(Interface, netaddr.IPPrefix)) error { func (ifaces List) ForeachInterfaceAddress(fn func(Interface, netip.Prefix)) error {
for _, iface := range ifaces { for _, iface := range ifaces {
addrs, err := iface.Addrs() addrs, err := iface.Addrs()
if err != nil { if err != nil {
@ -218,7 +218,7 @@ func (ifaces List) ForeachInterfaceAddress(fn func(Interface, netaddr.IPPrefix))
// ForeachInterface is a wrapper for GetList, then // ForeachInterface is a wrapper for GetList, then
// List.ForeachInterface. // List.ForeachInterface.
func ForeachInterface(fn func(Interface, []netaddr.IPPrefix)) error { func ForeachInterface(fn func(Interface, []netip.Prefix)) error {
ifaces, err := GetList() ifaces, err := GetList()
if err != nil { if err != nil {
return err return err
@ -229,7 +229,7 @@ func ForeachInterface(fn func(Interface, []netaddr.IPPrefix)) error {
// ForeachInterface calls fn for each interface in ifaces, with // ForeachInterface calls fn for each interface in ifaces, with
// all its addresses. The IPPrefix's IP is the IP address assigned to // all its addresses. The IPPrefix's IP is the IP address assigned to
// the interface, and Bits are the subnet mask. // the interface, and Bits are the subnet mask.
func (ifaces List) ForeachInterface(fn func(Interface, []netaddr.IPPrefix)) error { func (ifaces List) ForeachInterface(fn func(Interface, []netip.Prefix)) error {
ifaces, err := GetList() ifaces, err := GetList()
if err != nil { if err != nil {
return err return err
@ -239,7 +239,7 @@ func (ifaces List) ForeachInterface(fn func(Interface, []netaddr.IPPrefix)) erro
if err != nil { if err != nil {
return err return err
} }
var pfxs []netaddr.IPPrefix var pfxs []netip.Prefix
for _, a := range addrs { for _, a := range addrs {
switch v := a.(type) { switch v := a.(type) {
case *net.IPNet: case *net.IPNet:
@ -264,7 +264,7 @@ type State struct {
// configured on that interface. Each address is represented as an // configured on that interface. Each address is represented as an
// IPPrefix, where the IP is the interface IP address and Bits is // IPPrefix, where the IP is the interface IP address and Bits is
// the subnet mask. // the subnet mask.
InterfaceIPs map[string][]netaddr.IPPrefix InterfaceIPs map[string][]netip.Prefix
Interface map[string]Interface Interface map[string]Interface
// HaveV6 is whether this machine has an IPv6 Global or Unique Local Address // HaveV6 is whether this machine has an IPv6 Global or Unique Local Address
@ -358,11 +358,11 @@ func (s *State) String() string {
// An InterfaceFilter indicates whether EqualFiltered should use i when deciding whether two States are equal. // An InterfaceFilter indicates whether EqualFiltered should use i when deciding whether two States are equal.
// ips are all the IPPrefixes associated with i. // ips are all the IPPrefixes associated with i.
type InterfaceFilter func(i Interface, ips []netaddr.IPPrefix) bool type InterfaceFilter func(i Interface, ips []netip.Prefix) bool
// An IPFilter indicates whether EqualFiltered should use ip when deciding whether two States are equal. // An IPFilter indicates whether EqualFiltered should use ip when deciding whether two States are equal.
// ip is an ip address associated with some interface under consideration. // ip is an ip address associated with some interface under consideration.
type IPFilter func(ip netaddr.IP) bool type IPFilter func(ip netip.Addr) bool
// EqualFiltered reports whether s and s2 are equal, // EqualFiltered reports whether s and s2 are equal,
// considering only interfaces in s for which filter returns true, // considering only interfaces in s for which filter returns true,
@ -410,9 +410,9 @@ func interfacesEqual(a, b Interface) bool {
bytes.Equal([]byte(a.HardwareAddr), []byte(b.HardwareAddr)) bytes.Equal([]byte(a.HardwareAddr), []byte(b.HardwareAddr))
} }
func filteredIPPs(ipps []netaddr.IPPrefix, useIP IPFilter) []netaddr.IPPrefix { func filteredIPPs(ipps []netip.Prefix, useIP IPFilter) []netip.Prefix {
// TODO: rewrite prefixesEqualFiltered to avoid making copies // TODO: rewrite prefixesEqualFiltered to avoid making copies
x := make([]netaddr.IPPrefix, 0, len(ipps)) x := make([]netip.Prefix, 0, len(ipps))
for _, ipp := range ipps { for _, ipp := range ipps {
if useIP(ipp.Addr()) { if useIP(ipp.Addr()) {
x = append(x, ipp) x = append(x, ipp)
@ -421,11 +421,11 @@ func filteredIPPs(ipps []netaddr.IPPrefix, useIP IPFilter) []netaddr.IPPrefix {
return x return x
} }
func prefixesEqualFiltered(a, b []netaddr.IPPrefix, useIP IPFilter) bool { func prefixesEqualFiltered(a, b []netip.Prefix, useIP IPFilter) bool {
return prefixesEqual(filteredIPPs(a, useIP), filteredIPPs(b, useIP)) return prefixesEqual(filteredIPPs(a, useIP), filteredIPPs(b, useIP))
} }
func prefixesEqual(a, b []netaddr.IPPrefix) bool { func prefixesEqual(a, b []netip.Prefix) bool {
if len(a) != len(b) { if len(a) != len(b) {
return false return false
} }
@ -440,21 +440,21 @@ func prefixesEqual(a, b []netaddr.IPPrefix) bool {
// UseInterestingInterfaces is an InterfaceFilter that reports whether i is an interesting interface. // UseInterestingInterfaces is an InterfaceFilter that reports whether i is an interesting interface.
// An interesting interface if it is (a) not owned by Tailscale and (b) routes interesting IP addresses. // An interesting interface if it is (a) not owned by Tailscale and (b) routes interesting IP addresses.
// See UseInterestingIPs for the defition of an interesting IP address. // See UseInterestingIPs for the defition of an interesting IP address.
func UseInterestingInterfaces(i Interface, ips []netaddr.IPPrefix) bool { func UseInterestingInterfaces(i Interface, ips []netip.Prefix) bool {
return !isTailscaleInterface(i.Name, ips) && anyInterestingIP(ips) return !isTailscaleInterface(i.Name, ips) && anyInterestingIP(ips)
} }
// UseInterestingIPs is an IPFilter that reports whether ip is an interesting IP address. // UseInterestingIPs is an IPFilter that reports whether ip is an interesting IP address.
// An IP address is interesting if it is neither a lopback not a link local unicast IP address. // An IP address is interesting if it is neither a lopback not a link local unicast IP address.
func UseInterestingIPs(ip netaddr.IP) bool { func UseInterestingIPs(ip netip.Addr) bool {
return isInterestingIP(ip) return isInterestingIP(ip)
} }
// UseAllInterfaces is an InterfaceFilter that includes all interfaces. // UseAllInterfaces is an InterfaceFilter that includes all interfaces.
func UseAllInterfaces(i Interface, ips []netaddr.IPPrefix) bool { return true } func UseAllInterfaces(i Interface, ips []netip.Prefix) bool { return true }
// UseAllIPs is an IPFilter that includes all all IPs. // UseAllIPs is an IPFilter that includes all all IPs.
func UseAllIPs(ips netaddr.IP) bool { return true } func UseAllIPs(ips netip.Addr) bool { return true }
func (s *State) HasPAC() bool { return s != nil && s.PAC != "" } func (s *State) HasPAC() bool { return s != nil && s.PAC != "" }
@ -466,7 +466,7 @@ func (s *State) AnyInterfaceUp() bool {
return s != nil && (s.HaveV4 || s.HaveV6) return s != nil && (s.HaveV4 || s.HaveV6)
} }
func hasTailscaleIP(pfxs []netaddr.IPPrefix) bool { func hasTailscaleIP(pfxs []netip.Prefix) bool {
for _, pfx := range pfxs { for _, pfx := range pfxs {
if tsaddr.IsTailscaleIP(pfx.Addr()) { if tsaddr.IsTailscaleIP(pfx.Addr()) {
return true return true
@ -475,7 +475,7 @@ func hasTailscaleIP(pfxs []netaddr.IPPrefix) bool {
return false return false
} }
func isTailscaleInterface(name string, ips []netaddr.IPPrefix) bool { func isTailscaleInterface(name string, ips []netip.Prefix) bool {
if runtime.GOOS == "darwin" && strings.HasPrefix(name, "utun") && hasTailscaleIP(ips) { if runtime.GOOS == "darwin" && strings.HasPrefix(name, "utun") && hasTailscaleIP(ips) {
// On macOS in the sandboxed app (at least as of // On macOS in the sandboxed app (at least as of
// 2021-02-25), we often see two utun devices // 2021-02-25), we often see two utun devices
@ -497,10 +497,10 @@ func isTailscaleInterface(name string, ips []netaddr.IPPrefix) bool {
// It does not set the returned State.IsExpensive. The caller can populate that. // It does not set the returned State.IsExpensive. The caller can populate that.
func GetState() (*State, error) { func GetState() (*State, error) {
s := &State{ s := &State{
InterfaceIPs: make(map[string][]netaddr.IPPrefix), InterfaceIPs: make(map[string][]netip.Prefix),
Interface: make(map[string]Interface), Interface: make(map[string]Interface),
} }
if err := ForeachInterface(func(ni Interface, pfxs []netaddr.IPPrefix) { if err := ForeachInterface(func(ni Interface, pfxs []netip.Prefix) {
ifUp := ni.IsUp() ifUp := ni.IsUp()
s.Interface[ni.Name] = ni s.Interface[ni.Name] = ni
s.InterfaceIPs[ni.Name] = append(s.InterfaceIPs[ni.Name], pfxs...) s.InterfaceIPs[ni.Name] = append(s.InterfaceIPs[ni.Name], pfxs...)
@ -556,7 +556,7 @@ func HTTPOfListener(ln net.Listener) string {
var goodIP string var goodIP string
var privateIP string var privateIP string
ForeachInterfaceAddress(func(i Interface, pfx netaddr.IPPrefix) { ForeachInterfaceAddress(func(i Interface, pfx netip.Prefix) {
ip := pfx.Addr() ip := pfx.Addr()
if ip.IsPrivate() { if ip.IsPrivate() {
if privateIP == "" { if privateIP == "" {
@ -576,14 +576,14 @@ func HTTPOfListener(ln net.Listener) string {
} }
var likelyHomeRouterIP func() (netaddr.IP, bool) var likelyHomeRouterIP func() (netip.Addr, bool)
// LikelyHomeRouterIP returns the likely IP of the residential router, // LikelyHomeRouterIP returns the likely IP of the residential router,
// which will always be an IPv4 private address, if found. // which will always be an IPv4 private address, if found.
// In addition, it returns the IP address of the current machine on // In addition, it returns the IP address of the current machine on
// the LAN using that gateway. // the LAN using that gateway.
// This is used as the destination for UPnP, NAT-PMP, PCP, etc queries. // This is used as the destination for UPnP, NAT-PMP, PCP, etc queries.
func LikelyHomeRouterIP() (gateway, myIP netaddr.IP, ok bool) { func LikelyHomeRouterIP() (gateway, myIP netip.Addr, ok bool) {
if likelyHomeRouterIP != nil { if likelyHomeRouterIP != nil {
gateway, ok = likelyHomeRouterIP() gateway, ok = likelyHomeRouterIP()
if !ok { if !ok {
@ -593,7 +593,7 @@ func LikelyHomeRouterIP() (gateway, myIP netaddr.IP, ok bool) {
if !ok { if !ok {
return return
} }
ForeachInterfaceAddress(func(i Interface, pfx netaddr.IPPrefix) { ForeachInterfaceAddress(func(i Interface, pfx netip.Prefix) {
ip := pfx.Addr() ip := pfx.Addr()
if !i.IsUp() || !ip.IsValid() || myIP.IsValid() { if !i.IsUp() || !ip.IsValid() || myIP.IsValid() {
return return
@ -611,7 +611,7 @@ func LikelyHomeRouterIP() (gateway, myIP netaddr.IP, ok bool) {
// conceivably be used to get Internet connectivity. Globally routable and // conceivably be used to get Internet connectivity. Globally routable and
// private IPv4 addresses are always Usable, and link local 169.254.x.x // private IPv4 addresses are always Usable, and link local 169.254.x.x
// addresses are in some environments. // addresses are in some environments.
func isUsableV4(ip netaddr.IP) bool { func isUsableV4(ip netip.Addr) bool {
if !ip.Is4() || ip.IsLoopback() { if !ip.Is4() || ip.IsLoopback() {
return false return false
} }
@ -625,7 +625,7 @@ func isUsableV4(ip netaddr.IP) bool {
// conceivably be used to get Internet connectivity. Globally routable // conceivably be used to get Internet connectivity. Globally routable
// IPv6 addresses are always Usable, and Unique Local Addresses // IPv6 addresses are always Usable, and Unique Local Addresses
// (fc00::/7) are in some environments used with address translation. // (fc00::/7) are in some environments used with address translation.
func isUsableV6(ip netaddr.IP) bool { func isUsableV6(ip netip.Addr) bool {
return v6Global1.Contains(ip) || return v6Global1.Contains(ip) ||
(ip.Is6() && ip.IsPrivate() && !tsaddr.TailscaleULARange().Contains(ip)) (ip.Is6() && ip.IsPrivate() && !tsaddr.TailscaleULARange().Contains(ip))
} }
@ -636,7 +636,7 @@ func isUsableV6(ip netaddr.IP) bool {
// anyInterestingIP reports whether pfxs contains any IP that matches // anyInterestingIP reports whether pfxs contains any IP that matches
// isInterestingIP. // isInterestingIP.
func anyInterestingIP(pfxs []netaddr.IPPrefix) bool { func anyInterestingIP(pfxs []netip.Prefix) bool {
for _, pfx := range pfxs { for _, pfx := range pfxs {
if isInterestingIP(pfx.Addr()) { if isInterestingIP(pfx.Addr()) {
return true return true
@ -648,7 +648,7 @@ func anyInterestingIP(pfxs []netaddr.IPPrefix) bool {
// isInterestingIP reports whether ip is an interesting IP that we // isInterestingIP reports whether ip is an interesting IP that we
// should log in interfaces.State logging. We don't need to show // should log in interfaces.State logging. We don't need to show
// localhost or link-local addresses. // localhost or link-local addresses.
func isInterestingIP(ip netaddr.IP) bool { func isInterestingIP(ip netip.Addr) bool {
return !ip.IsLoopback() && !ip.IsLinkLocalUnicast() return !ip.IsLoopback() && !ip.IsLinkLocalUnicast()
} }
@ -727,7 +727,7 @@ func DefaultRoute() (DefaultRouteDetails, error) {
func HasCGNATInterface() (bool, error) { func HasCGNATInterface() (bool, error) {
hasCGNATInterface := false hasCGNATInterface := false
cgnatRange := tsaddr.CGNATRange() cgnatRange := tsaddr.CGNATRange()
err := ForeachInterface(func(i Interface, pfxs []netaddr.IPPrefix) { err := ForeachInterface(func(i Interface, pfxs []netip.Prefix) {
if hasCGNATInterface || !i.IsUp() || isTailscaleInterface(i.Name, pfxs) { if hasCGNATInterface || !i.IsUp() || isTailscaleInterface(i.Name, pfxs) {
return return
} }

View File

@ -15,6 +15,7 @@
"fmt" "fmt"
"log" "log"
"net" "net"
"net/netip"
"syscall" "syscall"
"golang.org/x/net/route" "golang.org/x/net/route"
@ -95,7 +96,7 @@ func init() {
likelyHomeRouterIP = likelyHomeRouterIPBSDFetchRIB likelyHomeRouterIP = likelyHomeRouterIPBSDFetchRIB
} }
func likelyHomeRouterIPBSDFetchRIB() (ret netaddr.IP, ok bool) { func likelyHomeRouterIPBSDFetchRIB() (ret netip.Addr, ok bool) {
rib, err := fetchRoutingTable() rib, err := fetchRoutingTable()
if err != nil { if err != nil {
log.Printf("routerIP/FetchRIB: %v", err) log.Printf("routerIP/FetchRIB: %v", err)

View File

@ -9,6 +9,7 @@
"fmt" "fmt"
"log" "log"
"net" "net"
"net/netip"
"syscall" "syscall"
"golang.org/x/net/route" "golang.org/x/net/route"
@ -89,7 +90,7 @@ func init() {
likelyHomeRouterIP = likelyHomeRouterIPDarwinFetchRIB likelyHomeRouterIP = likelyHomeRouterIPDarwinFetchRIB
} }
func likelyHomeRouterIPDarwinFetchRIB() (ret netaddr.IP, ok bool) { func likelyHomeRouterIPDarwinFetchRIB() (ret netip.Addr, ok bool) {
rib, err := fetchRoutingTable() rib, err := fetchRoutingTable()
if err != nil { if err != nil {
log.Printf("routerIP/FetchRIB: %v", err) log.Printf("routerIP/FetchRIB: %v", err)

View File

@ -11,7 +11,6 @@
"testing" "testing"
"go4.org/mem" "go4.org/mem"
"tailscale.com/net/netaddr"
"tailscale.com/util/lineread" "tailscale.com/util/lineread"
"tailscale.com/version" "tailscale.com/version"
) )
@ -42,7 +41,7 @@ func TestLikelyHomeRouterIPSyscallExec(t *testing.T) {
... ...
*/ */
func likelyHomeRouterIPDarwinExec() (ret netaddr.IP, ok bool) { func likelyHomeRouterIPDarwinExec() (ret netip.Addr, ok bool) {
if version.IsMobile() { if version.IsMobile() {
// Don't try to do subprocesses on iOS. Ends up with log spam like: // Don't try to do subprocesses on iOS. Ends up with log spam like:
// kernel: "Sandbox: IPNExtension(86580) deny(1) process-fork" // kernel: "Sandbox: IPNExtension(86580) deny(1) process-fork"

View File

@ -46,7 +46,7 @@ func init() {
ens18 00000000 0100000A 0003 0 0 0 00000000 0 0 0 ens18 00000000 0100000A 0003 0 0 0 00000000 0 0 0
ens18 0000000A 00000000 0001 0 0 0 0000FFFF 0 0 0 ens18 0000000A 00000000 0001 0 0 0 0000FFFF 0 0 0
*/ */
func likelyHomeRouterIPLinux() (ret netaddr.IP, ok bool) { func likelyHomeRouterIPLinux() (ret netip.Addr, ok bool) {
if procNetRouteErr.Get() { if procNetRouteErr.Get() {
// If we failed to read /proc/net/route previously, don't keep trying. // If we failed to read /proc/net/route previously, don't keep trying.
// But if we're on Android, go into the Android path. // But if we're on Android, go into the Android path.
@ -104,7 +104,7 @@ func likelyHomeRouterIPLinux() (ret netaddr.IP, ok bool) {
// Android apps don't have permission to read /proc/net/route, at // Android apps don't have permission to read /proc/net/route, at
// least on Google devices and the Android emulator. // least on Google devices and the Android emulator.
func likelyHomeRouterIPAndroid() (ret netaddr.IP, ok bool) { func likelyHomeRouterIPAndroid() (ret netip.Addr, ok bool) {
cmd := exec.Command("/system/bin/ip", "route", "show", "table", "0") cmd := exec.Command("/system/bin/ip", "route", "show", "table", "0")
out, err := cmd.StdoutPipe() out, err := cmd.StdoutPipe()
if err != nil { if err != nil {

View File

@ -9,8 +9,6 @@
"net" "net"
"net/netip" "net/netip"
"testing" "testing"
"tailscale.com/net/netaddr"
) )
func TestGetState(t *testing.T) { func TestGetState(t *testing.T) {
@ -76,7 +74,7 @@ func TestStateEqualFilteredIPFilter(t *testing.T) {
// has gained an "uninteresting" IP address. // has gained an "uninteresting" IP address.
s1 := &State{ s1 := &State{
InterfaceIPs: map[string][]netaddr.IPPrefix{"x": { InterfaceIPs: map[string][]netip.Prefix{"x": {
netip.MustParsePrefix("42.0.0.0/8"), netip.MustParsePrefix("42.0.0.0/8"),
netip.MustParsePrefix("169.254.0.0/16"), // link local unicast netip.MustParsePrefix("169.254.0.0/16"), // link local unicast
}}, }},
@ -84,7 +82,7 @@ func TestStateEqualFilteredIPFilter(t *testing.T) {
} }
s2 := &State{ s2 := &State{
InterfaceIPs: map[string][]netaddr.IPPrefix{"x": { InterfaceIPs: map[string][]netip.Prefix{"x": {
netip.MustParsePrefix("42.0.0.0/8"), netip.MustParsePrefix("42.0.0.0/8"),
netip.MustParsePrefix("169.254.0.0/16"), // link local unicast netip.MustParsePrefix("169.254.0.0/16"), // link local unicast
netip.MustParsePrefix("127.0.0.0/8"), // loopback (added) netip.MustParsePrefix("127.0.0.0/8"), // loopback (added)
@ -126,8 +124,8 @@ func TestStateString(t *testing.T) {
Interface: &net.Interface{}, Interface: &net.Interface{},
}, },
}, },
InterfaceIPs: map[string][]netaddr.IPPrefix{ InterfaceIPs: map[string][]netip.Prefix{
"eth0": []netaddr.IPPrefix{ "eth0": []netip.Prefix{
netip.MustParsePrefix("10.0.0.2/8"), netip.MustParsePrefix("10.0.0.2/8"),
}, },
}, },

View File

@ -7,6 +7,7 @@
import ( import (
"log" "log"
"net" "net"
"net/netip"
"net/url" "net/url"
"strings" "strings"
"syscall" "syscall"
@ -27,7 +28,7 @@ func init() {
getPAC = getPACWindows getPAC = getPACWindows
} }
func likelyHomeRouterIPWindows() (ret netaddr.IP, ok bool) { func likelyHomeRouterIPWindows() (ret netip.Addr, ok bool) {
rs, err := winipcfg.GetIPForwardTable2(windows.AF_INET) rs, err := winipcfg.GetIPForwardTable2(windows.AF_INET)
if err != nil { if err != nil {
log.Printf("routerIP/GetIPForwardTable2 error: %v", err) log.Printf("routerIP/GetIPForwardTable2 error: %v", err)
@ -94,7 +95,7 @@ func likelyHomeRouterIPWindows() (ret netaddr.IP, ok bool) {
if ret.IsValid() && !ret.IsPrivate() { if ret.IsValid() && !ret.IsPrivate() {
// Default route has a non-private gateway // Default route has a non-private gateway
return netaddr.IP{}, false return netip.Addr{}, false
} }
return ret, ret.IsValid() return ret, ret.IsValid()

View File

@ -15,14 +15,8 @@
"net/netip" "net/netip"
) )
type (
IP = netip.Addr
IPPort = netip.AddrPort
IPPrefix = netip.Prefix
)
// IPv4 returns the IP of the IPv4 address a.b.c.d. // IPv4 returns the IP of the IPv4 address a.b.c.d.
func IPv4(a, b, c, d uint8) IP { func IPv4(a, b, c, d uint8) netip.Addr {
return netip.AddrFrom4([4]byte{a, b, c, d}) return netip.AddrFrom4([4]byte{a, b, c, d})
} }
@ -30,41 +24,10 @@ func IPv4(a, b, c, d uint8) IP {
// v6-mapped IPv4 address. // v6-mapped IPv4 address.
// //
// It is equivalent to calling IPv6Raw(addr).Unmap(). // It is equivalent to calling IPv6Raw(addr).Unmap().
func IPFrom16(a [16]byte) IP { func IPFrom16(a [16]byte) netip.Addr {
return netip.AddrFrom16(a).Unmap() return netip.AddrFrom16(a).Unmap()
} }
// IPv6Raw returns the IPv6 address given by the bytes in addr, without an
// implicit Unmap call to unmap any v6-mapped IPv4 address.
func IPv6Raw(a [16]byte) IP {
return netip.AddrFrom16(a) // no implicit unmapping
}
// IPFrom4 returns the IPv4 address given by the bytes in addr. It is equivalent
// to calling IPv4(addr[0], addr[1], addr[2], addr[3]).
func IPFrom4(a [4]byte) IP {
return netip.AddrFrom4(a)
}
// IPPrefixFrom returns an IPPrefix with IP ip and provided bits prefix length.
// It does not allocate.
func IPPrefixFrom(ip IP, bits uint8) IPPrefix {
return netip.PrefixFrom(ip, int(bits))
}
// IPPortFrom returns an IPPort with IP ip and port port. It does not allocate.
func IPPortFrom(ip IP, port uint16) IPPort {
return netip.AddrPortFrom(ip, port)
}
// FromStdIPRaw returns an IP from the standard library's IP type.
// If std is invalid, ok is false.
// Unlike FromStdIP, FromStdIPRaw does not do an implicit Unmap if
// len(std) == 16 and contains an IPv6-mapped IPv4 address.
func FromStdIPRaw(std net.IP) (ip IP, ok bool) {
return netip.AddrFromSlice(std)
}
// FromStdIP returns an IP from the standard library's IP type. // FromStdIP returns an IP from the standard library's IP type.
// //
// If std is invalid, ok is false. // If std is invalid, ok is false.
@ -74,9 +37,9 @@ func FromStdIPRaw(std net.IP) (ip IP, ok bool) {
// returned, without the IPv6 wrapper. This is the common form returned by // returned, without the IPv6 wrapper. This is the common form returned by
// the standard library's ParseIP: https://play.golang.org/p/qdjylUkKWxl. // the standard library's ParseIP: https://play.golang.org/p/qdjylUkKWxl.
// To convert a standard library IP without the implicit unmapping, use // To convert a standard library IP without the implicit unmapping, use
// FromStdIPRaw. // netip.AddrFromSlice.
func FromStdIP(std net.IP) (ip IP, ok bool) { func FromStdIP(std net.IP) (ip netip.Addr, ok bool) {
ret, ok := FromStdIPRaw(std) ret, ok := netip.AddrFromSlice(std)
if !ok { if !ok {
return ret, false return ret, false
} }
@ -88,21 +51,21 @@ func FromStdIP(std net.IP) (ip IP, ok bool) {
// FromStdIPNet returns an IPPrefix from the standard library's IPNet type. // FromStdIPNet returns an IPPrefix from the standard library's IPNet type.
// If std is invalid, ok is false. // If std is invalid, ok is false.
func FromStdIPNet(std *net.IPNet) (prefix IPPrefix, ok bool) { func FromStdIPNet(std *net.IPNet) (prefix netip.Prefix, ok bool) {
ip, ok := FromStdIP(std.IP) ip, ok := FromStdIP(std.IP)
if !ok { if !ok {
return IPPrefix{}, false return netip.Prefix{}, false
} }
if l := len(std.Mask); l != net.IPv4len && l != net.IPv6len { if l := len(std.Mask); l != net.IPv4len && l != net.IPv6len {
// Invalid mask. // Invalid mask.
return IPPrefix{}, false return netip.Prefix{}, false
} }
ones, bits := std.Mask.Size() ones, bits := std.Mask.Size()
if ones == 0 && bits == 0 { if ones == 0 && bits == 0 {
// IPPrefix does not support non-contiguous masks. // IPPrefix does not support non-contiguous masks.
return IPPrefix{}, false return netip.Prefix{}, false
} }
return netip.PrefixFrom(ip, ones), true return netip.PrefixFrom(ip, ones), true
@ -110,7 +73,7 @@ func FromStdIPNet(std *net.IPNet) (prefix IPPrefix, ok bool) {
// FromStdAddr maps the components of a standard library TCPAddr or // FromStdAddr maps the components of a standard library TCPAddr or
// UDPAddr into an IPPort. // UDPAddr into an IPPort.
func FromStdAddr(stdIP net.IP, port int, zone string) (_ IPPort, ok bool) { func FromStdAddr(stdIP net.IP, port int, zone string) (_ netip.AddrPort, ok bool) {
ip, ok := FromStdIP(stdIP) ip, ok := FromStdIP(stdIP)
if !ok || port < 0 || port > math.MaxUint16 { if !ok || port < 0 || port > math.MaxUint16 {
return return

View File

@ -211,7 +211,7 @@ func (c *Client) vlogf(format string, a ...any) {
// handleHairSTUN reports whether pkt (from src) was our magic hairpin // handleHairSTUN reports whether pkt (from src) was our magic hairpin
// probe packet that we sent to ourselves. // probe packet that we sent to ourselves.
func (c *Client) handleHairSTUNLocked(pkt []byte, src netaddr.IPPort) bool { func (c *Client) handleHairSTUNLocked(pkt []byte, src netip.AddrPort) bool {
rs := c.curState rs := c.curState
if rs == nil { if rs == nil {
return false return false
@ -234,7 +234,7 @@ func (c *Client) MakeNextReportFull() {
c.nextFull = true c.nextFull = true
} }
func (c *Client) ReceiveSTUNPacket(pkt []byte, src netaddr.IPPort) { func (c *Client) ReceiveSTUNPacket(pkt []byte, src netip.AddrPort) {
c.vlogf("received STUN packet from %s", src) c.vlogf("received STUN packet from %s", src)
if src.Addr().Is4() { if src.Addr().Is4() {
@ -526,7 +526,7 @@ func (c *Client) readPackets(ctx context.Context, pc net.PacketConn) {
type reportState struct { type reportState struct {
c *Client c *Client
hairTX stun.TxID hairTX stun.TxID
gotHairSTUN chan netaddr.IPPort gotHairSTUN chan netip.AddrPort
hairTimeout chan struct{} // closed on timeout hairTimeout chan struct{} // closed on timeout
pc4 STUNConn pc4 STUNConn
pc6 STUNConn pc6 STUNConn
@ -538,7 +538,7 @@ type reportState struct {
mu sync.Mutex mu sync.Mutex
sentHairCheck bool sentHairCheck bool
report *Report // to be returned by GetReport report *Report // to be returned by GetReport
inFlight map[stun.TxID]func(netaddr.IPPort) // called without c.mu held inFlight map[stun.TxID]func(netip.AddrPort) // called without c.mu held
gotEP4 string gotEP4 string
timers []*time.Timer timers []*time.Timer
} }
@ -590,7 +590,7 @@ func (rs *reportState) probeWouldHelp(probe probe, node *tailcfg.DERPNode) bool
return false return false
} }
func (rs *reportState) startHairCheckLocked(dst netaddr.IPPort) { func (rs *reportState) startHairCheckLocked(dst netip.AddrPort) {
if rs.sentHairCheck || rs.incremental { if rs.sentHairCheck || rs.incremental {
return return
} }
@ -642,9 +642,9 @@ func (rs *reportState) stopTimers() {
// addNodeLatency updates rs to note that node's latency is d. If ipp // addNodeLatency updates rs to note that node's latency is d. If ipp
// is non-zero (for all but HTTPS replies), it's recorded as our UDP // is non-zero (for all but HTTPS replies), it's recorded as our UDP
// IP:port. // IP:port.
func (rs *reportState) addNodeLatency(node *tailcfg.DERPNode, ipp netaddr.IPPort, d time.Duration) { func (rs *reportState) addNodeLatency(node *tailcfg.DERPNode, ipp netip.AddrPort, d time.Duration) {
var ipPortStr string var ipPortStr string
if ipp != (netaddr.IPPort{}) { if ipp != (netip.AddrPort{}) {
ipPortStr = net.JoinHostPort(ipp.Addr().String(), fmt.Sprint(ipp.Port())) ipPortStr = net.JoinHostPort(ipp.Addr().String(), fmt.Sprint(ipp.Port()))
} }
@ -772,9 +772,9 @@ func (c *Client) GetReport(ctx context.Context, dm *tailcfg.DERPMap) (_ *Report,
rs := &reportState{ rs := &reportState{
c: c, c: c,
report: newReport(), report: newReport(),
inFlight: map[stun.TxID]func(netaddr.IPPort){}, inFlight: map[stun.TxID]func(netip.AddrPort){},
hairTX: stun.NewTxID(), // random payload hairTX: stun.NewTxID(), // random payload
gotHairSTUN: make(chan netaddr.IPPort, 1), gotHairSTUN: make(chan netip.AddrPort, 1),
hairTimeout: make(chan struct{}), hairTimeout: make(chan struct{}),
stopProbeCh: make(chan struct{}, 1), stopProbeCh: make(chan struct{}, 1),
} }
@ -1008,20 +1008,20 @@ func (c *Client) runHTTPOnlyChecks(ctx context.Context, last *Report, rs *report
return return
} }
d := c.timeNow().Sub(t0) d := c.timeNow().Sub(t0)
rs.addNodeLatency(node, netaddr.IPPort{}, d) rs.addNodeLatency(node, netip.AddrPort{}, d)
}() }()
} }
wg.Wait() wg.Wait()
return nil return nil
} }
func (c *Client) measureHTTPSLatency(ctx context.Context, reg *tailcfg.DERPRegion) (time.Duration, netaddr.IP, error) { func (c *Client) measureHTTPSLatency(ctx context.Context, reg *tailcfg.DERPRegion) (time.Duration, netip.Addr, error) {
metricHTTPSend.Add(1) metricHTTPSend.Add(1)
var result httpstat.Result var result httpstat.Result
ctx, cancel := context.WithTimeout(httpstat.WithHTTPStat(ctx, &result), overallProbeTimeout) ctx, cancel := context.WithTimeout(httpstat.WithHTTPStat(ctx, &result), overallProbeTimeout)
defer cancel() defer cancel()
var ip netaddr.IP var ip netip.Addr
dc := derphttp.NewNetcheckClient(c.logf) dc := derphttp.NewNetcheckClient(c.logf)
tlsConn, tcpConn, node, err := dc.DialRegionTLS(ctx, reg) tlsConn, tcpConn, node, err := dc.DialRegionTLS(ctx, reg)
@ -1033,7 +1033,7 @@ func (c *Client) measureHTTPSLatency(ctx context.Context, reg *tailcfg.DERPRegio
if ta, ok := tlsConn.RemoteAddr().(*net.TCPAddr); ok { if ta, ok := tlsConn.RemoteAddr().(*net.TCPAddr); ok {
ip, _ = netaddr.FromStdIP(ta.IP) ip, _ = netaddr.FromStdIP(ta.IP)
} }
if ip == (netaddr.IP{}) { if ip == (netip.Addr{}) {
return 0, ip, fmt.Errorf("no unexpected RemoteAddr %#v", tlsConn.RemoteAddr()) return 0, ip, fmt.Errorf("no unexpected RemoteAddr %#v", tlsConn.RemoteAddr())
} }
@ -1250,7 +1250,7 @@ func (rs *reportState) runProbe(ctx context.Context, dm *tailcfg.DERPMap, probe
sent := time.Now() // after DNS lookup above sent := time.Now() // after DNS lookup above
rs.mu.Lock() rs.mu.Lock()
rs.inFlight[txID] = func(ipp netaddr.IPPort) { rs.inFlight[txID] = func(ipp netip.AddrPort) {
rs.addNodeLatency(node, ipp, time.Since(sent)) rs.addNodeLatency(node, ipp, time.Since(sent))
cancelSet() // abort other nodes in this set cancelSet() // abort other nodes in this set
} }

View File

@ -9,6 +9,7 @@
"context" "context"
"fmt" "fmt"
"net" "net"
"net/netip"
"reflect" "reflect"
"sort" "sort"
"strconv" "strconv"
@ -17,7 +18,6 @@
"time" "time"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
"tailscale.com/net/stun" "tailscale.com/net/stun"
"tailscale.com/net/stun/stuntest" "tailscale.com/net/stun/stuntest"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
@ -28,14 +28,14 @@ func TestHairpinSTUN(t *testing.T) {
c := &Client{ c := &Client{
curState: &reportState{ curState: &reportState{
hairTX: tx, hairTX: tx,
gotHairSTUN: make(chan netaddr.IPPort, 1), gotHairSTUN: make(chan netip.AddrPort, 1),
}, },
} }
req := stun.Request(tx) req := stun.Request(tx)
if !stun.Is(req) { if !stun.Is(req) {
t.Fatal("expected STUN message") t.Fatal("expected STUN message")
} }
if !c.handleHairSTUNLocked(req, netaddr.IPPort{}) { if !c.handleHairSTUNLocked(req, netip.AddrPort{}) {
t.Fatal("expected true") t.Fatal("expected true")
} }
select { select {

View File

@ -7,15 +7,14 @@
import ( import (
"errors" "errors"
"net/netip"
"runtime" "runtime"
"tailscale.com/net/netaddr"
) )
var ErrNotImplemented = errors.New("not implemented for GOOS=" + runtime.GOOS) var ErrNotImplemented = errors.New("not implemented for GOOS=" + runtime.GOOS)
type Entry struct { type Entry struct {
Local, Remote netaddr.IPPort Local, Remote netip.AddrPort
Pid int Pid int
State string // TODO: type? State string // TODO: type?
} }

View File

@ -9,6 +9,7 @@
"errors" "errors"
"fmt" "fmt"
"math/bits" "math/bits"
"net/netip"
"syscall" "syscall"
"unsafe" "unsafe"
@ -153,22 +154,22 @@ func state(v uint32) string {
return fmt.Sprintf("unknown-state-%d", v) return fmt.Sprintf("unknown-state-%d", v)
} }
func ipport4(addr uint32, port uint16) netaddr.IPPort { func ipport4(addr uint32, port uint16) netip.AddrPort {
if !endian.Big { if !endian.Big {
addr = bits.ReverseBytes32(addr) addr = bits.ReverseBytes32(addr)
} }
return netaddr.IPPortFrom( return netip.AddrPortFrom(
netaddr.IPv4(byte(addr>>24), byte(addr>>16), byte(addr>>8), byte(addr)), netaddr.IPv4(byte(addr>>24), byte(addr>>16), byte(addr>>8), byte(addr)),
port) port)
} }
func ipport6(addr [16]byte, scope uint32, port uint16) netaddr.IPPort { func ipport6(addr [16]byte, scope uint32, port uint16) netip.AddrPort {
ip := netaddr.IPFrom16(addr) ip := netaddr.IPFrom16(addr)
if scope != 0 { if scope != 0 {
// TODO: something better here? // TODO: something better here?
ip = ip.WithZone(fmt.Sprint(scope)) ip = ip.WithZone(fmt.Sprint(scope))
} }
return netaddr.IPPortFrom(ip, port) return netip.AddrPortFrom(ip, port)
} }
func port(v *uint32) uint16 { func port(v *uint32) uint16 {

View File

@ -8,6 +8,7 @@
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"net/netip"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@ -16,19 +17,18 @@
"strings" "strings"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
) )
// protocolsRequiredForForwarding reports whether IPv4 and/or IPv6 protocols are // protocolsRequiredForForwarding reports whether IPv4 and/or IPv6 protocols are
// required to forward the specified routes. // required to forward the specified routes.
// The state param must be specified. // The state param must be specified.
func protocolsRequiredForForwarding(routes []netaddr.IPPrefix, state *interfaces.State) (v4, v6 bool) { func protocolsRequiredForForwarding(routes []netip.Prefix, state *interfaces.State) (v4, v6 bool) {
if len(routes) == 0 { if len(routes) == 0 {
// Nothing to route, so no need to warn. // Nothing to route, so no need to warn.
return false, false return false, false
} }
localIPs := make(map[netaddr.IP]bool) localIPs := make(map[netip.Addr]bool)
for _, addrs := range state.InterfaceIPs { for _, addrs := range state.InterfaceIPs {
for _, pfx := range addrs { for _, pfx := range addrs {
localIPs[pfx.Addr()] = true localIPs[pfx.Addr()] = true
@ -59,7 +59,7 @@ func protocolsRequiredForForwarding(routes []netaddr.IPPrefix, state *interfaces
// It returns an error if it is unable to determine if IP forwarding is enabled. // It returns an error if it is unable to determine if IP forwarding is enabled.
// It returns a warning describing configuration issues if IP forwarding is // It returns a warning describing configuration issues if IP forwarding is
// non-functional or partly functional. // non-functional or partly functional.
func CheckIPForwarding(routes []netaddr.IPPrefix, state *interfaces.State) (warn, err error) { func CheckIPForwarding(routes []netip.Prefix, state *interfaces.State) (warn, err error) {
if runtime.GOOS != "linux" { if runtime.GOOS != "linux" {
switch runtime.GOOS { switch runtime.GOOS {
case "dragonfly", "freebsd", "netbsd", "openbsd": case "dragonfly", "freebsd", "netbsd", "openbsd":

View File

@ -7,8 +7,8 @@
import ( import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"net/netip"
"tailscale.com/net/netaddr"
"tailscale.com/types/ipproto" "tailscale.com/types/ipproto"
) )
@ -19,8 +19,8 @@
type IP4Header struct { type IP4Header struct {
IPProto ipproto.Proto IPProto ipproto.Proto
IPID uint16 IPID uint16
Src netaddr.IP Src netip.Addr
Dst netaddr.IP Dst netip.Addr
} }
// Len implements Header. // Len implements Header.

View File

@ -6,8 +6,8 @@
import ( import (
"encoding/binary" "encoding/binary"
"net/netip"
"tailscale.com/net/netaddr"
"tailscale.com/types/ipproto" "tailscale.com/types/ipproto"
) )
@ -18,8 +18,8 @@
type IP6Header struct { type IP6Header struct {
IPProto ipproto.Proto IPProto ipproto.Proto
IPID uint32 // only lower 20 bits used IPID uint32 // only lower 20 bits used
Src netaddr.IP Src netip.Addr
Dst netaddr.IP Dst netip.Addr
} }
// Len implements Header. // Len implements Header.

View File

@ -54,9 +54,9 @@ type Parsed struct {
IPProto ipproto.Proto IPProto ipproto.Proto
// SrcIP4 is the source address. Family matches IPVersion. Port is // SrcIP4 is the source address. Family matches IPVersion. Port is
// valid iff IPProto == TCP || IPProto == UDP. // valid iff IPProto == TCP || IPProto == UDP.
Src netaddr.IPPort Src netip.AddrPort
// DstIP4 is the destination address. Family matches IPVersion. // DstIP4 is the destination address. Family matches IPVersion.
Dst netaddr.IPPort Dst netip.AddrPort
// TCPFlags is the packet's TCP flag bits. Valid iff IPProto == TCP. // TCPFlags is the packet's TCP flag bits. Valid iff IPProto == TCP.
TCPFlags TCPFlag TCPFlags TCPFlag
} }

View File

@ -10,7 +10,6 @@
"reflect" "reflect"
"testing" "testing"
"tailscale.com/net/netaddr"
"tailscale.com/tstest" "tailscale.com/tstest"
"tailscale.com/types/ipproto" "tailscale.com/types/ipproto"
) )
@ -27,7 +26,7 @@
Fragment = ipproto.Fragment Fragment = ipproto.Fragment
) )
func mustIPPort(s string) netaddr.IPPort { func mustIPPort(s string) netip.AddrPort {
ipp, err := netip.ParseAddrPort(s) ipp, err := netip.ParseAddrPort(s)
if err != nil { if err != nil {
panic(err) panic(err)

View File

@ -14,9 +14,9 @@
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"net/netip"
"tailscale.com/net/flowtrack" "tailscale.com/net/flowtrack"
"tailscale.com/net/netaddr"
"tailscale.com/types/ipproto" "tailscale.com/types/ipproto"
) )
@ -36,10 +36,10 @@
// In the future it might also accept 16 byte IP flow src/dst IPs // In the future it might also accept 16 byte IP flow src/dst IPs
// after the header, if they're different than the IP-level ones. // after the header, if they're different than the IP-level ones.
type TailscaleRejectedHeader struct { type TailscaleRejectedHeader struct {
IPSrc netaddr.IP // IPv4 or IPv6 header's src IP IPSrc netip.Addr // IPv4 or IPv6 header's src IP
IPDst netaddr.IP // IPv4 or IPv6 header's dst IP IPDst netip.Addr // IPv4 or IPv6 header's dst IP
Src netaddr.IPPort // rejected flow's src Src netip.AddrPort // rejected flow's src
Dst netaddr.IPPort // rejected flow's dst Dst netip.AddrPort // rejected flow's dst
Proto ipproto.Proto // proto that was rejected (TCP or UDP) Proto ipproto.Proto // proto that was rejected (TCP or UDP)
Reason TailscaleRejectReason // why the connection was rejected Reason TailscaleRejectReason // why the connection was rejected
@ -192,8 +192,8 @@ func (pp *Parsed) AsTailscaleRejectedHeader() (h TailscaleRejectedHeader, ok boo
Reason: TailscaleRejectReason(p[2]), Reason: TailscaleRejectReason(p[2]),
IPSrc: pp.Src.Addr(), IPSrc: pp.Src.Addr(),
IPDst: pp.Dst.Addr(), IPDst: pp.Dst.Addr(),
Src: netaddr.IPPortFrom(pp.Dst.Addr(), binary.BigEndian.Uint16(p[3:5])), Src: netip.AddrPortFrom(pp.Dst.Addr(), binary.BigEndian.Uint16(p[3:5])),
Dst: netaddr.IPPortFrom(pp.Src.Addr(), binary.BigEndian.Uint16(p[5:7])), Dst: netip.AddrPortFrom(pp.Src.Addr(), binary.BigEndian.Uint16(p[5:7])),
} }
if len(p) > 7 { if len(p) > 7 {
flags := p[7] flags := p[7]

View File

@ -9,8 +9,7 @@
import ( import (
"context" "context"
"net/netip"
"tailscale.com/net/netaddr"
) )
type upnpClient any type upnpClient any
@ -23,9 +22,9 @@ func parseUPnPDiscoResponse([]byte) (uPnPDiscoResponse, error) {
func (c *Client) getUPnPPortMapping( func (c *Client) getUPnPPortMapping(
ctx context.Context, ctx context.Context,
gw netaddr.IP, gw netip.Addr,
internal netaddr.IPPort, internal netip.AddrPort,
prevPort uint16, prevPort uint16,
) (external netaddr.IPPort, ok bool) { ) (external netip.AddrPort, ok bool) {
return netaddr.IPPort{}, false return netip.AddrPort{}, false
} }

View File

@ -10,6 +10,7 @@
"net" "net"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"net/netip"
"sync" "sync"
"testing" "testing"
@ -101,7 +102,7 @@ func (d *TestIGD) TestUPnPPort() uint16 {
return uint16(d.upnpConn.LocalAddr().(*net.UDPAddr).Port) return uint16(d.upnpConn.LocalAddr().(*net.UDPAddr).Port)
} }
func testIPAndGateway() (gw, ip netaddr.IP, ok bool) { func testIPAndGateway() (gw, ip netip.Addr, ok bool) {
return netaddr.IPv4(127, 0, 0, 1), netaddr.IPv4(1, 2, 3, 4), true return netaddr.IPv4(127, 0, 0, 1), netaddr.IPv4(1, 2, 3, 4), true
} }
@ -187,7 +188,7 @@ func (d *TestIGD) servePxP() {
} }
} }
func (d *TestIGD) handlePMPQuery(pkt []byte, src netaddr.IPPort) { func (d *TestIGD) handlePMPQuery(pkt []byte, src netip.AddrPort) {
d.inc(&d.counters.numPMPRecv) d.inc(&d.counters.numPMPRecv)
if len(pkt) < 2 { if len(pkt) < 2 {
return return
@ -205,7 +206,7 @@ func (d *TestIGD) handlePMPQuery(pkt []byte, src netaddr.IPPort) {
// TODO // TODO
} }
func (d *TestIGD) handlePCPQuery(pkt []byte, src netaddr.IPPort) { func (d *TestIGD) handlePCPQuery(pkt []byte, src netip.AddrPort) {
d.inc(&d.counters.numPCPRecv) d.inc(&d.counters.numPCPRecv)
if len(pkt) < 24 { if len(pkt) < 24 {
return return

View File

@ -9,6 +9,7 @@
"crypto/rand" "crypto/rand"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"net/netip"
"time" "time"
"tailscale.com/net/netaddr" "tailscale.com/net/netaddr"
@ -49,9 +50,9 @@
type pcpMapping struct { type pcpMapping struct {
c *Client c *Client
gw netaddr.IPPort gw netip.AddrPort
internal netaddr.IPPort internal netip.AddrPort
external netaddr.IPPort external netip.AddrPort
renewAfter time.Time renewAfter time.Time
goodUntil time.Time goodUntil time.Time
@ -62,7 +63,7 @@ type pcpMapping struct {
func (p *pcpMapping) GoodUntil() time.Time { return p.goodUntil } func (p *pcpMapping) GoodUntil() time.Time { return p.goodUntil }
func (p *pcpMapping) RenewAfter() time.Time { return p.renewAfter } func (p *pcpMapping) RenewAfter() time.Time { return p.renewAfter }
func (p *pcpMapping) External() netaddr.IPPort { return p.external } func (p *pcpMapping) External() netip.AddrPort { return p.external }
func (p *pcpMapping) Release(ctx context.Context) { func (p *pcpMapping) Release(ctx context.Context) {
uc, err := p.c.listenPacket(ctx, "udp4", ":0") uc, err := p.c.listenPacket(ctx, "udp4", ":0")
if err != nil { if err != nil {
@ -78,10 +79,10 @@ func (p *pcpMapping) Release(ctx context.Context) {
// If prevPort is not known, it should be set to 0. // If prevPort is not known, it should be set to 0.
// If prevExternalIP is not known, it should be set to 0.0.0.0. // If prevExternalIP is not known, it should be set to 0.0.0.0.
func buildPCPRequestMappingPacket( func buildPCPRequestMappingPacket(
myIP netaddr.IP, myIP netip.Addr,
localPort, prevPort uint16, localPort, prevPort uint16,
lifetimeSec uint32, lifetimeSec uint32,
prevExternalIP netaddr.IP, prevExternalIP netip.Addr,
) (pkt []byte) { ) (pkt []byte) {
// 24 byte common PCP header + 36 bytes of MAP-specific fields // 24 byte common PCP header + 36 bytes of MAP-specific fields
pkt = make([]byte, 24+36) pkt = make([]byte, 24+36)
@ -127,7 +128,7 @@ func parsePCPMapResponse(resp []byte) (*pcpMapping, error) {
copy(externalIPBytes[:], resp[44:]) copy(externalIPBytes[:], resp[44:])
externalIP := netaddr.IPFrom16(externalIPBytes) externalIP := netaddr.IPFrom16(externalIPBytes)
external := netaddr.IPPortFrom(externalIP, externalPort) external := netip.AddrPortFrom(externalIP, externalPort)
lifetime := time.Second * time.Duration(res.Lifetime) lifetime := time.Second * time.Duration(res.Lifetime)
now := time.Now() now := time.Now()
@ -141,7 +142,7 @@ func parsePCPMapResponse(resp []byte) (*pcpMapping, error) {
} }
// pcpAnnounceRequest generates a PCP packet with an ANNOUNCE opcode. // pcpAnnounceRequest generates a PCP packet with an ANNOUNCE opcode.
func pcpAnnounceRequest(myIP netaddr.IP) []byte { func pcpAnnounceRequest(myIP netip.Addr) []byte {
// See https://tools.ietf.org/html/rfc6887#section-7.1 // See https://tools.ietf.org/html/rfc6887#section-7.1
pkt := make([]byte, 24) pkt := make([]byte, 24)
pkt[0] = pcpVersion pkt[0] = pcpVersion

View File

@ -57,7 +57,7 @@
// Client is a port mapping client. // Client is a port mapping client.
type Client struct { type Client struct {
logf logger.Logf logf logger.Logf
ipAndGateway func() (gw, ip netaddr.IP, ok bool) ipAndGateway func() (gw, ip netip.Addr, ok bool)
onChange func() // or nil onChange func() // or nil
testPxPPort uint16 // if non-zero, pxpPort to use for tests testPxPPort uint16 // if non-zero, pxpPort to use for tests
testUPnPPort uint16 // if non-zero, uPnPPort to use for tests testUPnPPort uint16 // if non-zero, uPnPPort to use for tests
@ -69,13 +69,13 @@ type Client struct {
// off a createMapping goroutine). // off a createMapping goroutine).
runningCreate bool runningCreate bool
lastMyIP netaddr.IP lastMyIP netip.Addr
lastGW netaddr.IP lastGW netip.Addr
closed bool closed bool
lastProbe time.Time lastProbe time.Time
pmpPubIP netaddr.IP // non-zero if known pmpPubIP netip.Addr // non-zero if known
pmpPubIPTime time.Time // time pmpPubIP last verified pmpPubIPTime time.Time // time pmpPubIP last verified
pmpLastEpoch uint32 pmpLastEpoch uint32
@ -105,7 +105,7 @@ type mapping interface {
// renewAfter returns the earliest time that the mapping should be renewed. // renewAfter returns the earliest time that the mapping should be renewed.
RenewAfter() time.Time RenewAfter() time.Time
// externalIPPort indicates what port the mapping can be reached from on the outside. // externalIPPort indicates what port the mapping can be reached from on the outside.
External() netaddr.IPPort External() netip.AddrPort
} }
// HaveMapping reports whether we have a current valid mapping. // HaveMapping reports whether we have a current valid mapping.
@ -120,9 +120,9 @@ func (c *Client) HaveMapping() bool {
// All fields are immutable once created. // All fields are immutable once created.
type pmpMapping struct { type pmpMapping struct {
c *Client c *Client
gw netaddr.IPPort gw netip.AddrPort
external netaddr.IPPort external netip.AddrPort
internal netaddr.IPPort internal netip.AddrPort
renewAfter time.Time // the time at which we want to renew the mapping renewAfter time.Time // the time at which we want to renew the mapping
goodUntil time.Time // the mapping's total lifetime goodUntil time.Time // the mapping's total lifetime
epoch uint32 epoch uint32
@ -135,7 +135,7 @@ func (m *pmpMapping) externalValid() bool {
func (p *pmpMapping) GoodUntil() time.Time { return p.goodUntil } func (p *pmpMapping) GoodUntil() time.Time { return p.goodUntil }
func (p *pmpMapping) RenewAfter() time.Time { return p.renewAfter } func (p *pmpMapping) RenewAfter() time.Time { return p.renewAfter }
func (p *pmpMapping) External() netaddr.IPPort { return p.external } func (p *pmpMapping) External() netip.AddrPort { return p.external }
// Release does a best effort fire-and-forget release of the PMP mapping m. // Release does a best effort fire-and-forget release of the PMP mapping m.
func (m *pmpMapping) Release(ctx context.Context) { func (m *pmpMapping) Release(ctx context.Context) {
@ -164,7 +164,7 @@ func NewClient(logf logger.Logf, onChange func()) *Client {
// SetGatewayLookupFunc set the func that returns the machine's default gateway IP, and // SetGatewayLookupFunc set the func that returns the machine's default gateway IP, and
// the primary IP address for that gateway. It must be called before the client is used. // the primary IP address for that gateway. It must be called before the client is used.
// If not called, interfaces.LikelyHomeRouterIP is used. // If not called, interfaces.LikelyHomeRouterIP is used.
func (c *Client) SetGatewayLookupFunc(f func() (gw, myIP netaddr.IP, ok bool)) { func (c *Client) SetGatewayLookupFunc(f func() (gw, myIP netip.Addr, ok bool)) {
c.ipAndGateway = f c.ipAndGateway = f
} }
@ -203,11 +203,11 @@ func (c *Client) SetLocalPort(localPort uint16) {
c.invalidateMappingsLocked(true) c.invalidateMappingsLocked(true)
} }
func (c *Client) gatewayAndSelfIP() (gw, myIP netaddr.IP, ok bool) { func (c *Client) gatewayAndSelfIP() (gw, myIP netip.Addr, ok bool) {
gw, myIP, ok = c.ipAndGateway() gw, myIP, ok = c.ipAndGateway()
if !ok { if !ok {
gw = netaddr.IP{} gw = netip.Addr{}
myIP = netaddr.IP{} myIP = netip.Addr{}
} }
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
@ -273,7 +273,7 @@ func (c *Client) invalidateMappingsLocked(releaseOld bool) {
} }
c.mapping = nil c.mapping = nil
} }
c.pmpPubIP = netaddr.IP{} c.pmpPubIP = netip.Addr{}
c.pmpPubIPTime = time.Time{} c.pmpPubIPTime = time.Time{}
c.pcpSawTime = time.Time{} c.pcpSawTime = time.Time{}
c.uPnPSawTime = time.Time{} c.uPnPSawTime = time.Time{}
@ -350,7 +350,7 @@ func IsNoMappingError(err error) bool {
// If there's not one, it starts up a background goroutine to create one. // If there's not one, it starts up a background goroutine to create one.
// If the background goroutine ends up creating one, the onChange hook registered with the // If the background goroutine ends up creating one, the onChange hook registered with the
// NewClient constructor (if any) will fire. // NewClient constructor (if any) will fire.
func (c *Client) GetCachedMappingOrStartCreatingOne() (external netaddr.IPPort, ok bool) { func (c *Client) GetCachedMappingOrStartCreatingOne() (external netip.AddrPort, ok bool) {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
@ -366,7 +366,7 @@ func (c *Client) GetCachedMappingOrStartCreatingOne() (external netaddr.IPPort,
} }
c.maybeStartMappingLocked() c.maybeStartMappingLocked()
return netaddr.IPPort{}, false return netip.AddrPort{}, false
} }
// maybeStartMappingLocked starts a createMapping goroutine up, if one isn't already running. // maybeStartMappingLocked starts a createMapping goroutine up, if one isn't already running.
@ -404,21 +404,21 @@ func (c *Client) createMapping() {
// //
// If no mapping is available, the error will be of type // If no mapping is available, the error will be of type
// NoMappingError; see IsNoMappingError. // NoMappingError; see IsNoMappingError.
func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPort, err error) { func (c *Client) createOrGetMapping(ctx context.Context) (external netip.AddrPort, err error) {
if DisableUPnP && DisablePCP && DisablePMP { if DisableUPnP && DisablePCP && DisablePMP {
return netaddr.IPPort{}, NoMappingError{ErrNoPortMappingServices} return netip.AddrPort{}, NoMappingError{ErrNoPortMappingServices}
} }
gw, myIP, ok := c.gatewayAndSelfIP() gw, myIP, ok := c.gatewayAndSelfIP()
if !ok { if !ok {
return netaddr.IPPort{}, NoMappingError{ErrGatewayRange} return netip.AddrPort{}, NoMappingError{ErrGatewayRange}
} }
if gw.Is6() { if gw.Is6() {
return netaddr.IPPort{}, NoMappingError{ErrGatewayIPv6} return netip.AddrPort{}, NoMappingError{ErrGatewayIPv6}
} }
c.mu.Lock() c.mu.Lock()
localPort := c.localPort localPort := c.localPort
internalAddr := netaddr.IPPortFrom(myIP, localPort) internalAddr := netip.AddrPortFrom(myIP, localPort)
// prevPort is the port we had most previously, if any. We try // prevPort is the port we had most previously, if any. We try
// to ask for the same port. 0 means to give us any port. // to ask for the same port. 0 means to give us any port.
@ -440,7 +440,7 @@ func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPor
if external, ok := c.getUPnPPortMapping(ctx, gw, internalAddr, prevPort); ok { if external, ok := c.getUPnPPortMapping(ctx, gw, internalAddr, prevPort); ok {
return external, nil return external, nil
} }
return netaddr.IPPort{}, NoMappingError{ErrNoPortMappingServices} return netip.AddrPort{}, NoMappingError{ErrNoPortMappingServices}
} }
// If we just did a Probe (e.g. via netchecker) but didn't // If we just did a Probe (e.g. via netchecker) but didn't
@ -457,7 +457,7 @@ func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPor
// construct it upon receiving that packet. // construct it upon receiving that packet.
m := &pmpMapping{ m := &pmpMapping{
c: c, c: c,
gw: netaddr.IPPortFrom(gw, c.pxpPort()), gw: netip.AddrPortFrom(gw, c.pxpPort()),
internal: internalAddr, internal: internalAddr,
} }
if haveRecentPMP { if haveRecentPMP {
@ -469,20 +469,20 @@ func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPor
if external, ok := c.getUPnPPortMapping(ctx, gw, internalAddr, prevPort); ok { if external, ok := c.getUPnPPortMapping(ctx, gw, internalAddr, prevPort); ok {
return external, nil return external, nil
} }
return netaddr.IPPort{}, NoMappingError{ErrNoPortMappingServices} return netip.AddrPort{}, NoMappingError{ErrNoPortMappingServices}
} }
c.mu.Unlock() c.mu.Unlock()
uc, err := c.listenPacket(ctx, "udp4", ":0") uc, err := c.listenPacket(ctx, "udp4", ":0")
if err != nil { if err != nil {
return netaddr.IPPort{}, err return netip.AddrPort{}, err
} }
defer uc.Close() defer uc.Close()
uc.SetReadDeadline(time.Now().Add(portMapServiceTimeout)) uc.SetReadDeadline(time.Now().Add(portMapServiceTimeout))
defer closeCloserOnContextDone(ctx, uc)() defer closeCloserOnContextDone(ctx, uc)()
pxpAddr := netaddr.IPPortFrom(gw, c.pxpPort()) pxpAddr := netip.AddrPortFrom(gw, c.pxpPort())
preferPCP := !DisablePCP && (DisablePMP || (!haveRecentPMP && haveRecentPCP)) preferPCP := !DisablePCP && (DisablePMP || (!haveRecentPMP && haveRecentPCP))
@ -495,7 +495,7 @@ func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPor
if neterror.TreatAsLostUDP(err) { if neterror.TreatAsLostUDP(err) {
err = NoMappingError{ErrNoPortMappingServices} err = NoMappingError{ErrNoPortMappingServices}
} }
return netaddr.IPPort{}, err return netip.AddrPort{}, err
} }
} else { } else {
// Ask for our external address if needed. // Ask for our external address if needed.
@ -504,7 +504,7 @@ func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPor
if neterror.TreatAsLostUDP(err) { if neterror.TreatAsLostUDP(err) {
err = NoMappingError{ErrNoPortMappingServices} err = NoMappingError{ErrNoPortMappingServices}
} }
return netaddr.IPPort{}, err return netip.AddrPort{}, err
} }
} }
@ -513,7 +513,7 @@ func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPor
if neterror.TreatAsLostUDP(err) { if neterror.TreatAsLostUDP(err) {
err = NoMappingError{ErrNoPortMappingServices} err = NoMappingError{ErrNoPortMappingServices}
} }
return netaddr.IPPort{}, err return netip.AddrPort{}, err
} }
} }
@ -522,13 +522,13 @@ func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPor
n, srci, err := uc.ReadFrom(res) n, srci, err := uc.ReadFrom(res)
if err != nil { if err != nil {
if ctx.Err() == context.Canceled { if ctx.Err() == context.Canceled {
return netaddr.IPPort{}, err return netip.AddrPort{}, err
} }
// fallback to UPnP portmapping // fallback to UPnP portmapping
if mapping, ok := c.getUPnPPortMapping(ctx, gw, internalAddr, prevPort); ok { if mapping, ok := c.getUPnPPortMapping(ctx, gw, internalAddr, prevPort); ok {
return mapping, nil return mapping, nil
} }
return netaddr.IPPort{}, NoMappingError{ErrNoPortMappingServices} return netip.AddrPort{}, NoMappingError{ErrNoPortMappingServices}
} }
srcu := srci.(*net.UDPAddr) srcu := srci.(*net.UDPAddr)
src, ok := netaddr.FromStdAddr(srcu.IP, srcu.Port, srcu.Zone) src, ok := netaddr.FromStdAddr(srcu.IP, srcu.Port, srcu.Zone)
@ -545,7 +545,7 @@ func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPor
continue continue
} }
if pres.ResultCode != 0 { if pres.ResultCode != 0 {
return netaddr.IPPort{}, NoMappingError{fmt.Errorf("PMP response Op=0x%x,Res=0x%x", pres.OpCode, pres.ResultCode)} return netip.AddrPort{}, NoMappingError{fmt.Errorf("PMP response Op=0x%x,Res=0x%x", pres.OpCode, pres.ResultCode)}
} }
if pres.OpCode == pmpOpReply|pmpOpMapPublicAddr { if pres.OpCode == pmpOpReply|pmpOpMapPublicAddr {
m.external = netip.AddrPortFrom(pres.PublicAddr, m.external.Port()) m.external = netip.AddrPortFrom(pres.PublicAddr, m.external.Port())
@ -563,18 +563,18 @@ func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPor
if err != nil { if err != nil {
c.logf("failed to get PCP mapping: %v", err) c.logf("failed to get PCP mapping: %v", err)
// PCP should only have a single packet response // PCP should only have a single packet response
return netaddr.IPPort{}, NoMappingError{ErrNoPortMappingServices} return netip.AddrPort{}, NoMappingError{ErrNoPortMappingServices}
} }
pcpMapping.c = c pcpMapping.c = c
pcpMapping.internal = m.internal pcpMapping.internal = m.internal
pcpMapping.gw = netaddr.IPPortFrom(gw, c.pxpPort()) pcpMapping.gw = netip.AddrPortFrom(gw, c.pxpPort())
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
c.mapping = pcpMapping c.mapping = pcpMapping
return pcpMapping.external, nil return pcpMapping.external, nil
default: default:
c.logf("unknown PMP/PCP version number: %d %v", version, res[:n]) c.logf("unknown PMP/PCP version number: %d %v", version, res[:n])
return netaddr.IPPort{}, NoMappingError{ErrNoPortMappingServices} return netip.AddrPort{}, NoMappingError{ErrNoPortMappingServices}
} }
} }
@ -632,7 +632,7 @@ type pmpResponse struct {
ExternalPort uint16 ExternalPort uint16
// For public addr ops: // For public addr ops:
PublicAddr netaddr.IP PublicAddr netip.Addr
} }
func parsePMPResponse(pkt []byte) (res pmpResponse, ok bool) { func parsePMPResponse(pkt []byte) (res pmpResponse, ok bool) {
@ -701,9 +701,9 @@ func (c *Client) Probe(ctx context.Context) (res ProbeResult, err error) {
defer cancel() defer cancel()
defer closeCloserOnContextDone(ctx, uc)() defer closeCloserOnContextDone(ctx, uc)()
pxpAddr := netaddr.IPPortFrom(gw, c.pxpPort()) pxpAddr := netip.AddrPortFrom(gw, c.pxpPort())
upnpAddr := netaddr.IPPortFrom(gw, c.upnpPort()) upnpAddr := netip.AddrPortFrom(gw, c.upnpPort())
upnpMulticastAddr := netaddr.IPPortFrom(netaddr.IPv4(239, 255, 255, 250), c.upnpPort()) upnpMulticastAddr := netip.AddrPortFrom(netaddr.IPv4(239, 255, 255, 250), c.upnpPort())
// Don't send probes to services that we recently learned (for // Don't send probes to services that we recently learned (for
// the same gw/myIP) are available. See // the same gw/myIP) are available. See

View File

@ -24,7 +24,6 @@
"github.com/tailscale/goupnp" "github.com/tailscale/goupnp"
"github.com/tailscale/goupnp/dcps/internetgateway2" "github.com/tailscale/goupnp/dcps/internetgateway2"
"tailscale.com/control/controlknobs" "tailscale.com/control/controlknobs"
"tailscale.com/net/netaddr"
"tailscale.com/net/netns" "tailscale.com/net/netns"
"tailscale.com/types/logger" "tailscale.com/types/logger"
) )
@ -36,9 +35,9 @@
// upnpMapping is a port mapping over the upnp protocol. After being created it is immutable, // upnpMapping is a port mapping over the upnp protocol. After being created it is immutable,
// but the client field may be shared across mapping instances. // but the client field may be shared across mapping instances.
type upnpMapping struct { type upnpMapping struct {
gw netaddr.IP gw netip.Addr
external netaddr.IPPort external netip.AddrPort
internal netaddr.IPPort internal netip.AddrPort
goodUntil time.Time goodUntil time.Time
renewAfter time.Time renewAfter time.Time
@ -48,7 +47,7 @@ type upnpMapping struct {
func (u *upnpMapping) GoodUntil() time.Time { return u.goodUntil } func (u *upnpMapping) GoodUntil() time.Time { return u.goodUntil }
func (u *upnpMapping) RenewAfter() time.Time { return u.renewAfter } func (u *upnpMapping) RenewAfter() time.Time { return u.renewAfter }
func (u *upnpMapping) External() netaddr.IPPort { return u.external } func (u *upnpMapping) External() netip.AddrPort { return u.external }
func (u *upnpMapping) Release(ctx context.Context) { func (u *upnpMapping) Release(ctx context.Context) {
u.client.DeletePortMapping(ctx, "", u.external.Port(), "udp") u.client.DeletePortMapping(ctx, "", u.external.Port(), "udp")
} }
@ -154,7 +153,7 @@ func addAnyPortMapping(
// //
// The provided ctx is not retained in the returned upnpClient, but // The provided ctx is not retained in the returned upnpClient, but
// its associated HTTP client is (if set via goupnp.WithHTTPClient). // its associated HTTP client is (if set via goupnp.WithHTTPClient).
func getUPnPClient(ctx context.Context, logf logger.Logf, gw netaddr.IP, meta uPnPDiscoResponse) (client upnpClient, err error) { func getUPnPClient(ctx context.Context, logf logger.Logf, gw netip.Addr, meta uPnPDiscoResponse) (client upnpClient, err error) {
if controlknobs.DisableUPnP() || DisableUPnP { if controlknobs.DisableUPnP() || DisableUPnP {
return nil, nil return nil, nil
} }
@ -233,12 +232,12 @@ func (c *Client) upnpHTTPClientLocked() *http.Client {
// port and an error. // port and an error.
func (c *Client) getUPnPPortMapping( func (c *Client) getUPnPPortMapping(
ctx context.Context, ctx context.Context,
gw netaddr.IP, gw netip.Addr,
internal netaddr.IPPort, internal netip.AddrPort,
prevPort uint16, prevPort uint16,
) (external netaddr.IPPort, ok bool) { ) (external netip.AddrPort, ok bool) {
if controlknobs.DisableUPnP() || DisableUPnP { if controlknobs.DisableUPnP() || DisableUPnP {
return netaddr.IPPort{}, false return netip.AddrPort{}, false
} }
now := time.Now() now := time.Now()
upnp := &upnpMapping{ upnp := &upnpMapping{
@ -262,11 +261,11 @@ func (c *Client) getUPnPPortMapping(
c.logf("getUPnPClient: %T, %v", client, err) c.logf("getUPnPClient: %T, %v", client, err)
} }
if err != nil { if err != nil {
return netaddr.IPPort{}, false return netip.AddrPort{}, false
} }
} }
if client == nil { if client == nil {
return netaddr.IPPort{}, false return netip.AddrPort{}, false
} }
var newPort uint16 var newPort uint16
@ -282,7 +281,7 @@ func (c *Client) getUPnPPortMapping(
c.logf("addAnyPortMapping: %v, %v", newPort, err) c.logf("addAnyPortMapping: %v, %v", newPort, err)
} }
if err != nil { if err != nil {
return netaddr.IPPort{}, false return netip.AddrPort{}, false
} }
// TODO cache this ip somewhere? // TODO cache this ip somewhere?
extIP, err := client.GetExternalIPAddress(ctx) extIP, err := client.GetExternalIPAddress(ctx)
@ -291,14 +290,14 @@ func (c *Client) getUPnPPortMapping(
} }
if err != nil { if err != nil {
// TODO this doesn't seem right // TODO this doesn't seem right
return netaddr.IPPort{}, false return netip.AddrPort{}, false
} }
externalIP, err := netip.ParseAddr(extIP) externalIP, err := netip.ParseAddr(extIP)
if err != nil { if err != nil {
return netaddr.IPPort{}, false return netip.AddrPort{}, false
} }
upnp.external = netaddr.IPPortFrom(externalIP, newPort) upnp.external = netip.AddrPortFrom(externalIP, newPort)
d := time.Duration(pmpMapLifetimeSec) * time.Second d := time.Duration(pmpMapLifetimeSec) * time.Second
upnp.goodUntil = now.Add(d) upnp.goodUntil = now.Add(d)
upnp.renewAfter = now.Add(d / 2) upnp.renewAfter = now.Add(d / 2)

View File

@ -17,7 +17,7 @@
// ChromeOSVMRange returns the subset of the CGNAT IPv4 range used by // ChromeOSVMRange returns the subset of the CGNAT IPv4 range used by
// ChromeOS to interconnect the host OS to containers and VMs. We // ChromeOS to interconnect the host OS to containers and VMs. We
// avoid allocating Tailscale IPs from it, to avoid conflicts. // avoid allocating Tailscale IPs from it, to avoid conflicts.
func ChromeOSVMRange() netaddr.IPPrefix { func ChromeOSVMRange() netip.Prefix {
chromeOSRange.Do(func() { mustPrefix(&chromeOSRange.v, "100.115.92.0/23") }) chromeOSRange.Do(func() { mustPrefix(&chromeOSRange.v, "100.115.92.0/23") })
return chromeOSRange.v return chromeOSRange.v
} }
@ -28,7 +28,7 @@ func ChromeOSVMRange() netaddr.IPPrefix {
// is the superset range that Tailscale assigns out of. // is the superset range that Tailscale assigns out of.
// See https://tailscale.com/kb/1015/100.x-addresses. // See https://tailscale.com/kb/1015/100.x-addresses.
// Note that Tailscale does not assign out of the ChromeOSVMRange. // Note that Tailscale does not assign out of the ChromeOSVMRange.
func CGNATRange() netaddr.IPPrefix { func CGNATRange() netip.Prefix {
cgnatRange.Do(func() { mustPrefix(&cgnatRange.v, "100.64.0.0/10") }) cgnatRange.Do(func() { mustPrefix(&cgnatRange.v, "100.64.0.0/10") })
return cgnatRange.v return cgnatRange.v
} }
@ -47,7 +47,7 @@ func CGNATRange() netaddr.IPPrefix {
// provided by Tailscale itself such as the MagicDNS proxy. // provided by Tailscale itself such as the MagicDNS proxy.
// //
// For IPv6, use TailscaleServiceIPv6. // For IPv6, use TailscaleServiceIPv6.
func TailscaleServiceIP() netaddr.IP { func TailscaleServiceIP() netip.Addr {
return netaddr.IPv4(100, 100, 100, 100) // "100.100.100.100" for those grepping return netaddr.IPv4(100, 100, 100, 100) // "100.100.100.100" for those grepping
} }
@ -55,14 +55,14 @@ func TailscaleServiceIP() netaddr.IP {
// provided by Tailscale itself such as the MagicDNS proxy. // provided by Tailscale itself such as the MagicDNS proxy.
// //
// For IPv4, use TailscaleServiceIP. // For IPv4, use TailscaleServiceIP.
func TailscaleServiceIPv6() netaddr.IP { func TailscaleServiceIPv6() netip.Addr {
serviceIPv6.Do(func() { mustPrefix(&serviceIPv6.v, "fd7a:115c:a1e0::53/128") }) serviceIPv6.Do(func() { mustPrefix(&serviceIPv6.v, "fd7a:115c:a1e0::53/128") })
return serviceIPv6.v.Addr() return serviceIPv6.v.Addr()
} }
// IsTailscaleIP reports whether ip is an IP address in a range that // IsTailscaleIP reports whether ip is an IP address in a range that
// Tailscale assigns from. // Tailscale assigns from.
func IsTailscaleIP(ip netaddr.IP) bool { func IsTailscaleIP(ip netip.Addr) bool {
if ip.Is4() { if ip.Is4() {
return CGNATRange().Contains(ip) && !ChromeOSVMRange().Contains(ip) return CGNATRange().Contains(ip) && !ChromeOSVMRange().Contains(ip)
} }
@ -71,14 +71,14 @@ func IsTailscaleIP(ip netaddr.IP) bool {
// TailscaleULARange returns the IPv6 Unique Local Address range that // TailscaleULARange returns the IPv6 Unique Local Address range that
// is the superset range that Tailscale assigns out of. // is the superset range that Tailscale assigns out of.
func TailscaleULARange() netaddr.IPPrefix { func TailscaleULARange() netip.Prefix {
tsUlaRange.Do(func() { mustPrefix(&tsUlaRange.v, "fd7a:115c:a1e0::/48") }) tsUlaRange.Do(func() { mustPrefix(&tsUlaRange.v, "fd7a:115c:a1e0::/48") })
return tsUlaRange.v return tsUlaRange.v
} }
// TailscaleViaRange returns the IPv6 Unique Local Address subset range // TailscaleViaRange returns the IPv6 Unique Local Address subset range
// TailscaleULARange that's used for IPv4 tunneling via IPv6. // TailscaleULARange that's used for IPv4 tunneling via IPv6.
func TailscaleViaRange() netaddr.IPPrefix { func TailscaleViaRange() netip.Prefix {
// Mnemonic: "b1a" sounds like "via". // Mnemonic: "b1a" sounds like "via".
tsViaRange.Do(func() { mustPrefix(&tsViaRange.v, "fd7a:115c:a1e0:b1a::/64") }) tsViaRange.Do(func() { mustPrefix(&tsViaRange.v, "fd7a:115c:a1e0:b1a::/64") })
return tsViaRange.v return tsViaRange.v
@ -86,7 +86,7 @@ func TailscaleViaRange() netaddr.IPPrefix {
// Tailscale4To6Range returns the subset of TailscaleULARange used for // Tailscale4To6Range returns the subset of TailscaleULARange used for
// auto-translated Tailscale ipv4 addresses. // auto-translated Tailscale ipv4 addresses.
func Tailscale4To6Range() netaddr.IPPrefix { func Tailscale4To6Range() netip.Prefix {
// This IP range has no significance, beyond being a subset of // This IP range has no significance, beyond being a subset of
// TailscaleULARange. The bits from /48 to /104 were picked at // TailscaleULARange. The bits from /48 to /104 were picked at
// random. // random.
@ -96,7 +96,7 @@ func Tailscale4To6Range() netaddr.IPPrefix {
// TailscaleEphemeral6Range returns the subset of TailscaleULARange // TailscaleEphemeral6Range returns the subset of TailscaleULARange
// used for ephemeral IPv6-only Tailscale nodes. // used for ephemeral IPv6-only Tailscale nodes.
func TailscaleEphemeral6Range() netaddr.IPPrefix { func TailscaleEphemeral6Range() netip.Prefix {
// This IP range has no significance, beyond being a subset of // This IP range has no significance, beyond being a subset of
// TailscaleULARange. The bits from /48 to /64 were picked at // TailscaleULARange. The bits from /48 to /64 were picked at
// random, with the only criterion being to not be the conflict // random, with the only criterion being to not be the conflict
@ -112,16 +112,16 @@ func TailscaleEphemeral6Range() netaddr.IPPrefix {
// //
// Currently used to work around a Windows limitation when programming // Currently used to work around a Windows limitation when programming
// IPv6 routes in corner cases. // IPv6 routes in corner cases.
func Tailscale4To6Placeholder() netaddr.IP { func Tailscale4To6Placeholder() netip.Addr {
return Tailscale4To6Range().Addr() return Tailscale4To6Range().Addr()
} }
// Tailscale4To6 returns a Tailscale IPv6 address that maps 1:1 to the // Tailscale4To6 returns a Tailscale IPv6 address that maps 1:1 to the
// given Tailscale IPv4 address. Returns a zero IP if ipv4 isn't a // given Tailscale IPv4 address. Returns a zero IP if ipv4 isn't a
// Tailscale IPv4 address. // Tailscale IPv4 address.
func Tailscale4To6(ipv4 netaddr.IP) netaddr.IP { func Tailscale4To6(ipv4 netip.Addr) netip.Addr {
if !ipv4.Is4() || !IsTailscaleIP(ipv4) { if !ipv4.Is4() || !IsTailscaleIP(ipv4) {
return netaddr.IP{} return netip.Addr{}
} }
ret := Tailscale4To6Range().Addr().As16() ret := Tailscale4To6Range().Addr().As16()
v4 := ipv4.As4() v4 := ipv4.As4()
@ -133,15 +133,15 @@ func Tailscale4To6(ipv4 netaddr.IP) netaddr.IP {
// tailscale IPv6 address within the 4To6 range. The IPv4 address // tailscale IPv6 address within the 4To6 range. The IPv4 address
// and true are returned if the given address was in the correct range, // and true are returned if the given address was in the correct range,
// false if not. // false if not.
func Tailscale6to4(ipv6 netaddr.IP) (netaddr.IP, bool) { func Tailscale6to4(ipv6 netip.Addr) (netip.Addr, bool) {
if !ipv6.Is6() || !Tailscale4To6Range().Contains(ipv6) { if !ipv6.Is6() || !Tailscale4To6Range().Contains(ipv6) {
return netaddr.IP{}, false return netip.Addr{}, false
} }
v6 := ipv6.As16() v6 := ipv6.As16()
return netaddr.IPv4(100, v6[13], v6[14], v6[15]), true return netaddr.IPv4(100, v6[13], v6[14], v6[15]), true
} }
func mustPrefix(v *netaddr.IPPrefix, prefix string) { func mustPrefix(v *netip.Prefix, prefix string) {
var err error var err error
*v, err = netip.ParsePrefix(prefix) *v, err = netip.ParsePrefix(prefix)
if err != nil { if err != nil {
@ -151,7 +151,7 @@ func mustPrefix(v *netaddr.IPPrefix, prefix string) {
type oncePrefix struct { type oncePrefix struct {
sync.Once sync.Once
v netaddr.IPPrefix v netip.Prefix
} }
// NewContainsIPFunc returns a func that reports whether ip is in addrs. // NewContainsIPFunc returns a func that reports whether ip is in addrs.
@ -161,11 +161,11 @@ type oncePrefix struct {
// one IPv6 address). // one IPv6 address).
// //
// Otherwise the implementation is somewhat slow. // Otherwise the implementation is somewhat slow.
func NewContainsIPFunc(addrs []netaddr.IPPrefix) func(ip netaddr.IP) bool { func NewContainsIPFunc(addrs []netip.Prefix) func(ip netip.Addr) bool {
// Specialize the three common cases: no address, just IPv4 // Specialize the three common cases: no address, just IPv4
// (or just IPv6), and both IPv4 and IPv6. // (or just IPv6), and both IPv4 and IPv6.
if len(addrs) == 0 { if len(addrs) == 0 {
return func(netaddr.IP) bool { return false } return func(netip.Addr) bool { return false }
} }
// If any addr is more than a single IP, then just do the slow // If any addr is more than a single IP, then just do the slow
// linear thing until // linear thing until
@ -174,8 +174,8 @@ func NewContainsIPFunc(addrs []netaddr.IPPrefix) func(ip netaddr.IP) bool {
if a.IsSingleIP() { if a.IsSingleIP() {
continue continue
} }
acopy := append([]netaddr.IPPrefix(nil), addrs...) acopy := append([]netip.Prefix(nil), addrs...)
return func(ip netaddr.IP) bool { return func(ip netip.Addr) bool {
for _, a := range acopy { for _, a := range acopy {
if a.Contains(ip) { if a.Contains(ip) {
return true return true
@ -187,23 +187,23 @@ func NewContainsIPFunc(addrs []netaddr.IPPrefix) func(ip netaddr.IP) bool {
// Fast paths for 1 and 2 IPs: // Fast paths for 1 and 2 IPs:
if len(addrs) == 1 { if len(addrs) == 1 {
a := addrs[0] a := addrs[0]
return func(ip netaddr.IP) bool { return ip == a.Addr() } return func(ip netip.Addr) bool { return ip == a.Addr() }
} }
if len(addrs) == 2 { if len(addrs) == 2 {
a, b := addrs[0], addrs[1] a, b := addrs[0], addrs[1]
return func(ip netaddr.IP) bool { return ip == a.Addr() || ip == b.Addr() } return func(ip netip.Addr) bool { return ip == a.Addr() || ip == b.Addr() }
} }
// General case: // General case:
m := map[netaddr.IP]bool{} m := map[netip.Addr]bool{}
for _, a := range addrs { for _, a := range addrs {
m[a.Addr()] = true m[a.Addr()] = true
} }
return func(ip netaddr.IP) bool { return m[ip] } return func(ip netip.Addr) bool { return m[ip] }
} }
// PrefixesContainsFunc reports whether f is true for any IPPrefix in // PrefixesContainsFunc reports whether f is true for any IPPrefix in
// ipp. // ipp.
func PrefixesContainsFunc(ipp []netaddr.IPPrefix, f func(netaddr.IPPrefix) bool) bool { func PrefixesContainsFunc(ipp []netip.Prefix, f func(netip.Prefix) bool) bool {
for _, v := range ipp { for _, v := range ipp {
if f(v) { if f(v) {
return true return true
@ -213,7 +213,7 @@ func PrefixesContainsFunc(ipp []netaddr.IPPrefix, f func(netaddr.IPPrefix) bool)
} }
// PrefixesContainsIP reports whether any prefix in ipp contains ip. // PrefixesContainsIP reports whether any prefix in ipp contains ip.
func PrefixesContainsIP(ipp []netaddr.IPPrefix, ip netaddr.IP) bool { func PrefixesContainsIP(ipp []netip.Prefix, ip netip.Addr) bool {
for _, r := range ipp { for _, r := range ipp {
if r.Contains(ip) { if r.Contains(ip) {
return true return true
@ -223,7 +223,7 @@ func PrefixesContainsIP(ipp []netaddr.IPPrefix, ip netaddr.IP) bool {
} }
// IPsContainsFunc reports whether f is true for any IP in ips. // IPsContainsFunc reports whether f is true for any IP in ips.
func IPsContainsFunc(ips []netaddr.IP, f func(netaddr.IP) bool) bool { func IPsContainsFunc(ips []netip.Addr, f func(netip.Addr) bool) bool {
for _, v := range ips { for _, v := range ips {
if f(v) { if f(v) {
return true return true
@ -233,14 +233,14 @@ func IPsContainsFunc(ips []netaddr.IP, f func(netaddr.IP) bool) bool {
} }
// PrefixIs4 reports whether p is an IPv4 prefix. // PrefixIs4 reports whether p is an IPv4 prefix.
func PrefixIs4(p netaddr.IPPrefix) bool { return p.Addr().Is4() } func PrefixIs4(p netip.Prefix) bool { return p.Addr().Is4() }
// PrefixIs6 reports whether p is an IPv6 prefix. // PrefixIs6 reports whether p is an IPv6 prefix.
func PrefixIs6(p netaddr.IPPrefix) bool { return p.Addr().Is6() } func PrefixIs6(p netip.Prefix) bool { return p.Addr().Is6() }
// ContainsExitRoutes reports whether rr contains both the IPv4 and // ContainsExitRoutes reports whether rr contains both the IPv4 and
// IPv6 /0 route. // IPv6 /0 route.
func ContainsExitRoutes(rr []netaddr.IPPrefix) bool { func ContainsExitRoutes(rr []netip.Prefix) bool {
var v4, v6 bool var v4, v6 bool
for _, r := range rr { for _, r := range rr {
if r == allIPv4 { if r == allIPv4 {
@ -258,18 +258,18 @@ func ContainsExitRoutes(rr []netaddr.IPPrefix) bool {
) )
// AllIPv4 returns 0.0.0.0/0. // AllIPv4 returns 0.0.0.0/0.
func AllIPv4() netaddr.IPPrefix { return allIPv4 } func AllIPv4() netip.Prefix { return allIPv4 }
// AllIPv6 returns ::/0. // AllIPv6 returns ::/0.
func AllIPv6() netaddr.IPPrefix { return allIPv6 } func AllIPv6() netip.Prefix { return allIPv6 }
// ExitRoutes returns a slice containing AllIPv4 and AllIPv6. // ExitRoutes returns a slice containing AllIPv4 and AllIPv6.
func ExitRoutes() []netaddr.IPPrefix { return []netaddr.IPPrefix{allIPv4, allIPv6} } func ExitRoutes() []netip.Prefix { return []netip.Prefix{allIPv4, allIPv6} }
// FilterPrefixes returns a new slice, not aliasing in, containing elements of // FilterPrefixes returns a new slice, not aliasing in, containing elements of
// in that match f. // in that match f.
func FilterPrefixesCopy(in []netaddr.IPPrefix, f func(netaddr.IPPrefix) bool) []netaddr.IPPrefix { func FilterPrefixesCopy(in []netip.Prefix, f func(netip.Prefix) bool) []netip.Prefix {
var out []netaddr.IPPrefix var out []netip.Prefix
for _, v := range in { for _, v := range in {
if f(v) { if f(v) {
out = append(out, v) out = append(out, v)
@ -280,7 +280,7 @@ func FilterPrefixesCopy(in []netaddr.IPPrefix, f func(netaddr.IPPrefix) bool) []
// IsViaPrefix reports whether p is a CIDR in the Tailscale "via" range. // IsViaPrefix reports whether p is a CIDR in the Tailscale "via" range.
// See TailscaleViaRange. // See TailscaleViaRange.
func IsViaPrefix(p netaddr.IPPrefix) bool { func IsViaPrefix(p netip.Prefix) bool {
return TailscaleViaRange().Contains(p.Addr()) return TailscaleViaRange().Contains(p.Addr())
} }
@ -288,16 +288,16 @@ func IsViaPrefix(p netaddr.IPPrefix) bool {
// "via" IPv4-in-IPv6 address. // "via" IPv4-in-IPv6 address.
// //
// If ip is not a via address, it returns ip unchanged. // If ip is not a via address, it returns ip unchanged.
func UnmapVia(ip netaddr.IP) netaddr.IP { func UnmapVia(ip netip.Addr) netip.Addr {
if TailscaleViaRange().Contains(ip) { if TailscaleViaRange().Contains(ip) {
a := ip.As16() a := ip.As16()
return netaddr.IPFrom4(*(*[4]byte)(a[12:16])) return netip.AddrFrom4(*(*[4]byte)(a[12:16]))
} }
return ip return ip
} }
// MapVia returns an IPv6 "via" route for an IPv4 CIDR in a given siteID. // MapVia returns an IPv6 "via" route for an IPv4 CIDR in a given siteID.
func MapVia(siteID uint32, v4 netaddr.IPPrefix) (via netaddr.IPPrefix, err error) { func MapVia(siteID uint32, v4 netip.Prefix) (via netip.Prefix, err error) {
if !v4.Addr().Is4() { if !v4.Addr().Is4() {
return via, errors.New("want IPv4 CIDR with a site ID") return via, errors.New("want IPv4 CIDR with a site ID")
} }

View File

@ -13,7 +13,7 @@
func TestInCrostiniRange(t *testing.T) { func TestInCrostiniRange(t *testing.T) {
tests := []struct { tests := []struct {
ip netaddr.IP ip netip.Addr
want bool want bool
}{ }{
{netaddr.IPv4(192, 168, 0, 1), false}, {netaddr.IPv4(192, 168, 0, 1), false},
@ -53,25 +53,25 @@ func TestCGNATRange(t *testing.T) {
} }
func TestNewContainsIPFunc(t *testing.T) { func TestNewContainsIPFunc(t *testing.T) {
f := NewContainsIPFunc([]netaddr.IPPrefix{netip.MustParsePrefix("10.0.0.0/8")}) f := NewContainsIPFunc([]netip.Prefix{netip.MustParsePrefix("10.0.0.0/8")})
if f(netip.MustParseAddr("8.8.8.8")) { if f(netip.MustParseAddr("8.8.8.8")) {
t.Fatal("bad") t.Fatal("bad")
} }
if !f(netip.MustParseAddr("10.1.2.3")) { if !f(netip.MustParseAddr("10.1.2.3")) {
t.Fatal("bad") t.Fatal("bad")
} }
f = NewContainsIPFunc([]netaddr.IPPrefix{netip.MustParsePrefix("10.1.2.3/32")}) f = NewContainsIPFunc([]netip.Prefix{netip.MustParsePrefix("10.1.2.3/32")})
if !f(netip.MustParseAddr("10.1.2.3")) { if !f(netip.MustParseAddr("10.1.2.3")) {
t.Fatal("bad") t.Fatal("bad")
} }
f = NewContainsIPFunc([]netaddr.IPPrefix{ f = NewContainsIPFunc([]netip.Prefix{
netip.MustParsePrefix("10.1.2.3/32"), netip.MustParsePrefix("10.1.2.3/32"),
netip.MustParsePrefix("::2/128"), netip.MustParsePrefix("::2/128"),
}) })
if !f(netip.MustParseAddr("::2")) { if !f(netip.MustParseAddr("::2")) {
t.Fatal("bad") t.Fatal("bad")
} }
f = NewContainsIPFunc([]netaddr.IPPrefix{ f = NewContainsIPFunc([]netip.Prefix{
netip.MustParsePrefix("10.1.2.3/32"), netip.MustParsePrefix("10.1.2.3/32"),
netip.MustParsePrefix("10.1.2.4/32"), netip.MustParsePrefix("10.1.2.4/32"),
netip.MustParsePrefix("::2/128"), netip.MustParsePrefix("::2/128"),
@ -81,7 +81,7 @@ func TestNewContainsIPFunc(t *testing.T) {
} }
} }
var sinkIP netaddr.IP var sinkIP netip.Addr
func BenchmarkTailscaleServiceAddr(b *testing.B) { func BenchmarkTailscaleServiceAddr(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()

View File

@ -13,7 +13,6 @@
"strconv" "strconv"
"strings" "strings"
"tailscale.com/net/netaddr"
"tailscale.com/types/netmap" "tailscale.com/types/netmap"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
) )
@ -23,7 +22,7 @@
// //
// Example keys are "foo.domain.tld.beta.tailscale.net" and "foo", // Example keys are "foo.domain.tld.beta.tailscale.net" and "foo",
// both without trailing dots, and both always lowercase. // both without trailing dots, and both always lowercase.
type dnsMap map[string]netaddr.IP type dnsMap map[string]netip.Addr
// canonMapKey canonicalizes its input s to be a dnsMap map key. // canonMapKey canonicalizes its input s to be a dnsMap map key.
func canonMapKey(s string) string { func canonMapKey(s string) string {
@ -98,15 +97,15 @@ func splitHostPort(addr string) (host string, port uint16, err error) {
// //
// The error is [exactly] errUnresolved if the addr is a name that isn't known // The error is [exactly] errUnresolved if the addr is a name that isn't known
// in the map. // in the map.
func (m dnsMap) resolveMemory(ctx context.Context, network, addr string) (_ netaddr.IPPort, err error) { func (m dnsMap) resolveMemory(ctx context.Context, network, addr string) (_ netip.AddrPort, err error) {
host, port, err := splitHostPort(addr) host, port, err := splitHostPort(addr)
if err != nil { if err != nil {
// addr malformed or invalid port. // addr malformed or invalid port.
return netaddr.IPPort{}, err return netip.AddrPort{}, err
} }
if ip, err := netip.ParseAddr(host); err == nil { if ip, err := netip.ParseAddr(host); err == nil {
// addr was literal ip:port. // addr was literal ip:port.
return netaddr.IPPortFrom(ip, port), nil return netip.AddrPortFrom(ip, port), nil
} }
// Host is not an IP, so assume it's a DNS name. // Host is not an IP, so assume it's a DNS name.
@ -114,8 +113,8 @@ func (m dnsMap) resolveMemory(ctx context.Context, network, addr string) (_ neta
// Try MagicDNS first, otherwise a real DNS lookup. // Try MagicDNS first, otherwise a real DNS lookup.
ip := m[canonMapKey(host)] ip := m[canonMapKey(host)]
if ip.IsValid() { if ip.IsValid() {
return netaddr.IPPortFrom(ip, port), nil return netip.AddrPortFrom(ip, port), nil
} }
return netaddr.IPPort{}, errUnresolved return netip.AddrPort{}, errUnresolved
} }

View File

@ -9,7 +9,6 @@
"reflect" "reflect"
"testing" "testing"
"tailscale.com/net/netaddr"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/netmap" "tailscale.com/types/netmap"
) )
@ -26,7 +25,7 @@ func TestDNSMapFromNetworkMap(t *testing.T) {
name: "self", name: "self",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Name: "foo.tailnet", Name: "foo.tailnet",
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
pfx("100.102.103.104/32"), pfx("100.102.103.104/32"),
pfx("100::123/128"), pfx("100::123/128"),
}, },
@ -40,21 +39,21 @@ func TestDNSMapFromNetworkMap(t *testing.T) {
name: "self_and_peers", name: "self_and_peers",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Name: "foo.tailnet", Name: "foo.tailnet",
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
pfx("100.102.103.104/32"), pfx("100.102.103.104/32"),
pfx("100::123/128"), pfx("100::123/128"),
}, },
Peers: []*tailcfg.Node{ Peers: []*tailcfg.Node{
{ {
Name: "a.tailnet", Name: "a.tailnet",
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
pfx("100.0.0.201/32"), pfx("100.0.0.201/32"),
pfx("100::201/128"), pfx("100::201/128"),
}, },
}, },
{ {
Name: "b.tailnet", Name: "b.tailnet",
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
pfx("100::202/128"), pfx("100::202/128"),
}, },
}, },
@ -73,20 +72,20 @@ func TestDNSMapFromNetworkMap(t *testing.T) {
name: "self_has_v6_only", name: "self_has_v6_only",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Name: "foo.tailnet", Name: "foo.tailnet",
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
pfx("100::123/128"), pfx("100::123/128"),
}, },
Peers: []*tailcfg.Node{ Peers: []*tailcfg.Node{
{ {
Name: "a.tailnet", Name: "a.tailnet",
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
pfx("100.0.0.201/32"), pfx("100.0.0.201/32"),
pfx("100::201/128"), pfx("100::201/128"),
}, },
}, },
{ {
Name: "b.tailnet", Name: "b.tailnet",
Addresses: []netaddr.IPPrefix{ Addresses: []netip.Prefix{
pfx("100::202/128"), pfx("100::202/128"),
}, },
}, },

View File

@ -38,11 +38,11 @@ type Dialer struct {
Logf logger.Logf Logf logger.Logf
// UseNetstackForIP if non-nil is whether NetstackDialTCP (if // UseNetstackForIP if non-nil is whether NetstackDialTCP (if
// it's non-nil) should be used to dial the provided IP. // it's non-nil) should be used to dial the provided IP.
UseNetstackForIP func(netaddr.IP) bool UseNetstackForIP func(netip.Addr) bool
// NetstackDialTCP dials the provided IPPort using netstack. // NetstackDialTCP dials the provided IPPort using netstack.
// If nil, it's not used. // If nil, it's not used.
NetstackDialTCP func(context.Context, netaddr.IPPort) (net.Conn, error) NetstackDialTCP func(context.Context, netip.AddrPort) (net.Conn, error)
peerDialControlFuncAtomic atomic.Value // of func() func(network, address string, c syscall.RawConn) error peerDialControlFuncAtomic atomic.Value // of func() func(network, address string, c syscall.RawConn) error
@ -208,7 +208,7 @@ func (d *Dialer) SetNetMap(nm *netmap.NetworkMap) {
d.dns = m d.dns = m
} }
func (d *Dialer) userDialResolve(ctx context.Context, network, addr string) (netaddr.IPPort, error) { func (d *Dialer) userDialResolve(ctx context.Context, network, addr string) (netip.AddrPort, error) {
d.mu.Lock() d.mu.Lock()
dns := d.dns dns := d.dns
exitDNSDoH := d.exitDNSDoHBase exitDNSDoH := d.exitDNSDoHBase
@ -227,7 +227,7 @@ func (d *Dialer) userDialResolve(ctx context.Context, network, addr string) (net
host, port, err := splitHostPort(addr) host, port, err := splitHostPort(addr)
if err != nil { if err != nil {
// addr is malformed. // addr is malformed.
return netaddr.IPPort{}, err return netip.AddrPort{}, err
} }
var r net.Resolver var r net.Resolver
@ -245,13 +245,13 @@ func (d *Dialer) userDialResolve(ctx context.Context, network, addr string) (net
ips, err := r.LookupIP(ctx, ipNetOfNetwork(network), host) ips, err := r.LookupIP(ctx, ipNetOfNetwork(network), host)
if err != nil { if err != nil {
return netaddr.IPPort{}, err return netip.AddrPort{}, err
} }
if len(ips) == 0 { if len(ips) == 0 {
return netaddr.IPPort{}, fmt.Errorf("DNS lookup returned no results for %q", host) return netip.AddrPort{}, fmt.Errorf("DNS lookup returned no results for %q", host)
} }
ip, _ := netaddr.FromStdIP(ips[0]) ip, _ := netaddr.FromStdIP(ips[0])
return netaddr.IPPortFrom(ip, port), nil return netip.AddrPortFrom(ip, port), nil
} }
// ipNetOfNetwork returns "ip", "ip4", or "ip6" corresponding // ipNetOfNetwork returns "ip", "ip4", or "ip6" corresponding

View File

@ -7,6 +7,7 @@
import ( import (
"fmt" "fmt"
"net" "net"
"net/netip"
"os" "os"
"os/exec" "os/exec"
@ -246,8 +247,8 @@ func (t *Wrapper) handleDHCPRequest(ethBuf []byte) bool {
pkt := packLayer2UDP( pkt := packLayer2UDP(
offer.ToBytes(), offer.ToBytes(),
ourMAC, ethSrcMAC, ourMAC, ethSrcMAC,
netaddr.IPPortFrom(netaddr.IPv4(100, 100, 100, 100), 67), // src netip.AddrPortFrom(netaddr.IPv4(100, 100, 100, 100), 67), // src
netaddr.IPPortFrom(netaddr.IPv4(255, 255, 255, 255), 68), // dst netip.AddrPortFrom(netaddr.IPv4(255, 255, 255, 255), 68), // dst
) )
n, err := t.tdev.Write(pkt, 0) n, err := t.tdev.Write(pkt, 0)
if tapDebug { if tapDebug {
@ -273,8 +274,8 @@ func (t *Wrapper) handleDHCPRequest(ethBuf []byte) bool {
pkt := packLayer2UDP( pkt := packLayer2UDP(
ack.ToBytes(), ack.ToBytes(),
ourMAC, ethSrcMAC, ourMAC, ethSrcMAC,
netaddr.IPPortFrom(netaddr.IPv4(100, 100, 100, 100), 67), // src netip.AddrPortFrom(netaddr.IPv4(100, 100, 100, 100), 67), // src
netaddr.IPPortFrom(netaddr.IPv4(255, 255, 255, 255), 68), // dst netip.AddrPortFrom(netaddr.IPv4(255, 255, 255, 255), 68), // dst
) )
n, err := t.tdev.Write(pkt, 0) n, err := t.tdev.Write(pkt, 0)
if tapDebug { if tapDebug {
@ -288,7 +289,7 @@ func (t *Wrapper) handleDHCPRequest(ethBuf []byte) bool {
return consumePacket return consumePacket
} }
func packLayer2UDP(payload []byte, srcMAC, dstMAC net.HardwareAddr, src, dst netaddr.IPPort) []byte { func packLayer2UDP(payload []byte, srcMAC, dstMAC net.HardwareAddr, src, dst netip.AddrPort) []byte {
buf := make([]byte, header.EthernetMinimumSize+header.UDPMinimumSize+header.IPv4MinimumSize+len(payload)) buf := make([]byte, header.EthernetMinimumSize+header.UDPMinimumSize+header.IPv4MinimumSize+len(payload))
payloadStart := len(buf) - len(payload) payloadStart := len(buf) - len(payload)
copy(buf[payloadStart:], payload) copy(buf[payloadStart:], payload)

View File

@ -10,6 +10,7 @@
"errors" "errors"
"fmt" "fmt"
"io" "io"
"net/netip"
"os" "os"
"strings" "strings"
"sync" "sync"
@ -21,7 +22,6 @@
"golang.zx2c4.com/wireguard/tun" "golang.zx2c4.com/wireguard/tun"
"gvisor.dev/gvisor/pkg/tcpip/stack" "gvisor.dev/gvisor/pkg/tcpip/stack"
"tailscale.com/disco" "tailscale.com/disco"
"tailscale.com/net/netaddr"
"tailscale.com/net/packet" "tailscale.com/net/packet"
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
"tailscale.com/tstime/mono" "tailscale.com/tstime/mono"
@ -82,7 +82,7 @@ type Wrapper struct {
// you might need to add a pad32.Four field here. // you might need to add a pad32.Four field here.
lastActivityAtomic mono.Time // time of last send or receive lastActivityAtomic mono.Time // time of last send or receive
destIPActivity atomic.Value // of map[netaddr.IP]func() destIPActivity atomic.Value // of map[netip.Addr]func()
destMACAtomic atomic.Value // of [6]byte destMACAtomic atomic.Value // of [6]byte
discoKey atomic.Value // of key.DiscoPublic discoKey atomic.Value // of key.DiscoPublic
@ -158,7 +158,7 @@ type Wrapper struct {
// PeerAPIPort, if non-nil, returns the peerapi port that's // PeerAPIPort, if non-nil, returns the peerapi port that's
// running for the given IP address. // running for the given IP address.
PeerAPIPort func(netaddr.IP) (port uint16, ok bool) PeerAPIPort func(netip.Addr) (port uint16, ok bool)
// disableFilter disables all filtering when set. This should only be used in tests. // disableFilter disables all filtering when set. This should only be used in tests.
disableFilter bool disableFilter bool
@ -222,7 +222,7 @@ func wrap(logf logger.Logf, tdev tun.Device, isTAP bool) *Wrapper {
// destination (the map keys). // destination (the map keys).
// //
// The map ownership passes to the Wrapper. It must be non-nil. // The map ownership passes to the Wrapper. It must be non-nil.
func (t *Wrapper) SetDestIPActivityFuncs(m map[netaddr.IP]func()) { func (t *Wrapper) SetDestIPActivityFuncs(m map[netip.Addr]func()) {
t.destIPActivity.Store(m) t.destIPActivity.Store(m)
} }
@ -429,8 +429,8 @@ func (t *Wrapper) sendOutbound(r tunReadResult) {
} }
var ( var (
magicDNSIPPort = netaddr.IPPortFrom(tsaddr.TailscaleServiceIP(), 0) // 100.100.100.100:0 magicDNSIPPort = netip.AddrPortFrom(tsaddr.TailscaleServiceIP(), 0) // 100.100.100.100:0
magicDNSIPPortv6 = netaddr.IPPortFrom(tsaddr.TailscaleServiceIPv6(), 0) magicDNSIPPortv6 = netip.AddrPortFrom(tsaddr.TailscaleServiceIPv6(), 0)
) )
func (t *Wrapper) filterOut(p *packet.Parsed) filter.Response { func (t *Wrapper) filterOut(p *packet.Parsed) filter.Response {
@ -544,7 +544,7 @@ func (t *Wrapper) Read(buf []byte, offset int) (int, error) {
defer parsedPacketPool.Put(p) defer parsedPacketPool.Put(p)
p.Decode(buf[offset : offset+n]) p.Decode(buf[offset : offset+n])
if m, ok := t.destIPActivity.Load().(map[netaddr.IP]func()); ok { if m, ok := t.destIPActivity.Load().(map[netip.Addr]func()); ok {
if fn := m[p.Dst.Addr()]; fn != nil { if fn := m[p.Dst.Addr()]; fn != nil {
fn() fn()
} }

View File

@ -77,7 +77,7 @@ func tcp4syn(src, dst string, sport, dport uint16) []byte {
return both return both
} }
func nets(nets ...string) (ret []netaddr.IPPrefix) { func nets(nets ...string) (ret []netip.Prefix) {
for _, s := range nets { for _, s := range nets {
if i := strings.IndexByte(s, '/'); i == -1 { if i := strings.IndexByte(s, '/'); i == -1 {
ip, err := netip.ParseAddr(s) ip, err := netip.ParseAddr(s)
@ -88,7 +88,7 @@ func nets(nets ...string) (ret []netaddr.IPPrefix) {
if ip.Is6() { if ip.Is6() {
bits = 128 bits = 128
} }
ret = append(ret, netaddr.IPPrefixFrom(ip, bits)) ret = append(ret, netip.PrefixFrom(ip, int(bits)))
} else { } else {
pfx, err := netip.ParsePrefix(s) pfx, err := netip.ParsePrefix(s)
if err != nil { if err != nil {
@ -428,7 +428,7 @@ func TestAtomic64Alignment(t *testing.T) {
func TestPeerAPIBypass(t *testing.T) { func TestPeerAPIBypass(t *testing.T) {
wrapperWithPeerAPI := &Wrapper{ wrapperWithPeerAPI := &Wrapper{
PeerAPIPort: func(ip netaddr.IP) (port uint16, ok bool) { PeerAPIPort: func(ip netip.Addr) (port uint16, ok bool) {
if ip == netip.MustParseAddr("100.64.1.2") { if ip == netip.MustParseAddr("100.64.1.2") {
return 60000, true return 60000, true
} }
@ -446,7 +446,7 @@ func TestPeerAPIBypass(t *testing.T) {
{ {
name: "reject_nil_filter", name: "reject_nil_filter",
w: &Wrapper{ w: &Wrapper{
PeerAPIPort: func(netaddr.IP) (port uint16, ok bool) { PeerAPIPort: func(netip.Addr) (port uint16, ok bool) {
return 60000, true return 60000, true
}, },
}, },

View File

@ -405,7 +405,7 @@ func (c *conn) sshPolicy() (_ *tailcfg.SSHPolicy, ok bool) {
return nil, false return nil, false
} }
func toIPPort(a net.Addr) (ipp netaddr.IPPort) { func toIPPort(a net.Addr) (ipp netip.AddrPort) {
ta, ok := a.(*net.TCPAddr) ta, ok := a.(*net.TCPAddr)
if !ok { if !ok {
return return
@ -414,7 +414,7 @@ func toIPPort(a net.Addr) (ipp netaddr.IPPort) {
if !ok { if !ok {
return return
} }
return netaddr.IPPortFrom(tanetaddr, uint16(ta.Port)) return netip.AddrPortFrom(tanetaddr, uint16(ta.Port))
} }
// connInfo returns a populated sshConnInfo from the provided arguments, // connInfo returns a populated sshConnInfo from the provided arguments,
@ -1103,10 +1103,10 @@ type sshConnInfo struct {
sshUser string sshUser string
// src is the Tailscale IP and port that the connection came from. // src is the Tailscale IP and port that the connection came from.
src netaddr.IPPort src netip.AddrPort
// dst is the Tailscale IP and port that the connection came for. // dst is the Tailscale IP and port that the connection came for.
dst netaddr.IPPort dst netip.AddrPort
// node is srcIP's node. // node is srcIP's node.
node *tailcfg.Node node *tailcfg.Node

View File

@ -10,11 +10,11 @@
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"net/netip"
"reflect" "reflect"
"strings" "strings"
"time" "time"
"tailscale.com/net/netaddr"
"tailscale.com/types/dnstype" "tailscale.com/types/dnstype"
"tailscale.com/types/key" "tailscale.com/types/key"
"tailscale.com/types/opt" "tailscale.com/types/opt"
@ -170,10 +170,10 @@ type Node struct {
KeyExpiry time.Time KeyExpiry time.Time
Machine key.MachinePublic Machine key.MachinePublic
DiscoKey key.DiscoPublic DiscoKey key.DiscoPublic
Addresses []netaddr.IPPrefix // IP addresses of this Node directly Addresses []netip.Prefix // IP addresses of this Node directly
AllowedIPs []netaddr.IPPrefix // range of IP addresses to route to this node AllowedIPs []netip.Prefix // range of IP addresses to route to this node
Endpoints []string `json:",omitempty"` // IP+port (public via STUN, and local LANs) Endpoints []string `json:",omitempty"` // IP+port (public via STUN, and local LANs)
DERP string `json:",omitempty"` // DERP-in-IP:port ("127.3.3.40:N") endpoint DERP string `json:",omitempty"` // DERP-in-IP:port ("127.3.3.40:N") endpoint
Hostinfo HostinfoView Hostinfo HostinfoView
Created time.Time Created time.Time
@ -190,7 +190,7 @@ type Node struct {
// is currently the primary subnet router for, as determined // is currently the primary subnet router for, as determined
// by the control plane. It does not include the self address // by the control plane. It does not include the self address
// values from Addresses that are in AllowedIPs. // values from Addresses that are in AllowedIPs.
PrimaryRoutes []netaddr.IPPrefix `json:",omitempty"` PrimaryRoutes []netip.Prefix `json:",omitempty"`
// LastSeen is when the node was last online. It is not // LastSeen is when the node was last online. It is not
// updated when Online is true. It is nil if the current // updated when Online is true. It is nil if the current
@ -454,24 +454,24 @@ type Service struct {
// Because it contains pointers (slices), this type should not be used // Because it contains pointers (slices), this type should not be used
// as a value type. // as a value type.
type Hostinfo struct { type Hostinfo struct {
IPNVersion string `json:",omitempty"` // version of this code IPNVersion string `json:",omitempty"` // version of this code
FrontendLogID string `json:",omitempty"` // logtail ID of frontend instance FrontendLogID string `json:",omitempty"` // logtail ID of frontend instance
BackendLogID string `json:",omitempty"` // logtail ID of backend instance BackendLogID string `json:",omitempty"` // logtail ID of backend instance
OS string `json:",omitempty"` // operating system the client runs on (a version.OS value) OS string `json:",omitempty"` // operating system the client runs on (a version.OS value)
OSVersion string `json:",omitempty"` // operating system version, with optional distro prefix ("Debian 10.4", "Windows 10 Pro 10.0.19041") OSVersion string `json:",omitempty"` // operating system version, with optional distro prefix ("Debian 10.4", "Windows 10 Pro 10.0.19041")
Desktop opt.Bool `json:",omitempty"` // if a desktop was detected on Linux Desktop opt.Bool `json:",omitempty"` // if a desktop was detected on Linux
Package string `json:",omitempty"` // Tailscale package to disambiguate ("choco", "appstore", etc; "" for unknown) Package string `json:",omitempty"` // Tailscale package to disambiguate ("choco", "appstore", etc; "" for unknown)
DeviceModel string `json:",omitempty"` // mobile phone model ("Pixel 3a", "iPhone12,3") DeviceModel string `json:",omitempty"` // mobile phone model ("Pixel 3a", "iPhone12,3")
Hostname string `json:",omitempty"` // name of the host the client runs on Hostname string `json:",omitempty"` // name of the host the client runs on
ShieldsUp bool `json:",omitempty"` // indicates whether the host is blocking incoming connections ShieldsUp bool `json:",omitempty"` // indicates whether the host is blocking incoming connections
ShareeNode bool `json:",omitempty"` // indicates this node exists in netmap because it's owned by a shared-to user ShareeNode bool `json:",omitempty"` // indicates this node exists in netmap because it's owned by a shared-to user
GoArch string `json:",omitempty"` // the host's GOARCH value (of the running binary) GoArch string `json:",omitempty"` // the host's GOARCH value (of the running binary)
RoutableIPs []netaddr.IPPrefix `json:",omitempty"` // set of IP ranges this client can route RoutableIPs []netip.Prefix `json:",omitempty"` // set of IP ranges this client can route
RequestTags []string `json:",omitempty"` // set of ACL tags this node wants to claim RequestTags []string `json:",omitempty"` // set of ACL tags this node wants to claim
Services []Service `json:",omitempty"` // services advertised by this machine Services []Service `json:",omitempty"` // services advertised by this machine
NetInfo *NetInfo `json:",omitempty"` NetInfo *NetInfo `json:",omitempty"`
SSH_HostKeys []string `json:"sshHostKeys,omitempty"` // if advertised SSH_HostKeys []string `json:"sshHostKeys,omitempty"` // if advertised
Cloud string `json:",omitempty"` Cloud string `json:",omitempty"`
// NOTE: any new fields containing pointers in this type // NOTE: any new fields containing pointers in this type
// require changes to Hostinfo.Equal. // require changes to Hostinfo.Equal.
@ -854,7 +854,7 @@ func (et EndpointType) String() string {
// broken up into two parallel slices in MapRequest, for compatibility // broken up into two parallel slices in MapRequest, for compatibility
// reasons. But this type is used in the codebase. // reasons. But this type is used in the codebase.
type Endpoint struct { type Endpoint struct {
Addr netaddr.IPPort Addr netip.AddrPort
Type EndpointType Type EndpointType
} }
@ -946,7 +946,7 @@ type NetPortRange struct {
type CapGrant struct { type CapGrant struct {
// Dsts are the destination IP ranges that this capabilty // Dsts are the destination IP ranges that this capabilty
// grant matches. // grant matches.
Dsts []netaddr.IPPrefix Dsts []netip.Prefix
// Caps are the capabilities the source IP matched by // Caps are the capabilities the source IP matched by
// FilterRule.SrcIPs are granted to the destination IP, // FilterRule.SrcIPs are granted to the destination IP,
@ -1059,7 +1059,7 @@ type DNSConfig struct {
// MapRequest.Version >=9 and <14. // MapRequest.Version >=9 and <14.
// Nameservers are the IP addresses of the nameservers to use. // Nameservers are the IP addresses of the nameservers to use.
Nameservers []netaddr.IP `json:",omitempty"` Nameservers []netip.Addr `json:",omitempty"`
// PerDomain is not set by the control server, and does nothing. // PerDomain is not set by the control server, and does nothing.
PerDomain bool `json:",omitempty"` PerDomain bool `json:",omitempty"`
@ -1149,7 +1149,7 @@ type PingRequest struct {
// IP is the ping target. // IP is the ping target.
// It is used in TSMP pings, if IP is invalid or empty then do a HEAD request to the URL. // It is used in TSMP pings, if IP is invalid or empty then do a HEAD request to the URL.
IP netaddr.IP IP netip.Addr
} }
// PingResponse provides result information for a TSMP or Disco PingRequest. // PingResponse provides result information for a TSMP or Disco PingRequest.
@ -1446,7 +1446,7 @@ func eqStrings(a, b []string) bool {
return true return true
} }
func eqCIDRs(a, b []netaddr.IPPrefix) bool { func eqCIDRs(a, b []netip.Prefix) bool {
if len(a) != len(b) || ((a == nil) != (b == nil)) { if len(a) != len(b) || ((a == nil) != (b == nil)) {
return false return false
} }

View File

@ -13,7 +13,6 @@
"testing" "testing"
"time" "time"
"tailscale.com/net/netaddr"
"tailscale.com/tstest" "tailscale.com/tstest"
"tailscale.com/types/key" "tailscale.com/types/key"
"tailscale.com/version" "tailscale.com/version"
@ -40,7 +39,7 @@ func TestHostinfoEqual(t *testing.T) {
have, hiHandles) have, hiHandles)
} }
nets := func(strs ...string) (ns []netaddr.IPPrefix) { nets := func(strs ...string) (ns []netip.Prefix) {
for _, s := range strs { for _, s := range strs {
n, err := netip.ParsePrefix(s) n, err := netip.ParsePrefix(s)
if err != nil { if err != nil {
@ -225,12 +224,12 @@ func TestHostinfoHowEqual(t *testing.T) {
a: &Hostinfo{ a: &Hostinfo{
IPNVersion: "1", IPNVersion: "1",
ShieldsUp: false, ShieldsUp: false,
RoutableIPs: []netaddr.IPPrefix{netip.MustParsePrefix("1.2.3.0/24")}, RoutableIPs: []netip.Prefix{netip.MustParsePrefix("1.2.3.0/24")},
}, },
b: &Hostinfo{ b: &Hostinfo{
IPNVersion: "2", IPNVersion: "2",
ShieldsUp: true, ShieldsUp: true,
RoutableIPs: []netaddr.IPPrefix{netip.MustParsePrefix("1.2.3.0/25")}, RoutableIPs: []netip.Prefix{netip.MustParsePrefix("1.2.3.0/25")},
}, },
want: []string{"IPNVersion", "ShieldsUp", "RoutableIPs"}, want: []string{"IPNVersion", "ShieldsUp", "RoutableIPs"},
}, },
@ -403,23 +402,23 @@ func TestNodeEqual(t *testing.T) {
true, true,
}, },
{ {
&Node{Addresses: []netaddr.IPPrefix{}}, &Node{Addresses: []netip.Prefix{}},
&Node{Addresses: nil}, &Node{Addresses: nil},
false, false,
}, },
{ {
&Node{Addresses: []netaddr.IPPrefix{}}, &Node{Addresses: []netip.Prefix{}},
&Node{Addresses: []netaddr.IPPrefix{}}, &Node{Addresses: []netip.Prefix{}},
true, true,
}, },
{ {
&Node{AllowedIPs: []netaddr.IPPrefix{}}, &Node{AllowedIPs: []netip.Prefix{}},
&Node{AllowedIPs: nil}, &Node{AllowedIPs: nil},
false, false,
}, },
{ {
&Node{Addresses: []netaddr.IPPrefix{}}, &Node{Addresses: []netip.Prefix{}},
&Node{Addresses: []netaddr.IPPrefix{}}, &Node{Addresses: []netip.Prefix{}},
true, true,
}, },
{ {
@ -566,8 +565,8 @@ func TestCloneNode(t *testing.T) {
}{ }{
{"nil_fields", &Node{}}, {"nil_fields", &Node{}},
{"zero_fields", &Node{ {"zero_fields", &Node{
Addresses: make([]netaddr.IPPrefix, 0), Addresses: make([]netip.Prefix, 0),
AllowedIPs: make([]netaddr.IPPrefix, 0), AllowedIPs: make([]netip.Prefix, 0),
Endpoints: make([]string, 0), Endpoints: make([]string, 0),
}}, }},
} }

View File

@ -14,6 +14,7 @@
"log" "log"
"net" "net"
"net/http" "net/http"
"net/netip"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -32,7 +33,6 @@
"tailscale.com/logpolicy" "tailscale.com/logpolicy"
"tailscale.com/logtail" "tailscale.com/logtail"
"tailscale.com/logtail/filch" "tailscale.com/logtail/filch"
"tailscale.com/net/netaddr"
"tailscale.com/net/nettest" "tailscale.com/net/nettest"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
"tailscale.com/smallzstd" "tailscale.com/smallzstd"
@ -272,11 +272,11 @@ func (s *Server) start() error {
if err := ns.Start(); err != nil { if err := ns.Start(); err != nil {
return fmt.Errorf("failed to start netstack: %w", err) return fmt.Errorf("failed to start netstack: %w", err)
} }
s.dialer.UseNetstackForIP = func(ip netaddr.IP) bool { s.dialer.UseNetstackForIP = func(ip netip.Addr) bool {
_, ok := eng.PeerForIP(ip) _, ok := eng.PeerForIP(ip)
return ok return ok
} }
s.dialer.NetstackDialTCP = func(ctx context.Context, dst netaddr.IPPort) (net.Conn, error) { s.dialer.NetstackDialTCP = func(ctx context.Context, dst netip.AddrPort) (net.Conn, error) {
return ns.DialContextTCP(ctx, dst) return ns.DialContextTCP(ctx, dst)
} }

View File

@ -34,7 +34,6 @@
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/ipn/store" "tailscale.com/ipn/store"
"tailscale.com/net/netaddr"
"tailscale.com/safesocket" "tailscale.com/safesocket"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/tstest" "tailscale.com/tstest"
@ -814,10 +813,10 @@ func (n *testNode) AwaitListening() {
} }
} }
func (n *testNode) AwaitIPs() []netaddr.IP { func (n *testNode) AwaitIPs() []netip.Addr {
t := n.env.t t := n.env.t
t.Helper() t.Helper()
var addrs []netaddr.IP var addrs []netip.Addr
if err := tstest.WaitFor(20*time.Second, func() error { if err := tstest.WaitFor(20*time.Second, func() error {
cmd := n.Tailscale("ip") cmd := n.Tailscale("ip")
cmd.Stdout = nil // in case --verbose-tailscale was set cmd.Stdout = nil // in case --verbose-tailscale was set
@ -828,7 +827,7 @@ func (n *testNode) AwaitIPs() []netaddr.IP {
} }
ips := string(out) ips := string(out)
ipslice := strings.Fields(ips) ipslice := strings.Fields(ips)
addrs = make([]netaddr.IP, len(ipslice)) addrs = make([]netip.Addr, len(ipslice))
for i, ip := range ipslice { for i, ip := range ipslice {
netIP, err := netip.ParseAddr(ip) netIP, err := netip.ParseAddr(ip)
@ -848,7 +847,7 @@ func (n *testNode) AwaitIPs() []netaddr.IP {
} }
// AwaitIP returns the IP address of n. // AwaitIP returns the IP address of n.
func (n *testNode) AwaitIP() netaddr.IP { func (n *testNode) AwaitIP() netip.Addr {
t := n.env.t t := n.env.t
t.Helper() t.Helper()
ips := n.AwaitIPs() ips := n.AwaitIPs()

View File

@ -23,7 +23,6 @@
_ "tailscale.com/logtail" _ "tailscale.com/logtail"
_ "tailscale.com/net/dns" _ "tailscale.com/net/dns"
_ "tailscale.com/net/interfaces" _ "tailscale.com/net/interfaces"
_ "tailscale.com/net/netaddr"
_ "tailscale.com/net/netns" _ "tailscale.com/net/netns"
_ "tailscale.com/net/portmapper" _ "tailscale.com/net/portmapper"
_ "tailscale.com/net/proxymux" _ "tailscale.com/net/proxymux"

View File

@ -23,7 +23,6 @@
_ "tailscale.com/logtail" _ "tailscale.com/logtail"
_ "tailscale.com/net/dns" _ "tailscale.com/net/dns"
_ "tailscale.com/net/interfaces" _ "tailscale.com/net/interfaces"
_ "tailscale.com/net/netaddr"
_ "tailscale.com/net/netns" _ "tailscale.com/net/netns"
_ "tailscale.com/net/portmapper" _ "tailscale.com/net/portmapper"
_ "tailscale.com/net/proxymux" _ "tailscale.com/net/proxymux"

View File

@ -23,7 +23,6 @@
_ "tailscale.com/logtail" _ "tailscale.com/logtail"
_ "tailscale.com/net/dns" _ "tailscale.com/net/dns"
_ "tailscale.com/net/interfaces" _ "tailscale.com/net/interfaces"
_ "tailscale.com/net/netaddr"
_ "tailscale.com/net/netns" _ "tailscale.com/net/netns"
_ "tailscale.com/net/portmapper" _ "tailscale.com/net/portmapper"
_ "tailscale.com/net/proxymux" _ "tailscale.com/net/proxymux"

View File

@ -23,7 +23,6 @@
_ "tailscale.com/logtail" _ "tailscale.com/logtail"
_ "tailscale.com/net/dns" _ "tailscale.com/net/dns"
_ "tailscale.com/net/interfaces" _ "tailscale.com/net/interfaces"
_ "tailscale.com/net/netaddr"
_ "tailscale.com/net/netns" _ "tailscale.com/net/netns"
_ "tailscale.com/net/portmapper" _ "tailscale.com/net/portmapper"
_ "tailscale.com/net/proxymux" _ "tailscale.com/net/proxymux"

View File

@ -28,7 +28,6 @@
_ "tailscale.com/logtail/backoff" _ "tailscale.com/logtail/backoff"
_ "tailscale.com/net/dns" _ "tailscale.com/net/dns"
_ "tailscale.com/net/interfaces" _ "tailscale.com/net/interfaces"
_ "tailscale.com/net/netaddr"
_ "tailscale.com/net/netns" _ "tailscale.com/net/netns"
_ "tailscale.com/net/portmapper" _ "tailscale.com/net/portmapper"
_ "tailscale.com/net/proxymux" _ "tailscale.com/net/proxymux"

View File

@ -312,7 +312,7 @@ func (s *Server) AddFakeNode() {
r := nk.Raw32() r := nk.Raw32()
id := int64(binary.LittleEndian.Uint64(r[:])) id := int64(binary.LittleEndian.Uint64(r[:]))
ip := netaddr.IPv4(r[0], r[1], r[2], r[3]) ip := netaddr.IPv4(r[0], r[1], r[2], r[3])
addr := netaddr.IPPrefixFrom(ip, 32) addr := netip.PrefixFrom(ip, 32)
s.nodes[nk] = &tailcfg.Node{ s.nodes[nk] = &tailcfg.Node{
ID: tailcfg.NodeID(id), ID: tailcfg.NodeID(id),
StableID: tailcfg.StableNodeID(fmt.Sprintf("TESTCTRL%08x", id)), StableID: tailcfg.StableNodeID(fmt.Sprintf("TESTCTRL%08x", id)),
@ -321,8 +321,8 @@ func (s *Server) AddFakeNode() {
Key: nk, Key: nk,
MachineAuthorized: true, MachineAuthorized: true,
DiscoKey: dk, DiscoKey: dk,
Addresses: []netaddr.IPPrefix{addr}, Addresses: []netip.Prefix{addr},
AllowedIPs: []netaddr.IPPrefix{addr}, AllowedIPs: []netip.Prefix{addr},
} }
// TODO: send updates to other (non-fake?) nodes // TODO: send updates to other (non-fake?) nodes
} }
@ -475,10 +475,10 @@ func (s *Server) serveRegister(w http.ResponseWriter, r *http.Request, mkey key.
machineAuthorized := true // TODO: add Server.RequireMachineAuth machineAuthorized := true // TODO: add Server.RequireMachineAuth
v4Prefix := netaddr.IPPrefixFrom(netaddr.IPv4(100, 64, uint8(tailcfg.NodeID(user.ID)>>8), uint8(tailcfg.NodeID(user.ID))), 32) v4Prefix := netip.PrefixFrom(netaddr.IPv4(100, 64, uint8(tailcfg.NodeID(user.ID)>>8), uint8(tailcfg.NodeID(user.ID))), 32)
v6Prefix := netaddr.IPPrefixFrom(tsaddr.Tailscale4To6(v4Prefix.Addr()), 128) v6Prefix := netip.PrefixFrom(tsaddr.Tailscale4To6(v4Prefix.Addr()), 128)
allowedIPs := []netaddr.IPPrefix{ allowedIPs := []netip.Prefix{
v4Prefix, v4Prefix,
v6Prefix, v6Prefix,
} }
@ -761,10 +761,10 @@ func (s *Server) MapResponse(req *tailcfg.MapRequest) (res *tailcfg.MapResponse,
return res.Peers[i].ID < res.Peers[j].ID return res.Peers[i].ID < res.Peers[j].ID
}) })
v4Prefix := netaddr.IPPrefixFrom(netaddr.IPv4(100, 64, uint8(tailcfg.NodeID(user.ID)>>8), uint8(tailcfg.NodeID(user.ID))), 32) v4Prefix := netip.PrefixFrom(netaddr.IPv4(100, 64, uint8(tailcfg.NodeID(user.ID)>>8), uint8(tailcfg.NodeID(user.ID))), 32)
v6Prefix := netaddr.IPPrefixFrom(tsaddr.Tailscale4To6(v4Prefix.Addr()), 128) v6Prefix := netip.PrefixFrom(tsaddr.Tailscale4To6(v4Prefix.Addr()), 128)
res.Node.Addresses = []netaddr.IPPrefix{ res.Node.Addresses = []netip.Prefix{
v4Prefix, v4Prefix,
v6Prefix, v6Prefix,
} }

View File

@ -6,11 +6,11 @@
import ( import (
"io" "io"
"net/netip"
"runtime" "runtime"
"testing" "testing"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
) )
func deriveBindhost(t *testing.T) string { func deriveBindhost(t *testing.T) string {
@ -22,7 +22,7 @@ func deriveBindhost(t *testing.T) string {
} }
var ret string var ret string
err = interfaces.ForeachInterfaceAddress(func(i interfaces.Interface, prefix netaddr.IPPrefix) { err = interfaces.ForeachInterfaceAddress(func(i interfaces.Interface, prefix netip.Prefix) {
if ret != "" || i.Name != ifName { if ret != "" || i.Name != ifName {
return return
} }

Some files were not shown because too many files have changed in this diff Show More