all: convert more code to use net/netip directly

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

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

Updates #5162

Change-Id: Ia7a86893fe21c7e3ee1ec823e8aba288d4566cd8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/5177/head
Brad Fitzpatrick 2 years ago committed by Brad Fitzpatrick
parent 6a396731eb
commit a12aad6b47

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

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

@ -13,15 +13,14 @@ import (
"encoding/json"
"fmt"
"net/http"
"tailscale.com/net/netaddr"
"net/netip"
)
// Routes contains the lists of subnet routes that are currently advertised by a device,
// as well as the subnets that are enabled to be routed by the device.
type Routes struct {
AdvertisedRoutes []netaddr.IPPrefix `json:"advertisedRoutes"`
EnabledRoutes []netaddr.IPPrefix `json:"enabledRoutes"`
AdvertisedRoutes []netip.Prefix `json:"advertisedRoutes"`
EnabledRoutes []netip.Prefix `json:"enabledRoutes"`
}
// Routes retrieves the list of subnet routes that have been enabled for a device.
@ -56,14 +55,14 @@ func (c *Client) Routes(ctx context.Context, deviceID string) (routes *Routes, e
}
type postRoutesParams struct {
Routes []netaddr.IPPrefix `json:"routes"`
Routes []netip.Prefix `json:"routes"`
}
// SetRoutes updates the list of subnets that are enabled for a device.
// 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) {
func (c *Client) SetRoutes(ctx context.Context, deviceID string, subnets []netip.Prefix) (routes *Routes, err error) {
defer func() {
if err != nil {
err = fmt.Errorf("tailscale.SetRoutes: %w", err)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -7,8 +7,6 @@ package publicdns
import (
"net/netip"
"testing"
"tailscale.com/net/netaddr"
)
func TestInit(t *testing.T) {
@ -24,12 +22,12 @@ func TestInit(t *testing.T) {
func TestDohV6(t *testing.T) {
tests := []struct {
in string
firstIP netaddr.IP
firstIP netip.Addr
want bool
}{
{"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},
{"bogus", netip.Addr{}, false},
}
for _, test := range tests {
t.Run(test.in, func(t *testing.T) {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading…
Cancel
Save