net/netaddr: start migrating to net/netip via new netaddr adapter package

Updates #5162

Change-Id: Id7bdec303b25471f69d542f8ce43805328d56c12
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/5173/head
Brad Fitzpatrick 2 years ago committed by Brad Fitzpatrick
parent 7b1a91dfd3
commit 7eaf5e509f

@ -14,7 +14,7 @@ import (
"fmt"
"net/http"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
)
// ACLRow defines a rule that grants access by a set of users or groups to a set

@ -28,10 +28,10 @@ import (
"time"
"go4.org/mem"
"inet.af/netaddr"
"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"

@ -14,7 +14,7 @@ import (
"fmt"
"net/http"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
)
// Routes contains the lists of subnet routes that are currently advertised by a device,
@ -60,7 +60,7 @@ type postRoutesParams struct {
}
// SetRoutes updates the list of subnets that are enabled for a device.
// Subnets must be parsable by inet.af/netaddr.ParseIPPrefix.
// Subnets must be parsable by tailscale.com/net/netaddr.ParseIPPrefix.
// 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) {

@ -135,13 +135,13 @@ func tailscaleIP(who *apitype.WhoIsResponse) string {
return ""
}
for _, nodeIP := range who.Node.Addresses {
if nodeIP.IP().Is4() && nodeIP.IsSingleIP() {
return nodeIP.IP().String()
if nodeIP.Addr().Is4() && nodeIP.IsSingleIP() {
return nodeIP.Addr().String()
}
}
for _, nodeIP := range who.Node.Addresses {
if nodeIP.IsSingleIP() {
return nodeIP.IP().String()
return nodeIP.Addr().String()
}
}
return ""

@ -15,9 +15,9 @@ import (
qt "github.com/frankban/quicktest"
"github.com/google/go-cmp/cmp"
"inet.af/netaddr"
"tailscale.com/ipn"
"tailscale.com/ipn/ipnstate"
"tailscale.com/net/netaddr"
"tailscale.com/tstest"
"tailscale.com/types/persist"
"tailscale.com/types/preftype"

@ -17,6 +17,7 @@ import (
"log"
"net"
"net/http"
"net/netip"
"os"
"runtime"
"strconv"
@ -24,10 +25,10 @@ import (
"time"
"github.com/peterbourgon/ff/v3/ffcli"
"inet.af/netaddr"
"tailscale.com/control/controlhttp"
"tailscale.com/hostinfo"
"tailscale.com/ipn"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsaddr"
"tailscale.com/paths"
"tailscale.com/safesocket"
@ -408,19 +409,19 @@ func runVia(ctx context.Context, args []string) error {
if err != nil {
return err
}
if !ipp.IP().Is6() {
if !ipp.Addr().Is6() {
return errors.New("with one argument, expect an IPv6 CIDR")
}
if !tsaddr.TailscaleViaRange().Contains(ipp.IP()) {
if !tsaddr.TailscaleViaRange().Contains(ipp.Addr()) {
return errors.New("not a via route")
}
if ipp.Bits() < 96 {
return errors.New("short length, want /96 or more")
}
v4 := tsaddr.UnmapVia(ipp.IP())
a := ipp.IP().As16()
v4 := tsaddr.UnmapVia(ipp.Addr())
a := ipp.Addr().As16()
siteID := binary.BigEndian.Uint32(a[8:12])
fmt.Printf("site %v (0x%x), %v\n", siteID, siteID, netaddr.IPPrefixFrom(v4, ipp.Bits()-96))
fmt.Printf("site %v (0x%x), %v\n", siteID, siteID, netip.PrefixFrom(v4, ipp.Bits()-96))
case 2:
siteID, err := strconv.ParseUint(args[0], 0, 32)
if err != nil {

@ -23,10 +23,10 @@ import (
"github.com/peterbourgon/ff/v3/ffcli"
"golang.org/x/time/rate"
"inet.af/netaddr"
"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"
@ -179,7 +179,7 @@ func getTargetStableID(ctx context.Context, ipStr string) (id tailcfg.StableNode
for _, ft := range fts {
n := ft.Node
for _, a := range n.Addresses {
if a.IP() != ip {
if a.Addr() != ip {
continue
}
isOffline = n.Online != nil && !*n.Online
@ -281,7 +281,7 @@ func runCpTargets(ctx context.Context, args []string) error {
if detail != "" {
detail = "\t" + detail
}
printf("%s\t%s%s\n", n.Addresses[0].IP(), n.ComputedName, detail)
printf("%s\t%s%s\n", n.Addresses[0].Addr(), n.ComputedName, detail)
}
return nil
}

@ -11,8 +11,8 @@ import (
"fmt"
"github.com/peterbourgon/ff/v3/ffcli"
"inet.af/netaddr"
"tailscale.com/ipn/ipnstate"
"tailscale.com/net/netaddr"
)
var ipCmd = &ffcli.Command{

@ -16,8 +16,8 @@ import (
"time"
"github.com/peterbourgon/ff/v3/ffcli"
"inet.af/netaddr"
"tailscale.com/ipn/ipnstate"
"tailscale.com/net/netaddr"
"tailscale.com/tailcfg"
)

@ -17,9 +17,9 @@ import (
"strings"
"github.com/peterbourgon/ff/v3/ffcli"
"inet.af/netaddr"
"tailscale.com/envknob"
"tailscale.com/ipn/ipnstate"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsaddr"
"tailscale.com/version"
)
@ -166,7 +166,7 @@ func nodeDNSNameFromArg(st *ipnstate.Status, arg string) (dnsName string, ok boo
argIP, _ := netaddr.ParseIP(arg)
for _, ps := range st.Peer {
dnsName = ps.DNSName
if !argIP.IsZero() {
if argIP.IsValid() {
for _, ip := range ps.TailscaleIPs {
if ip == argIP {
return dnsName, true

@ -18,10 +18,10 @@ import (
"github.com/peterbourgon/ff/v3/ffcli"
"github.com/toqueteos/webbrowser"
"inet.af/netaddr"
"tailscale.com/ipn"
"tailscale.com/ipn/ipnstate"
"tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
"tailscale.com/util/dnsname"
)

@ -24,9 +24,9 @@ import (
shellquote "github.com/kballard/go-shellquote"
"github.com/peterbourgon/ff/v3/ffcli"
qrcode "github.com/skip2/go-qrcode"
"inet.af/netaddr"
"tailscale.com/ipn"
"tailscale.com/ipn/ipnstate"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsaddr"
"tailscale.com/safesocket"
"tailscale.com/tailcfg"
@ -210,7 +210,7 @@ func validateViaPrefix(ipp netaddr.IPPrefix) error {
if ipp.Bits() < (128 - 32) {
return fmt.Errorf("%v 4-in-6 prefix must be at least a /%v", ipp, 128-32)
}
a := ipp.IP().As16()
a := ipp.Addr().As16()
// The first 64 bits of a are the via prefix.
// The next 32 bits are the "site ID".
// The last 32 bits are the IPv4.
@ -266,7 +266,7 @@ func calcAdvertiseRoutes(advertiseRoutes string, advertiseDefaultRoute bool) ([]
if routes[i].Bits() != routes[j].Bits() {
return routes[i].Bits() < routes[j].Bits()
}
return routes[i].IP().Less(routes[j].IP())
return routes[i].Addr().Less(routes[j].Addr())
})
return routes, nil
}
@ -913,10 +913,10 @@ func prefsToFlags(env upCheckEnv, prefs *ipn.Prefs) (flagVal map[string]any) {
ret := make(map[string]any)
exitNodeIPStr := func() string {
if !prefs.ExitNodeIP.IsZero() {
if prefs.ExitNodeIP.IsValid() {
return prefs.ExitNodeIP.String()
}
if prefs.ExitNodeID.IsZero() || env.curExitNodeIP.IsZero() {
if prefs.ExitNodeID.IsZero() || !env.curExitNodeIP.IsValid() {
return ""
}
return env.curExitNodeIP.String()
@ -995,9 +995,9 @@ func hasExitNodeRoutes(rr []netaddr.IPPrefix) bool {
var v4, v6 bool
for _, r := range rr {
if r.Bits() == 0 {
if r.IP().Is4() {
if r.Addr().Is4() {
v4 = true
} else if r.IP().Is6() {
} else if r.Addr().Is6() {
v6 = true
}
}
@ -1027,7 +1027,7 @@ func exitNodeIP(p *ipn.Prefs, st *ipnstate.Status) (ip netaddr.IP) {
if p == nil {
return
}
if !p.ExitNodeIP.IsZero() {
if p.ExitNodeIP.IsValid() {
return p.ExitNodeIP
}
id := p.ExitNodeID

@ -27,8 +27,8 @@ import (
"strings"
"github.com/peterbourgon/ff/v3/ffcli"
"inet.af/netaddr"
"tailscale.com/ipn"
"tailscale.com/net/netaddr"
"tailscale.com/tailcfg"
"tailscale.com/types/preftype"
"tailscale.com/util/groupmember"

@ -26,11 +26,9 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
github.com/tailscale/goupnp/ssdp from github.com/tailscale/goupnp
github.com/tcnksm/go-httpstat from tailscale.com/net/netcheck
github.com/toqueteos/webbrowser from tailscale.com/cmd/tailscale/cli
💣 go4.org/intern from inet.af/netaddr
💣 go4.org/mem from tailscale.com/derp+
go4.org/unsafe/assume-no-moving-gc from go4.org/intern
go4.org/netipx from tailscale.com/wgengine/filter
W 💣 golang.zx2c4.com/wireguard/windows/tunnel/winipcfg from tailscale.com/net/interfaces+
inet.af/netaddr from tailscale.com/cmd/tailscale/cli+
nhooyr.io/websocket from tailscale.com/derp/derphttp+
nhooyr.io/websocket/internal/errd from nhooyr.io/websocket
nhooyr.io/websocket/internal/xsync from nhooyr.io/websocket
@ -54,6 +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/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
@ -78,6 +77,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
tailscale.com/types/key from tailscale.com/derp+
tailscale.com/types/logger from tailscale.com/cmd/tailscale/cli+
tailscale.com/types/netmap from tailscale.com/ipn
tailscale.com/types/nettype from tailscale.com/net/netcheck+
tailscale.com/types/opt from tailscale.com/net/netcheck+
tailscale.com/types/pad32 from tailscale.com/derp
tailscale.com/types/persist from tailscale.com/ipn
@ -190,7 +190,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
net/http/cgi from tailscale.com/cmd/tailscale/cli
net/http/httptrace from github.com/tcnksm/go-httpstat+
net/http/internal from net/http
net/netip from net
net/netip from net+
net/textproto from golang.org/x/net/http/httpguts+
net/url from crypto/x509+
os from crypto/rand+

@ -25,11 +25,11 @@ import (
"strings"
"time"
"inet.af/netaddr"
"tailscale.com/derp/derphttp"
"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"

@ -113,9 +113,10 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
L github.com/u-root/uio/uio from github.com/insomniacslk/dhcp/dhcpv4+
L 💣 github.com/vishvananda/netlink/nl from github.com/tailscale/netlink
L github.com/vishvananda/netns from github.com/tailscale/netlink+
💣 go4.org/intern from inet.af/netaddr
W 💣 go4.org/intern from inet.af/netaddr
💣 go4.org/mem from tailscale.com/control/controlbase+
go4.org/unsafe/assume-no-moving-gc from go4.org/intern
go4.org/netipx from tailscale.com/ipn/ipnlocal+
W go4.org/unsafe/assume-no-moving-gc from go4.org/intern
W 💣 golang.zx2c4.com/wintun from golang.zx2c4.com/wireguard/tun
💣 golang.zx2c4.com/wireguard/conn from golang.zx2c4.com/wireguard/device+
W 💣 golang.zx2c4.com/wireguard/conn/winrio from golang.zx2c4.com/wireguard/conn
@ -168,7 +169,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
gvisor.dev/gvisor/pkg/tcpip/transport/tcpconntrack from gvisor.dev/gvisor/pkg/tcpip/stack
gvisor.dev/gvisor/pkg/tcpip/transport/udp from tailscale.com/net/tstun+
gvisor.dev/gvisor/pkg/waiter from gvisor.dev/gvisor/pkg/context+
inet.af/netaddr from tailscale.com/control/controlclient+
W inet.af/netaddr from inet.af/wf
inet.af/peercred from tailscale.com/ipn/ipnserver
W 💣 inet.af/wf from tailscale.com/wf
nhooyr.io/websocket from tailscale.com/derp/derphttp+
@ -216,6 +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/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+
@ -252,7 +254,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/types/key from tailscale.com/control/controlbase+
tailscale.com/types/logger from tailscale.com/control/controlclient+
tailscale.com/types/netmap from tailscale.com/control/controlclient+
tailscale.com/types/nettype from tailscale.com/wgengine/magicsock
tailscale.com/types/nettype from tailscale.com/wgengine/magicsock+
tailscale.com/types/opt from tailscale.com/control/controlclient+
tailscale.com/types/pad32 from tailscale.com/derp
tailscale.com/types/persist from tailscale.com/control/controlclient+
@ -269,7 +271,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/util/lineread from tailscale.com/hostinfo+
tailscale.com/util/mak from tailscale.com/control/controlclient+
tailscale.com/util/multierr from tailscale.com/control/controlclient+
tailscale.com/util/netconv from tailscale.com/wgengine/magicsock
tailscale.com/util/osshare from tailscale.com/ipn/ipnlocal+
tailscale.com/util/pidowner from tailscale.com/ipn/ipnserver
tailscale.com/util/racebuild from tailscale.com/logpolicy

@ -29,7 +29,6 @@ import (
"syscall"
"time"
"inet.af/netaddr"
"tailscale.com/cmd/tailscaled/childproc"
"tailscale.com/control/controlclient"
"tailscale.com/envknob"
@ -39,6 +38,7 @@ 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"

@ -32,12 +32,12 @@ import (
"golang.org/x/sys/windows/svc"
"golang.org/x/sys/windows/svc/eventlog"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
"inet.af/netaddr"
"tailscale.com/envknob"
"tailscale.com/ipn/ipnserver"
"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"

@ -24,12 +24,12 @@ import (
"time"
"golang.org/x/crypto/ssh"
"inet.af/netaddr"
"tailscale.com/control/controlclient"
"tailscale.com/ipn"
"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"
@ -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.IP().String() }),
Addresses: mapSlice(nm.Addresses, func(a netaddr.IPPrefix) 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.IP().String() }),
Addresses: mapSlice(p.Addresses, func(a netaddr.IPPrefix) string { return a.Addr().String() }),
MachineKey: p.Machine.String(),
NodeKey: p.Key.String(),
},

@ -8,7 +8,7 @@ package tests
import (
"fmt"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
)
//go:generate go run tailscale.com/cmd/viewer --type=StructWithPtrs,StructWithoutPtrs,Map,StructWithSlices

@ -7,7 +7,7 @@
package tests
import (
"inet.af/netaddr"
"net/netip"
)
// Clone makes a deep copy of StructWithPtrs.
@ -50,7 +50,7 @@ func (src *StructWithoutPtrs) Clone() *StructWithoutPtrs {
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
var _StructWithoutPtrsCloneNeedsRegeneration = StructWithoutPtrs(struct {
Int int
Pfx netaddr.IPPrefix
Pfx netip.Prefix
}{})
// Clone makes a deep copy of Map.
@ -178,6 +178,6 @@ var _StructWithSlicesCloneNeedsRegeneration = StructWithSlices(struct {
Structs []StructWithPtrs
Ints []*int
Slice []string
Prefixes []netaddr.IPPrefix
Prefixes []netip.Prefix
Data []byte
}{})

@ -9,9 +9,9 @@ package tests
import (
"encoding/json"
"errors"
"net/netip"
"go4.org/mem"
"inet.af/netaddr"
"tailscale.com/types/views"
)
@ -134,13 +134,13 @@ func (v *StructWithoutPtrsView) UnmarshalJSON(b []byte) error {
return nil
}
func (v StructWithoutPtrsView) Int() int { return v.ж.Int }
func (v StructWithoutPtrsView) Pfx() netaddr.IPPrefix { return v.ж.Pfx }
func (v StructWithoutPtrsView) Int() int { return v.ж.Int }
func (v StructWithoutPtrsView) Pfx() netip.Prefix { return v.ж.Pfx }
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
var _StructWithoutPtrsViewNeedsRegeneration = StructWithoutPtrs(struct {
Int int
Pfx netaddr.IPPrefix
Pfx netip.Prefix
}{})
// View returns a readonly view of Map.
@ -311,6 +311,6 @@ var _StructWithSlicesViewNeedsRegeneration = StructWithSlices(struct {
Structs []StructWithPtrs
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":
case "inet.af/netaddr.IPPrefix", "net/netip.Prefix":
it.Import("tailscale.com/types/views")
writeTemplate("ipPrefixSliceField")
default:

@ -26,7 +26,6 @@ import (
"time"
"go4.org/mem"
"inet.af/netaddr"
"tailscale.com/control/controlknobs"
"tailscale.com/envknob"
"tailscale.com/health"
@ -37,6 +36,7 @@ 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"
@ -1408,7 +1408,7 @@ func (c *Direct) DoNoiseRequest(req *http.Request) (*http.Response, error) {
// doPingerPing sends a Ping to pr.IP using pinger, and sends an http request back to
// pr.URL with ping response data.
func doPingerPing(logf logger.Logf, c *http.Client, pr *tailcfg.PingRequest, pinger Pinger, pingType tailcfg.PingType) {
if pr.URL == "" || pr.IP.IsZero() || pinger == nil {
if pr.URL == "" || !pr.IP.IsValid() || pinger == nil {
logf("invalid ping request: missing url, ip or pinger")
return
}

@ -11,9 +11,9 @@ import (
"testing"
"time"
"inet.af/netaddr"
"tailscale.com/hostinfo"
"tailscale.com/ipn/ipnstate"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsdial"
"tailscale.com/tailcfg"
"tailscale.com/types/key"

@ -9,8 +9,8 @@ import (
"log"
"sort"
"inet.af/netaddr"
"tailscale.com/envknob"
"tailscale.com/net/netaddr"
"tailscale.com/tailcfg"
"tailscale.com/types/key"
"tailscale.com/types/logger"
@ -309,7 +309,7 @@ func filterSelfAddresses(in []netaddr.IPPrefix) (ret []netaddr.IPPrefix) {
return in
case debugSelfIPv6Only:
for _, a := range in {
if a.IP().Is6() {
if a.Addr().Is6() {
ret = append(ret, a)
}
}

@ -17,7 +17,7 @@ import (
"go4.org/mem"
"golang.org/x/time/rate"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/types/key"
"tailscale.com/types/logger"
)

@ -36,11 +36,11 @@ import (
"go4.org/mem"
"golang.org/x/sync/errgroup"
"golang.org/x/time/rate"
"inet.af/netaddr"
"tailscale.com/client/tailscale"
"tailscale.com/disco"
"tailscale.com/envknob"
"tailscale.com/metrics"
"tailscale.com/net/netaddr"
"tailscale.com/syncs"
"tailscale.com/types/key"
"tailscale.com/types/logger"

@ -30,10 +30,10 @@ import (
"time"
"go4.org/mem"
"inet.af/netaddr"
"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"

@ -26,7 +26,7 @@ import (
"net"
"go4.org/mem"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/types/key"
)
@ -180,7 +180,7 @@ const epLength = 16 + 2 // 16 byte IP address + 2 byte port
func (m *CallMeMaybe) AppendMarshal(b []byte) []byte {
ret, p := appendMsgHeader(b, TypeCallMeMaybe, v0, epLength*len(m.MyNumber))
for _, ipp := range m.MyNumber {
a := ipp.IP().As16()
a := ipp.Addr().As16()
copy(p[:], a[:])
binary.BigEndian.PutUint16(p[16:], ipp.Port())
p = p[epLength:]
@ -219,7 +219,7 @@ const pongLen = 12 + 16 + 2
func (m *Pong) AppendMarshal(b []byte) []byte {
ret, d := appendMsgHeader(b, TypePong, v0, pongLen)
d = d[copy(d, m.TxID[:]):]
ip16 := m.Src.IP().As16()
ip16 := m.Src.Addr().As16()
d = d[copy(d, ip16[:]):]
binary.BigEndian.PutUint16(d, m.Src.Port())
return ret

@ -11,7 +11,7 @@ import (
"testing"
"go4.org/mem"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/types/key"
)

@ -54,6 +54,7 @@ require (
github.com/u-root/u-root v0.8.0
github.com/vishvananda/netlink v1.1.1-0.20211118161826-650dca95af54
go4.org/mem v0.0.0-20210711025021-927187094b94
go4.org/netipx v0.0.0-20220725152314-7e7bdc8411bf
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f
golang.org/x/net v0.0.0-20220607020251-c690dde0001d
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f

@ -1248,6 +1248,8 @@ go4.org/intern v0.0.0-20211027215823-ae77deb06f29 h1:UXLjNohABv4S58tHmeuIZDO6e3m
go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA=
go4.org/mem v0.0.0-20210711025021-927187094b94 h1:OAAkygi2Js191AJP1Ds42MhJRgeofeKGjuoUqNp1QC4=
go4.org/mem v0.0.0-20210711025021-927187094b94/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g=
go4.org/netipx v0.0.0-20220725152314-7e7bdc8411bf h1:IdwJUzqoIo5lkr2EOyKoe5qipUaEjbOKKY5+fzPBZ3A=
go4.org/netipx v0.0.0-20220725152314-7e7bdc8411bf/go.mod h1:+QXzaoURFd0rGDIjDNpyIkv+F9R7EmeKorvlKRnhqgA=
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222175341-b30ae309168e/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=

@ -8,7 +8,7 @@ import (
"sync"
"time"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/tailcfg"
"tailscale.com/types/logger"
"tailscale.com/types/netmap"

@ -7,7 +7,8 @@
package ipn
import (
"inet.af/netaddr"
"net/netip"
"tailscale.com/tailcfg"
"tailscale.com/types/persist"
"tailscale.com/types/preftype"
@ -36,7 +37,7 @@ var _PrefsCloneNeedsRegeneration = Prefs(struct {
RouteAll bool
AllowSingleHosts bool
ExitNodeID tailcfg.StableNodeID
ExitNodeIP netaddr.IP
ExitNodeIP netip.Addr
ExitNodeAllowLANAccess bool
CorpDNS bool
RunSSH bool
@ -47,7 +48,7 @@ var _PrefsCloneNeedsRegeneration = Prefs(struct {
Hostname string
NotepadURLs bool
ForceDaemon bool
AdvertiseRoutes []netaddr.IPPrefix
AdvertiseRoutes []netip.Prefix
NoSNAT bool
NetfilterMode preftype.NetfilterMode
OperatorUser string

@ -6,12 +6,13 @@ package ipnlocal
import (
"encoding/json"
"net/netip"
"reflect"
"testing"
"inet.af/netaddr"
"tailscale.com/ipn"
"tailscale.com/net/dns"
"tailscale.com/net/netaddr"
"tailscale.com/tailcfg"
"tailscale.com/tstest"
"tailscale.com/types/dnstype"
@ -23,7 +24,7 @@ import (
func ipps(ippStrs ...string) (ipps []netaddr.IPPrefix) {
for _, s := range ippStrs {
if ip, err := netaddr.ParseIP(s); err == nil {
ipps = append(ipps, netaddr.IPPrefixFrom(ip, ip.BitLen()))
ipps = append(ipps, netip.PrefixFrom(ip, ip.BitLen()))
continue
}
ipps = append(ipps, netaddr.MustParseIPPrefix(s))

@ -11,6 +11,7 @@ import (
"io"
"net"
"net/http"
"net/netip"
"os"
"os/user"
"path/filepath"
@ -22,7 +23,7 @@ import (
"sync/atomic"
"time"
"inet.af/netaddr"
"go4.org/netipx"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/control/controlclient"
"tailscale.com/envknob"
@ -33,6 +34,7 @@ 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"
@ -231,7 +233,7 @@ func NewLocalBackend(logf logger.Logf, logid string, store ipn.StateStore, diale
}
// Default filter blocks everything and logs nothing, until Start() is called.
b.setFilter(filter.NewAllowNone(logf, &netaddr.IPSet{}))
b.setFilter(filter.NewAllowNone(logf, &netipx.IPSet{}))
b.statusChanged = sync.NewCond(&b.statusLock)
b.e.SetStatusCallback(b.setWgengineStatus)
@ -498,8 +500,8 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
}
var tailscaleIPs = make([]netaddr.IP, 0, len(p.Addresses))
for _, addr := range p.Addresses {
if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.IP()) {
tailscaleIPs = append(tailscaleIPs, addr.IP())
if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.Addr()) {
tailscaleIPs = append(tailscaleIPs, addr.Addr())
}
}
exitNodeOption := tsaddr.PrefixesContainsFunc(p.AllowedIPs, func(r netaddr.IPPrefix) bool {
@ -543,7 +545,7 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
func (b *LocalBackend) WhoIs(ipp netaddr.IPPort) (n *tailcfg.Node, u tailcfg.UserProfile, ok bool) {
b.mu.Lock()
defer b.mu.Unlock()
n, ok = b.nodeByAddr[ipp.IP()]
n, ok = b.nodeByAddr[ipp.Addr()]
if !ok {
var ip netaddr.IP
if ipp.Port() != 0 {
@ -580,9 +582,9 @@ func (b *LocalBackend) PeerCaps(src netaddr.IP) []string {
if !a.IsSingleIP() {
continue
}
dstIP := a.IP()
dstIP := a.Addr()
if dstIP.BitLen() == src.BitLen() {
return filt.AppendCaps(nil, src, a.IP())
return filt.AppendCaps(nil, src, a.Addr())
}
}
return nil
@ -750,7 +752,7 @@ func (b *LocalBackend) findExitNodeIDLocked(nm *netmap.NetworkMap) (prefsChanged
// If we have a desired IP on file, try to find the corresponding
// node.
if b.prefs.ExitNodeIP.IsZero() {
if !b.prefs.ExitNodeIP.IsValid() {
return false
}
@ -762,7 +764,7 @@ func (b *LocalBackend) findExitNodeIDLocked(nm *netmap.NetworkMap) (prefsChanged
for _, peer := range nm.Peers {
for _, addr := range peer.Addresses {
if !addr.IsSingleIP() || addr.IP() != b.prefs.ExitNodeIP {
if !addr.IsSingleIP() || addr.Addr() != b.prefs.ExitNodeIP {
continue
}
// Found the node being referenced, upgrade prefs to
@ -1123,8 +1125,8 @@ func (b *LocalBackend) updateFilterLocked(netMap *netmap.NetworkMap, prefs *ipn.
haveNetmap = netMap != nil
addrs []netaddr.IPPrefix
packetFilter []filter.Match
localNetsB netaddr.IPSetBuilder
logNetsB netaddr.IPSetBuilder
localNetsB netipx.IPSetBuilder
logNetsB netipx.IPSetBuilder
shieldsUp = prefs == nil || prefs.ShieldsUp // Be conservative when not ready
)
// Log traffic for Tailscale IPs.
@ -1241,9 +1243,9 @@ func internalAndExternalInterfaces() (internal, external []netaddr.IPPrefix, err
func internalAndExternalInterfacesFrom(il interfaces.List, goos string) (internal, external []netaddr.IPPrefix, err error) {
// We use an IPSetBuilder here to canonicalize the prefixes
// and to remove any duplicate entries.
var internalBuilder, externalBuilder netaddr.IPSetBuilder
var internalBuilder, externalBuilder netipx.IPSetBuilder
if err := il.ForeachInterfaceAddress(func(iface interfaces.Interface, pfx netaddr.IPPrefix) {
if tsaddr.IsTailscaleIP(pfx.IP()) {
if tsaddr.IsTailscaleIP(pfx.Addr()) {
return
}
if pfx.IsSingleIP() {
@ -1284,16 +1286,16 @@ func internalAndExternalInterfacesFrom(il interfaces.List, goos string) (interna
return iSet.Prefixes(), eSet.Prefixes(), nil
}
func interfaceRoutes() (ips *netaddr.IPSet, hostIPs []netaddr.IP, err error) {
var b netaddr.IPSetBuilder
func interfaceRoutes() (ips *netipx.IPSet, hostIPs []netaddr.IP, err error) {
var b netipx.IPSetBuilder
if err := interfaces.ForeachInterfaceAddress(func(_ interfaces.Interface, pfx netaddr.IPPrefix) {
if tsaddr.IsTailscaleIP(pfx.IP()) {
if tsaddr.IsTailscaleIP(pfx.Addr()) {
return
}
if pfx.IsSingleIP() {
return
}
hostIPs = append(hostIPs, pfx.IP())
hostIPs = append(hostIPs, pfx.Addr())
b.AddPrefix(pfx)
}); err != nil {
return nil, nil, err
@ -1306,8 +1308,8 @@ func interfaceRoutes() (ips *netaddr.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 *netaddr.IPSet, hostIPs []netaddr.IP) (*netaddr.IPSet, error) {
var b netaddr.IPSetBuilder
func shrinkDefaultRoute(route netaddr.IPPrefix, localInterfaceRoutes *netipx.IPSet, hostIPs []netaddr.IP) (*netipx.IPSet, error) {
var b netipx.IPSetBuilder
// Add the default route.
b.AddPrefix(route)
// Remove the local interface routes.
@ -2089,7 +2091,7 @@ func (b *LocalBackend) ServePeerAPIConnection(remote, local netaddr.IPPort, c ne
b.mu.Lock()
defer b.mu.Unlock()
for _, pln := range b.peerAPIListeners {
if pln.ip == local.IP() {
if pln.ip == local.Addr() {
go pln.ServeConn(remote, c)
return
}
@ -2312,8 +2314,8 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Log
var ips []netaddr.IP
for _, addr := range addrs {
if selfV6Only {
if addr.IP().Is6() {
ips = append(ips, addr.IP())
if addr.Addr().Is6() {
ips = append(ips, addr.Addr())
}
continue
}
@ -2325,10 +2327,10 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Log
// https://github.com/tailscale/tailscale/issues/1152
// tracks adding the right capability reporting to
// enable AAAA in MagicDNS.
if addr.IP().Is6() && have4 {
if addr.Addr().Is6() && have4 {
continue
}
ips = append(ips, addr.IP())
ips = append(ips, addr.Addr())
}
dcfg.Hosts[fqdn] = ips
}
@ -2520,7 +2522,7 @@ func (b *LocalBackend) initPeerAPIListener() {
if len(b.netMap.Addresses) == len(b.peerAPIListeners) {
allSame := true
for i, pln := range b.peerAPIListeners {
if pln.ip != b.netMap.Addresses[i].IP() {
if pln.ip != b.netMap.Addresses[i].Addr() {
allSame = false
break
}
@ -2563,20 +2565,20 @@ func (b *LocalBackend) initPeerAPIListener() {
var err error
skipListen := i > 0 && isNetstack
if !skipListen {
ln, err = ps.listen(a.IP(), b.prevIfState)
ln, err = ps.listen(a.Addr(), b.prevIfState)
if err != nil {
if peerAPIListenAsync {
// Expected. But we fix it later in linkChange
// ("peerAPIListeners too low").
continue
}
b.logf("[unexpected] peerapi listen(%q) error: %v", a.IP(), err)
b.logf("[unexpected] peerapi listen(%q) error: %v", a.Addr(), err)
continue
}
}
pln := &peerAPIListener{
ps: ps,
ip: a.IP(),
ip: a.Addr(),
ln: ln, // nil for 2nd+ on netstack
lb: b,
}
@ -2585,7 +2587,7 @@ func (b *LocalBackend) initPeerAPIListener() {
} else {
pln.port = ln.Addr().(*net.TCPAddr).Port
}
pln.urlStr = "http://" + net.JoinHostPort(a.IP().String(), strconv.Itoa(pln.port))
pln.urlStr = "http://" + net.JoinHostPort(a.Addr().String(), strconv.Itoa(pln.port))
b.logf("peerapi: serving on %s", pln.urlStr)
go pln.serve()
b.peerAPIListeners = append(b.peerAPIListeners, pln)
@ -2636,14 +2638,14 @@ func peerRoutes(peers []wgcfg.Peer, cgnatThreshold int) (routes []netaddr.IPPref
for _, aip := range peer.AllowedIPs {
aip = unmapIPPrefix(aip)
// Only add the Tailscale IPv6 ULA once, if we see anybody using part of it.
if aip.IP().Is6() && aip.IsSingleIP() && tsULA.Contains(aip.IP()) {
if aip.Addr().Is6() && aip.IsSingleIP() && tsULA.Contains(aip.Addr()) {
if !didULA {
didULA = true
routes = append(routes, tsULA)
}
continue
}
if aip.IsSingleIP() && cgNAT.Contains(aip.IP()) {
if aip.IsSingleIP() && cgNAT.Contains(aip.Addr()) {
cgNATIPs = append(cgNATIPs, aip)
} else {
routes = append(routes, aip)
@ -2664,10 +2666,10 @@ func peerRoutes(peers []wgcfg.Peer, cgnatThreshold int) (routes []netaddr.IPPref
}
func ipPrefixLess(ri, rj netaddr.IPPrefix) bool {
if ri.IP() == rj.IP() {
if ri.Addr() == rj.Addr() {
return ri.Bits() < rj.Bits()
}
return ri.IP().Less(rj.IP())
return ri.Addr().Less(rj.Addr())
}
// routerConfig produces a router.Config from a wireguard config and IPN prefs.
@ -2695,7 +2697,7 @@ func (b *LocalBackend) routerConfig(cfg *wgcfg.Config, prefs *ipn.Prefs, oneCGNA
// likely to break some functionality, but if the user expressed a
// preference for routing remotely, we want to avoid leaking
// traffic at the expense of functionality.
if prefs.ExitNodeID != "" || !prefs.ExitNodeIP.IsZero() {
if prefs.ExitNodeID != "" || prefs.ExitNodeIP.IsValid() {
var default4, default6 bool
for _, route := range rs.Routes {
switch route {
@ -2741,7 +2743,7 @@ func (b *LocalBackend) routerConfig(cfg *wgcfg.Config, prefs *ipn.Prefs, oneCGNA
}
func unmapIPPrefix(ipp netaddr.IPPrefix) netaddr.IPPrefix {
return netaddr.IPPrefixFrom(ipp.IP().Unmap(), ipp.Bits())
return netip.PrefixFrom(ipp.Addr().Unmap(), ipp.Bits())
}
func unmapIPPrefixes(ippsList ...[]netaddr.IPPrefix) (ret []netaddr.IPPrefix) {
@ -2828,7 +2830,7 @@ func (b *LocalBackend) enterState(newState ipn.State) {
case ipn.Running:
var addrs []string
for _, addr := range netMap.Addresses {
addrs = append(addrs, addr.IP().String())
addrs = append(addrs, addr.Addr().String())
}
systemd.Status("Connected; %s; %s", activeLogin, strings.Join(addrs, " "))
default:
@ -3114,7 +3116,7 @@ func (b *LocalBackend) setNetMapLocked(nm *netmap.NetworkMap) {
addNode := func(n *tailcfg.Node) {
for _, ipp := range n.Addresses {
if ipp.IsSingleIP() {
b.nodeByAddr[ipp.IP()] = n
b.nodeByAddr[ipp.Addr()] = n
}
}
}
@ -3294,9 +3296,9 @@ func peerAPIBase(nm *netmap.NetworkMap, peer *tailcfg.Node) string {
continue
}
switch {
case a.IP().Is4():
case a.Addr().Is4():
have4 = true
case a.IP().Is6():
case a.Addr().Is6():
have6 = true
}
}
@ -3318,7 +3320,7 @@ func peerAPIBase(nm *netmap.NetworkMap, peer *tailcfg.Node) string {
case have6 && p6 != 0:
ipp = netaddr.IPPortFrom(nodeIP(peer, netaddr.IP.Is6), p6)
}
if ipp.IP().IsZero() {
if !ipp.Addr().IsValid() {
return ""
}
return fmt.Sprintf("http://%v", ipp)
@ -3326,8 +3328,8 @@ func peerAPIBase(nm *netmap.NetworkMap, peer *tailcfg.Node) string {
func nodeIP(n *tailcfg.Node, pred func(netaddr.IP) bool) netaddr.IP {
for _, a := range n.Addresses {
if a.IsSingleIP() && pred(a.IP()) {
return a.IP()
if a.IsSingleIP() && pred(a.Addr()) {
return a.Addr()
}
}
return netaddr.IP{}
@ -3369,9 +3371,9 @@ func (b *LocalBackend) OfferingExitNode() bool {
if r.Bits() != 0 {
continue
}
if r.IP().Is4() {
if r.Addr().Is4() {
def4 = true
} else if r.IP().Is6() {
} else if r.Addr().Is6() {
def6 = true
}
}
@ -3543,7 +3545,7 @@ func (b *LocalBackend) handleQuad100Port80Conn(w http.ResponseWriter, r *http.Re
}
io.WriteString(w, "<p>Local addresses:</p><ul>\n")
for _, ipp := range b.netMap.Addresses {
fmt.Fprintf(w, "<li>%v</li>\n", ipp.IP())
fmt.Fprintf(w, "<li>%v</li>\n", ipp.Addr())
}
io.WriteString(w, "</ul>\n")
}

@ -12,10 +12,11 @@ import (
"testing"
"time"
"inet.af/netaddr"
"go4.org/netipx"
"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"
@ -173,7 +174,7 @@ func TestShrinkDefaultRoute(t *testing.T) {
out: []string{
"fe80::1",
"ff00::1",
tsaddr.TailscaleULARange().IP().String(),
tsaddr.TailscaleULARange().Addr().String(),
},
localIPFn: func(ip netaddr.IP) bool { return !inRemove(ip) && ip.Is6() },
},
@ -182,7 +183,7 @@ func TestShrinkDefaultRoute(t *testing.T) {
// Construct a fake local network environment to make this test hermetic.
// localInterfaceRoutes and hostIPs would normally come from calling interfaceRoutes,
// and localAddresses would normally come from calling interfaces.LocalAddresses.
var b netaddr.IPSetBuilder
var b netipx.IPSetBuilder
for _, c := range []string{"127.0.0.0/8", "192.168.9.0/24", "fe80::/32"} {
p := netaddr.MustParseIPPrefix(c)
b.AddPrefix(p)
@ -561,7 +562,7 @@ func TestInternalAndExternalInterfaces(t *testing.T) {
ip := interfaces.Interface{
Interface: &net.Interface{},
AltAddrs: []net.Addr{
ippfx.IPNet(),
netipx.PrefixIPNet(ippfx),
},
}
if loopback {

@ -31,7 +31,6 @@ import (
"github.com/kortschak/wol"
"golang.org/x/net/dns/dnsmessage"
"inet.af/netaddr"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/health"
"tailscale.com/hostinfo"
@ -39,6 +38,7 @@ import (
"tailscale.com/logtail/backoff"
"tailscale.com/net/dns/resolver"
"tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
"tailscale.com/net/netutil"
"tailscale.com/syncs"
"tailscale.com/tailcfg"
@ -577,7 +577,7 @@ func (h *peerAPIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
<body>
<h1>Hello, %s (%v)</h1>
This is my Tailscale device. Your device is %v.
`, html.EscapeString(who), h.remoteAddr.IP(), html.EscapeString(h.peerNode.ComputedName))
`, html.EscapeString(who), h.remoteAddr.Addr(), html.EscapeString(h.peerNode.ComputedName))
if h.isSelf {
fmt.Fprintf(w, "<p>You are the owner of this node.\n")
@ -693,7 +693,7 @@ func (h *peerAPIHandler) canWakeOnLAN() bool {
}
func (h *peerAPIHandler) peerHasCap(wantCap string) bool {
for _, hasCap := range h.ps.b.PeerCaps(h.remoteAddr.IP()) {
for _, hasCap := range h.ps.b.PeerCaps(h.remoteAddr.Addr()) {
if hasCap == wantCap {
return true
}
@ -801,7 +801,7 @@ func (h *peerAPIHandler) handlePeerPut(w http.ResponseWriter, r *http.Request) {
}
d := time.Since(t0).Round(time.Second / 10)
h.logf("got put of %s in %v from %v/%v", approxSize(finalSize), d, h.remoteAddr.IP, h.peerNode.ComputedName)
h.logf("got put of %s in %v from %v/%v", approxSize(finalSize), d, h.remoteAddr.Addr(), h.peerNode.ComputedName)
// TODO: set modtime
// TODO: some real response
@ -925,12 +925,11 @@ func (h *peerAPIHandler) handleWakeOnLAN(w http.ResponseWriter, r *http.Request)
}
for ifName, ips := range st.InterfaceIPs {
for _, ip := range ips {
if ip.IP().IsLoopback() || ip.IP().Is6() {
if ip.Addr().IsLoopback() || ip.Addr().Is6() {
continue
}
ipa := ip.IP().IPAddr()
local := &net.UDPAddr{
IP: ipa.IP,
IP: ip.Addr().AsSlice(),
Port: 0,
}
remote := &net.UDPAddr{
@ -982,7 +981,7 @@ func (h *peerAPIHandler) replyToDNSQueries() bool {
// arbitrary. DNS runs over TCP and UDP, so sure... we check
// TCP.
dstIP := netaddr.IPv4(0, 0, 0, 0)
remoteIP := h.remoteAddr.IP()
remoteIP := h.remoteAddr.Addr()
if remoteIP.Is6() {
// autogroup:internet for IPv6 is defined to start with 2000::/3,
// so use 2000::0 as the probe "the internet" address.
@ -1171,7 +1170,7 @@ func writePrettyDNSReply(w io.Writer, res []byte) (err error) {
// See docs on fakePeerAPIListener.
func newFakePeerAPIListener(ip netaddr.IP) net.Listener {
return &fakePeerAPIListener{
addr: netaddr.IPPortFrom(ip, 1).TCPAddr(),
addr: net.TCPAddrFromAddrPort(netaddr.IPPortFrom(ip, 1)),
closed: make(chan struct{}),
}
}

@ -12,8 +12,8 @@ import (
"fmt"
"net"
"inet.af/netaddr"
"tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
"tailscale.com/net/netns"
)

@ -19,8 +19,9 @@ import (
"strings"
"testing"
"inet.af/netaddr"
"go4.org/netipx"
"tailscale.com/ipn"
"tailscale.com/net/netaddr"
"tailscale.com/tailcfg"
"tailscale.com/tstest"
"tailscale.com/types/logger"
@ -607,7 +608,7 @@ func TestPeerAPIReplyToDNSQueries(t *testing.T) {
t.Errorf("unexpectedly doing DNS without filter")
}
h.ps.b.setFilter(filter.NewAllowNone(logger.Discard, new(netaddr.IPSet)))
h.ps.b.setFilter(filter.NewAllowNone(logger.Discard, new(netipx.IPSet)))
if h.replyToDNSQueries() {
t.Errorf("unexpectedly doing DNS without filter")
}

@ -29,7 +29,6 @@ import (
"time"
"go4.org/mem"
"inet.af/netaddr"
"inet.af/peercred"
"tailscale.com/control/controlclient"
"tailscale.com/envknob"
@ -37,6 +36,7 @@ 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"
@ -154,7 +154,7 @@ func (s *Server) getConnIdentity(c net.Conn) (ci connIdentity, err error) {
if err != nil {
return ci, fmt.Errorf("parsing local remote: %w", err)
}
if !la.IP().IsLoopback() || !ra.IP().IsLoopback() {
if !la.Addr().IsLoopback() || !ra.Addr().IsLoopback() {
return ci, errors.New("non-loopback connection")
}
tab, err := netstat.Get()
@ -1168,7 +1168,7 @@ func findTrueNASTaildropDir(name string) (dir string, err error) {
// findQnapTaildropDir checks if a Shared Folder named "Taildrop" exists.
func findQnapTaildropDir(name string) (string, error) {
dir := fmt.Sprintf("/share/%s", name)
fi, err := os.Stat(dir)
fi, err := os.Stat(dir)
if err != nil {
return "", fmt.Errorf("shared folder %q not found", name)
}
@ -1181,7 +1181,7 @@ func findQnapTaildropDir(name string) (string, error) {
if err != nil {
return "", fmt.Errorf("symlink to shared folder %q not found", name)
}
if fi, err = os.Stat(fullpath); err == nil && fi.IsDir() {
if fi, err = os.Stat(fullpath); err == nil && fi.IsDir() {
return dir, nil // return the symlink, how QNAP set it up
}
return "", fmt.Errorf("shared folder %q not found", name)

@ -17,7 +17,7 @@ import (
"sync"
"time"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/tailcfg"
"tailscale.com/types/key"
"tailscale.com/types/views"

@ -24,11 +24,11 @@ import (
"sync"
"time"
"inet.af/netaddr"
"tailscale.com/client/tailscale/apitype"
"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"
@ -242,7 +242,7 @@ func (h *Handler) serveWhoIs(w http.ResponseWriter, r *http.Request) {
res := &apitype.WhoIsResponse{
Node: n,
UserProfile: &u,
Caps: b.PeerCaps(ipp.IP()),
Caps: b.PeerCaps(ipp.Addr()),
}
j, err := json.MarshalIndent(res, "", "\t")
if err != nil {

@ -11,15 +11,16 @@ import (
"fmt"
"io/ioutil"
"log"
"net/netip"
"os"
"path/filepath"
"reflect"
"runtime"
"strings"
"inet.af/netaddr"
"tailscale.com/atomicfile"
"tailscale.com/ipn/ipnstate"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsaddr"
"tailscale.com/tailcfg"
"tailscale.com/types/persist"
@ -308,7 +309,7 @@ func (p *Prefs) pretty(goos string) string {
if p.ShieldsUp {
sb.WriteString("shields=true ")
}
if !p.ExitNodeIP.IsZero() {
if p.ExitNodeIP.IsValid() {
fmt.Fprintf(&sb, "exit=%v lan=%t ", p.ExitNodeIP, p.ExitNodeAllowLANAccess)
} else if !p.ExitNodeID.IsZero() {
fmt.Fprintf(&sb, "exit=%v lan=%t ", p.ExitNodeID, p.ExitNodeAllowLANAccess)
@ -478,7 +479,7 @@ func (p *Prefs) SetAdvertiseExitNode(runExit bool) {
}
p.AdvertiseRoutes = append(p.AdvertiseRoutes,
netaddr.IPPrefixFrom(netaddr.IPv4(0, 0, 0, 0), 0),
netaddr.IPPrefixFrom(netaddr.IPv6Unspecified(), 0))
netaddr.IPPrefixFrom(netip.IPv6Unspecified(), 0))
}
// peerWithTailscaleIP returns the peer in st with the provided

@ -16,8 +16,8 @@ import (
"time"
"go4.org/mem"
"inet.af/netaddr"
"tailscale.com/ipn/ipnstate"
"tailscale.com/net/netaddr"
"tailscale.com/tailcfg"
"tailscale.com/tstest"
"tailscale.com/types/key"

@ -9,8 +9,8 @@ import (
"fmt"
"sort"
"inet.af/netaddr"
"tailscale.com/net/dns/resolver"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsaddr"
"tailscale.com/types/dnstype"
"tailscale.com/util/dnsname"

@ -20,8 +20,8 @@ import (
"strings"
"time"
"inet.af/netaddr"
"tailscale.com/net/dns/resolvconffile"
"tailscale.com/net/netaddr"
"tailscale.com/types/logger"
"tailscale.com/util/dnsname"
"tailscale.com/version/distro"

@ -15,7 +15,7 @@ import (
"testing"
qt "github.com/frankban/quicktest"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/util/dnsname"
)

@ -15,9 +15,9 @@ import (
"sync/atomic"
"time"
"inet.af/netaddr"
"tailscale.com/health"
"tailscale.com/net/dns/resolver"
"tailscale.com/net/netaddr"
"tailscale.com/net/packet"
"tailscale.com/net/tsaddr"
"tailscale.com/net/tsdial"
@ -242,7 +242,7 @@ func (m *Manager) compileConfig(cfg Config) (rcfg resolver.Config, ocfg OSConfig
func toIPsOnly(resolvers []*dnstype.Resolver) (ret []netaddr.IP) {
for _, r := range resolvers {
if ipp, ok := r.IPPort(); ok && ipp.Port() == 53 {
ret = append(ret, ipp.IP())
ret = append(ret, ipp.Addr())
}
}
return ret
@ -299,11 +299,11 @@ func (m *Manager) NextPacket() ([]byte, error) {
var buf []byte
switch {
case resp.to.IP().Is4():
case resp.to.Addr().Is4():
h := packet.UDP4Header{
IP4Header: packet.IP4Header{
Src: magicDNSIP,
Dst: resp.to.IP(),
Dst: resp.to.Addr(),
},
SrcPort: 53,
DstPort: resp.to.Port(),
@ -312,11 +312,11 @@ func (m *Manager) NextPacket() ([]byte, error) {
buf = make([]byte, offset+hlen+len(resp.pkt))
copy(buf[offset+hlen:], resp.pkt)
h.Marshal(buf[offset:])
case resp.to.IP().Is6():
case resp.to.Addr().Is6():
h := packet.UDP6Header{
IP6Header: packet.IP6Header{
Src: magicDNSIPv6,
Dst: resp.to.IP(),
Dst: resp.to.Addr(),
},
SrcPort: 53,
DstPort: resp.to.Port(),

@ -13,8 +13,8 @@ import (
"time"
"github.com/godbus/dbus/v5"
"inet.af/netaddr"
"tailscale.com/health"
"tailscale.com/net/netaddr"
"tailscale.com/types/logger"
"tailscale.com/util/cmpver"
)

@ -12,7 +12,7 @@ import (
"github.com/google/go-cmp/cmp"
dns "golang.org/x/net/dns/dnsmessage"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsdial"
"tailscale.com/util/dnsname"
)

@ -11,8 +11,8 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"inet.af/netaddr"
"tailscale.com/net/dns/resolver"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsdial"
"tailscale.com/types/dnstype"
"tailscale.com/util/dnsname"
@ -396,7 +396,7 @@ 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 {
if ipp.Port() == 53 {
return ipp.IP().String()
return ipp.Addr().String()
}
return ipp.String()
})

@ -16,8 +16,8 @@ import (
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/registry"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
"inet.af/netaddr"
"tailscale.com/envknob"
"tailscale.com/net/netaddr"
"tailscale.com/types/logger"
"tailscale.com/util/dnsname"
)

@ -14,7 +14,7 @@ import (
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/registry"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/util/dnsname"
"tailscale.com/util/winutil"
)

@ -14,8 +14,8 @@ import (
"time"
"github.com/godbus/dbus/v5"
"inet.af/netaddr"
"tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
"tailscale.com/util/dnsname"
"tailscale.com/util/endian"
)

@ -7,7 +7,7 @@ package dns
import (
"errors"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/util/dnsname"
)

@ -9,7 +9,7 @@ package publicdns
import (
"sync"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
)
var knownDoH = map[netaddr.IP]string{} // 8.8.8.8 => "https://..."

@ -7,7 +7,7 @@ package publicdns
import (
"testing"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
)
func TestInit(t *testing.T) {

@ -19,7 +19,7 @@ import (
"os"
"strings"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/util/dnsname"
)

@ -9,7 +9,7 @@ import (
"strings"
"testing"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/util/dnsname"
)

@ -15,11 +15,11 @@ import (
"strings"
"time"
"tailscale.com/logtail/backoff"
"github.com/godbus/dbus/v5"
"golang.org/x/sys/unix"
"inet.af/netaddr"
"tailscale.com/health"
"tailscale.com/logtail/backoff"
"tailscale.com/net/netaddr"
"tailscale.com/types/logger"
"tailscale.com/util/dnsname"
)
@ -78,7 +78,7 @@ type resolvedLinkDomain struct {
// changeRequest tracks latest OSConfig and related error responses to update.
type changeRequest struct {
config OSConfig // configs OSConfigs, one per each SetDNS call
res chan <- error // response channel
res chan<- error // response channel
}
// resolvedManager is an OSConfigurator which uses the systemd-resolved DBus API.
@ -139,8 +139,8 @@ func (m *resolvedManager) SetDNS(config OSConfig) error {
func (m *resolvedManager) run(ctx context.Context) {
var (
conn *dbus.Conn
signals chan *dbus.Signal
conn *dbus.Conn
signals chan *dbus.Signal
rManager dbus.BusObject // rManager is the Resolved DBus connection
)
bo := backoff.NewBackoff("resolved-dbus", m.logf, 30*time.Second)

@ -24,16 +24,17 @@ import (
"time"
dns "golang.org/x/net/dns/dnsmessage"
"inet.af/netaddr"
"tailscale.com/envknob"
"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"
"tailscale.com/types/dnstype"
"tailscale.com/types/logger"
"tailscale.com/types/nettype"
"tailscale.com/util/cloudenv"
"tailscale.com/util/dnsname"
"tailscale.com/wgengine/monitor"
@ -267,7 +268,7 @@ func resolversWithDelays(resolvers []*dnstype.Resolver) []resolverAndDelay {
if !ok {
continue
}
dohBase, ok := publicdns.KnownDoH()[ipp.IP()]
dohBase, ok := publicdns.KnownDoH()[ipp.Addr()]
if !ok || didDoH[dohBase] {
continue
}
@ -288,12 +289,12 @@ func resolversWithDelays(resolvers []*dnstype.Resolver) []resolverAndDelay {
rr = append(rr, resolverAndDelay{name: r})
continue
}
ip := ipp.IP()
ip := ipp.Addr()
var startDelay time.Duration
if host, ok := publicdns.KnownDoH()[ip]; ok {
// We already did the DoH query early. These
startDelay = dohHeadStart
key := hostAndFam{host, ip.BitLen()}
key := hostAndFam{host, uint8(ip.BitLen())}
if done[key] > 0 {
startDelay += wellKnownHostBackupDelay
}
@ -364,13 +365,9 @@ func (f *forwarder) setRoutes(routesBySuffix map[dnsname.FQDN][]*dnstype.Resolve
f.cloudHostFallback = cloudHostFallback
}
var stdNetPacketListener packetListener = new(net.ListenConfig)
var stdNetPacketListener nettype.PacketListenerWithNetIP = nettype.MakePacketListenerWithNetIP(new(net.ListenConfig))
type packetListener interface {
ListenPacket(ctx context.Context, network, address string) (net.PacketConn, error)
}
func (f *forwarder) packetListener(ip netaddr.IP) (packetListener, error) {
func (f *forwarder) packetListener(ip netaddr.IP) (nettype.PacketListenerWithNetIP, error) {
if f.linkSel == nil || initListenConfig == nil {
return stdNetPacketListener, nil
}
@ -382,7 +379,7 @@ func (f *forwarder) packetListener(ip netaddr.IP) (packetListener, error) {
if err := initListenConfig(lc, f.linkMon, linkName); err != nil {
return nil, err
}
return lc, nil
return nettype.MakePacketListenerWithNetIP(lc), nil
}
// getKnownDoHClientForProvider returns an HTTP client for a specific DoH
@ -528,11 +525,17 @@ func (f *forwarder) sendUDP(ctx context.Context, fq *forwardQuery, rr resolverAn
}
metricDNSFwdUDP.Add(1)
ln, err := f.packetListener(ipp.IP())
ln, err := f.packetListener(ipp.Addr())
if err != nil {
return nil, err
}
conn, err := ln.ListenPacket(ctx, "udp", ":0")
// Specify the exact UDP family to work around https://github.com/golang/go/issues/52264
udpFam := "udp4"
if ipp.Addr().Is6() {
udpFam = "udp6"
}
conn, err := ln.ListenPacket(ctx, udpFam, ":0")
if err != nil {
f.logf("ListenPacket failed: %v", err)
return nil, err
@ -542,7 +545,7 @@ func (f *forwarder) sendUDP(ctx context.Context, fq *forwardQuery, rr resolverAn
fq.closeOnCtxDone.Add(conn)
defer fq.closeOnCtxDone.Remove(conn)
if _, err := conn.WriteTo(fq.packet, ipp.UDPAddr()); err != nil {
if _, err := conn.WriteToUDPAddrPort(fq.packet, ipp); err != nil {
metricDNSFwdUDPErrorWrite.Add(1)
if err := ctx.Err(); err != nil {
return nil, err

@ -14,6 +14,7 @@ import (
"fmt"
"io"
"net"
"net/netip"
"os"
"runtime"
"sort"
@ -24,8 +25,8 @@ import (
"time"
dns "golang.org/x/net/dns/dnsmessage"
"inet.af/netaddr"
"tailscale.com/net/dns/resolvconffile"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsaddr"
"tailscale.com/net/tsdial"
"tailscale.com/types/dnstype"
@ -680,8 +681,8 @@ func (r *Resolver) parseViaDomain(domain dnsname.FQDN, typ dns.Type) (netaddr.IP
}
// MapVia will never error when given an ipv4 netaddr.IPPrefix.
out, _ := tsaddr.MapVia(uint32(prefix), netaddr.IPPrefixFrom(ip4, ip4.BitLen()))
return out.IP(), true
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.

@ -11,7 +11,7 @@ import (
"testing"
"github.com/miekg/dns"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
)
// This file exists to isolate the test infrastructure
@ -41,7 +41,7 @@ func resolveToIP(ipv4, ipv6 netaddr.IP, ns string) dns.HandlerFunc {
Rrtype: dns.TypeA,
Class: dns.ClassINET,
},
A: ipv4.IPAddr().IP,
A: ipv4.AsSlice(),
}
case dns.TypeAAAA:
ans = &dns.AAAA{
@ -50,7 +50,7 @@ func resolveToIP(ipv4, ipv6 netaddr.IP, ns string) dns.HandlerFunc {
Rrtype: dns.TypeAAAA,
Class: dns.ClassINET,
},
AAAA: ipv6.IPAddr().IP,
AAAA: ipv6.AsSlice(),
}
case dns.TypeNS:
ans = &dns.NS{
@ -93,7 +93,7 @@ func resolveToIPLowercase(ipv4, ipv6 netaddr.IP, ns string) dns.HandlerFunc {
Rrtype: dns.TypeA,
Class: dns.ClassINET,
},
A: ipv4.IPAddr().IP,
A: ipv4.AsSlice(),
}
case dns.TypeAAAA:
ans = &dns.AAAA{
@ -102,7 +102,7 @@ func resolveToIPLowercase(ipv4, ipv6 netaddr.IP, ns string) dns.HandlerFunc {
Rrtype: dns.TypeAAAA,
Class: dns.ClassINET,
},
AAAA: ipv6.IPAddr().IP,
AAAA: ipv6.AsSlice(),
}
case dns.TypeNS:
ans = &dns.NS{
@ -244,7 +244,7 @@ func dnsHandler(answers ...any) dns.HandlerFunc {
Rrtype: dns.TypeA,
Class: dns.ClassINET,
},
A: ip.IPAddr().IP,
A: ip.AsSlice(),
})
} else if ip.Is6() {
m.Answer = append(m.Answer, &dns.AAAA{
@ -253,7 +253,7 @@ func dnsHandler(answers ...any) dns.HandlerFunc {
Rrtype: dns.TypeAAAA,
Class: dns.ClassINET,
},
AAAA: ip.IPAddr().IP,
AAAA: ip.AsSlice(),
})
}
case dns.PTR:

@ -23,7 +23,7 @@ import (
miekdns "github.com/miekg/dns"
"golang.org/x/net/dns/dnsmessage"
dns "golang.org/x/net/dns/dnsmessage"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsdial"
"tailscale.com/tstest"
"tailscale.com/types/dnstype"

@ -19,8 +19,8 @@ import (
"sync"
"time"
"inet.af/netaddr"
"tailscale.com/envknob"
"tailscale.com/net/netaddr"
"tailscale.com/util/cloudenv"
"tailscale.com/util/singleflight"
)
@ -153,7 +153,10 @@ func (r *Resolver) LookupIP(ctx context.Context, host string) (ip, v6 net.IP, al
return nil, nil, nil, fmt.Errorf("dnscache: unexpected hostname %q doesn't match expected %q", host, r.SingleHost)
}
for _, naIP := range r.SingleHostStaticResult {
ipa := naIP.IPAddr()
ipa := &net.IPAddr{
IP: naIP.AsSlice(),
Zone: naIP.Zone(),
}
if ip == nil && naIP.Is4() {
ip = ipa.IP
}
@ -273,7 +276,10 @@ func (r *Resolver) lookupIP(host string) (ip, ip6 net.IP, allIPs []net.IPAddr, e
if err == nil {
ips = nil
for _, fip := range fips {
ips = append(ips, *fip.IPAddr())
ips = append(ips, net.IPAddr{
IP: fip.AsSlice(),
Zone: fip.Zone(),
})
}
}
}

@ -14,7 +14,7 @@ import (
"testing"
"time"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
)
var dialTest = flag.String("dial-test", "", "if non-empty, addr:port to test dial")

@ -90,18 +90,25 @@
"RegionName": "r2",
"Nodes": [
{
"Name": "2a",
"Name": "2d",
"RegionID": 2,
"HostName": "derp2.tailscale.com",
"IPv4": "167.172.206.31",
"IPv6": "2604:a880:2:d1::c5:7001"
"HostName": "derp2d.tailscale.com",
"IPv4": "192.73.252.65",
"IPv6": "2607:f740:0:3f::287"
},
{
"Name": "2b",
"Name": "2e",
"RegionID": 2,
"HostName": "derp2b.tailscale.com",
"IPv4": "64.227.106.23",
"IPv6": "2604:a880:4:1d0::29:9000"
"HostName": "derp2e.tailscale.com",
"IPv4": "192.73.252.134",
"IPv6": "2607:f740:0:3f::44c"
},
{
"Name": "2f",
"RegionID": 2,
"HostName": "derp2f.tailscale.com",
"IPv4": "208.111.34.178",
"IPv6": "2607:f740:0:3f::f4"
}
]
},

@ -21,7 +21,7 @@ import (
"net/url"
"time"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/net/netns"
"tailscale.com/net/tlsdial"
"tailscale.com/net/tshttpproxy"
@ -29,7 +29,7 @@ import (
)
func Lookup(ctx context.Context, host string) ([]netaddr.IP, error) {
if ip, err := netaddr.ParseIP(host); err == nil && !ip.IsZero() {
if ip, err := netaddr.ParseIP(host); err == nil && ip.IsValid() {
return []netaddr.IP{ip}, nil
}

@ -14,7 +14,7 @@ import (
"container/list"
"fmt"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/types/ipproto"
)

@ -7,7 +7,7 @@ package flowtrack
import (
"testing"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/tstest"
)

@ -14,8 +14,8 @@ import (
"sort"
"strings"
"inet.af/netaddr"
"tailscale.com/hostinfo"
"tailscale.com/net/netaddr"
"tailscale.com/net/tsaddr"
"tailscale.com/net/tshttpproxy"
)
@ -248,7 +248,7 @@ func (ifaces List) ForeachInterface(fn func(Interface, []netaddr.IPPrefix)) erro
}
}
sort.Slice(pfxs, func(i, j int) bool {
return pfxs[i].IP().Less(pfxs[j].IP())
return pfxs[i].Addr().Less(pfxs[j].Addr())
})
fn(iface, pfxs)
}
@ -326,7 +326,7 @@ func (s *State) String() string {
fmt.Fprintf(&sb, "%s:[", ifName)
needSpace := false
for _, pfx := range s.InterfaceIPs[ifName] {
if !isInterestingIP(pfx.IP()) {
if !isInterestingIP(pfx.Addr()) {
continue
}
if needSpace {
@ -413,7 +413,7 @@ func filteredIPPs(ipps []netaddr.IPPrefix, useIP IPFilter) []netaddr.IPPrefix {
// TODO: rewrite prefixesEqualFiltered to avoid making copies
x := make([]netaddr.IPPrefix, 0, len(ipps))
for _, ipp := range ipps {
if useIP(ipp.IP()) {
if useIP(ipp.Addr()) {
x = append(x, ipp)
}
}
@ -467,7 +467,7 @@ func (s *State) AnyInterfaceUp() bool {
func hasTailscaleIP(pfxs []netaddr.IPPrefix) bool {
for _, pfx := range pfxs {
if tsaddr.IsTailscaleIP(pfx.IP()) {
if tsaddr.IsTailscaleIP(pfx.Addr()) {
return true
}
}
@ -507,11 +507,11 @@ func GetState() (*State, error) {
return
}
for _, pfx := range pfxs {
if pfx.IP().IsLoopback() {
if pfx.Addr().IsLoopback() {
continue
}
s.HaveV6 = s.HaveV6 || isUsableV6(pfx.IP())
s.HaveV4 = s.HaveV4 || isUsableV4(pfx.IP())
s.HaveV6 = s.HaveV6 || isUsableV6(pfx.Addr())
s.HaveV4 = s.HaveV4 || isUsableV4(pfx.Addr())
}
}); err != nil {
return nil, err
@ -556,7 +556,7 @@ func HTTPOfListener(ln net.Listener) string {
var goodIP string
var privateIP string
ForeachInterfaceAddress(func(i Interface, pfx netaddr.IPPrefix) {
ip := pfx.IP()
ip := pfx.Addr()
if ip.IsPrivate() {
if privateIP == "" {
privateIP = ip.String()
@ -593,8 +593,8 @@ func LikelyHomeRouterIP() (gateway, myIP netaddr.IP, ok bool) {
return
}
ForeachInterfaceAddress(func(i Interface, pfx netaddr.IPPrefix) {
ip := pfx.IP()
if !i.IsUp() || ip.IsZero() || !myIP.IsZero() {
ip := pfx.Addr()
if !i.IsUp() || !ip.IsValid() || myIP.IsValid() {
return
}
if gateway.IsPrivate() && ip.IsPrivate() {
@ -603,7 +603,7 @@ func LikelyHomeRouterIP() (gateway, myIP netaddr.IP, ok bool) {
return
}
})
return gateway, myIP, !myIP.IsZero()
return gateway, myIP, myIP.IsValid()
}
// isUsableV4 reports whether ip is a usable IPv4 address which could
@ -637,7 +637,7 @@ var (
// isInterestingIP.
func anyInterestingIP(pfxs []netaddr.IPPrefix) bool {
for _, pfx := range pfxs {
if isInterestingIP(pfx.IP()) {
if isInterestingIP(pfx.Addr()) {
return true
}
}

@ -19,7 +19,7 @@ import (
"golang.org/x/net/route"
"golang.org/x/sys/unix"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
)
func defaultRoute() (d DefaultRouteDetails, err error) {

@ -13,7 +13,7 @@ import (
"golang.org/x/net/route"
"golang.org/x/sys/unix"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
)
func defaultRoute() (d DefaultRouteDetails, err error) {

@ -10,7 +10,7 @@ import (
"testing"
"go4.org/mem"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/util/lineread"
"tailscale.com/version"
)
@ -80,7 +80,7 @@ func likelyHomeRouterIPDarwinExec() (ret netaddr.IP, ok bool) {
}
return nil
})
return ret, !ret.IsZero()
return ret, ret.IsValid()
}
func TestFetchRoutingTable(t *testing.T) {

@ -21,7 +21,7 @@ import (
"github.com/mdlayher/netlink"
"go4.org/mem"
"golang.org/x/sys/unix"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/syncs"
"tailscale.com/util/lineread"
)
@ -98,7 +98,7 @@ func likelyHomeRouterIPLinux() (ret netaddr.IP, ok bool) {
}
log.Printf("interfaces: failed to read /proc/net/route: %v", err)
}
return ret, !ret.IsZero()
return ret, ret.IsValid()
}
// Android apps don't have permission to read /proc/net/route, at
@ -133,7 +133,7 @@ func likelyHomeRouterIPAndroid() (ret netaddr.IP, ok bool) {
})
cmd.Process.Kill()
cmd.Wait()
return ret, !ret.IsZero()
return ret, ret.IsValid()
}
func defaultRoute() (d DefaultRouteDetails, err error) {

@ -9,7 +9,7 @@ import (
"net"
"testing"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
)
func TestGetState(t *testing.T) {

@ -14,7 +14,7 @@ import (
"golang.org/x/sys/windows"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/tsconst"
)
@ -92,12 +92,12 @@ func likelyHomeRouterIPWindows() (ret netaddr.IP, ok bool) {
}
}
if !ret.IsZero() && !ret.IsPrivate() {
if ret.IsValid() && !ret.IsPrivate() {
// Default route has a non-private gateway
return netaddr.IP{}, false
}
return ret, !ret.IsZero()
return ret, ret.IsValid()
}
// NonTailscaleMTUs returns a map of interface LUID to interface MTU,

@ -0,0 +1,135 @@
// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package netaddr is a transitional package while we finish migrating from inet.af/netaddr
// to Go 1.18's net/netip.
//
// TODO(bradfitz): delete this package eventually. Tracking bug is
// https://github.com/tailscale/tailscale/issues/5162
package netaddr
import (
"math"
"net"
"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 {
return netip.AddrFrom4([4]byte{a, b, c, d})
}
// IPFrom16 returns the IP address given by the bytes in addr, unmapping any
// v6-mapped IPv4 address.
//
// It is equivalent to calling IPv6Raw(addr).Unmap().
func IPFrom16(a [16]byte) IP {
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.
//
// FromStdIP implicitly unmaps IPv6-mapped IPv4 addresses. That is, if
// len(std) == 16 and contains an IPv4 address, only the IPv4 part is
// 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)
if !ok {
return ret, false
}
if ret.Is4In6() {
return ret.Unmap(), true
}
return ret, true
}
// 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) {
ip, ok := FromStdIP(std.IP)
if !ok {
return IPPrefix{}, false
}
if l := len(std.Mask); l != net.IPv4len && l != net.IPv6len {
// Invalid mask.
return IPPrefix{}, false
}
ones, bits := std.Mask.Size()
if ones == 0 && bits == 0 {
// IPPrefix does not support non-contiguous masks.
return IPPrefix{}, false
}
return netip.PrefixFrom(ip, ones), true
}
// 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) {
ip, ok := FromStdIP(stdIP)
if !ok || port < 0 || port > math.MaxUint16 {
return
}
ip = ip.Unmap()
if zone != "" {
if ip.Is4() {
ok = false
return
}
ip = ip.WithZone(zone)
}
return netip.AddrPortFrom(ip, uint16(port)), true
}
func ParseIP(s string) (IP, error) { return netip.ParseAddr(s) }
func ParseIPPrefix(s string) (IPPrefix, error) { return netip.ParsePrefix(s) }
func ParseIPPort(s string) (IPPort, error) { return netip.ParseAddrPort(s) }
func MustParseIP(s string) IP { return netip.MustParseAddr(s) }
func MustParseIPPrefix(s string) IPPrefix { return netip.MustParsePrefix(s) }
func MustParseIPPort(s string) IPPort { return netip.MustParseAddrPort(s) }

@ -16,16 +16,17 @@ import (
"log"
"net"
"net/http"
"net/netip"
"runtime"
"sort"
"sync"
"time"
"github.com/tcnksm/go-httpstat"
"inet.af/netaddr"
"tailscale.com/derp/derphttp"
"tailscale.com/envknob"
"tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
"tailscale.com/net/neterror"
"tailscale.com/net/netns"
"tailscale.com/net/portmapper"
@ -33,6 +34,7 @@ import (
"tailscale.com/syncs"
"tailscale.com/tailcfg"
"tailscale.com/types/logger"
"tailscale.com/types/nettype"
"tailscale.com/types/opt"
"tailscale.com/util/clientmetric"
)
@ -179,6 +181,7 @@ type Client struct {
// STUNConn is the interface required by the netcheck Client when
// reusing an existing UDP connection.
type STUNConn interface {
WriteToUDPAddrPort([]byte, netip.AddrPort) (int, error)
WriteTo([]byte, net.Addr) (int, error)
ReadFrom([]byte) (int, net.Addr, error)
}
@ -234,9 +237,9 @@ func (c *Client) MakeNextReportFull() {
func (c *Client) ReceiveSTUNPacket(pkt []byte, src netaddr.IPPort) {
c.vlogf("received STUN packet from %s", src)
if src.IP().Is4() {
if src.Addr().Is4() {
metricSTUNRecv4.Add(1)
} else if src.IP().Is6() {
} else if src.Addr().Is6() {
metricSTUNRecv6.Add(1)
}
@ -527,7 +530,7 @@ type reportState struct {
hairTimeout chan struct{} // closed on timeout
pc4 STUNConn
pc6 STUNConn
pc4Hair net.PacketConn
pc4Hair nettype.PacketConn
incremental bool // doing a lite, follow-up netcheck
stopProbeCh chan struct{}
waitPortMap sync.WaitGroup
@ -592,9 +595,8 @@ func (rs *reportState) startHairCheckLocked(dst netaddr.IPPort) {
return
}
rs.sentHairCheck = true
ua := dst.UDPAddr()
rs.pc4Hair.WriteTo(stun.Request(rs.hairTX), ua)
rs.c.vlogf("sent haircheck to %v", ua)
rs.pc4Hair.WriteToUDPAddrPort(stun.Request(rs.hairTX), dst)
rs.c.vlogf("sent haircheck to %v", dst)
time.AfterFunc(hairpinCheckTimeout, func() { close(rs.hairTimeout) })
}
@ -643,7 +645,7 @@ func (rs *reportState) stopTimers() {
func (rs *reportState) addNodeLatency(node *tailcfg.DERPNode, ipp netaddr.IPPort, d time.Duration) {
var ipPortStr string
if ipp != (netaddr.IPPort{}) {
ipPortStr = net.JoinHostPort(ipp.IP().String(), fmt.Sprint(ipp.Port()))
ipPortStr = net.JoinHostPort(ipp.Addr().String(), fmt.Sprint(ipp.Port()))
}
rs.mu.Lock()
@ -668,13 +670,13 @@ func (rs *reportState) addNodeLatency(node *tailcfg.DERPNode, ipp netaddr.IPPort
}
switch {
case ipp.IP().Is6():
case ipp.Addr().Is6():
updateLatency(ret.RegionV6Latency, node.RegionID, d)
ret.IPv6 = true
ret.GlobalV6 = ipPortStr
// TODO: track MappingVariesByDestIP for IPv6
// too? Would be sad if so, but who knows.
case ipp.IP().Is4():
case ipp.Addr().Is4():
updateLatency(ret.RegionV4Latency, node.RegionID, d)
ret.IPv4 = true
if rs.gotEP4 == "" {
@ -809,14 +811,14 @@ func (c *Client) GetReport(ctx context.Context, dm *tailcfg.DERPMap) (_ *Report,
// See if IPv6 works at all, or if it's been hard disabled at the
// OS level.
v6udp, err := netns.Listener(c.logf).ListenPacket(ctx, "udp6", "[::1]:0")
v6udp, err := nettype.MakePacketListenerWithNetIP(netns.Listener(c.logf)).ListenPacket(ctx, "udp6", "[::1]:0")
if err == nil {
rs.report.OSHasIPv6 = true
v6udp.Close()
}
// Create a UDP4 socket used for sending to our discovered IPv4 address.
rs.pc4Hair, err = netns.Listener(c.logf).ListenPacket(ctx, "udp4", ":0")
rs.pc4Hair, err = nettype.MakePacketListenerWithNetIP(netns.Listener(c.logf)).ListenPacket(ctx, "udp4", ":0")
if err != nil {
c.logf("udp4: %v", err)
return nil, err
@ -844,7 +846,7 @@ func (c *Client) GetReport(ctx context.Context, dm *tailcfg.DERPMap) (_ *Report,
if f := c.GetSTUNConn4; f != nil {
rs.pc4 = f()
} else {
u4, err := netns.Listener(c.logf).ListenPacket(ctx, "udp4", c.udpBindAddr())
u4, err := nettype.MakePacketListenerWithNetIP(netns.Listener(c.logf)).ListenPacket(ctx, "udp4", c.udpBindAddr())
if err != nil {
c.logf("udp4: %v", err)
return nil, err
@ -857,7 +859,7 @@ func (c *Client) GetReport(ctx context.Context, dm *tailcfg.DERPMap) (_ *Report,
if f := c.GetSTUNConn6; f != nil {
rs.pc6 = f()
} else {
u6, err := netns.Listener(c.logf).ListenPacket(ctx, "udp6", c.udpBindAddr())
u6, err := nettype.MakePacketListenerWithNetIP(netns.Listener(c.logf)).ListenPacket(ctx, "udp6", c.udpBindAddr())
if err != nil {
c.logf("udp6: %v", err)
} else {
@ -1238,7 +1240,7 @@ func (rs *reportState) runProbe(ctx context.Context, dm *tailcfg.DERPMap, probe
}
addr := c.nodeAddr(ctx, node, probe.proto)
if addr == nil {
if !addr.IsValid() {
return
}
@ -1257,7 +1259,7 @@ func (rs *reportState) runProbe(ctx context.Context, dm *tailcfg.DERPMap, probe
switch probe.proto {
case probeIPv4:
metricSTUNSend4.Add(1)
n, err := rs.pc4.WriteTo(req, addr)
n, err := rs.pc4.WriteToUDPAddrPort(req, addr)
if n == len(req) && err == nil || neterror.TreatAsLostUDP(err) {
rs.mu.Lock()
rs.report.IPv4CanSend = true
@ -1265,7 +1267,7 @@ func (rs *reportState) runProbe(ctx context.Context, dm *tailcfg.DERPMap, probe
}
case probeIPv6:
metricSTUNSend6.Add(1)
n, err := rs.pc6.WriteTo(req, addr)
n, err := rs.pc6.WriteToUDPAddrPort(req, addr)
if n == len(req) && err == nil || neterror.TreatAsLostUDP(err) {
rs.mu.Lock()
rs.report.IPv6CanSend = true
@ -1279,26 +1281,26 @@ func (rs *reportState) runProbe(ctx context.Context, dm *tailcfg.DERPMap, probe
// proto is 4 or 6
// If it returns nil, the node is skipped.
func (c *Client) nodeAddr(ctx context.Context, n *tailcfg.DERPNode, proto probeProto) *net.UDPAddr {
func (c *Client) nodeAddr(ctx context.Context, n *tailcfg.DERPNode, proto probeProto) (ap netip.AddrPort) {
port := n.STUNPort
if port == 0 {
port = 3478
}
if port < 0 || port > 1<<16-1 {
return nil
return
}
if n.STUNTestIP != "" {
ip, err := netaddr.ParseIP(n.STUNTestIP)
if err != nil {
return nil
return
}
if proto == probeIPv4 && ip.Is6() {
return nil
return
}
if proto == probeIPv6 && ip.Is4() {
return nil
return
}
return netaddr.IPPortFrom(ip, uint16(port)).UDPAddr()
return netip.AddrPortFrom(ip, uint16(port))
}
switch proto {
@ -1306,30 +1308,31 @@ func (c *Client) nodeAddr(ctx context.Context, n *tailcfg.DERPNode, proto probeP
if n.IPv4 != "" {
ip, _ := netaddr.ParseIP(n.IPv4)
if !ip.Is4() {
return nil
return
}
return netaddr.IPPortFrom(ip, uint16(port)).UDPAddr()
return netip.AddrPortFrom(ip, uint16(port))
}
case probeIPv6:
if n.IPv6 != "" {
ip, _ := netaddr.ParseIP(n.IPv6)
if !ip.Is6() {
return nil
return
}
return netaddr.IPPortFrom(ip, uint16(port)).UDPAddr()
return netip.AddrPortFrom(ip, uint16(port))
}
default:
return nil
return
}
// TODO(bradfitz): add singleflight+dnscache here.
addrs, _ := net.DefaultResolver.LookupIPAddr(ctx, n.HostName)
for _, a := range addrs {
if (a.IP.To4() != nil) == (proto == probeIPv4) {
return &net.UDPAddr{IP: a.IP, Port: port}
na, _ := netaddr.FromStdIP(a.IP.To4())
return netip.AddrPortFrom(na, uint16(port))
}
}
return nil
return
}
func regionHasDERPNode(r *tailcfg.DERPRegion) bool {

@ -16,8 +16,8 @@ import (
"testing"
"time"
"inet.af/netaddr"
"tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
"tailscale.com/net/stun"
"tailscale.com/net/stun/stuntest"
"tailscale.com/tailcfg"

@ -18,7 +18,7 @@ import (
"context"
"net"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/net/netknob"
"tailscale.com/syncs"
"tailscale.com/types/logger"

@ -9,7 +9,7 @@ import (
"errors"
"runtime"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
)
var ErrNotImplemented = errors.New("not implemented for GOOS=" + runtime.GOOS)

@ -13,7 +13,7 @@ import (
"unsafe"
"golang.org/x/sys/windows"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/util/endian"
)

@ -15,8 +15,8 @@ import (
"strconv"
"strings"
"inet.af/netaddr"
"tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
)
// protocolsRequiredForForwarding reports whether IPv4 and/or IPv6 protocols are
@ -31,7 +31,7 @@ func protocolsRequiredForForwarding(routes []netaddr.IPPrefix, state *interfaces
localIPs := make(map[netaddr.IP]bool)
for _, addrs := range state.InterfaceIPs {
for _, pfx := range addrs {
localIPs[pfx.IP()] = true
localIPs[pfx.Addr()] = true
}
}
@ -39,10 +39,10 @@ func protocolsRequiredForForwarding(routes []netaddr.IPPrefix, state *interfaces
// It's possible to advertise a route to one of the local
// machine's local IPs. IP forwarding isn't required for this
// to work, so we shouldn't warn for such exports.
if r.IsSingleIP() && localIPs[r.IP()] {
if r.IsSingleIP() && localIPs[r.Addr()] {
continue
}
if r.IP().Is4() {
if r.Addr().Is4() {
v4 = true
} else {
v6 = true

@ -7,7 +7,7 @@ package packet
import (
"testing"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/types/ipproto"
)

@ -8,7 +8,7 @@ import (
"encoding/binary"
"errors"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/types/ipproto"
)

@ -7,7 +7,7 @@ package packet
import (
"encoding/binary"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/types/ipproto"
)

@ -8,9 +8,10 @@ import (
"encoding/binary"
"fmt"
"net"
"net/netip"
"strings"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/types/ipproto"
)
@ -126,8 +127,8 @@ func (q *Parsed) decode4(b []byte) {
}
// If it's valid IPv4, then the IP addresses are valid
q.Src = q.Src.WithIP(netaddr.IPv4(b[12], b[13], b[14], b[15]))
q.Dst = q.Dst.WithIP(netaddr.IPv4(b[16], b[17], b[18], b[19]))
q.Src = withIP(q.Src, netaddr.IPv4(b[12], b[13], b[14], b[15]))
q.Dst = withIP(q.Dst, netaddr.IPv4(b[16], b[17], b[18], b[19]))
q.subofs = int((b[0] & 0x0F) << 2)
if q.subofs > q.length {
@ -169,8 +170,8 @@ func (q *Parsed) decode4(b []byte) {
q.IPProto = unknown
return
}
q.Src = q.Src.WithPort(0)
q.Dst = q.Dst.WithPort(0)
q.Src = withPort(q.Src, 0)
q.Dst = withPort(q.Dst, 0)
q.dataofs = q.subofs + icmp4HeaderLength
return
case ipproto.IGMP:
@ -182,8 +183,8 @@ func (q *Parsed) decode4(b []byte) {
q.IPProto = unknown
return
}
q.Src = q.Src.WithPort(binary.BigEndian.Uint16(sub[0:2]))
q.Dst = q.Dst.WithPort(binary.BigEndian.Uint16(sub[2:4]))
q.Src = withPort(q.Src, binary.BigEndian.Uint16(sub[0:2]))
q.Dst = withPort(q.Dst, binary.BigEndian.Uint16(sub[2:4]))
q.TCPFlags = TCPFlag(sub[13])
headerLength := (sub[12] & 0xF0) >> 2
q.dataofs = q.subofs + int(headerLength)
@ -193,8 +194,8 @@ func (q *Parsed) decode4(b []byte) {
q.IPProto = unknown
return
}
q.Src = q.Src.WithPort(binary.BigEndian.Uint16(sub[0:2]))
q.Dst = q.Dst.WithPort(binary.BigEndian.Uint16(sub[2:4]))
q.Src = withPort(q.Src, binary.BigEndian.Uint16(sub[0:2]))
q.Dst = withPort(q.Dst, binary.BigEndian.Uint16(sub[2:4]))
q.dataofs = q.subofs + udpHeaderLength
return
case ipproto.SCTP:
@ -202,8 +203,8 @@ func (q *Parsed) decode4(b []byte) {
q.IPProto = unknown
return
}
q.Src = q.Src.WithPort(binary.BigEndian.Uint16(sub[0:2]))
q.Dst = q.Dst.WithPort(binary.BigEndian.Uint16(sub[2:4]))
q.Src = withPort(q.Src, binary.BigEndian.Uint16(sub[0:2]))
q.Dst = withPort(q.Dst, binary.BigEndian.Uint16(sub[2:4]))
return
case ipproto.TSMP:
// Inter-tailscale messages.
@ -251,8 +252,8 @@ func (q *Parsed) decode6(b []byte) {
// always well-formed stdlib IPs.
srcIP, _ := netaddr.FromStdIP(net.IP(b[8:24]))
dstIP, _ := netaddr.FromStdIP(net.IP(b[24:40]))
q.Src = q.Src.WithIP(srcIP)
q.Dst = q.Dst.WithIP(dstIP)
q.Src = withIP(q.Src, srcIP)
q.Dst = withIP(q.Dst, dstIP)
// We don't support any IPv6 extension headers. Don't try to
// be clever. Therefore, the IP subprotocol always starts at
@ -276,16 +277,16 @@ func (q *Parsed) decode6(b []byte) {
q.IPProto = unknown
return
}
q.Src = q.Src.WithPort(0)
q.Dst = q.Dst.WithPort(0)
q.Src = withPort(q.Src, 0)
q.Dst = withPort(q.Dst, 0)
q.dataofs = q.subofs + icmp6HeaderLength
case ipproto.TCP:
if len(sub) < tcpHeaderLength {
q.IPProto = unknown
return
}
q.Src = q.Src.WithPort(binary.BigEndian.Uint16(sub[0:2]))
q.Dst = q.Dst.WithPort(binary.BigEndian.Uint16(sub[2:4]))
q.Src = withPort(q.Src, binary.BigEndian.Uint16(sub[0:2]))
q.Dst = withPort(q.Dst, binary.BigEndian.Uint16(sub[2:4]))
q.TCPFlags = TCPFlag(sub[13])
headerLength := (sub[12] & 0xF0) >> 2
q.dataofs = q.subofs + int(headerLength)
@ -295,16 +296,16 @@ func (q *Parsed) decode6(b []byte) {
q.IPProto = unknown
return
}
q.Src = q.Src.WithPort(binary.BigEndian.Uint16(sub[0:2]))
q.Dst = q.Dst.WithPort(binary.BigEndian.Uint16(sub[2:4]))
q.Src = withPort(q.Src, binary.BigEndian.Uint16(sub[0:2]))
q.Dst = withPort(q.Dst, binary.BigEndian.Uint16(sub[2:4]))
q.dataofs = q.subofs + udpHeaderLength
case ipproto.SCTP:
if len(sub) < sctpHeaderLength {
q.IPProto = unknown
return
}
q.Src = q.Src.WithPort(binary.BigEndian.Uint16(sub[0:2]))
q.Dst = q.Dst.WithPort(binary.BigEndian.Uint16(sub[2:4]))
q.Src = withPort(q.Src, binary.BigEndian.Uint16(sub[0:2]))
q.Dst = withPort(q.Dst, binary.BigEndian.Uint16(sub[2:4]))
return
case ipproto.TSMP:
// Inter-tailscale messages.
@ -324,8 +325,8 @@ func (q *Parsed) IP4Header() IP4Header {
return IP4Header{
IPID: ipid,
IPProto: q.IPProto,
Src: q.Src.IP(),
Dst: q.Dst.IP(),
Src: q.Src.Addr(),
Dst: q.Dst.Addr(),
}
}
@ -337,8 +338,8 @@ func (q *Parsed) IP6Header() IP6Header {
return IP6Header{
IPID: ipid,
IPProto: q.IPProto,
Src: q.Src.IP(),
Dst: q.Dst.IP(),
Src: q.Src.Addr(),
Dst: q.Dst.Addr(),
}
}
@ -488,3 +489,11 @@ func Hexdump(b []byte) string {
}
return out.String()
}
func withIP(ap netip.AddrPort, ip netip.Addr) netip.AddrPort {
return netip.AddrPortFrom(ip, ap.Port())
}
func withPort(ap netip.AddrPort, port uint16) netip.AddrPort {
return netip.AddrPortFrom(ap.Addr(), port)
}

@ -9,7 +9,7 @@ import (
"reflect"
"testing"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/tstest"
"tailscale.com/types/ipproto"
)

@ -15,8 +15,8 @@ import (
"errors"
"fmt"
"inet.af/netaddr"
"tailscale.com/net/flowtrack"
"tailscale.com/net/netaddr"
"tailscale.com/types/ipproto"
)
@ -143,7 +143,7 @@ func (h TailscaleRejectedHeader) Marshal(buf []byte) error {
if len(buf) > maxPacketLength {
return errLargePacket
}
if h.Src.IP().Is4() {
if h.Src.Addr().Is4() {
iph := IP4Header{
IPProto: ipproto.TSMP,
Src: h.IPSrc,
@ -151,7 +151,7 @@ func (h TailscaleRejectedHeader) Marshal(buf []byte) error {
}
iph.Marshal(buf)
buf = buf[ip4HeaderLength:]
} else if h.Src.IP().Is6() {
} else if h.Src.Addr().Is6() {
iph := IP6Header{
IPProto: ipproto.TSMP,
Src: h.IPSrc,
@ -190,10 +190,10 @@ func (pp *Parsed) AsTailscaleRejectedHeader() (h TailscaleRejectedHeader, ok boo
h = TailscaleRejectedHeader{
Proto: ipproto.Proto(p[1]),
Reason: TailscaleRejectReason(p[2]),
IPSrc: pp.Src.IP(),
IPDst: pp.Dst.IP(),
Src: netaddr.IPPortFrom(pp.Dst.IP(), binary.BigEndian.Uint16(p[3:5])),
Dst: netaddr.IPPortFrom(pp.Src.IP(), binary.BigEndian.Uint16(p[5:7])),
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])),
}
if len(p) > 7 {
flags := p[7]

@ -7,7 +7,7 @@ package packet
import (
"testing"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
)
func TestTailscaleRejectedHeader(t *testing.T) {

@ -10,7 +10,7 @@ package portmapper
import (
"context"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
)
type upnpClient any

@ -13,7 +13,7 @@ import (
"sync"
"testing"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/syncs"
"tailscale.com/types/logger"
)
@ -214,10 +214,10 @@ func (d *TestIGD) handlePCPQuery(pkt []byte, src netaddr.IPPort) {
pktSrcBytes := [16]byte{}
copy(pktSrcBytes[:], pkt[8:24])
pktSrc := netaddr.IPFrom16(pktSrcBytes)
if pktSrc != src.IP() {
if pktSrc != src.Addr() {
// TODO this error isn't fatal but should be rejected by server.
// Since it's a test it's difficult to get them the same though.
d.logf("mismatch of packet source and source IP: got %v, expected %v", pktSrc, src.IP())
d.logf("mismatch of packet source and source IP: got %v, expected %v", pktSrc, src.Addr())
}
switch op {
case pcpOpAnnounce:
@ -226,7 +226,7 @@ func (d *TestIGD) handlePCPQuery(pkt []byte, src netaddr.IPPort) {
return
}
resp := buildPCPDiscoResponse(pkt)
if _, err := d.pxpConn.WriteTo(resp, src.UDPAddr()); err != nil {
if _, err := d.pxpConn.WriteTo(resp, net.UDPAddrFromAddrPort(src)); err != nil {
d.inc(&d.counters.numFailedWrites)
}
case pcpOpMap:
@ -240,7 +240,7 @@ func (d *TestIGD) handlePCPQuery(pkt []byte, src netaddr.IPPort) {
return
}
resp := buildPCPMapResponse(pkt)
d.pxpConn.WriteTo(resp, src.UDPAddr())
d.pxpConn.WriteTo(resp, net.UDPAddrFromAddrPort(src))
default:
// unknown op code, ignore it for now.
d.inc(&d.counters.numPCPOtherRecv)

@ -11,7 +11,7 @@ import (
"fmt"
"time"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
)
// References:
@ -69,8 +69,8 @@ func (p *pcpMapping) Release(ctx context.Context) {
return
}
defer uc.Close()
pkt := buildPCPRequestMappingPacket(p.internal.IP(), p.internal.Port(), p.external.Port(), 0, p.external.IP())
uc.WriteTo(pkt, p.gw.UDPAddr())
pkt := buildPCPRequestMappingPacket(p.internal.Addr(), p.internal.Port(), p.external.Port(), 0, p.external.Addr())
uc.WriteToUDPAddrPort(pkt, p.gw)
}
// buildPCPRequestMappingPacket generates a PCP packet with a MAP opcode.

@ -8,7 +8,7 @@ import (
"encoding/binary"
"testing"
"inet.af/netaddr"
"tailscale.com/net/netaddr"
)
var examplePCPMapResponse = []byte{2, 129, 0, 0, 0, 0, 28, 32, 0, 2, 155, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 112, 9, 24, 241, 208, 251, 45, 157, 76, 10, 188, 17, 0, 0, 0, 4, 210, 4, 210, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 135, 180, 175, 246}

@ -14,15 +14,17 @@ import (
"io"
"net"
"net/http"
"net/netip"
"sync"
"time"
"go4.org/mem"
"inet.af/netaddr"
"tailscale.com/net/interfaces"
"tailscale.com/net/netaddr"
"tailscale.com/net/neterror"
"tailscale.com/net/netns"
"tailscale.com/types/logger"
"tailscale.com/types/nettype"
"tailscale.com/util/clientmetric"
)
@ -128,7 +130,7 @@ type pmpMapping struct {
// externalValid reports whether m.external is valid, with both its IP and Port populated.
func (m *pmpMapping) externalValid() bool {
return !m.external.IP().IsZero() && m.external.Port() != 0
return m.external.Addr().IsValid() && m.external.Port() != 0
}
func (p *pmpMapping) GoodUntil() time.Time { return p.goodUntil }
@ -143,7 +145,7 @@ func (m *pmpMapping) Release(ctx context.Context) {
}
defer uc.Close()
pkt := buildPMPRequestMappingPacket(m.internal.Port(), m.external.Port(), pmpMapLifetimeDelete)
uc.WriteTo(pkt, m.gw.UDPAddr())
uc.WriteToUDPAddrPort(pkt, m.gw)
}
// NewClient returns a new portmapping client.
@ -236,7 +238,7 @@ func (c *Client) upnpPort() uint16 {
return upnpDefaultPort
}
func (c *Client) listenPacket(ctx context.Context, network, addr string) (net.PacketConn, error) {
func (c *Client) listenPacket(ctx context.Context, network, addr string) (nettype.PacketConn, error) {
// When running under testing conditions, we bind the IGD server
// to localhost, and may be running in an environment where our
// netns code would decide that binding the portmapper client
@ -251,9 +253,17 @@ func (c *Client) listenPacket(ctx context.Context, network, addr string) (net.Pa
// so we don't care.
if c.testPxPPort != 0 || c.testUPnPPort != 0 {
var lc net.ListenConfig
return lc.ListenPacket(ctx, network, addr)
pc, err := lc.ListenPacket(ctx, network, addr)
if err != nil {
return nil, err
}
return pc.(*net.UDPConn), nil
}
pc, err := netns.Listener(c.logf).ListenPacket(ctx, network, addr)
if err != nil {
return nil, err
}
return netns.Listener(c.logf).ListenPacket(ctx, network, addr)
return pc.(*net.UDPConn), nil
}
func (c *Client) invalidateMappingsLocked(releaseOld bool) {
@ -277,7 +287,7 @@ func (c *Client) sawPMPRecently() bool {
}
func (c *Client) sawPMPRecentlyLocked() bool {
return !c.pmpPubIP.IsZero() && c.pmpPubIPTime.After(time.Now().Add(-trustServiceStillAvailableDuration))
return c.pmpPubIP.IsValid() && c.pmpPubIPTime.After(time.Now().Add(-trustServiceStillAvailableDuration))
}
func (c *Client) sawPCPRecently() bool {
@ -333,6 +343,7 @@ func IsNoMappingError(err error) bool {
var (
ErrNoPortMappingServices = errors.New("no port mapping services were found")
ErrGatewayRange = errors.New("skipping portmap; gateway range likely lacks support")
ErrGatewayIPv6 = errors.New("skipping portmap; no IPv6 support for portmapping")
)
// GetCachedMappingOrStartCreatingOne quickly returns with our current cached portmapping, if any.
@ -401,6 +412,9 @@ func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPor
if !ok {
return netaddr.IPPort{}, NoMappingError{ErrGatewayRange}
}
if gw.Is6() {
return netaddr.IPPort{}, NoMappingError{ErrGatewayIPv6}
}
c.mu.Lock()
localPort := c.localPort
@ -447,7 +461,7 @@ func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPor
internal: internalAddr,
}
if haveRecentPMP {
m.external = m.external.WithIP(c.pmpPubIP)
m.external = netip.AddrPortFrom(c.pmpPubIP, m.external.Port())
}
if c.lastProbe.After(now.Add(-5*time.Second)) && !haveRecentPMP && !haveRecentPCP {
c.mu.Unlock()
@ -469,7 +483,6 @@ func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPor
defer closeCloserOnContextDone(ctx, uc)()
pxpAddr := netaddr.IPPortFrom(gw, c.pxpPort())
pxpAddru := pxpAddr.UDPAddr()
preferPCP := !DisablePCP && (DisablePMP || (!haveRecentPMP && haveRecentPCP))
@ -478,7 +491,7 @@ func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPor
// TODO replace wildcardIP here with previous external if known.
// Only do PCP mapping in the case when PMP did not appear to be available recently.
pkt := buildPCPRequestMappingPacket(myIP, localPort, prevPort, pcpMapLifetimeSec, wildcardIP)
if _, err := uc.WriteTo(pkt, pxpAddru); err != nil {
if _, err := uc.WriteToUDPAddrPort(pkt, pxpAddr); err != nil {
if neterror.TreatAsLostUDP(err) {
err = NoMappingError{ErrNoPortMappingServices}
}
@ -486,8 +499,8 @@ func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPor
}
} else {
// Ask for our external address if needed.
if m.external.IP().IsZero() {
if _, err := uc.WriteTo(pmpReqExternalAddrPacket, pxpAddru); err != nil {
if !m.external.Addr().IsValid() {
if _, err := uc.WriteToUDPAddrPort(pmpReqExternalAddrPacket, pxpAddr); err != nil {
if neterror.TreatAsLostUDP(err) {
err = NoMappingError{ErrNoPortMappingServices}
}
@ -496,7 +509,7 @@ func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPor
}
pkt := buildPMPRequestMappingPacket(localPort, prevPort, pmpMapLifetimeSec)
if _, err := uc.WriteTo(pkt, pxpAddru); err != nil {
if _, err := uc.WriteToUDPAddrPort(pkt, pxpAddr); err != nil {
if neterror.TreatAsLostUDP(err) {
err = NoMappingError{ErrNoPortMappingServices}
}
@ -535,10 +548,10 @@ func (c *Client) createOrGetMapping(ctx context.Context) (external netaddr.IPPor
return netaddr.IPPort{}, NoMappingError{fmt.Errorf("PMP response Op=0x%x,Res=0x%x", pres.OpCode, pres.ResultCode)}
}
if pres.OpCode == pmpOpReply|pmpOpMapPublicAddr {
m.external = m.external.WithIP(pres.PublicAddr)
m.external = netip.AddrPortFrom(pres.PublicAddr, m.external.Port())
}
if pres.OpCode == pmpOpReply|pmpOpMapUDP {
m.external = m.external.WithPort(pres.ExternalPort)
m.external = netip.AddrPortFrom(m.external.Addr(), pres.ExternalPort)
d := time.Duration(pres.MappingValidSeconds) * time.Second
now := time.Now()
m.goodUntil = now.Add(d)
@ -688,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()).UDPAddr()
upnpAddr := netaddr.IPPortFrom(gw, c.upnpPort()).UDPAddr()
upnpMulticastAddr := netaddr.IPPortFrom(netaddr.IPv4(239, 255, 255, 250), c.upnpPort()).UDPAddr()
pxpAddr := netaddr.IPPortFrom(gw, c.pxpPort())
upnpAddr := netaddr.IPPortFrom(gw, c.upnpPort())
upnpMulticastAddr := netaddr.IPPortFrom(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
@ -699,13 +712,13 @@ func (c *Client) Probe(ctx context.Context) (res ProbeResult, err error) {
res.PMP = true
} else if !DisablePMP {
metricPMPSent.Add(1)
uc.WriteTo(pmpReqExternalAddrPacket, pxpAddr)
uc.WriteToUDPAddrPort(pmpReqExternalAddrPacket, pxpAddr)
}
if c.sawPCPRecently() {
res.PCP = true
} else if !DisablePCP {
metricPCPSent.Add(1)
uc.WriteTo(pcpAnnounceRequest(myIP), pxpAddr)
uc.WriteToUDPAddrPort(pcpAnnounceRequest(myIP), pxpAddr)
}
if c.sawUPnPRecently() {
res.UPnP = true
@ -756,9 +769,9 @@ func (c *Client) Probe(ctx context.Context) (res ProbeResult, err error) {
// their first descriptor (like urn:schemas-wifialliance-org:device:WFADevice:1)
// in response to ssdp:all. https://github.com/tailscale/tailscale/issues/3557
metricUPnPSent.Add(1)
uc.WriteTo(uPnPPacket, upnpAddr)
uc.WriteTo(uPnPPacket, upnpMulticastAddr)
uc.WriteTo(uPnPIGDPacket, upnpMulticastAddr)
uc.WriteToUDPAddrPort(uPnPPacket, upnpAddr)
uc.WriteToUDPAddrPort(uPnPPacket, upnpMulticastAddr)
uc.WriteToUDPAddrPort(uPnPIGDPacket, upnpMulticastAddr)
}
buf := make([]byte, 1500)

@ -116,7 +116,7 @@ func TestPCPIntegration(t *testing.T) {
if err != nil {
t.Fatalf("failed to get mapping: %v", err)
}
if external.IsZero() {
if !external.IsValid() {
t.Errorf("got zero IP, expected non-zero")
}
if c.mapping == nil {

@ -22,8 +22,8 @@ import (
"github.com/tailscale/goupnp"
"github.com/tailscale/goupnp/dcps/internetgateway2"
"inet.af/netaddr"
"tailscale.com/control/controlknobs"
"tailscale.com/net/netaddr"
"tailscale.com/net/netns"
"tailscale.com/types/logger"
)
@ -174,7 +174,7 @@ func getUPnPClient(ctx context.Context, logf logger.Logf, gw netaddr.IP, meta uP
if err != nil {
return nil, fmt.Errorf("unexpected host %q in %q", u.Host, meta.Location)
}
if ipp.IP() != gw {
if ipp.Addr() != gw {
return nil, fmt.Errorf("UPnP discovered root %q does not match gateway IP %v; ignoring UPnP",
meta.Location, gw)
}
@ -274,7 +274,7 @@ func (c *Client) getUPnPPortMapping(
client,
prevPort,
internal.Port(),
internal.IP().String(),
internal.Addr().String(),
time.Second*pmpMapLifetimeSec,
)
if VerboseLogs {

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

Loading…
Cancel
Save