فهرست منبع

all: use various net/netip parse funcs directly

Mechanical change with perl+goimports.

Changed {Must,}Parse{IP,IPPrefix,IPPort} to their netip variants, then
goimports -d .

Finally, removed the net/netaddr wrappers, to prevent future use.

Updates #5162

Change-Id: I59c0e38b5fbca5a935d701645789cddf3d7863ad
Signed-off-by: Brad Fitzpatrick <[email protected]>
Brad Fitzpatrick 3 سال پیش
والد
کامیت
6a396731eb
84فایلهای تغییر یافته به همراه401 افزوده شده و 355 حذف شده
  1. 1 1
      client/tailscale/routes.go
  2. 33 32
      cmd/tailscale/cli/cli_test.go
  3. 2 3
      cmd/tailscale/cli/debug.go
  4. 3 2
      cmd/tailscale/cli/file.go
  5. 2 2
      cmd/tailscale/cli/ip.go
  6. 2 2
      cmd/tailscale/cli/ping.go
  7. 3 3
      cmd/tailscale/cli/ssh.go
  8. 6 5
      cmd/tailscale/cli/up.go
  9. 3 3
      cmd/tailscale/cli/web.go
  10. 3 2
      cmd/tailscaled/debug.go
  11. 2 1
      derp/derp_client.go
  12. 3 2
      derp/derp_server.go
  13. 2 1
      derp/derphttp/derphttp_client.go
  14. 4 3
      disco/disco_test.go
  15. 3 3
      ipn/ipnlocal/dnsconfig_test.go
  16. 10 10
      ipn/ipnlocal/local.go
  17. 32 31
      ipn/ipnlocal/local_test.go
  18. 2 1
      ipn/ipnlocal/peerapi.go
  19. 5 4
      ipn/ipnlocal/peerapi_test.go
  20. 3 2
      ipn/ipnserver/server.go
  21. 3 2
      ipn/localapi/localapi.go
  22. 1 1
      ipn/prefs.go
  23. 8 7
      ipn/prefs_test.go
  24. 6 5
      net/dns/direct_test.go
  25. 7 6
      net/dns/manager_test.go
  26. 4 3
      net/dns/manager_windows.go
  27. 3 2
      net/dns/manager_windows_test.go
  28. 2 1
      net/dns/nm.go
  29. 2 1
      net/dns/publicdns/publicdns.go
  30. 3 2
      net/dns/publicdns/publicdns_test.go
  31. 2 1
      net/dns/resolvconffile/resolvconffile.go
  32. 4 3
      net/dns/resolvconffile/resolvconffile_test.go
  33. 3 3
      net/dns/resolver/tsdns.go
  34. 16 15
      net/dns/resolver/tsdns_test.go
  35. 7 6
      net/dnscache/dnscache_test.go
  36. 4 3
      net/dnsfallback/dnsfallback.go
  37. 5 5
      net/flowtrack/flowtrack_test.go
  38. 2 1
      net/interfaces/interfaces.go
  39. 2 1
      net/interfaces/interfaces_darwin_test.go
  40. 2 1
      net/interfaces/interfaces_linux.go
  41. 8 7
      net/interfaces/interfaces_test.go
  42. 0 8
      net/netaddr/netaddr.go
  43. 5 5
      net/netcheck/netcheck.go
  44. 2 2
      net/netns/netns.go
  45. 3 3
      net/packet/icmp6_test.go
  46. 2 1
      net/packet/packet_test.go
  47. 13 14
      net/packet/tsmp_test.go
  48. 2 1
      net/portmapper/pcp_test.go
  49. 1 1
      net/portmapper/portmapper.go
  50. 3 2
      net/portmapper/upnp.go
  51. 2 2
      net/stun/stuntest/stuntest.go
  52. 3 3
      net/tsaddr/tsaddr.go
  53. 14 13
      net/tsaddr/tsaddr_test.go
  54. 3 2
      net/tsdial/dnsmap.go
  55. 3 2
      net/tsdial/dnsmap_test.go
  56. 2 1
      net/tsdial/tsdial.go
  57. 9 8
      net/tstun/wrap_test.go
  58. 2 1
      ssh/tailssh/tailssh.go
  59. 4 4
      ssh/tailssh/tailssh_test.go
  60. 4 3
      tailcfg/tailcfg_test.go
  61. 2 1
      tstest/integration/integration_test.go
  62. 2 1
      tstest/integration/testcontrol/testcontrol.go
  63. 2 1
      tstest/integration/vms/harness_test.go
  64. 2 1
      tstest/integration/vms/vms_test.go
  65. 3 3
      tstest/natlab/natlab.go
  66. 1 1
      tstest/natlab/natlab_test.go
  67. 2 2
      tsweb/tsweb.go
  68. 7 3
      types/dnstype/dnstype.go
  69. 2 1
      types/views/views_test.go
  70. 17 16
      util/deephash/deephash_test.go
  71. 5 4
      wf/firewall.go
  72. 3 3
      wgengine/bench/bench.go
  73. 20 19
      wgengine/filter/filter_test.go
  74. 5 4
      wgengine/filter/tailcfg.go
  75. 6 6
      wgengine/magicsock/magicsock.go
  76. 8 8
      wgengine/magicsock/magicsock_test.go
  77. 1 1
      wgengine/router/ifconfig_windows.go
  78. 2 2
      wgengine/router/ifconfig_windows_test.go
  79. 2 2
      wgengine/router/router_linux_test.go
  80. 3 2
      wgengine/router/router_test.go
  81. 2 2
      wgengine/userspace.go
  82. 4 3
      wgengine/userspace_test.go
  83. 3 3
      wgengine/wgcfg/device_test.go
  84. 2 1
      wgengine/wgcfg/parser_test.go

+ 1 - 1
client/tailscale/routes.go

@@ -60,7 +60,7 @@ type postRoutesParams struct {
 }
 
 // SetRoutes updates the list of subnets that are enabled for a device.
-// Subnets must be parsable by tailscale.com/net/netaddr.ParseIPPrefix.
+// Subnets must be parsable by net/netip.ParsePrefix.
 // 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.
 func (c *Client) SetRoutes(ctx context.Context, deviceID string, subnets []netaddr.IPPrefix) (routes *Routes, err error) {

+ 33 - 32
cmd/tailscale/cli/cli_test.go

@@ -9,6 +9,7 @@ import (
 	"encoding/json"
 	"flag"
 	"fmt"
+	"net/netip"
 	"reflect"
 	"strings"
 	"testing"
@@ -153,9 +154,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
 				CorpDNS:          true,
 				NetfilterMode:    preftype.NetfilterOn,
 				AdvertiseRoutes: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("10.0.42.0/24"),
-					netaddr.MustParseIPPrefix("0.0.0.0/0"),
-					netaddr.MustParseIPPrefix("::/0"),
+					netip.MustParsePrefix("10.0.42.0/24"),
+					netip.MustParsePrefix("0.0.0.0/0"),
+					netip.MustParsePrefix("::/0"),
 				},
 			},
 			want: accidentalUpPrefix + " --advertise-routes=10.0.42.0/24 --advertise-exit-node",
@@ -169,9 +170,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
 				CorpDNS:          true,
 				NetfilterMode:    preftype.NetfilterOn,
 				AdvertiseRoutes: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("10.0.42.0/24"),
-					netaddr.MustParseIPPrefix("0.0.0.0/0"),
-					netaddr.MustParseIPPrefix("::/0"),
+					netip.MustParsePrefix("10.0.42.0/24"),
+					netip.MustParsePrefix("0.0.0.0/0"),
+					netip.MustParsePrefix("::/0"),
 				},
 			},
 			want: "",
@@ -185,9 +186,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
 				CorpDNS:          true,
 				NetfilterMode:    preftype.NetfilterOn,
 				AdvertiseRoutes: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("10.0.42.0/24"),
-					netaddr.MustParseIPPrefix("0.0.0.0/0"),
-					netaddr.MustParseIPPrefix("::/0"),
+					netip.MustParsePrefix("10.0.42.0/24"),
+					netip.MustParsePrefix("0.0.0.0/0"),
+					netip.MustParsePrefix("::/0"),
 				},
 			},
 			want: "",
@@ -213,7 +214,7 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
 				NetfilterMode:    preftype.NetfilterOn,
 
 				AdvertiseRoutes: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("1.2.0.0/16"),
+					netip.MustParsePrefix("1.2.0.0/16"),
 				},
 			},
 			want: accidentalUpPrefix + " --advertise-exit-node --advertise-routes=1.2.0.0/16",
@@ -227,9 +228,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
 				CorpDNS:          true,
 				NetfilterMode:    preftype.NetfilterOn,
 				AdvertiseRoutes: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("0.0.0.0/0"),
-					netaddr.MustParseIPPrefix("::/0"),
-					netaddr.MustParseIPPrefix("1.2.0.0/16"),
+					netip.MustParsePrefix("0.0.0.0/0"),
+					netip.MustParsePrefix("::/0"),
+					netip.MustParsePrefix("1.2.0.0/16"),
 				},
 			},
 			want: accidentalUpPrefix + " --advertise-exit-node --advertise-routes=1.2.0.0/16",
@@ -255,16 +256,16 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
 				ControlURL:       ipn.DefaultControlURL,
 				RouteAll:         true,
 				AllowSingleHosts: false,
-				ExitNodeIP:       netaddr.MustParseIP("100.64.5.6"),
+				ExitNodeIP:       netip.MustParseAddr("100.64.5.6"),
 				CorpDNS:          false,
 				ShieldsUp:        true,
 				AdvertiseTags:    []string{"tag:foo", "tag:bar"},
 				Hostname:         "myhostname",
 				ForceDaemon:      true,
 				AdvertiseRoutes: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("10.0.0.0/16"),
-					netaddr.MustParseIPPrefix("0.0.0.0/0"),
-					netaddr.MustParseIPPrefix("::/0"),
+					netip.MustParsePrefix("10.0.0.0/16"),
+					netip.MustParsePrefix("0.0.0.0/0"),
+					netip.MustParsePrefix("::/0"),
 				},
 				NetfilterMode: preftype.NetfilterNoDivert,
 				OperatorUser:  "alice",
@@ -280,14 +281,14 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
 				ControlURL:       ipn.DefaultControlURL,
 				RouteAll:         true,
 				AllowSingleHosts: false,
-				ExitNodeIP:       netaddr.MustParseIP("100.64.5.6"),
+				ExitNodeIP:       netip.MustParseAddr("100.64.5.6"),
 				CorpDNS:          false,
 				ShieldsUp:        true,
 				AdvertiseTags:    []string{"tag:foo", "tag:bar"},
 				Hostname:         "myhostname",
 				ForceDaemon:      true,
 				AdvertiseRoutes: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("10.0.0.0/16"),
+					netip.MustParsePrefix("10.0.0.0/16"),
 				},
 				NetfilterMode: preftype.NetfilterNoDivert,
 				OperatorUser:  "alice",
@@ -345,9 +346,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
 				CorpDNS:          true,
 				NetfilterMode:    preftype.NetfilterOn,
 				AdvertiseRoutes: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("0.0.0.0/0"),
-					netaddr.MustParseIPPrefix("::/0"),
-					netaddr.MustParseIPPrefix("1.2.0.0/16"),
+					netip.MustParsePrefix("0.0.0.0/0"),
+					netip.MustParsePrefix("::/0"),
+					netip.MustParsePrefix("1.2.0.0/16"),
 				},
 			},
 			want: accidentalUpPrefix + " --operator=expbits --advertise-exit-node --advertise-routes=1.2.0.0/16",
@@ -361,9 +362,9 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
 				CorpDNS:          true,
 				NetfilterMode:    preftype.NetfilterOn,
 				AdvertiseRoutes: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("0.0.0.0/0"),
-					netaddr.MustParseIPPrefix("::/0"),
-					netaddr.MustParseIPPrefix("1.2.0.0/16"),
+					netip.MustParsePrefix("0.0.0.0/0"),
+					netip.MustParsePrefix("::/0"),
+					netip.MustParsePrefix("1.2.0.0/16"),
 				},
 			},
 			want: accidentalUpPrefix + " --advertise-routes=1.2.0.0/16 --operator=expbits --advertise-exit-node",
@@ -391,14 +392,14 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
 				CorpDNS:          true,
 				NetfilterMode:    preftype.NetfilterOn,
 
-				ExitNodeIP: netaddr.MustParseIP("100.64.5.4"),
+				ExitNodeIP: netip.MustParseAddr("100.64.5.4"),
 			},
 			want: accidentalUpPrefix + " --hostname=foo --exit-node=100.64.5.4",
 		},
 		{
 			name:          "error_exit_node_omit_with_id_pref",
 			flags:         []string{"--hostname=foo"},
-			curExitNodeIP: netaddr.MustParseIP("100.64.5.7"),
+			curExitNodeIP: netip.MustParseAddr("100.64.5.7"),
 			curPrefs: &ipn.Prefs{
 				ControlURL:       ipn.DefaultControlURL,
 				AllowSingleHosts: true,
@@ -412,7 +413,7 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
 		{
 			name:          "error_exit_node_and_allow_lan_omit_with_id_pref", // Isue 3480
 			flags:         []string{"--hostname=foo"},
-			curExitNodeIP: netaddr.MustParseIP("100.2.3.4"),
+			curExitNodeIP: netip.MustParseAddr("100.2.3.4"),
 			curPrefs: &ipn.Prefs{
 				ControlURL:       ipn.DefaultControlURL,
 				AllowSingleHosts: true,
@@ -563,8 +564,8 @@ func TestPrefsFromUpArgs(t *testing.T) {
 				AllowSingleHosts: true,
 				CorpDNS:          true,
 				AdvertiseRoutes: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("0.0.0.0/0"),
-					netaddr.MustParseIPPrefix("::/0"),
+					netip.MustParsePrefix("0.0.0.0/0"),
+					netip.MustParsePrefix("::/0"),
 				},
 				NetfilterMode: preftype.NetfilterOn,
 			},
@@ -631,7 +632,7 @@ func TestPrefsFromUpArgs(t *testing.T) {
 				exitNodeIP: "100.105.106.107",
 			},
 			st: &ipnstate.Status{
-				TailscaleIPs: []netaddr.IP{netaddr.MustParseIP("100.105.106.107")},
+				TailscaleIPs: []netaddr.IP{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?`,
 		},
@@ -672,7 +673,7 @@ func TestPrefsFromUpArgs(t *testing.T) {
 				WantRunning: true,
 				NoSNAT:      true,
 				AdvertiseRoutes: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("fd7a:115c:a1e0:b1a::bb:10.0.0.0/112"),
+					netip.MustParsePrefix("fd7a:115c:a1e0:b1a::bb:10.0.0.0/112"),
 				},
 			},
 		},

+ 2 - 3
cmd/tailscale/cli/debug.go

@@ -28,7 +28,6 @@ import (
 	"tailscale.com/control/controlhttp"
 	"tailscale.com/hostinfo"
 	"tailscale.com/ipn"
-	"tailscale.com/net/netaddr"
 	"tailscale.com/net/tsaddr"
 	"tailscale.com/paths"
 	"tailscale.com/safesocket"
@@ -405,7 +404,7 @@ func runVia(ctx context.Context, args []string) error {
 	default:
 		return errors.New("expect either <site-id> <v4-cidr> or <v6-route>")
 	case 1:
-		ipp, err := netaddr.ParseIPPrefix(args[0])
+		ipp, err := netip.ParsePrefix(args[0])
 		if err != nil {
 			return err
 		}
@@ -430,7 +429,7 @@ func runVia(ctx context.Context, args []string) error {
 		if siteID > 0xff {
 			return fmt.Errorf("site-id values over 255 are currently reserved")
 		}
-		ipp, err := netaddr.ParseIPPrefix(args[1])
+		ipp, err := netip.ParsePrefix(args[1])
 		if err != nil {
 			return err
 		}

+ 3 - 2
cmd/tailscale/cli/file.go

@@ -14,6 +14,7 @@ import (
 	"log"
 	"mime"
 	"net/http"
+	"net/netip"
 	"os"
 	"path"
 	"path/filepath"
@@ -85,7 +86,7 @@ func runCp(ctx context.Context, args []string) error {
 		hadBrackets = true
 		target = strings.TrimSuffix(strings.TrimPrefix(target, "["), "]")
 	}
-	if ip, err := netaddr.ParseIP(target); err == nil && ip.Is6() && !hadBrackets {
+	if ip, err := netip.ParseAddr(target); err == nil && ip.Is6() && !hadBrackets {
 		return fmt.Errorf("an IPv6 literal must be written as [%s]", ip)
 	} else if hadBrackets && (err != nil || !ip.Is6()) {
 		return errors.New("unexpected brackets around target")
@@ -168,7 +169,7 @@ func runCp(ctx context.Context, args []string) error {
 }
 
 func getTargetStableID(ctx context.Context, ipStr string) (id tailcfg.StableNodeID, isOffline bool, err error) {
-	ip, err := netaddr.ParseIP(ipStr)
+	ip, err := netip.ParseAddr(ipStr)
 	if err != nil {
 		return "", false, err
 	}

+ 2 - 2
cmd/tailscale/cli/ip.go

@@ -9,10 +9,10 @@ import (
 	"errors"
 	"flag"
 	"fmt"
+	"net/netip"
 
 	"github.com/peterbourgon/ff/v3/ffcli"
 	"tailscale.com/ipn/ipnstate"
-	"tailscale.com/net/netaddr"
 )
 
 var ipCmd = &ffcli.Command{
@@ -100,7 +100,7 @@ func runIP(ctx context.Context, args []string) error {
 }
 
 func peerMatchingIP(st *ipnstate.Status, ipStr string) (ps *ipnstate.PeerStatus, ok bool) {
-	ip, err := netaddr.ParseIP(ipStr)
+	ip, err := netip.ParseAddr(ipStr)
 	if err != nil {
 		return
 	}

+ 2 - 2
cmd/tailscale/cli/ping.go

@@ -11,13 +11,13 @@ import (
 	"fmt"
 	"log"
 	"net"
+	"net/netip"
 	"os"
 	"strings"
 	"time"
 
 	"github.com/peterbourgon/ff/v3/ffcli"
 	"tailscale.com/ipn/ipnstate"
-	"tailscale.com/net/netaddr"
 	"tailscale.com/tailcfg"
 )
 
@@ -116,7 +116,7 @@ func runPing(ctx context.Context, args []string) error {
 	for {
 		n++
 		ctx, cancel := context.WithTimeout(ctx, pingArgs.timeout)
-		pr, err := localClient.Ping(ctx, netaddr.MustParseIP(ip), pingType())
+		pr, err := localClient.Ping(ctx, netip.MustParseAddr(ip), pingType())
 		cancel()
 		if err != nil {
 			if errors.Is(err, context.DeadlineExceeded) {

+ 3 - 3
cmd/tailscale/cli/ssh.go

@@ -10,6 +10,7 @@ import (
 	"errors"
 	"fmt"
 	"log"
+	"net/netip"
 	"os"
 	"os/user"
 	"path/filepath"
@@ -19,7 +20,6 @@ import (
 	"github.com/peterbourgon/ff/v3/ffcli"
 	"tailscale.com/envknob"
 	"tailscale.com/ipn/ipnstate"
-	"tailscale.com/net/netaddr"
 	"tailscale.com/net/tsaddr"
 	"tailscale.com/version"
 )
@@ -163,7 +163,7 @@ func nodeDNSNameFromArg(st *ipnstate.Status, arg string) (dnsName string, ok boo
 	if arg == "" {
 		return
 	}
-	argIP, _ := netaddr.ParseIP(arg)
+	argIP, _ := netip.ParseAddr(arg)
 	for _, ps := range st.Peer {
 		dnsName = ps.DNSName
 		if argIP.IsValid() {
@@ -202,7 +202,7 @@ func isSSHOverTailscale() bool {
 	if !ok {
 		return false
 	}
-	ip, err := netaddr.ParseIP(ipStr)
+	ip, err := netip.ParseAddr(ipStr)
 	if err != nil {
 		return false
 	}

+ 6 - 5
cmd/tailscale/cli/up.go

@@ -13,6 +13,7 @@ import (
 	"flag"
 	"fmt"
 	"log"
+	"net/netip"
 	"os"
 	"reflect"
 	"runtime"
@@ -199,8 +200,8 @@ func warnf(format string, args ...any) {
 }
 
 var (
-	ipv4default = netaddr.MustParseIPPrefix("0.0.0.0/0")
-	ipv6default = netaddr.MustParseIPPrefix("::/0")
+	ipv4default = netip.MustParsePrefix("0.0.0.0/0")
+	ipv6default = netip.MustParsePrefix("::/0")
 )
 
 func validateViaPrefix(ipp netaddr.IPPrefix) error {
@@ -229,7 +230,7 @@ func calcAdvertiseRoutes(advertiseRoutes string, advertiseDefaultRoute bool) ([]
 		var default4, default6 bool
 		advroutes := strings.Split(advertiseRoutes, ",")
 		for _, s := range advroutes {
-			ipp, err := netaddr.ParseIPPrefix(s)
+			ipp, err := netip.ParsePrefix(s)
 			if err != nil {
 				return nil, fmt.Errorf("%q is not a valid IP address or CIDR prefix", s)
 			}
@@ -255,8 +256,8 @@ func calcAdvertiseRoutes(advertiseRoutes string, advertiseDefaultRoute bool) ([]
 		}
 	}
 	if advertiseDefaultRoute {
-		routeMap[netaddr.MustParseIPPrefix("0.0.0.0/0")] = true
-		routeMap[netaddr.MustParseIPPrefix("::/0")] = true
+		routeMap[netip.MustParsePrefix("0.0.0.0/0")] = true
+		routeMap[netip.MustParsePrefix("::/0")] = true
 	}
 	routes := make([]netaddr.IPPrefix, 0, len(routeMap))
 	for r := range routeMap {

+ 3 - 3
cmd/tailscale/cli/web.go

@@ -20,6 +20,7 @@ import (
 	"net"
 	"net/http"
 	"net/http/cgi"
+	"net/netip"
 	"net/url"
 	"os"
 	"os/exec"
@@ -28,7 +29,6 @@ import (
 
 	"github.com/peterbourgon/ff/v3/ffcli"
 	"tailscale.com/ipn"
-	"tailscale.com/net/netaddr"
 	"tailscale.com/tailcfg"
 	"tailscale.com/types/preftype"
 	"tailscale.com/util/groupmember"
@@ -393,8 +393,8 @@ func webHandler(w http.ResponseWriter, r *http.Request) {
 		Status:       st.BackendState,
 		DeviceName:   deviceName,
 	}
-	exitNodeRouteV4 := netaddr.MustParseIPPrefix("0.0.0.0/0")
-	exitNodeRouteV6 := netaddr.MustParseIPPrefix("::/0")
+	exitNodeRouteV4 := netip.MustParsePrefix("0.0.0.0/0")
+	exitNodeRouteV6 := netip.MustParsePrefix("::/0")
 	for _, r := range prefs.AdvertiseRoutes {
 		if r == exitNodeRouteV4 || r == exitNodeRouteV6 {
 			data.AdvertiseExitNode = true

+ 3 - 2
cmd/tailscaled/debug.go

@@ -20,6 +20,7 @@ import (
 	"net"
 	"net/http"
 	"net/http/httptrace"
+	"net/netip"
 	"net/url"
 	"os"
 	"strings"
@@ -269,8 +270,8 @@ func debugPortmap(ctx context.Context) error {
 	gatewayAndSelfIP := func() (gw, self netaddr.IP, ok bool) {
 		if v := os.Getenv("TS_DEBUG_GW_SELF"); strings.Contains(v, "/") {
 			i := strings.Index(v, "/")
-			gw = netaddr.MustParseIP(v[:i])
-			self = netaddr.MustParseIP(v[i+1:])
+			gw = netip.MustParseAddr(v[:i])
+			self = netip.MustParseAddr(v[i+1:])
 			return gw, self, true
 		}
 		return linkMon.GatewayAndSelfIP()

+ 2 - 1
derp/derp_client.go

@@ -11,6 +11,7 @@ import (
 	"errors"
 	"fmt"
 	"io"
+	"net/netip"
 	"sync"
 	"sync/atomic"
 	"time"
@@ -609,5 +610,5 @@ func (c *Client) LocalAddr() (netaddr.IPPort, error) {
 	if a == nil {
 		return netaddr.IPPort{}, errors.New("nil addr")
 	}
-	return netaddr.ParseIPPort(a.String())
+	return netip.ParseAddrPort(a.String())
 }

+ 3 - 2
derp/derp_server.go

@@ -25,6 +25,7 @@ import (
 	"math/rand"
 	"net"
 	"net/http"
+	"net/netip"
 	"os/exec"
 	"runtime"
 	"strconv"
@@ -663,7 +664,7 @@ func (s *Server) accept(ctx context.Context, nc Conn, brw *bufio.ReadWriter, rem
 	ctx, cancel := context.WithCancel(ctx)
 	defer cancel()
 
-	remoteIPPort, _ := netaddr.ParseIPPort(remoteAddr)
+	remoteIPPort, _ := netip.ParseAddrPort(remoteAddr)
 
 	c := &sclient{
 		connNum:        connNum,
@@ -1768,7 +1769,7 @@ func parseSSOutput(raw string) map[netaddr.IPPort]BytesSentRecv {
 		if len(ipInfo) < 5 {
 			continue
 		}
-		src, err := netaddr.ParseIPPort(ipInfo[4])
+		src, err := netip.ParseAddrPort(ipInfo[4])
 		if err != nil {
 			continue
 		}

+ 2 - 1
derp/derphttp/derphttp_client.go

@@ -22,6 +22,7 @@ import (
 	"io/ioutil"
 	"net"
 	"net/http"
+	"net/netip"
 	"net/url"
 	"runtime"
 	"strings"
@@ -583,7 +584,7 @@ func shouldDialProto(s string, pred func(netaddr.IP) bool) bool {
 	if s == "" {
 		return true
 	}
-	ip, _ := netaddr.ParseIP(s)
+	ip, _ := netip.ParseAddr(s)
 	return pred(ip)
 }
 

+ 4 - 3
disco/disco_test.go

@@ -6,6 +6,7 @@ package disco
 
 import (
 	"fmt"
+	"net/netip"
 	"reflect"
 	"strings"
 	"testing"
@@ -61,8 +62,8 @@ func TestMarshalAndParse(t *testing.T) {
 			name: "call_me_maybe_endpoints",
 			m: &CallMeMaybe{
 				MyNumber: []netaddr.IPPort{
-					netaddr.MustParseIPPort("1.2.3.4:567"),
-					netaddr.MustParseIPPort("[2001::3456]:789"),
+					netip.MustParseAddrPort("1.2.3.4:567"),
+					netip.MustParseAddrPort("[2001::3456]:789"),
 				},
 			},
 			want: "03 00 00 00 00 00 00 00 00 00 00 00 ff ff 01 02 03 04 02 37 20 01 00 00 00 00 00 00 00 00 00 00 00 00 34 56 03 15",
@@ -94,7 +95,7 @@ func TestMarshalAndParse(t *testing.T) {
 }
 
 func mustIPPort(s string) netaddr.IPPort {
-	ipp, err := netaddr.ParseIPPort(s)
+	ipp, err := netip.ParseAddrPort(s)
 	if err != nil {
 		panic(err)
 	}

+ 3 - 3
ipn/ipnlocal/dnsconfig_test.go

@@ -23,18 +23,18 @@ import (
 
 func ipps(ippStrs ...string) (ipps []netaddr.IPPrefix) {
 	for _, s := range ippStrs {
-		if ip, err := netaddr.ParseIP(s); err == nil {
+		if ip, err := netip.ParseAddr(s); err == nil {
 			ipps = append(ipps, netip.PrefixFrom(ip, ip.BitLen()))
 			continue
 		}
-		ipps = append(ipps, netaddr.MustParseIPPrefix(s))
+		ipps = append(ipps, netip.MustParsePrefix(s))
 	}
 	return
 }
 
 func ips(ss ...string) (ips []netaddr.IP) {
 	for _, s := range ss {
-		ips = append(ips, netaddr.MustParseIP(s))
+		ips = append(ips, netip.MustParseAddr(s))
 	}
 	return
 }

+ 10 - 10
ipn/ipnlocal/local.go

@@ -1208,19 +1208,19 @@ func (b *LocalBackend) setFilter(f *filter.Filter) {
 
 var removeFromDefaultRoute = []netaddr.IPPrefix{
 	// RFC1918 LAN ranges
-	netaddr.MustParseIPPrefix("192.168.0.0/16"),
-	netaddr.MustParseIPPrefix("172.16.0.0/12"),
-	netaddr.MustParseIPPrefix("10.0.0.0/8"),
+	netip.MustParsePrefix("192.168.0.0/16"),
+	netip.MustParsePrefix("172.16.0.0/12"),
+	netip.MustParsePrefix("10.0.0.0/8"),
 	// IPv4 link-local
-	netaddr.MustParseIPPrefix("169.254.0.0/16"),
+	netip.MustParsePrefix("169.254.0.0/16"),
 	// IPv4 multicast
-	netaddr.MustParseIPPrefix("224.0.0.0/4"),
+	netip.MustParsePrefix("224.0.0.0/4"),
 	// Tailscale IPv4 range
 	tsaddr.CGNATRange(),
 	// IPv6 Link-local addresses
-	netaddr.MustParseIPPrefix("fe80::/10"),
+	netip.MustParsePrefix("fe80::/10"),
 	// IPv6 multicast
-	netaddr.MustParseIPPrefix("ff00::/8"),
+	netip.MustParsePrefix("ff00::/8"),
 	// Tailscale IPv6 range
 	tsaddr.TailscaleULARange(),
 }
@@ -2346,7 +2346,7 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Log
 			// TODO: more
 			continue
 		}
-		ip, err := netaddr.ParseIP(rec.Value)
+		ip, err := netip.ParseAddr(rec.Value)
 		if err != nil {
 			// Ignore.
 			continue
@@ -2622,8 +2622,8 @@ func magicDNSRootDomains(nm *netmap.NetworkMap) []dnsname.FQDN {
 }
 
 var (
-	ipv4Default = netaddr.MustParseIPPrefix("0.0.0.0/0")
-	ipv6Default = netaddr.MustParseIPPrefix("::/0")
+	ipv4Default = netip.MustParsePrefix("0.0.0.0/0")
+	ipv6Default = netip.MustParsePrefix("::/0")
 )
 
 // peerRoutes returns the routerConfig.Routes to access peers.

+ 32 - 31
ipn/ipnlocal/local_test.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"net"
 	"net/http"
+	"net/netip"
 	"reflect"
 	"testing"
 	"time"
@@ -26,13 +27,13 @@ import (
 )
 
 func TestNetworkMapCompare(t *testing.T) {
-	prefix1, err := netaddr.ParseIPPrefix("192.168.0.0/24")
+	prefix1, err := netip.ParsePrefix("192.168.0.0/24")
 	if err != nil {
 		t.Fatal(err)
 	}
 	node1 := &tailcfg.Node{Addresses: []netaddr.IPPrefix{prefix1}}
 
-	prefix2, err := netaddr.ParseIPPrefix("10.0.0.0/8")
+	prefix2, err := netip.ParsePrefix("10.0.0.0/8")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -185,7 +186,7 @@ func TestShrinkDefaultRoute(t *testing.T) {
 	// and localAddresses would normally come from calling interfaces.LocalAddresses.
 	var b netipx.IPSetBuilder
 	for _, c := range []string{"127.0.0.0/8", "192.168.9.0/24", "fe80::/32"} {
-		p := netaddr.MustParseIPPrefix(c)
+		p := netip.MustParsePrefix(c)
 		b.AddPrefix(p)
 	}
 	localInterfaceRoutes, err := b.IPSet()
@@ -193,28 +194,28 @@ func TestShrinkDefaultRoute(t *testing.T) {
 		t.Fatal(err)
 	}
 	hostIPs := []netaddr.IP{
-		netaddr.MustParseIP("127.0.0.1"),
-		netaddr.MustParseIP("192.168.9.39"),
-		netaddr.MustParseIP("fe80::1"),
-		netaddr.MustParseIP("fe80::437d:feff:feca:49a7"),
+		netip.MustParseAddr("127.0.0.1"),
+		netip.MustParseAddr("192.168.9.39"),
+		netip.MustParseAddr("fe80::1"),
+		netip.MustParseAddr("fe80::437d:feff:feca:49a7"),
 	}
 	localAddresses := []netaddr.IP{
-		netaddr.MustParseIP("192.168.9.39"),
+		netip.MustParseAddr("192.168.9.39"),
 	}
 
 	for _, test := range tests {
-		def := netaddr.MustParseIPPrefix(test.route)
+		def := netip.MustParsePrefix(test.route)
 		got, err := shrinkDefaultRoute(def, localInterfaceRoutes, hostIPs)
 		if err != nil {
 			t.Fatalf("shrinkDefaultRoute(%q): %v", test.route, err)
 		}
 		for _, ip := range test.in {
-			if !got.Contains(netaddr.MustParseIP(ip)) {
+			if !got.Contains(netip.MustParseAddr(ip)) {
 				t.Errorf("shrink(%q).Contains(%v) = false, want true", test.route, ip)
 			}
 		}
 		for _, ip := range test.out {
-			if got.Contains(netaddr.MustParseIP(ip)) {
+			if got.Contains(netip.MustParseAddr(ip)) {
 				t.Errorf("shrink(%q).Contains(%v) = true, want false", test.route, ip)
 			}
 		}
@@ -228,7 +229,7 @@ func TestShrinkDefaultRoute(t *testing.T) {
 }
 
 func TestPeerRoutes(t *testing.T) {
-	pp := netaddr.MustParseIPPrefix
+	pp := netip.MustParsePrefix
 	tests := []struct {
 		name  string
 		peers []wgcfg.Peer
@@ -363,13 +364,13 @@ func TestPeerAPIBase(t *testing.T) {
 			name: "self_only_4_them_both",
 			nm: &netmap.NetworkMap{
 				Addresses: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("100.64.1.1/32"),
+					netip.MustParsePrefix("100.64.1.1/32"),
 				},
 			},
 			peer: &tailcfg.Node{
 				Addresses: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("100.64.1.2/32"),
-					netaddr.MustParseIPPrefix("fe70::2/128"),
+					netip.MustParsePrefix("100.64.1.2/32"),
+					netip.MustParsePrefix("fe70::2/128"),
 				},
 				Hostinfo: (&tailcfg.Hostinfo{
 					Services: []tailcfg.Service{
@@ -384,13 +385,13 @@ func TestPeerAPIBase(t *testing.T) {
 			name: "self_only_6_them_both",
 			nm: &netmap.NetworkMap{
 				Addresses: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("fe70::1/128"),
+					netip.MustParsePrefix("fe70::1/128"),
 				},
 			},
 			peer: &tailcfg.Node{
 				Addresses: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("100.64.1.2/32"),
-					netaddr.MustParseIPPrefix("fe70::2/128"),
+					netip.MustParsePrefix("100.64.1.2/32"),
+					netip.MustParsePrefix("fe70::2/128"),
 				},
 				Hostinfo: (&tailcfg.Hostinfo{
 					Services: []tailcfg.Service{
@@ -405,14 +406,14 @@ func TestPeerAPIBase(t *testing.T) {
 			name: "self_both_them_only_4",
 			nm: &netmap.NetworkMap{
 				Addresses: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("100.64.1.1/32"),
-					netaddr.MustParseIPPrefix("fe70::1/128"),
+					netip.MustParsePrefix("100.64.1.1/32"),
+					netip.MustParsePrefix("fe70::1/128"),
 				},
 			},
 			peer: &tailcfg.Node{
 				Addresses: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("100.64.1.2/32"),
-					netaddr.MustParseIPPrefix("fe70::2/128"),
+					netip.MustParsePrefix("100.64.1.2/32"),
+					netip.MustParsePrefix("fe70::2/128"),
 				},
 				Hostinfo: (&tailcfg.Hostinfo{
 					Services: []tailcfg.Service{
@@ -426,14 +427,14 @@ func TestPeerAPIBase(t *testing.T) {
 			name: "self_both_them_only_6",
 			nm: &netmap.NetworkMap{
 				Addresses: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("100.64.1.1/32"),
-					netaddr.MustParseIPPrefix("fe70::1/128"),
+					netip.MustParsePrefix("100.64.1.1/32"),
+					netip.MustParsePrefix("fe70::1/128"),
 				},
 			},
 			peer: &tailcfg.Node{
 				Addresses: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("100.64.1.2/32"),
-					netaddr.MustParseIPPrefix("fe70::2/128"),
+					netip.MustParsePrefix("100.64.1.2/32"),
+					netip.MustParsePrefix("fe70::2/128"),
 				},
 				Hostinfo: (&tailcfg.Hostinfo{
 					Services: []tailcfg.Service{
@@ -447,14 +448,14 @@ func TestPeerAPIBase(t *testing.T) {
 			name: "self_both_them_no_peerapi_service",
 			nm: &netmap.NetworkMap{
 				Addresses: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("100.64.1.1/32"),
-					netaddr.MustParseIPPrefix("fe70::1/128"),
+					netip.MustParsePrefix("100.64.1.1/32"),
+					netip.MustParsePrefix("fe70::1/128"),
 				},
 			},
 			peer: &tailcfg.Node{
 				Addresses: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("100.64.1.2/32"),
-					netaddr.MustParseIPPrefix("fe70::2/128"),
+					netip.MustParsePrefix("100.64.1.2/32"),
+					netip.MustParsePrefix("fe70::2/128"),
 				},
 			},
 			want: "",
@@ -558,7 +559,7 @@ func TestInternalAndExternalInterfaces(t *testing.T) {
 		return il
 	}
 	newInterface := func(name, pfx string, wsl2, loopback bool) interfacePrefix {
-		ippfx := netaddr.MustParseIPPrefix(pfx)
+		ippfx := netip.MustParsePrefix(pfx)
 		ip := interfaces.Interface{
 			Interface: &net.Interface{},
 			AltAddrs: []net.Addr{

+ 2 - 1
ipn/ipnlocal/peerapi.go

@@ -16,6 +16,7 @@ import (
 	"io/fs"
 	"net"
 	"net/http"
+	"net/netip"
 	"net/url"
 	"os"
 	"path"
@@ -985,7 +986,7 @@ func (h *peerAPIHandler) replyToDNSQueries() bool {
 	if remoteIP.Is6() {
 		// autogroup:internet for IPv6 is defined to start with 2000::/3,
 		// so use 2000::0 as the probe "the internet" address.
-		dstIP = netaddr.MustParseIP("2000::")
+		dstIP = netip.MustParseAddr("2000::")
 	}
 	verdict := f.CheckTCP(remoteIP, dstIP, 53)
 	return verdict == filter.Accept

+ 5 - 4
ipn/ipnlocal/peerapi_test.go

@@ -13,6 +13,7 @@ import (
 	"math/rand"
 	"net/http"
 	"net/http/httptest"
+	"net/netip"
 	"os"
 	"path/filepath"
 	"runtime"
@@ -583,7 +584,7 @@ func TestPeerAPIReplyToDNSQueries(t *testing.T) {
 		t.Errorf("for isSelf = false; want true")
 	}
 	h.isSelf = false
-	h.remoteAddr = netaddr.MustParseIPPort("100.150.151.152:12345")
+	h.remoteAddr = netip.MustParseAddrPort("100.150.151.152:12345")
 
 	eng, _ := wgengine.NewFakeUserspaceEngine(logger.Discard, 0)
 	h.ps = &peerAPIServer{
@@ -596,8 +597,8 @@ func TestPeerAPIReplyToDNSQueries(t *testing.T) {
 	}
 	h.ps.b.prefs = &ipn.Prefs{
 		AdvertiseRoutes: []netaddr.IPPrefix{
-			netaddr.MustParseIPPrefix("0.0.0.0/0"),
-			netaddr.MustParseIPPrefix("::/0"),
+			netip.MustParsePrefix("0.0.0.0/0"),
+			netip.MustParsePrefix("::/0"),
 		},
 	}
 	if !h.ps.b.OfferingExitNode() {
@@ -621,7 +622,7 @@ func TestPeerAPIReplyToDNSQueries(t *testing.T) {
 	}
 
 	// Also test IPv6.
-	h.remoteAddr = netaddr.MustParseIPPort("[fe70::1]:12345")
+	h.remoteAddr = netip.MustParseAddrPort("[fe70::1]:12345")
 	if !h.replyToDNSQueries() {
 		t.Errorf("unexpectedly IPv6 deny; wanted to be a DNS server")
 	}

+ 3 - 2
ipn/ipnserver/server.go

@@ -16,6 +16,7 @@ import (
 	"log"
 	"net"
 	"net/http"
+	"net/netip"
 	"os"
 	"os/exec"
 	"os/signal"
@@ -146,11 +147,11 @@ func (s *Server) getConnIdentity(c net.Conn) (ci connIdentity, err error) {
 		ci.Creds, _ = peercred.Get(c)
 		return ci, nil
 	}
-	la, err := netaddr.ParseIPPort(c.LocalAddr().String())
+	la, err := netip.ParseAddrPort(c.LocalAddr().String())
 	if err != nil {
 		return ci, fmt.Errorf("parsing local address: %w", err)
 	}
-	ra, err := netaddr.ParseIPPort(c.RemoteAddr().String())
+	ra, err := netip.ParseAddrPort(c.RemoteAddr().String())
 	if err != nil {
 		return ci, fmt.Errorf("parsing local remote: %w", err)
 	}

+ 3 - 2
ipn/localapi/localapi.go

@@ -16,6 +16,7 @@ import (
 	"net"
 	"net/http"
 	"net/http/httputil"
+	"net/netip"
 	"net/url"
 	"reflect"
 	"runtime"
@@ -225,7 +226,7 @@ func (h *Handler) serveWhoIs(w http.ResponseWriter, r *http.Request) {
 	var ipp netaddr.IPPort
 	if v := r.FormValue("addr"); v != "" {
 		var err error
-		ipp, err = netaddr.ParseIPPort(v)
+		ipp, err = netip.ParseAddrPort(v)
 		if err != nil {
 			http.Error(w, "invalid 'addr' parameter", 400)
 			return
@@ -667,7 +668,7 @@ func (h *Handler) servePing(w http.ResponseWriter, r *http.Request) {
 		http.Error(w, "missing 'ip' parameter", 400)
 		return
 	}
-	ip, err := netaddr.ParseIP(ipStr)
+	ip, err := netip.ParseAddr(ipStr)
 	if err != nil {
 		http.Error(w, "invalid IP", 400)
 		return

+ 1 - 1
ipn/prefs.go

@@ -524,7 +524,7 @@ func exitNodeIPOfArg(s string, st *ipnstate.Status) (ip netaddr.IP, err error) {
 	if s == "" {
 		return ip, os.ErrInvalid
 	}
-	ip, err = netaddr.ParseIP(s)
+	ip, err = netip.ParseAddr(s)
 	if err == nil {
 		// If we're online already and have a netmap, double check that the IP
 		// address specified is valid.

+ 8 - 7
ipn/prefs_test.go

@@ -9,6 +9,7 @@ import (
 	"errors"
 	"fmt"
 	"io/ioutil"
+	"net/netip"
 	"os"
 	"reflect"
 	"strings"
@@ -64,7 +65,7 @@ func TestPrefsEqual(t *testing.T) {
 
 	nets := func(strs ...string) (ns []netaddr.IPPrefix) {
 		for _, s := range strs {
-			n, err := netaddr.ParseIPPrefix(s)
+			n, err := netip.ParsePrefix(s)
 			if err != nil {
 				panic(err)
 			}
@@ -137,13 +138,13 @@ func TestPrefsEqual(t *testing.T) {
 		},
 
 		{
-			&Prefs{ExitNodeIP: netaddr.MustParseIP("1.2.3.4")},
+			&Prefs{ExitNodeIP: netip.MustParseAddr("1.2.3.4")},
 			&Prefs{},
 			false,
 		},
 		{
-			&Prefs{ExitNodeIP: netaddr.MustParseIP("1.2.3.4")},
-			&Prefs{ExitNodeIP: netaddr.MustParseIP("1.2.3.4")},
+			&Prefs{ExitNodeIP: netip.MustParseAddr("1.2.3.4")},
+			&Prefs{ExitNodeIP: netip.MustParseAddr("1.2.3.4")},
 			true,
 		},
 
@@ -415,7 +416,7 @@ func TestPrefsPretty(t *testing.T) {
 		},
 		{
 			Prefs{
-				ExitNodeIP: netaddr.MustParseIP("1.2.3.4"),
+				ExitNodeIP: netip.MustParseAddr("1.2.3.4"),
 			},
 			"linux",
 			`Prefs{ra=false mesh=false dns=false want=false exit=1.2.3.4 lan=false routes=[] nf=off Persist=nil}`,
@@ -659,7 +660,7 @@ func TestPrefsExitNode(t *testing.T) {
 		t.Errorf("default shouldn't advertise exit node")
 	}
 	p.AdvertiseRoutes = []netaddr.IPPrefix{
-		netaddr.MustParseIPPrefix("10.0.0.0/16"),
+		netip.MustParsePrefix("10.0.0.0/16"),
 	}
 	p.SetAdvertiseExitNode(true)
 	if got, want := len(p.AdvertiseRoutes), 3; got != want {
@@ -682,7 +683,7 @@ func TestPrefsExitNode(t *testing.T) {
 }
 
 func TestExitNodeIPOfArg(t *testing.T) {
-	mustIP := netaddr.MustParseIP
+	mustIP := netip.MustParseAddr
 	tests := []struct {
 		name    string
 		arg     string

+ 6 - 5
net/dns/direct_test.go

@@ -8,6 +8,7 @@ import (
 	"errors"
 	"fmt"
 	"io/fs"
+	"net/netip"
 	"os"
 	"path/filepath"
 	"strings"
@@ -81,7 +82,7 @@ func testDirect(t *testing.T, fs wholeFileFS) {
 
 	m := directManager{logf: t.Logf, fs: fs}
 	if err := m.SetDNS(OSConfig{
-		Nameservers:   []netaddr.IP{netaddr.MustParseIP("8.8.8.8"), netaddr.MustParseIP("8.8.4.4")},
+		Nameservers:   []netaddr.IP{netip.MustParseAddr("8.8.8.8"), netip.MustParseAddr("8.8.4.4")},
 		SearchDomains: []dnsname.FQDN{"ts.net.", "ts-dns.test."},
 		MatchDomains:  []dnsname.FQDN{"ignored."},
 	}); err != nil {
@@ -108,7 +109,7 @@ search ts.net ts-dns.test
 	assertBaseState(t)
 
 	// Test that Close cleans up resolv.conf.
-	if err := m.SetDNS(OSConfig{Nameservers: []netaddr.IP{netaddr.MustParseIP("8.8.8.8")}}); err != nil {
+	if err := m.SetDNS(OSConfig{Nameservers: []netaddr.IP{netip.MustParseAddr("8.8.8.8")}}); err != nil {
 		t.Fatal(err)
 	}
 	if err := m.Close(); err != nil {
@@ -150,21 +151,21 @@ func TestReadResolve(t *testing.T) {
 		{in: `nameserver 192.168.0.100`,
 			want: OSConfig{
 				Nameservers: []netaddr.IP{
-					netaddr.MustParseIP("192.168.0.100"),
+					netip.MustParseAddr("192.168.0.100"),
 				},
 			},
 		},
 		{in: `nameserver 192.168.0.100 # comment`,
 			want: OSConfig{
 				Nameservers: []netaddr.IP{
-					netaddr.MustParseIP("192.168.0.100"),
+					netip.MustParseAddr("192.168.0.100"),
 				},
 			},
 		},
 		{in: `nameserver 192.168.0.100#`,
 			want: OSConfig{
 				Nameservers: []netaddr.IP{
-					netaddr.MustParseIP("192.168.0.100"),
+					netip.MustParseAddr("192.168.0.100"),
 				},
 			},
 		},

+ 7 - 6
net/dns/manager_test.go

@@ -5,6 +5,7 @@
 package dns
 
 import (
+	"net/netip"
 	"runtime"
 	"strings"
 	"testing"
@@ -425,14 +426,14 @@ func TestManager(t *testing.T) {
 
 func mustIPs(strs ...string) (ret []netaddr.IP) {
 	for _, s := range strs {
-		ret = append(ret, netaddr.MustParseIP(s))
+		ret = append(ret, netip.MustParseAddr(s))
 	}
 	return ret
 }
 
 func mustIPPs(strs ...string) (ret []netaddr.IPPort) {
 	for _, s := range strs {
-		ret = append(ret, netaddr.MustParseIPPort(s))
+		ret = append(ret, netip.MustParseAddrPort(s))
 	}
 	return ret
 }
@@ -459,7 +460,7 @@ func hosts(strs ...string) (ret map[dnsname.FQDN][]netaddr.IP) {
 	var key dnsname.FQDN
 	ret = map[dnsname.FQDN][]netaddr.IP{}
 	for _, s := range strs {
-		if ip, err := netaddr.ParseIP(s); err == nil {
+		if ip, err := netip.ParseAddr(s); err == nil {
 			if key == "" {
 				panic("IP provided before name")
 			}
@@ -479,7 +480,7 @@ func hostsR(strs ...string) (ret map[dnsname.FQDN][]dnstype.Resolver) {
 	var key dnsname.FQDN
 	ret = map[dnsname.FQDN][]dnstype.Resolver{}
 	for _, s := range strs {
-		if ip, err := netaddr.ParseIP(s); err == nil {
+		if ip, err := netip.ParseAddr(s); err == nil {
 			if key == "" {
 				panic("IP provided before name")
 			}
@@ -504,12 +505,12 @@ func upstreams(strs ...string) (ret map[dnsname.FQDN][]*dnstype.Resolver) {
 				panic("IPPort provided before suffix")
 			}
 			ret[key] = nil
-		} else if ipp, err := netaddr.ParseIPPort(s); err == nil {
+		} else if ipp, err := netip.ParseAddrPort(s); err == nil {
 			if key == "" {
 				panic("IPPort provided before suffix")
 			}
 			ret[key] = append(ret[key], &dnstype.Resolver{Addr: ipp.String()})
-		} else if _, err := netaddr.ParseIP(s); err == nil {
+		} else if _, err := netip.ParseAddr(s); err == nil {
 			if key == "" {
 				panic("IPPort provided before suffix")
 			}

+ 4 - 3
net/dns/manager_windows.go

@@ -7,6 +7,7 @@ package dns
 import (
 	"errors"
 	"fmt"
+	"net/netip"
 	"os/exec"
 	"sort"
 	"strings"
@@ -422,9 +423,9 @@ func (m windowsManager) getBasePrimaryResolver() (resolvers []netaddr.IP, err er
 }
 
 var siteLocalResolvers = []netaddr.IP{
-	netaddr.MustParseIP("fec0:0:0:ffff::1"),
-	netaddr.MustParseIP("fec0:0:0:ffff::2"),
-	netaddr.MustParseIP("fec0:0:0:ffff::3"),
+	netip.MustParseAddr("fec0:0:0:ffff::1"),
+	netip.MustParseAddr("fec0:0:0:ffff::2"),
+	netip.MustParseAddr("fec0:0:0:ffff::3"),
 }
 
 func isWindows10OrBetter() bool {

+ 3 - 2
net/dns/manager_windows_test.go

@@ -8,6 +8,7 @@ import (
 	"context"
 	"fmt"
 	"math/rand"
+	"net/netip"
 	"strings"
 	"testing"
 	"time"
@@ -91,7 +92,7 @@ func TestManagerWindowsGPMove(t *testing.T) {
 	// Upon initialization of cfg, we should not have any NRPT rules
 	ensureNoRules(t)
 
-	resolvers := []netaddr.IP{netaddr.MustParseIP("1.1.1.1")}
+	resolvers := []netaddr.IP{netip.MustParseAddr("1.1.1.1")}
 	domains := genRandomSubdomains(t, 1)
 
 	// 1. Populate local NRPT
@@ -215,7 +216,7 @@ func runTest(t *testing.T, isLocal bool) {
 	// Upon initialization of cfg, we should not have any NRPT rules
 	ensureNoRules(t)
 
-	resolvers := []netaddr.IP{netaddr.MustParseIP("1.1.1.1")}
+	resolvers := []netaddr.IP{netip.MustParseAddr("1.1.1.1")}
 
 	domains := genRandomSubdomains(t, 2*nrptMaxDomainsPerRule+1)
 

+ 2 - 1
net/dns/nm.go

@@ -10,6 +10,7 @@ package dns
 import (
 	"context"
 	"fmt"
+	"net/netip"
 	"sort"
 	"time"
 
@@ -312,7 +313,7 @@ func (m *nmManager) GetBaseConfig() (OSConfig, error) {
 		if v, ok := cfg["nameservers"]; ok {
 			if ips, ok := v.Value().([]string); ok {
 				for _, s := range ips {
-					ip, err := netaddr.ParseIP(s)
+					ip, err := netip.ParseAddr(s)
 					if err != nil {
 						// hmm, what do? Shouldn't really happen.
 						continue

+ 2 - 1
net/dns/publicdns/publicdns.go

@@ -7,6 +7,7 @@
 package publicdns
 
 import (
+	"net/netip"
 	"sync"
 
 	"tailscale.com/net/netaddr"
@@ -45,7 +46,7 @@ func DoHV6(base string) (ip netaddr.IP, ok bool) {
 // addDoH parses a given well-formed ip string into a netaddr.IP type and
 // adds it to both knownDoH and dohIPsOFBase maps.
 func addDoH(ipStr, base string) {
-	ip := netaddr.MustParseIP(ipStr)
+	ip := netip.MustParseAddr(ipStr)
 	knownDoH[ip] = base
 	dohIPsOfBase[base] = append(dohIPsOfBase[base], ip)
 }

+ 3 - 2
net/dns/publicdns/publicdns_test.go

@@ -5,6 +5,7 @@
 package publicdns
 
 import (
+	"net/netip"
 	"testing"
 
 	"tailscale.com/net/netaddr"
@@ -26,8 +27,8 @@ func TestDohV6(t *testing.T) {
 		firstIP netaddr.IP
 		want    bool
 	}{
-		{"https://cloudflare-dns.com/dns-query", netaddr.MustParseIP("2606:4700:4700::1111"), true},
-		{"https://dns.google/dns-query", netaddr.MustParseIP("2001:4860:4860::8888"), 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},
 		{"bogus", netaddr.IP{}, false},
 	}
 	for _, test := range tests {

+ 2 - 1
net/dns/resolvconffile/resolvconffile.go

@@ -16,6 +16,7 @@ import (
 	"bytes"
 	"fmt"
 	"io"
+	"net/netip"
 	"os"
 	"strings"
 
@@ -74,7 +75,7 @@ func Parse(r io.Reader) (*Config, error) {
 			if len(nameserver) == len(s) {
 				return nil, fmt.Errorf("missing space after \"nameserver\" in %q", line)
 			}
-			ip, err := netaddr.ParseIP(nameserver)
+			ip, err := netip.ParseAddr(nameserver)
 			if err != nil {
 				return nil, err
 			}

+ 4 - 3
net/dns/resolvconffile/resolvconffile_test.go

@@ -5,6 +5,7 @@
 package resolvconffile
 
 import (
+	"net/netip"
 	"reflect"
 	"strings"
 	"testing"
@@ -22,21 +23,21 @@ func TestParse(t *testing.T) {
 		{in: `nameserver 192.168.0.100`,
 			want: &Config{
 				Nameservers: []netaddr.IP{
-					netaddr.MustParseIP("192.168.0.100"),
+					netip.MustParseAddr("192.168.0.100"),
 				},
 			},
 		},
 		{in: `nameserver 192.168.0.100 # comment`,
 			want: &Config{
 				Nameservers: []netaddr.IP{
-					netaddr.MustParseIP("192.168.0.100"),
+					netip.MustParseAddr("192.168.0.100"),
 				},
 			},
 		},
 		{in: `nameserver 192.168.0.100#`,
 			want: &Config{
 				Nameservers: []netaddr.IP{
-					netaddr.MustParseIP("192.168.0.100"),
+					netip.MustParseAddr("192.168.0.100"),
 				},
 			},
 		},

+ 3 - 3
net/dns/resolver/tsdns.go

@@ -670,7 +670,7 @@ func (r *Resolver) parseViaDomain(domain dnsname.FQDN, typ dns.Type) (netaddr.IP
 		ip4Str = fqdn[:lastDot]
 	}
 
-	ip4, err := netaddr.ParseIP(ip4Str)
+	ip4, err := netip.ParseAddr(ip4Str)
 	if err != nil {
 		return netaddr.IP{}, false // badly formed, dont respond
 	}
@@ -1068,7 +1068,7 @@ func rawNameToLower(name []byte) string {
 //   1.2.3.4
 func rdnsNameToIPv4(name dnsname.FQDN) (ip netaddr.IP, ok bool) {
 	s := strings.TrimSuffix(name.WithTrailingDot(), rdnsv4Suffix)
-	ip, err := netaddr.ParseIP(s)
+	ip, err := netip.ParseAddr(s)
 	if err != nil {
 		return netaddr.IP{}, false
 	}
@@ -1196,7 +1196,7 @@ func unARPA(a string) (ipStr string, ok bool) {
 	if strings.HasSuffix(a, suf4) {
 		s := strings.TrimSuffix(a, suf4)
 		// Parse and reverse octets.
-		ip, err := netaddr.ParseIP(s)
+		ip, err := netip.ParseAddr(s)
 		if err != nil || !ip.Is4() {
 			return "", false
 		}

+ 16 - 15
net/dns/resolver/tsdns_test.go

@@ -13,6 +13,7 @@ import (
 	"fmt"
 	"math/rand"
 	"net"
+	"net/netip"
 	"reflect"
 	"runtime"
 	"strconv"
@@ -32,13 +33,13 @@ import (
 )
 
 var (
-	testipv4 = netaddr.MustParseIP("1.2.3.4")
-	testipv6 = netaddr.MustParseIP("0001:0203:0405:0607:0809:0a0b:0c0d:0e0f")
+	testipv4 = netip.MustParseAddr("1.2.3.4")
+	testipv6 = netip.MustParseAddr("0001:0203:0405:0607:0809:0a0b:0c0d:0e0f")
 
 	testipv4Arpa = dnsname.FQDN("4.3.2.1.in-addr.arpa.")
 	testipv6Arpa = dnsname.FQDN("f.0.e.0.d.0.c.0.b.0.a.0.9.0.8.0.7.0.6.0.5.0.4.0.3.0.2.0.1.0.0.0.ip6.arpa.")
 
-	magicDNSv4Port = netaddr.MustParseIPPort("100.100.100.100:53")
+	magicDNSv4Port = netip.MustParseAddrPort("100.100.100.100:53")
 )
 
 var dnsCfg = Config{
@@ -237,7 +238,7 @@ func syncRespond(r *Resolver, query []byte) ([]byte, error) {
 }
 
 func mustIP(str string) netaddr.IP {
-	ip, err := netaddr.ParseIP(str)
+	ip, err := netip.ParseAddr(str)
 	if err != nil {
 		panic(err)
 	}
@@ -342,11 +343,11 @@ func TestResolveLocal(t *testing.T) {
 		{"mx-nxdomain", "test3.ipn.dev.", dns.TypeMX, netaddr.IP{}, dns.RCodeNameError},
 		{"ns-nxdomain", "test3.ipn.dev.", dns.TypeNS, netaddr.IP{}, dns.RCodeNameError},
 		{"onion-domain", "footest.onion.", dns.TypeA, netaddr.IP{}, dns.RCodeNameError},
-		{"magicdns", dnsSymbolicFQDN, dns.TypeA, netaddr.MustParseIP("100.100.100.100"), dns.RCodeSuccess},
-		{"via_hex", dnsname.FQDN("via-0xff.1.2.3.4."), dns.TypeAAAA, netaddr.MustParseIP("fd7a:115c:a1e0:b1a:0:ff:1.2.3.4"), dns.RCodeSuccess},
-		{"via_dec", dnsname.FQDN("via-1.10.0.0.1."), dns.TypeAAAA, netaddr.MustParseIP("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, netaddr.MustParseIP("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, netaddr.MustParseIP("fd7a:115c:a1e0:b1a:0:1:1.0.0.10"), 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_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_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_2", dnsname.FQDN("2.3.4.5.via-."), dns.TypeAAAA, netaddr.IP{}, dns.RCodeRefused},
 	}
@@ -644,8 +645,8 @@ func TestDelegate(t *testing.T) {
 }
 
 func TestDelegateSplitRoute(t *testing.T) {
-	test4 := netaddr.MustParseIP("2.3.4.5")
-	test6 := netaddr.MustParseIP("ff::1")
+	test4 := netip.MustParseAddr("2.3.4.5")
+	test6 := netip.MustParseAddr("ff::1")
 
 	server1 := serveDNS(t, "127.0.0.1:0",
 		"test.site.", resolveToIP(testipv4, testipv6, "dns.test.site."))
@@ -1048,16 +1049,16 @@ func TestHandleExitNodeDNSQueryWithNetPkg(t *testing.T) {
 		dnsHandler(),
 
 		"one-a.test.",
-		dnsHandler(netaddr.MustParseIP("1.2.3.4")),
+		dnsHandler(netip.MustParseAddr("1.2.3.4")),
 
 		"two-a.test.",
-		dnsHandler(netaddr.MustParseIP("1.2.3.4"), netaddr.MustParseIP("5.6.7.8")),
+		dnsHandler(netip.MustParseAddr("1.2.3.4"), netip.MustParseAddr("5.6.7.8")),
 
 		"one-aaaa.test.",
-		dnsHandler(netaddr.MustParseIP("1::2")),
+		dnsHandler(netip.MustParseAddr("1::2")),
 
 		"two-aaaa.test.",
-		dnsHandler(netaddr.MustParseIP("1::2"), netaddr.MustParseIP("3::4")),
+		dnsHandler(netip.MustParseAddr("1::2"), netip.MustParseAddr("3::4")),
 
 		"nx-domain.test.",
 		resolveToNXDOMAIN,

+ 7 - 6
net/dnscache/dnscache_test.go

@@ -10,6 +10,7 @@ import (
 	"flag"
 	"fmt"
 	"net"
+	"net/netip"
 	"reflect"
 	"testing"
 	"time"
@@ -42,7 +43,7 @@ func TestDialCall_DNSWasTrustworthy(t *testing.T) {
 		ip  netaddr.IP // IP we pretended to dial
 		err error      // the dial error or nil for success
 	}
-	mustIP := netaddr.MustParseIP
+	mustIP := netip.MustParseAddr
 	errFail := errors.New("some connect failure")
 	tests := []struct {
 		name  string
@@ -90,7 +91,7 @@ func TestDialCall_DNSWasTrustworthy(t *testing.T) {
 
 func TestDialCall_uniqueIPs(t *testing.T) {
 	dc := &dialCall{}
-	mustIP := netaddr.MustParseIP
+	mustIP := netip.MustParseAddr
 	errFail := errors.New("some connect failure")
 	dc.noteDialResult(mustIP("2003::1"), errFail)
 	dc.noteDialResult(mustIP("2003::2"), errFail)
@@ -116,10 +117,10 @@ func TestResolverAllHostStaticResult(t *testing.T) {
 	r := &Resolver{
 		SingleHost: "foo.bar",
 		SingleHostStaticResult: []netaddr.IP{
-			netaddr.MustParseIP("2001:4860:4860::8888"),
-			netaddr.MustParseIP("2001:4860:4860::8844"),
-			netaddr.MustParseIP("8.8.8.8"),
-			netaddr.MustParseIP("8.8.4.4"),
+			netip.MustParseAddr("2001:4860:4860::8888"),
+			netip.MustParseAddr("2001:4860:4860::8844"),
+			netip.MustParseAddr("8.8.8.8"),
+			netip.MustParseAddr("8.8.4.4"),
 		},
 	}
 	ip4, ip6, allIPs, err := r.LookupIP(context.Background(), "foo.bar")

+ 4 - 3
net/dnsfallback/dnsfallback.go

@@ -18,6 +18,7 @@ import (
 	"math/rand"
 	"net"
 	"net/http"
+	"net/netip"
 	"net/url"
 	"time"
 
@@ -29,7 +30,7 @@ import (
 )
 
 func Lookup(ctx context.Context, host string) ([]netaddr.IP, error) {
-	if ip, err := netaddr.ParseIP(host); err == nil && ip.IsValid() {
+	if ip, err := netip.ParseAddr(host); err == nil && ip.IsValid() {
 		return []netaddr.IP{ip}, nil
 	}
 
@@ -42,10 +43,10 @@ func Lookup(ctx context.Context, host string) ([]netaddr.IP, error) {
 	var cands4, cands6 []nameIP
 	for _, dr := range dm.Regions {
 		for _, n := range dr.Nodes {
-			if ip, err := netaddr.ParseIP(n.IPv4); err == nil {
+			if ip, err := netip.ParseAddr(n.IPv4); err == nil {
 				cands4 = append(cands4, nameIP{n.HostName, ip})
 			}
-			if ip, err := netaddr.ParseIP(n.IPv6); err == nil {
+			if ip, err := netip.ParseAddr(n.IPv6); err == nil {
 				cands6 = append(cands6, nameIP{n.HostName, ip})
 			}
 		}

+ 5 - 5
net/flowtrack/flowtrack_test.go

@@ -5,19 +5,19 @@
 package flowtrack
 
 import (
+	"net/netip"
 	"testing"
 
-	"tailscale.com/net/netaddr"
 	"tailscale.com/tstest"
 )
 
 func TestCache(t *testing.T) {
 	c := &Cache{MaxEntries: 2}
 
-	k1 := Tuple{Src: netaddr.MustParseIPPort("1.1.1.1:1"), Dst: netaddr.MustParseIPPort("1.1.1.1:1")}
-	k2 := Tuple{Src: netaddr.MustParseIPPort("1.1.1.1:1"), Dst: netaddr.MustParseIPPort("2.2.2.2:2")}
-	k3 := Tuple{Src: netaddr.MustParseIPPort("1.1.1.1:1"), Dst: netaddr.MustParseIPPort("3.3.3.3:3")}
-	k4 := Tuple{Src: netaddr.MustParseIPPort("1.1.1.1:1"), Dst: netaddr.MustParseIPPort("4.4.4.4:4")}
+	k1 := Tuple{Src: netip.MustParseAddrPort("1.1.1.1:1"), Dst: netip.MustParseAddrPort("1.1.1.1:1")}
+	k2 := Tuple{Src: netip.MustParseAddrPort("1.1.1.1:1"), Dst: netip.MustParseAddrPort("2.2.2.2:2")}
+	k3 := Tuple{Src: netip.MustParseAddrPort("1.1.1.1:1"), Dst: netip.MustParseAddrPort("3.3.3.3:3")}
+	k4 := Tuple{Src: netip.MustParseAddrPort("1.1.1.1:1"), Dst: netip.MustParseAddrPort("4.4.4.4:4")}
 
 	wantLen := func(want int) {
 		t.Helper()

+ 2 - 1
net/interfaces/interfaces.go

@@ -10,6 +10,7 @@ import (
 	"fmt"
 	"net"
 	"net/http"
+	"net/netip"
 	"runtime"
 	"sort"
 	"strings"
@@ -630,7 +631,7 @@ func isUsableV6(ip netaddr.IP) bool {
 }
 
 var (
-	v6Global1 = netaddr.MustParseIPPrefix("2000::/3")
+	v6Global1 = netip.MustParsePrefix("2000::/3")
 )
 
 // anyInterestingIP reports whether pfxs contains any IP that matches

+ 2 - 1
net/interfaces/interfaces_darwin_test.go

@@ -6,6 +6,7 @@ package interfaces
 
 import (
 	"errors"
+	"net/netip"
 	"os/exec"
 	"testing"
 
@@ -72,7 +73,7 @@ func likelyHomeRouterIPDarwinExec() (ret netaddr.IP, ok bool) {
 		if !mem.Contains(flagsm, mem.S("G")) {
 			return nil
 		}
-		ip, err := netaddr.ParseIP(string(mem.Append(nil, ipm)))
+		ip, err := netip.ParseAddr(string(mem.Append(nil, ipm)))
 		if err == nil && ip.IsPrivate() {
 			ret = ip
 			// We've found what we're looking for.

+ 2 - 1
net/interfaces/interfaces_linux.go

@@ -12,6 +12,7 @@ import (
 	"io"
 	"log"
 	"net"
+	"net/netip"
 	"os"
 	"os/exec"
 	"runtime"
@@ -125,7 +126,7 @@ func likelyHomeRouterIPAndroid() (ret netaddr.IP, ok bool) {
 			return nil
 		}
 		ipb := line[:sp]
-		if ip, err := netaddr.ParseIP(string(ipb)); err == nil && ip.Is4() {
+		if ip, err := netip.ParseAddr(string(ipb)); err == nil && ip.Is4() {
 			ret = ip
 			log.Printf("interfaces: found Android default route %v", ip)
 		}

+ 8 - 7
net/interfaces/interfaces_test.go

@@ -7,6 +7,7 @@ package interfaces
 import (
 	"encoding/json"
 	"net"
+	"net/netip"
 	"testing"
 
 	"tailscale.com/net/netaddr"
@@ -64,7 +65,7 @@ func TestIsUsableV6(t *testing.T) {
 	}
 
 	for _, test := range tests {
-		if got := isUsableV6(netaddr.MustParseIP(test.ip)); got != test.want {
+		if got := isUsableV6(netip.MustParseAddr(test.ip)); got != test.want {
 			t.Errorf("isUsableV6(%s) = %v, want %v", test.name, got, test.want)
 		}
 	}
@@ -76,17 +77,17 @@ func TestStateEqualFilteredIPFilter(t *testing.T) {
 
 	s1 := &State{
 		InterfaceIPs: map[string][]netaddr.IPPrefix{"x": {
-			netaddr.MustParseIPPrefix("42.0.0.0/8"),
-			netaddr.MustParseIPPrefix("169.254.0.0/16"), // link local unicast
+			netip.MustParsePrefix("42.0.0.0/8"),
+			netip.MustParsePrefix("169.254.0.0/16"), // link local unicast
 		}},
 		Interface: map[string]Interface{"x": {Interface: &net.Interface{Name: "x"}}},
 	}
 
 	s2 := &State{
 		InterfaceIPs: map[string][]netaddr.IPPrefix{"x": {
-			netaddr.MustParseIPPrefix("42.0.0.0/8"),
-			netaddr.MustParseIPPrefix("169.254.0.0/16"), // link local unicast
-			netaddr.MustParseIPPrefix("127.0.0.0/8"),    // loopback (added)
+			netip.MustParsePrefix("42.0.0.0/8"),
+			netip.MustParsePrefix("169.254.0.0/16"), // link local unicast
+			netip.MustParsePrefix("127.0.0.0/8"),    // loopback (added)
 		}},
 		Interface: map[string]Interface{"x": {Interface: &net.Interface{Name: "x"}}},
 	}
@@ -127,7 +128,7 @@ func TestStateString(t *testing.T) {
 				},
 				InterfaceIPs: map[string][]netaddr.IPPrefix{
 					"eth0": []netaddr.IPPrefix{
-						netaddr.MustParseIPPrefix("10.0.0.2/8"),
+						netip.MustParsePrefix("10.0.0.2/8"),
 					},
 				},
 				HaveV4: true,

+ 0 - 8
net/netaddr/netaddr.go

@@ -125,11 +125,3 @@ func FromStdAddr(stdIP net.IP, port int, zone string) (_ IPPort, ok bool) {
 	}
 	return netip.AddrPortFrom(ip, uint16(port)), true
 }
-
-func ParseIP(s string) (IP, error)             { return netip.ParseAddr(s) }
-func ParseIPPrefix(s string) (IPPrefix, error) { return netip.ParsePrefix(s) }
-func ParseIPPort(s string) (IPPort, error)     { return netip.ParseAddrPort(s) }
-
-func MustParseIP(s string) IP             { return netip.MustParseAddr(s) }
-func MustParseIPPrefix(s string) IPPrefix { return netip.MustParsePrefix(s) }
-func MustParseIPPort(s string) IPPort     { return netip.MustParseAddrPort(s) }

+ 5 - 5
net/netcheck/netcheck.go

@@ -467,7 +467,7 @@ func nodeMight6(n *tailcfg.DERPNode) bool {
 	if n.IPv6 == "" {
 		return true
 	}
-	ip, _ := netaddr.ParseIP(n.IPv6)
+	ip, _ := netip.ParseAddr(n.IPv6)
 	return ip.Is6()
 
 }
@@ -479,7 +479,7 @@ func nodeMight4(n *tailcfg.DERPNode) bool {
 	if n.IPv4 == "" {
 		return true
 	}
-	ip, _ := netaddr.ParseIP(n.IPv4)
+	ip, _ := netip.ParseAddr(n.IPv4)
 	return ip.Is4()
 }
 
@@ -1290,7 +1290,7 @@ func (c *Client) nodeAddr(ctx context.Context, n *tailcfg.DERPNode, proto probeP
 		return
 	}
 	if n.STUNTestIP != "" {
-		ip, err := netaddr.ParseIP(n.STUNTestIP)
+		ip, err := netip.ParseAddr(n.STUNTestIP)
 		if err != nil {
 			return
 		}
@@ -1306,7 +1306,7 @@ func (c *Client) nodeAddr(ctx context.Context, n *tailcfg.DERPNode, proto probeP
 	switch proto {
 	case probeIPv4:
 		if n.IPv4 != "" {
-			ip, _ := netaddr.ParseIP(n.IPv4)
+			ip, _ := netip.ParseAddr(n.IPv4)
 			if !ip.Is4() {
 				return
 			}
@@ -1314,7 +1314,7 @@ func (c *Client) nodeAddr(ctx context.Context, n *tailcfg.DERPNode, proto probeP
 		}
 	case probeIPv6:
 		if n.IPv6 != "" {
-			ip, _ := netaddr.ParseIP(n.IPv6)
+			ip, _ := netip.ParseAddr(n.IPv6)
 			if !ip.Is6() {
 				return
 			}

+ 2 - 2
net/netns/netns.go

@@ -17,8 +17,8 @@ package netns
 import (
 	"context"
 	"net"
+	"net/netip"
 
-	"tailscale.com/net/netaddr"
 	"tailscale.com/net/netknob"
 	"tailscale.com/syncs"
 	"tailscale.com/types/logger"
@@ -100,6 +100,6 @@ func isLocalhost(addr string) bool {
 		return true
 	}
 
-	ip, _ := netaddr.ParseIP(host)
+	ip, _ := netip.ParseAddr(host)
 	return ip.IsLoopback()
 }

+ 3 - 3
net/packet/icmp6_test.go

@@ -5,17 +5,17 @@
 package packet
 
 import (
+	"net/netip"
 	"testing"
 
-	"tailscale.com/net/netaddr"
 	"tailscale.com/types/ipproto"
 )
 
 func TestICMPv6PingResponse(t *testing.T) {
 	pingHdr := ICMP6Header{
 		IP6Header: IP6Header{
-			Src:     netaddr.MustParseIP("1::1"),
-			Dst:     netaddr.MustParseIP("2::2"),
+			Src:     netip.MustParseAddr("1::1"),
+			Dst:     netip.MustParseAddr("2::2"),
 			IPProto: ipproto.ICMPv6,
 		},
 		Type: ICMP6EchoRequest,

+ 2 - 1
net/packet/packet_test.go

@@ -6,6 +6,7 @@ package packet
 
 import (
 	"bytes"
+	"net/netip"
 	"reflect"
 	"testing"
 
@@ -27,7 +28,7 @@ const (
 )
 
 func mustIPPort(s string) netaddr.IPPort {
-	ipp, err := netaddr.ParseIPPort(s)
+	ipp, err := netip.ParseAddrPort(s)
 	if err != nil {
 		panic(err)
 	}

+ 13 - 14
net/packet/tsmp_test.go

@@ -5,9 +5,8 @@
 package packet
 
 import (
+	"net/netip"
 	"testing"
-
-	"tailscale.com/net/netaddr"
 )
 
 func TestTailscaleRejectedHeader(t *testing.T) {
@@ -17,10 +16,10 @@ func TestTailscaleRejectedHeader(t *testing.T) {
 	}{
 		{
 			h: TailscaleRejectedHeader{
-				IPSrc:  netaddr.MustParseIP("5.5.5.5"),
-				IPDst:  netaddr.MustParseIP("1.2.3.4"),
-				Src:    netaddr.MustParseIPPort("1.2.3.4:567"),
-				Dst:    netaddr.MustParseIPPort("5.5.5.5:443"),
+				IPSrc:  netip.MustParseAddr("5.5.5.5"),
+				IPDst:  netip.MustParseAddr("1.2.3.4"),
+				Src:    netip.MustParseAddrPort("1.2.3.4:567"),
+				Dst:    netip.MustParseAddrPort("5.5.5.5:443"),
 				Proto:  TCP,
 				Reason: RejectedDueToACLs,
 			},
@@ -28,10 +27,10 @@ func TestTailscaleRejectedHeader(t *testing.T) {
 		},
 		{
 			h: TailscaleRejectedHeader{
-				IPSrc:  netaddr.MustParseIP("2::2"),
-				IPDst:  netaddr.MustParseIP("1::1"),
-				Src:    netaddr.MustParseIPPort("[1::1]:567"),
-				Dst:    netaddr.MustParseIPPort("[2::2]:443"),
+				IPSrc:  netip.MustParseAddr("2::2"),
+				IPDst:  netip.MustParseAddr("1::1"),
+				Src:    netip.MustParseAddrPort("[1::1]:567"),
+				Dst:    netip.MustParseAddrPort("[2::2]:443"),
 				Proto:  UDP,
 				Reason: RejectedDueToShieldsUp,
 			},
@@ -39,10 +38,10 @@ func TestTailscaleRejectedHeader(t *testing.T) {
 		},
 		{
 			h: TailscaleRejectedHeader{
-				IPSrc:       netaddr.MustParseIP("2::2"),
-				IPDst:       netaddr.MustParseIP("1::1"),
-				Src:         netaddr.MustParseIPPort("[1::1]:567"),
-				Dst:         netaddr.MustParseIPPort("[2::2]:443"),
+				IPSrc:       netip.MustParseAddr("2::2"),
+				IPDst:       netip.MustParseAddr("1::1"),
+				Src:         netip.MustParseAddrPort("[1::1]:567"),
+				Dst:         netip.MustParseAddrPort("[2::2]:443"),
 				Proto:       UDP,
 				Reason:      RejectedDueToIPForwarding,
 				MaybeBroken: true,

+ 2 - 1
net/portmapper/pcp_test.go

@@ -6,6 +6,7 @@ package portmapper
 
 import (
 	"encoding/binary"
+	"net/netip"
 	"testing"
 
 	"tailscale.com/net/netaddr"
@@ -21,7 +22,7 @@ func TestParsePCPMapResponse(t *testing.T) {
 	if mapping == nil {
 		t.Fatalf("got nil mapping when expected non-nil")
 	}
-	expectedAddr := netaddr.MustParseIPPort("135.180.175.246:1234")
+	expectedAddr := netip.MustParseAddrPort("135.180.175.246:1234")
 	if mapping.external != expectedAddr {
 		t.Errorf("mismatched external address, got: %v, want: %v", mapping.external, expectedAddr)
 	}

+ 1 - 1
net/portmapper/portmapper.go

@@ -397,7 +397,7 @@ func (c *Client) createMapping() {
 }
 
 // wildcardIP is used when the previous external IP is not known for PCP port mapping.
-var wildcardIP = netaddr.MustParseIP("0.0.0.0")
+var wildcardIP = netip.MustParseAddr("0.0.0.0")
 
 // createOrGetMapping either creates a new mapping or returns a cached
 // valid one.

+ 3 - 2
net/portmapper/upnp.go

@@ -16,6 +16,7 @@ import (
 	"fmt"
 	"math/rand"
 	"net/http"
+	"net/netip"
 	"net/url"
 	"strings"
 	"time"
@@ -170,7 +171,7 @@ func getUPnPClient(ctx context.Context, logf logger.Logf, gw netaddr.IP, meta uP
 		return nil, err
 	}
 
-	ipp, err := netaddr.ParseIPPort(u.Host)
+	ipp, err := netip.ParseAddrPort(u.Host)
 	if err != nil {
 		return nil, fmt.Errorf("unexpected host %q in %q", u.Host, meta.Location)
 	}
@@ -292,7 +293,7 @@ func (c *Client) getUPnPPortMapping(
 		// TODO this doesn't seem right
 		return netaddr.IPPort{}, false
 	}
-	externalIP, err := netaddr.ParseIP(extIP)
+	externalIP, err := netip.ParseAddr(extIP)
 	if err != nil {
 		return netaddr.IPPort{}, false
 	}

+ 2 - 2
net/stun/stuntest/stuntest.go

@@ -9,12 +9,12 @@ import (
 	"context"
 	"fmt"
 	"net"
+	"net/netip"
 	"strconv"
 	"strings"
 	"sync"
 	"testing"
 
-	"tailscale.com/net/netaddr"
 	"tailscale.com/net/stun"
 	"tailscale.com/tailcfg"
 	"tailscale.com/types/nettype"
@@ -106,7 +106,7 @@ func DERPMapOf(stun ...string) *tailcfg.DERPMap {
 			panic(fmt.Sprintf("bogus port %q in %q", portStr, hostPortStr))
 		}
 		var ipv4, ipv6 string
-		ip, err := netaddr.ParseIP(host)
+		ip, err := netip.ParseAddr(host)
 		if err != nil {
 			panic(fmt.Sprintf("bogus non-IP STUN host %q in %q", host, hostPortStr))
 		}

+ 3 - 3
net/tsaddr/tsaddr.go

@@ -143,7 +143,7 @@ func Tailscale6to4(ipv6 netaddr.IP) (netaddr.IP, bool) {
 
 func mustPrefix(v *netaddr.IPPrefix, prefix string) {
 	var err error
-	*v, err = netaddr.ParseIPPrefix(prefix)
+	*v, err = netip.ParsePrefix(prefix)
 	if err != nil {
 		panic(err)
 	}
@@ -253,8 +253,8 @@ func ContainsExitRoutes(rr []netaddr.IPPrefix) bool {
 }
 
 var (
-	allIPv4 = netaddr.MustParseIPPrefix("0.0.0.0/0")
-	allIPv6 = netaddr.MustParseIPPrefix("::/0")
+	allIPv4 = netip.MustParsePrefix("0.0.0.0/0")
+	allIPv6 = netip.MustParsePrefix("::/0")
 )
 
 // AllIPv4 returns 0.0.0.0/0.

+ 14 - 13
net/tsaddr/tsaddr_test.go

@@ -5,6 +5,7 @@
 package tsaddr
 
 import (
+	"net/netip"
 	"testing"
 
 	"tailscale.com/net/netaddr"
@@ -52,30 +53,30 @@ func TestCGNATRange(t *testing.T) {
 }
 
 func TestNewContainsIPFunc(t *testing.T) {
-	f := NewContainsIPFunc([]netaddr.IPPrefix{netaddr.MustParseIPPrefix("10.0.0.0/8")})
-	if f(netaddr.MustParseIP("8.8.8.8")) {
+	f := NewContainsIPFunc([]netaddr.IPPrefix{netip.MustParsePrefix("10.0.0.0/8")})
+	if f(netip.MustParseAddr("8.8.8.8")) {
 		t.Fatal("bad")
 	}
-	if !f(netaddr.MustParseIP("10.1.2.3")) {
+	if !f(netip.MustParseAddr("10.1.2.3")) {
 		t.Fatal("bad")
 	}
-	f = NewContainsIPFunc([]netaddr.IPPrefix{netaddr.MustParseIPPrefix("10.1.2.3/32")})
-	if !f(netaddr.MustParseIP("10.1.2.3")) {
+	f = NewContainsIPFunc([]netaddr.IPPrefix{netip.MustParsePrefix("10.1.2.3/32")})
+	if !f(netip.MustParseAddr("10.1.2.3")) {
 		t.Fatal("bad")
 	}
 	f = NewContainsIPFunc([]netaddr.IPPrefix{
-		netaddr.MustParseIPPrefix("10.1.2.3/32"),
-		netaddr.MustParseIPPrefix("::2/128"),
+		netip.MustParsePrefix("10.1.2.3/32"),
+		netip.MustParsePrefix("::2/128"),
 	})
-	if !f(netaddr.MustParseIP("::2")) {
+	if !f(netip.MustParseAddr("::2")) {
 		t.Fatal("bad")
 	}
 	f = NewContainsIPFunc([]netaddr.IPPrefix{
-		netaddr.MustParseIPPrefix("10.1.2.3/32"),
-		netaddr.MustParseIPPrefix("10.1.2.4/32"),
-		netaddr.MustParseIPPrefix("::2/128"),
+		netip.MustParsePrefix("10.1.2.3/32"),
+		netip.MustParsePrefix("10.1.2.4/32"),
+		netip.MustParsePrefix("::2/128"),
 	})
-	if !f(netaddr.MustParseIP("10.1.2.4")) {
+	if !f(netip.MustParseAddr("10.1.2.4")) {
 		t.Fatal("bad")
 	}
 }
@@ -99,7 +100,7 @@ func TestUnmapVia(t *testing.T) {
 		{"fd7a:115c:a1e0:b1b::bb:10.2.1.4", "fd7a:115c:a1e0:b1b:0:bb:a02:104"}, // "b1b",not "bia"
 	}
 	for _, tt := range tests {
-		if got := UnmapVia(netaddr.MustParseIP(tt.ip)).String(); got != tt.want {
+		if got := UnmapVia(netip.MustParseAddr(tt.ip)).String(); got != tt.want {
 			t.Errorf("for %q: got %q, want %q", tt.ip, got, tt.want)
 		}
 	}

+ 3 - 2
net/tsdial/dnsmap.go

@@ -9,6 +9,7 @@ import (
 	"errors"
 	"fmt"
 	"net"
+	"net/netip"
 	"strconv"
 	"strings"
 
@@ -68,7 +69,7 @@ func dnsMapFromNetworkMap(nm *netmap.NetworkMap) dnsMap {
 		if rec.Type != "" {
 			continue
 		}
-		ip, err := netaddr.ParseIP(rec.Value)
+		ip, err := netip.ParseAddr(rec.Value)
 		if err != nil {
 			continue
 		}
@@ -103,7 +104,7 @@ func (m dnsMap) resolveMemory(ctx context.Context, network, addr string) (_ neta
 		// addr malformed or invalid port.
 		return netaddr.IPPort{}, err
 	}
-	if ip, err := netaddr.ParseIP(host); err == nil {
+	if ip, err := netip.ParseAddr(host); err == nil {
 		// addr was literal ip:port.
 		return netaddr.IPPortFrom(ip, port), nil
 	}

+ 3 - 2
net/tsdial/dnsmap_test.go

@@ -5,6 +5,7 @@
 package tsdial
 
 import (
+	"net/netip"
 	"reflect"
 	"testing"
 
@@ -14,8 +15,8 @@ import (
 )
 
 func TestDNSMapFromNetworkMap(t *testing.T) {
-	pfx := netaddr.MustParseIPPrefix
-	ip := netaddr.MustParseIP
+	pfx := netip.MustParsePrefix
+	ip := netip.MustParseAddr
 	tests := []struct {
 		name string
 		nm   *netmap.NetworkMap

+ 2 - 1
net/tsdial/tsdial.go

@@ -11,6 +11,7 @@ import (
 	"fmt"
 	"net"
 	"net/http"
+	"net/netip"
 	"runtime"
 	"strings"
 	"sync"
@@ -330,7 +331,7 @@ func (d *Dialer) dialPeerAPI(ctx context.Context, network, addr string) (net.Con
 	default:
 		return nil, fmt.Errorf("peerAPI dial requires tcp; %q not supported", network)
 	}
-	ipp, err := netaddr.ParseIPPort(addr)
+	ipp, err := netip.ParseAddrPort(addr)
 	if err != nil {
 		return nil, fmt.Errorf("peerAPI dial requires ip:port, not name resolution: %w", err)
 	}

+ 9 - 8
net/tstun/wrap_test.go

@@ -8,6 +8,7 @@ import (
 	"bytes"
 	"encoding/binary"
 	"fmt"
+	"net/netip"
 	"strconv"
 	"strings"
 	"testing"
@@ -28,11 +29,11 @@ import (
 )
 
 func udp4(src, dst string, sport, dport uint16) []byte {
-	sip, err := netaddr.ParseIP(src)
+	sip, err := netip.ParseAddr(src)
 	if err != nil {
 		panic(err)
 	}
-	dip, err := netaddr.ParseIP(dst)
+	dip, err := netip.ParseAddr(dst)
 	if err != nil {
 		panic(err)
 	}
@@ -49,11 +50,11 @@ func udp4(src, dst string, sport, dport uint16) []byte {
 }
 
 func tcp4syn(src, dst string, sport, dport uint16) []byte {
-	sip, err := netaddr.ParseIP(src)
+	sip, err := netip.ParseAddr(src)
 	if err != nil {
 		panic(err)
 	}
-	dip, err := netaddr.ParseIP(dst)
+	dip, err := netip.ParseAddr(dst)
 	if err != nil {
 		panic(err)
 	}
@@ -79,7 +80,7 @@ func tcp4syn(src, dst string, sport, dport uint16) []byte {
 func nets(nets ...string) (ret []netaddr.IPPrefix) {
 	for _, s := range nets {
 		if i := strings.IndexByte(s, '/'); i == -1 {
-			ip, err := netaddr.ParseIP(s)
+			ip, err := netip.ParseAddr(s)
 			if err != nil {
 				panic(err)
 			}
@@ -89,7 +90,7 @@ func nets(nets ...string) (ret []netaddr.IPPrefix) {
 			}
 			ret = append(ret, netaddr.IPPrefixFrom(ip, bits))
 		} else {
-			pfx, err := netaddr.ParseIPPrefix(s)
+			pfx, err := netip.ParsePrefix(s)
 			if err != nil {
 				panic(err)
 			}
@@ -150,7 +151,7 @@ func setfilter(logf logger.Logf, tun *Wrapper) {
 		{IPProto: protos, Srcs: nets("1.2.3.4"), Dsts: netports("5.6.7.8:98")},
 	}
 	var sb netipx.IPSetBuilder
-	sb.AddPrefix(netaddr.MustParseIPPrefix("1.2.0.0/16"))
+	sb.AddPrefix(netip.MustParsePrefix("1.2.0.0/16"))
 	ipSet, _ := sb.IPSet()
 	tun.SetFilter(filter.New(matches, ipSet, ipSet, nil, logf))
 }
@@ -428,7 +429,7 @@ func TestAtomic64Alignment(t *testing.T) {
 func TestPeerAPIBypass(t *testing.T) {
 	wrapperWithPeerAPI := &Wrapper{
 		PeerAPIPort: func(ip netaddr.IP) (port uint16, ok bool) {
-			if ip == netaddr.MustParseIP("100.64.1.2") {
+			if ip == netip.MustParseAddr("100.64.1.2") {
 				return 60000, true
 			}
 			return

+ 2 - 1
ssh/tailssh/tailssh.go

@@ -20,6 +20,7 @@ import (
 	"io/ioutil"
 	"net"
 	"net/http"
+	"net/netip"
 	"net/url"
 	"os"
 	"os/exec"
@@ -1227,7 +1228,7 @@ func (c *conn) principalMatchesTailscaleIdentity(p *tailcfg.SSHPrincipal) bool {
 		return true
 	}
 	if p.NodeIP != "" {
-		if ip, _ := netaddr.ParseIP(p.NodeIP); ip == ci.src.Addr() {
+		if ip, _ := netip.ParseAddr(p.NodeIP); ip == ci.src.Addr() {
 			return true
 		}
 	}

+ 4 - 4
ssh/tailssh/tailssh_test.go

@@ -16,6 +16,7 @@ import (
 	"net"
 	"net/http"
 	"net/http/httptest"
+	"net/netip"
 	"os"
 	"os/exec"
 	"os/user"
@@ -27,7 +28,6 @@ import (
 
 	"tailscale.com/ipn/ipnlocal"
 	"tailscale.com/ipn/store/mem"
-	"tailscale.com/net/netaddr"
 	"tailscale.com/net/tsdial"
 	"tailscale.com/tailcfg"
 	"tailscale.com/tempfork/gliderlabs/ssh"
@@ -153,7 +153,7 @@ func TestMatchRule(t *testing.T) {
 				Principals: []*tailcfg.SSHPrincipal{{NodeIP: "1.2.3.4"}},
 				SSHUsers:   map[string]string{"*": "ubuntu"},
 			},
-			ci:       &sshConnInfo{src: netaddr.MustParseIPPort("1.2.3.4:30343")},
+			ci:       &sshConnInfo{src: netip.MustParseAddrPort("1.2.3.4:30343")},
 			wantUser: "ubuntu",
 		},
 		{
@@ -246,8 +246,8 @@ func TestSSH(t *testing.T) {
 	sc.localUser = u
 	sc.info = &sshConnInfo{
 		sshUser: "test",
-		src:     netaddr.MustParseIPPort("1.2.3.4:32342"),
-		dst:     netaddr.MustParseIPPort("1.2.3.5:22"),
+		src:     netip.MustParseAddrPort("1.2.3.4:32342"),
+		dst:     netip.MustParseAddrPort("1.2.3.5:22"),
 		node:    &tailcfg.Node{},
 		uprof:   &tailcfg.UserProfile{},
 	}

+ 4 - 3
tailcfg/tailcfg_test.go

@@ -7,6 +7,7 @@ package tailcfg
 import (
 	"encoding"
 	"encoding/json"
+	"net/netip"
 	"reflect"
 	"strings"
 	"testing"
@@ -41,7 +42,7 @@ func TestHostinfoEqual(t *testing.T) {
 
 	nets := func(strs ...string) (ns []netaddr.IPPrefix) {
 		for _, s := range strs {
-			n, err := netaddr.ParseIPPrefix(s)
+			n, err := netip.ParsePrefix(s)
 			if err != nil {
 				panic(err)
 			}
@@ -224,12 +225,12 @@ func TestHostinfoHowEqual(t *testing.T) {
 			a: &Hostinfo{
 				IPNVersion:  "1",
 				ShieldsUp:   false,
-				RoutableIPs: []netaddr.IPPrefix{netaddr.MustParseIPPrefix("1.2.3.0/24")},
+				RoutableIPs: []netaddr.IPPrefix{netip.MustParsePrefix("1.2.3.0/24")},
 			},
 			b: &Hostinfo{
 				IPNVersion:  "2",
 				ShieldsUp:   true,
-				RoutableIPs: []netaddr.IPPrefix{netaddr.MustParseIPPrefix("1.2.3.0/25")},
+				RoutableIPs: []netaddr.IPPrefix{netip.MustParsePrefix("1.2.3.0/25")},
 			},
 			want: []string{"IPNVersion", "ShieldsUp", "RoutableIPs"},
 		},

+ 2 - 1
tstest/integration/integration_test.go

@@ -18,6 +18,7 @@ import (
 	"log"
 	"net/http"
 	"net/http/httptest"
+	"net/netip"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -830,7 +831,7 @@ func (n *testNode) AwaitIPs() []netaddr.IP {
 		addrs = make([]netaddr.IP, len(ipslice))
 
 		for i, ip := range ipslice {
-			netIP, err := netaddr.ParseIP(ip)
+			netIP, err := netip.ParseAddr(ip)
 			if err != nil {
 				t.Fatal(err)
 			}

+ 2 - 1
tstest/integration/testcontrol/testcontrol.go

@@ -19,6 +19,7 @@ import (
 	"math/rand"
 	"net/http"
 	"net/http/httptest"
+	"net/netip"
 	"net/url"
 	"sort"
 	"strings"
@@ -859,7 +860,7 @@ func filterInvalidIPv6Endpoints(eps []string) []string {
 }
 
 func keepClientEndpoint(ep string) bool {
-	ipp, err := netaddr.ParseIPPort(ep)
+	ipp, err := netip.ParseAddrPort(ep)
 	if err != nil {
 		// Shouldn't have made it this far if we unmarshalled
 		// the incoming JSON response.

+ 2 - 1
tstest/integration/vms/harness_test.go

@@ -14,6 +14,7 @@ import (
 	"log"
 	"net"
 	"net/http"
+	"net/netip"
 	"os"
 	"os/exec"
 	"path"
@@ -240,5 +241,5 @@ outer:
 }
 
 func bytes2Netaddr(inp []byte) netaddr.IP {
-	return netaddr.MustParseIP(string(bytes.TrimSpace(inp)))
+	return netip.MustParseAddr(string(bytes.TrimSpace(inp)))
 }

+ 2 - 1
tstest/integration/vms/vms_test.go

@@ -13,6 +13,7 @@ import (
 	"flag"
 	"fmt"
 	"net"
+	"net/netip"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -452,7 +453,7 @@ func (h *Harness) testDistro(t *testing.T, d Distro, ipm ipMapping) {
 				t.Fatalf("can't get IP: %v", err)
 			}
 
-			netaddr.MustParseIP(string(bytes.TrimSpace(ipBytes)))
+			netip.MustParseAddr(string(bytes.TrimSpace(ipBytes)))
 		})
 
 		t.Run("ping-"+tt.ipProto, func(t *testing.T) {

+ 3 - 3
tstest/natlab/natlab.go

@@ -81,7 +81,7 @@ func (p *Packet) setLocator(msg string, args ...any) {
 }
 
 func mustPrefix(s string) netaddr.IPPrefix {
-	ipp, err := netaddr.ParseIPPrefix(s)
+	ipp, err := netip.ParsePrefix(s)
 	if err != nil {
 		panic(err)
 	}
@@ -680,7 +680,7 @@ func (m *Machine) ListenPacket(ctx context.Context, network, address string) (ne
 		return nil, err
 	}
 	if host != "" {
-		ip, err = netaddr.ParseIP(host)
+		ip, err = netip.ParseAddr(host)
 		if err != nil {
 			return nil, err
 		}
@@ -841,7 +841,7 @@ func (c *conn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
 }
 
 func (c *conn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
-	ipp, err := netaddr.ParseIPPort(addr.String())
+	ipp, err := netip.ParseAddrPort(addr.String())
 	if err != nil {
 		return 0, fmt.Errorf("bogus addr %T %q", addr, addr.String())
 	}

+ 1 - 1
tstest/natlab/natlab_test.go

@@ -342,7 +342,7 @@ func testFirewall(t *testing.T, f *Firewall, tests []fwTest) {
 }
 
 func ipp(str string) netaddr.IPPort {
-	ipp, err := netaddr.ParseIPPort(str)
+	ipp, err := netip.ParseAddrPort(str)
 	if err != nil {
 		panic(err)
 	}

+ 2 - 2
tsweb/tsweb.go

@@ -17,6 +17,7 @@ import (
 	"net"
 	"net/http"
 	_ "net/http/pprof"
+	"net/netip"
 	"os"
 	"path/filepath"
 	"reflect"
@@ -29,7 +30,6 @@ import (
 	"go4.org/mem"
 	"tailscale.com/envknob"
 	"tailscale.com/metrics"
-	"tailscale.com/net/netaddr"
 	"tailscale.com/net/tsaddr"
 	"tailscale.com/types/logger"
 	"tailscale.com/version"
@@ -70,7 +70,7 @@ func AllowDebugAccess(r *http.Request) bool {
 	if err != nil {
 		return false
 	}
-	ip, err := netaddr.ParseIP(ipStr)
+	ip, err := netip.ParseAddr(ipStr)
 	if err != nil {
 		return false
 	}

+ 7 - 3
types/dnstype/dnstype.go

@@ -7,7 +7,11 @@ package dnstype
 
 //go:generate go run tailscale.com/cmd/cloner --type=Resolver --clonefunc=true
 
-import "tailscale.com/net/netaddr"
+import (
+	"net/netip"
+
+	"tailscale.com/net/netaddr"
+)
 
 // Resolver is the configuration for one DNS resolver.
 type Resolver struct {
@@ -37,10 +41,10 @@ func (r *Resolver) IPPort() (ipp netaddr.IPPort, ok bool) {
 		// cases.
 		return
 	}
-	if ip, err := netaddr.ParseIP(r.Addr); err == nil {
+	if ip, err := netip.ParseAddr(r.Addr); err == nil {
 		return netaddr.IPPortFrom(ip, 53), true
 	}
-	if ipp, err := netaddr.ParseIPPort(r.Addr); err == nil {
+	if ipp, err := netip.ParseAddrPort(r.Addr); err == nil {
 		return ipp, true
 	}
 	return

+ 2 - 1
types/views/views_test.go

@@ -7,6 +7,7 @@ package views
 import (
 	"bytes"
 	"encoding/json"
+	"net/netip"
 	"reflect"
 	"strings"
 	"testing"
@@ -18,7 +19,7 @@ import (
 func TestViewsJSON(t *testing.T) {
 	mustCIDR := func(cidrs ...string) (out []netaddr.IPPrefix) {
 		for _, cidr := range cidrs {
-			out = append(out, netaddr.MustParseIPPrefix(cidr))
+			out = append(out, netip.MustParsePrefix(cidr))
 		}
 		return
 	}

+ 17 - 16
util/deephash/deephash_test.go

@@ -13,6 +13,7 @@ import (
 	"io"
 	"math"
 	"math/rand"
+	"net/netip"
 	"reflect"
 	"runtime"
 	"testing"
@@ -199,24 +200,24 @@ func getVal() []any {
 		},
 		&router.Config{
 			Routes: []netaddr.IPPrefix{
-				netaddr.MustParseIPPrefix("1.2.3.0/24"),
-				netaddr.MustParseIPPrefix("1234::/64"),
+				netip.MustParsePrefix("1.2.3.0/24"),
+				netip.MustParsePrefix("1234::/64"),
 			},
 		},
 		map[dnsname.FQDN][]netaddr.IP{
-			dnsname.FQDN("a."): {netaddr.MustParseIP("1.2.3.4"), netaddr.MustParseIP("4.3.2.1")},
-			dnsname.FQDN("b."): {netaddr.MustParseIP("8.8.8.8"), netaddr.MustParseIP("9.9.9.9")},
-			dnsname.FQDN("c."): {netaddr.MustParseIP("6.6.6.6"), netaddr.MustParseIP("7.7.7.7")},
-			dnsname.FQDN("d."): {netaddr.MustParseIP("6.7.6.6"), netaddr.MustParseIP("7.7.7.8")},
-			dnsname.FQDN("e."): {netaddr.MustParseIP("6.8.6.6"), netaddr.MustParseIP("7.7.7.9")},
-			dnsname.FQDN("f."): {netaddr.MustParseIP("6.9.6.6"), netaddr.MustParseIP("7.7.7.0")},
+			dnsname.FQDN("a."): {netip.MustParseAddr("1.2.3.4"), netip.MustParseAddr("4.3.2.1")},
+			dnsname.FQDN("b."): {netip.MustParseAddr("8.8.8.8"), netip.MustParseAddr("9.9.9.9")},
+			dnsname.FQDN("c."): {netip.MustParseAddr("6.6.6.6"), netip.MustParseAddr("7.7.7.7")},
+			dnsname.FQDN("d."): {netip.MustParseAddr("6.7.6.6"), netip.MustParseAddr("7.7.7.8")},
+			dnsname.FQDN("e."): {netip.MustParseAddr("6.8.6.6"), netip.MustParseAddr("7.7.7.9")},
+			dnsname.FQDN("f."): {netip.MustParseAddr("6.9.6.6"), netip.MustParseAddr("7.7.7.0")},
 		},
 		map[dnsname.FQDN][]netaddr.IPPort{
-			dnsname.FQDN("a."): {netaddr.MustParseIPPort("1.2.3.4:11"), netaddr.MustParseIPPort("4.3.2.1:22")},
-			dnsname.FQDN("b."): {netaddr.MustParseIPPort("8.8.8.8:11"), netaddr.MustParseIPPort("9.9.9.9:22")},
-			dnsname.FQDN("c."): {netaddr.MustParseIPPort("8.8.8.8:12"), netaddr.MustParseIPPort("9.9.9.9:23")},
-			dnsname.FQDN("d."): {netaddr.MustParseIPPort("8.8.8.8:13"), netaddr.MustParseIPPort("9.9.9.9:24")},
-			dnsname.FQDN("e."): {netaddr.MustParseIPPort("8.8.8.8:14"), netaddr.MustParseIPPort("9.9.9.9:25")},
+			dnsname.FQDN("a."): {netip.MustParseAddrPort("1.2.3.4:11"), netip.MustParseAddrPort("4.3.2.1:22")},
+			dnsname.FQDN("b."): {netip.MustParseAddrPort("8.8.8.8:11"), netip.MustParseAddrPort("9.9.9.9:22")},
+			dnsname.FQDN("c."): {netip.MustParseAddrPort("8.8.8.8:12"), netip.MustParseAddrPort("9.9.9.9:23")},
+			dnsname.FQDN("d."): {netip.MustParseAddrPort("8.8.8.8:13"), netip.MustParseAddrPort("9.9.9.9:24")},
+			dnsname.FQDN("e."): {netip.MustParseAddrPort("8.8.8.8:14"), netip.MustParseAddrPort("9.9.9.9:25")},
 		},
 		map[key.DiscoPublic]bool{
 			key.DiscoPublicFromRaw32(mem.B([]byte{1: 1, 31: 0})): true,
@@ -405,7 +406,7 @@ func TestGetTypeHasher(t *testing.T) {
 	var (
 		someInt        = int('A')
 		someComplex128 = complex128(1 + 2i)
-		someIP         = netaddr.MustParseIP("1.2.3.4")
+		someIP         = netip.MustParseAddr("1.2.3.4")
 	)
 	tests := []struct {
 		name  string
@@ -497,7 +498,7 @@ func TestGetTypeHasher(t *testing.T) {
 		},
 		{
 			name: "netaddr.IP",
-			val:  netaddr.MustParseIP("fe80::123%foo"),
+			val:  netip.MustParseAddr("fe80::123%foo"),
 			out:  "\r\x00\x00\x00\x00\x00\x00\x00fe80::123%foo",
 		},
 		{
@@ -650,7 +651,7 @@ var filterRules = []tailcfg.FilterRule{
 		}},
 		IPProto: []int{1, 2, 3, 4},
 		CapGrant: []tailcfg.CapGrant{{
-			Dsts: []netaddr.IPPrefix{netaddr.MustParseIPPrefix("1.2.3.4/32")},
+			Dsts: []netaddr.IPPrefix{netip.MustParsePrefix("1.2.3.4/32")},
 			Caps: []string{"foo"},
 		}},
 	},

+ 5 - 4
wf/firewall.go

@@ -9,6 +9,7 @@ package wf
 
 import (
 	"fmt"
+	"net/netip"
 	"os"
 
 	"golang.org/x/sys/windows"
@@ -18,10 +19,10 @@ import (
 
 // Known addresses.
 var (
-	linkLocalRange           = netaddr.MustParseIPPrefix("ff80::/10")
-	linkLocalDHCPMulticast   = netaddr.MustParseIP("ff02::1:2")
-	siteLocalDHCPMulticast   = netaddr.MustParseIP("ff05::1:3")
-	linkLocalRouterMulticast = netaddr.MustParseIP("ff02::2")
+	linkLocalRange           = netip.MustParsePrefix("ff80::/10")
+	linkLocalDHCPMulticast   = netip.MustParseAddr("ff02::1:2")
+	siteLocalDHCPMulticast   = netip.MustParseAddr("ff05::1:3")
+	linkLocalRouterMulticast = netip.MustParseAddr("ff02::2")
 )
 
 type direction int

+ 3 - 3
wgengine/bench/bench.go

@@ -13,19 +13,19 @@ import (
 	"net"
 	"net/http"
 	"net/http/pprof"
+	"net/netip"
 	"os"
 	"strconv"
 	"time"
 
-	"tailscale.com/net/netaddr"
 	"tailscale.com/types/logger"
 )
 
 const PayloadSize = 1000
 const ICMPMinSize = 24
 
-var Addr1 = netaddr.MustParseIPPrefix("100.64.1.1/32")
-var Addr2 = netaddr.MustParseIPPrefix("100.64.1.2/32")
+var Addr1 = netip.MustParsePrefix("100.64.1.1/32")
+var Addr2 = netip.MustParsePrefix("100.64.1.2/32")
 
 func main() {
 	var logf logger.Logf = log.Printf

+ 20 - 19
wgengine/filter/filter_test.go

@@ -7,6 +7,7 @@ package filter
 import (
 	"encoding/hex"
 	"fmt"
+	"net/netip"
 	"reflect"
 	"strconv"
 	"strings"
@@ -439,16 +440,16 @@ func TestLoggingPrivacy(t *testing.T) {
 	}
 
 	var logB netipx.IPSetBuilder
-	logB.AddPrefix(netaddr.MustParseIPPrefix("100.64.0.0/10"))
+	logB.AddPrefix(netip.MustParsePrefix("100.64.0.0/10"))
 	logB.AddPrefix(tsaddr.TailscaleULARange())
 	f := newFilter(logf)
 	f.logIPs, _ = logB.IPSet()
 
 	var (
 		ts4       = netaddr.IPPortFrom(tsaddr.CGNATRange().Addr().Next(), 1234)
-		internet4 = netaddr.IPPortFrom(netaddr.MustParseIP("8.8.8.8"), 1234)
+		internet4 = netaddr.IPPortFrom(netip.MustParseAddr("8.8.8.8"), 1234)
 		ts6       = netaddr.IPPortFrom(tsaddr.TailscaleULARange().Addr().Next(), 1234)
-		internet6 = netaddr.IPPortFrom(netaddr.MustParseIP("2001::1"), 1234)
+		internet6 = netaddr.IPPortFrom(netip.MustParseAddr("2001::1"), 1234)
 	)
 
 	tests := []struct {
@@ -551,7 +552,7 @@ func TestLoggingPrivacy(t *testing.T) {
 	}
 }
 
-var mustIP = netaddr.MustParseIP
+var mustIP = netip.MustParseAddr
 
 func parsed(proto ipproto.Proto, src, dst string, sport, dport uint16) packet.Parsed {
 	sip, dip := mustIP(src), mustIP(dst)
@@ -657,7 +658,7 @@ func parseHexPkt(t *testing.T, h string) *packet.Parsed {
 }
 
 func mustIPPort(s string) netaddr.IPPort {
-	ipp, err := netaddr.ParseIPPort(s)
+	ipp, err := netip.ParseAddrPort(s)
 	if err != nil {
 		panic(err)
 	}
@@ -666,7 +667,7 @@ func mustIPPort(s string) netaddr.IPPort {
 
 func pfx(strs ...string) (ret []netaddr.IPPrefix) {
 	for _, s := range strs {
-		pfx, err := netaddr.ParseIPPrefix(s)
+		pfx, err := netip.ParsePrefix(s)
 		if err != nil {
 			panic(err)
 		}
@@ -678,7 +679,7 @@ func pfx(strs ...string) (ret []netaddr.IPPrefix) {
 func nets(nets ...string) (ret []netaddr.IPPrefix) {
 	for _, s := range nets {
 		if !strings.Contains(s, "/") {
-			ip, err := netaddr.ParseIP(s)
+			ip, err := netip.ParseAddr(s)
 			if err != nil {
 				panic(err)
 			}
@@ -688,7 +689,7 @@ func nets(nets ...string) (ret []netaddr.IPPrefix) {
 			}
 			ret = append(ret, netaddr.IPPrefixFrom(ip, bits))
 		} else {
-			pfx, err := netaddr.ParseIPPrefix(s)
+			pfx, err := netip.ParsePrefix(s)
 			if err != nil {
 				panic(err)
 			}
@@ -770,16 +771,16 @@ func TestMatchesFromFilterRules(t *testing.T) {
 					},
 					Dsts: []NetPortRange{
 						{
-							Net:   netaddr.MustParseIPPrefix("0.0.0.0/0"),
+							Net:   netip.MustParsePrefix("0.0.0.0/0"),
 							Ports: PortRange{22, 22},
 						},
 						{
-							Net:   netaddr.MustParseIPPrefix("::0/0"),
+							Net:   netip.MustParsePrefix("::0/0"),
 							Ports: PortRange{22, 22},
 						},
 					},
 					Srcs: []netaddr.IPPrefix{
-						netaddr.MustParseIPPrefix("100.64.1.1/32"),
+						netip.MustParsePrefix("100.64.1.1/32"),
 					},
 					Caps: []CapMatch{},
 				},
@@ -804,12 +805,12 @@ func TestMatchesFromFilterRules(t *testing.T) {
 					},
 					Dsts: []NetPortRange{
 						{
-							Net:   netaddr.MustParseIPPrefix("1.2.0.0/16"),
+							Net:   netip.MustParsePrefix("1.2.0.0/16"),
 							Ports: PortRange{22, 22},
 						},
 					},
 					Srcs: []netaddr.IPPrefix{
-						netaddr.MustParseIPPrefix("100.64.1.1/32"),
+						netip.MustParsePrefix("100.64.1.1/32"),
 					},
 					Caps: []CapMatch{},
 				},
@@ -834,8 +835,8 @@ func TestMatchesFromFilterRules(t *testing.T) {
 
 func TestNewAllowAllForTest(t *testing.T) {
 	f := NewAllowAllForTest(logger.Discard)
-	src := netaddr.MustParseIP("100.100.2.3")
-	dst := netaddr.MustParseIP("100.100.1.2")
+	src := netip.MustParseAddr("100.100.2.3")
+	dst := netip.MustParseAddr("100.100.1.2")
 	res := f.CheckTCP(src, dst, 80)
 	if res.IsDrop() {
 		t.Fatalf("unexpected drop verdict: %v", res)
@@ -885,7 +886,7 @@ func TestCaps(t *testing.T) {
 			SrcIPs: []string{"*"},
 			CapGrant: []tailcfg.CapGrant{{
 				Dsts: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("0.0.0.0/0"),
+					netip.MustParsePrefix("0.0.0.0/0"),
 				},
 				Caps: []string{"is_ipv4"},
 			}},
@@ -894,7 +895,7 @@ func TestCaps(t *testing.T) {
 			SrcIPs: []string{"*"},
 			CapGrant: []tailcfg.CapGrant{{
 				Dsts: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("::/0"),
+					netip.MustParsePrefix("::/0"),
 				},
 				Caps: []string{"is_ipv6"},
 			}},
@@ -903,7 +904,7 @@ func TestCaps(t *testing.T) {
 			SrcIPs: []string{"100.199.0.0/16"},
 			CapGrant: []tailcfg.CapGrant{{
 				Dsts: []netaddr.IPPrefix{
-					netaddr.MustParseIPPrefix("100.200.0.0/16"),
+					netip.MustParsePrefix("100.200.0.0/16"),
 				},
 				Caps: []string{"some_super_admin"},
 			}},
@@ -951,7 +952,7 @@ func TestCaps(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			got := filt.AppendCaps(nil, netaddr.MustParseIP(tt.src), netaddr.MustParseIP(tt.dst))
+			got := filt.AppendCaps(nil, netip.MustParseAddr(tt.src), netip.MustParseAddr(tt.dst))
 			if !reflect.DeepEqual(got, tt.want) {
 				t.Errorf("got %q; want %q", got, tt.want)
 			}

+ 5 - 4
wgengine/filter/tailcfg.go

@@ -6,6 +6,7 @@ package filter
 
 import (
 	"fmt"
+	"net/netip"
 	"strings"
 
 	"go4.org/netipx"
@@ -122,7 +123,7 @@ func parseIPSet(arg string, bits *int) ([]netaddr.IPPrefix, error) {
 		}, nil
 	}
 	if strings.Contains(arg, "/") {
-		pfx, err := netaddr.ParseIPPrefix(arg)
+		pfx, err := netip.ParsePrefix(arg)
 		if err != nil {
 			return nil, err
 		}
@@ -133,11 +134,11 @@ func parseIPSet(arg string, bits *int) ([]netaddr.IPPrefix, error) {
 	}
 	if strings.Count(arg, "-") == 1 {
 		ip1s, ip2s, _ := strings.Cut(arg, "-")
-		ip1, err := netaddr.ParseIP(ip1s)
+		ip1, err := netip.ParseAddr(ip1s)
 		if err != nil {
 			return nil, err
 		}
-		ip2, err := netaddr.ParseIP(ip2s)
+		ip2, err := netip.ParseAddr(ip2s)
 		if err != nil {
 			return nil, err
 		}
@@ -147,7 +148,7 @@ func parseIPSet(arg string, bits *int) ([]netaddr.IPPrefix, error) {
 		}
 		return r.Prefixes(), nil
 	}
-	ip, err := netaddr.ParseIP(arg)
+	ip, err := netip.ParseAddr(arg)
 	if err != nil {
 		return nil, fmt.Errorf("invalid IP address %q", arg)
 	}

+ 6 - 6
wgengine/magicsock/magicsock.go

@@ -441,7 +441,7 @@ func (c *Conn) addDerpPeerRoute(peer key.NodePublic, derpID int, dc *derphttp.Cl
 	mak.Set(&c.derpRoute, peer, derpRoute{derpID, dc})
 }
 
-var derpMagicIPAddr = netaddr.MustParseIP(tailcfg.DerpMagicIP)
+var derpMagicIPAddr = netip.MustParseAddr(tailcfg.DerpMagicIP)
 
 // activeDerp contains fields for an active DERP connection.
 type activeDerp struct {
@@ -1034,7 +1034,7 @@ func (c *Conn) determineEndpoints(ctx context.Context) ([]tailcfg.Endpoint, erro
 		// back.
 		return []tailcfg.Endpoint{
 			{
-				Addr: netaddr.MustParseIPPort("[fe80:123:456:789::1]:12345"),
+				Addr: netip.MustParseAddrPort("[fe80:123:456:789::1]:12345"),
 				Type: tailcfg.EndpointLocal,
 			},
 		}, nil
@@ -1044,7 +1044,7 @@ func (c *Conn) determineEndpoints(ctx context.Context) ([]tailcfg.Endpoint, erro
 	var eps []tailcfg.Endpoint                          // unique endpoints
 
 	ipp := func(s string) (ipp netaddr.IPPort) {
-		ipp, _ = netaddr.ParseIPPort(s)
+		ipp, _ = netip.ParseAddrPort(s)
 		return
 	}
 	addAddr := func(ipp netaddr.IPPort, et tailcfg.EndpointType) {
@@ -2359,7 +2359,7 @@ func (c *Conn) SetNetworkMap(nm *netmap.NetworkMap) {
 			c.logf("magicsock: created endpoint key=%s: disco=%s; %v", n.Key.ShortString(), n.DiscoKey.ShortString(), logger.ArgWriter(func(w *bufio.Writer) {
 				const derpPrefix = "127.3.3.40:"
 				if strings.HasPrefix(n.DERP, derpPrefix) {
-					ipp, _ := netaddr.ParseIPPort(n.DERP)
+					ipp, _ := netip.ParseAddrPort(n.DERP)
 					regionID := int(ipp.Port())
 					code := c.derpRegionCodeLocked(regionID)
 					if code != "" {
@@ -3751,7 +3751,7 @@ func (de *endpoint) updateFromNode(n *tailcfg.Node) {
 	if n.DERP == "" {
 		de.derpAddr = netaddr.IPPort{}
 	} else {
-		de.derpAddr, _ = netaddr.ParseIPPort(n.DERP)
+		de.derpAddr, _ = netip.ParseAddrPort(n.DERP)
 	}
 
 	for _, st := range de.endpointState {
@@ -3762,7 +3762,7 @@ func (de *endpoint) updateFromNode(n *tailcfg.Node) {
 			// Seems unlikely.
 			continue
 		}
-		ipp, err := netaddr.ParseIPPort(epStr)
+		ipp, err := netip.ParseAddrPort(epStr)
 		if err != nil {
 			de.c.logf("magicsock: bogus netmap endpoint %q", epStr)
 			continue

+ 8 - 8
wgengine/magicsock/magicsock_test.go

@@ -787,11 +787,11 @@ func TestActiveDiscovery(t *testing.T) {
 		inet := natlab.NewInternet()
 		lan1 := &natlab.Network{
 			Name:    "lan1",
-			Prefix4: netaddr.MustParseIPPrefix("192.168.0.0/24"),
+			Prefix4: netip.MustParsePrefix("192.168.0.0/24"),
 		}
 		lan2 := &natlab.Network{
 			Name:    "lan2",
-			Prefix4: netaddr.MustParseIPPrefix("192.168.1.0/24"),
+			Prefix4: netip.MustParsePrefix("192.168.1.0/24"),
 		}
 
 		sif := mstun.Attach("eth0", inet)
@@ -1010,24 +1010,24 @@ func testTwoDevicePing(t *testing.T, d *devices) {
 	m1cfg := &wgcfg.Config{
 		Name:       "peer1",
 		PrivateKey: m1.privateKey,
-		Addresses:  []netaddr.IPPrefix{netaddr.MustParseIPPrefix("1.0.0.1/32")},
+		Addresses:  []netaddr.IPPrefix{netip.MustParsePrefix("1.0.0.1/32")},
 		Peers: []wgcfg.Peer{
 			{
 				PublicKey:  m2.privateKey.Public(),
 				DiscoKey:   m2.conn.DiscoPublicKey(),
-				AllowedIPs: []netaddr.IPPrefix{netaddr.MustParseIPPrefix("1.0.0.2/32")},
+				AllowedIPs: []netaddr.IPPrefix{netip.MustParsePrefix("1.0.0.2/32")},
 			},
 		},
 	}
 	m2cfg := &wgcfg.Config{
 		Name:       "peer2",
 		PrivateKey: m2.privateKey,
-		Addresses:  []netaddr.IPPrefix{netaddr.MustParseIPPrefix("1.0.0.2/32")},
+		Addresses:  []netaddr.IPPrefix{netip.MustParsePrefix("1.0.0.2/32")},
 		Peers: []wgcfg.Peer{
 			{
 				PublicKey:  m1.privateKey.Public(),
 				DiscoKey:   m1.conn.DiscoPublicKey(),
-				AllowedIPs: []netaddr.IPPrefix{netaddr.MustParseIPPrefix("1.0.0.1/32")},
+				AllowedIPs: []netaddr.IPPrefix{netip.MustParsePrefix("1.0.0.1/32")},
 			},
 		},
 	}
@@ -1247,7 +1247,7 @@ func addTestEndpoint(tb testing.TB, conn *Conn, sendConn net.PacketConn) (key.No
 	if err != nil {
 		tb.Fatal(err)
 	}
-	conn.addValidDiscoPathForTest(nodeKey, netaddr.MustParseIPPort(sendConn.LocalAddr().String()))
+	conn.addValidDiscoPathForTest(nodeKey, netip.MustParseAddrPort(sendConn.LocalAddr().String()))
 	return nodeKey, discoKey
 }
 
@@ -1597,7 +1597,7 @@ func TestEndpointSetsEqual(t *testing.T) {
 func TestBetterAddr(t *testing.T) {
 	const ms = time.Millisecond
 	al := func(ipps string, d time.Duration) addrLatency {
-		return addrLatency{netaddr.MustParseIPPort(ipps), d}
+		return addrLatency{netip.MustParseAddrPort(ipps), d}
 	}
 	zero := addrLatency{}
 	tests := []struct {

+ 1 - 1
wgengine/router/ifconfig_windows.go

@@ -29,7 +29,7 @@ import (
 	"tailscale.com/wgengine/winnet"
 )
 
-var wintunLinkLocal = netaddr.MustParseIP("fe80::99d0:ec2d:b2e7:536b")
+var wintunLinkLocal = netip.MustParseAddr("fe80::99d0:ec2d:b2e7:536b")
 
 // monitorDefaultRoutes subscribes to route change events and updates
 // the Tailscale tunnel interface's MTU to match that of the

+ 2 - 2
wgengine/router/ifconfig_windows_test.go

@@ -8,12 +8,12 @@ import (
 	"fmt"
 	"math/rand"
 	"net"
+	"net/netip"
 	"strings"
 	"testing"
 
 	"go4.org/netipx"
 	"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
-	"tailscale.com/net/netaddr"
 )
 
 func randIP() net.IP {
@@ -35,7 +35,7 @@ func randRouteData() *winipcfg.RouteData {
 func TestRouteLess(t *testing.T) {
 	type D = winipcfg.RouteData
 	ipnet := func(s string) net.IPNet {
-		ipp, err := netaddr.ParseIPPrefix(s)
+		ipp, err := netip.ParsePrefix(s)
 		if err != nil {
 			t.Fatalf("error parsing test data %q: %v", s, err)
 		}

+ 2 - 2
wgengine/router/router_linux_test.go

@@ -8,6 +8,7 @@ import (
 	"errors"
 	"fmt"
 	"math/rand"
+	"net/netip"
 	"os"
 	"sort"
 	"strings"
@@ -17,7 +18,6 @@ import (
 	"github.com/google/go-cmp/cmp"
 	"github.com/vishvananda/netlink"
 	"golang.zx2c4.com/wireguard/tun"
-	"tailscale.com/net/netaddr"
 	"tailscale.com/tstest"
 	"tailscale.com/types/logger"
 	"tailscale.com/wgengine/monitor"
@@ -711,7 +711,7 @@ func TestDelRouteIdempotent(t *testing.T) {
 		"192.0.2.0/24",  // RFC 5737
 		"2001:DB8::/32", // RFC 3849
 	} {
-		cidr := netaddr.MustParseIPPrefix(s)
+		cidr := netip.MustParsePrefix(s)
 		if err := lt.r.addRoute(cidr); err != nil {
 			t.Error(err)
 			continue

+ 3 - 2
wgengine/router/router_test.go

@@ -5,6 +5,7 @@
 package router
 
 import (
+	"net/netip"
 	"reflect"
 	"testing"
 
@@ -15,7 +16,7 @@ import (
 func mustCIDRs(ss ...string) []netaddr.IPPrefix {
 	var ret []netaddr.IPPrefix
 	for _, s := range ss {
-		ret = append(ret, netaddr.MustParseIPPrefix(s))
+		ret = append(ret, netip.MustParsePrefix(s))
 	}
 	return ret
 }
@@ -37,7 +38,7 @@ func TestConfigEqual(t *testing.T) {
 
 	nets := func(strs ...string) (ns []netaddr.IPPrefix) {
 		for _, s := range strs {
-			n, err := netaddr.ParseIPPrefix(s)
+			n, err := netip.ParsePrefix(s)
 			if err != nil {
 				panic(err)
 			}

+ 2 - 2
wgengine/userspace.go

@@ -1589,9 +1589,9 @@ func dnsIPsOverTailscale(dnsCfg *dns.Config, routerCfg *router.Config) (ret []ne
 
 	add := func(resolvers []*dnstype.Resolver) {
 		for _, r := range resolvers {
-			ip, err := netaddr.ParseIP(r.Addr)
+			ip, err := netip.ParseAddr(r.Addr)
 			if err != nil {
-				if ipp, err := netaddr.ParseIPPort(r.Addr); err == nil {
+				if ipp, err := netip.ParseAddrPort(r.Addr); err == nil {
 					ip = ipp.Addr()
 				} else {
 					continue

+ 4 - 3
wgengine/userspace_test.go

@@ -6,6 +6,7 @@ package wgengine
 
 import (
 	"fmt"
+	"net/netip"
 	"reflect"
 	"testing"
 
@@ -223,9 +224,9 @@ func nkFromHex(hex string) key.NodePublic {
 // an experiment to see if genLocalAddrFunc was worth it. As of Go
 // 1.16, it still very much is. (30-40x faster)
 func BenchmarkGenLocalAddrFunc(b *testing.B) {
-	la1 := netaddr.MustParseIP("1.2.3.4")
-	la2 := netaddr.MustParseIP("::4")
-	lanot := netaddr.MustParseIP("5.5.5.5")
+	la1 := netip.MustParseAddr("1.2.3.4")
+	la2 := netip.MustParseAddr("::4")
+	lanot := netip.MustParseAddr("5.5.5.5")
 	var x bool
 	b.Run("map1", func(b *testing.B) {
 		b.ReportAllocs()

+ 3 - 3
wgengine/wgcfg/device_test.go

@@ -30,13 +30,13 @@ func TestDeviceConfig(t *testing.T) {
 		return k.Public(), k
 	}
 	k1, pk1 := newK()
-	ip1 := netaddr.MustParseIPPrefix("10.0.0.1/32")
+	ip1 := netip.MustParsePrefix("10.0.0.1/32")
 
 	k2, pk2 := newK()
-	ip2 := netaddr.MustParseIPPrefix("10.0.0.2/32")
+	ip2 := netip.MustParsePrefix("10.0.0.2/32")
 
 	k3, _ := newK()
-	ip3 := netaddr.MustParseIPPrefix("10.0.0.3/32")
+	ip3 := netip.MustParsePrefix("10.0.0.3/32")
 
 	cfg1 := &Config{
 		PrivateKey: pk1,

+ 2 - 1
wgengine/wgcfg/parser_test.go

@@ -8,6 +8,7 @@ import (
 	"bufio"
 	"bytes"
 	"io"
+	"net/netip"
 	"reflect"
 	"runtime"
 	"testing"
@@ -67,7 +68,7 @@ func BenchmarkFromUAPI(b *testing.B) {
 		return k.Public(), k
 	}
 	k1, pk1 := newK()
-	ip1 := netaddr.MustParseIPPrefix("10.0.0.1/32")
+	ip1 := netip.MustParsePrefix("10.0.0.1/32")
 
 	peer := Peer{
 		PublicKey:  k1,