all: adapt to opaque netaddr types

This commit is a mishmash of automated edits using gofmt:

gofmt -r 'netaddr.IPPort{IP: a, Port: b} -> netaddr.IPPortFrom(a, b)' -w .
gofmt -r 'netaddr.IPPrefix{IP: a, Port: b} -> netaddr.IPPrefixFrom(a, b)' -w .

gofmt -r 'a.IP.Is4 -> a.IP().Is4' -w .
gofmt -r 'a.IP.As16 -> a.IP().As16' -w .
gofmt -r 'a.IP.Is6 -> a.IP().Is6' -w .
gofmt -r 'a.IP.As4 -> a.IP().As4' -w .
gofmt -r 'a.IP.String -> a.IP().String' -w .

And regexps:

\w*(.*)\.Port = (.*)  ->  $1 = $1.WithPort($2)
\w*(.*)\.IP = (.*)  ->  $1 = $1.WithIP($2)

And lots of manual fixups.

Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Xe/synology-does-actually-work-with-subnet-routes-til
Josh Bleecher Snyder 4 years ago committed by Josh Bleecher Snyder
parent 4f92f405ee
commit 25df067dd0

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

@ -194,7 +194,7 @@ func discoverPeerAPIBase(ctx context.Context, ipStr string) (base string, lastSe
for _, ft := range fts { for _, ft := range fts {
n := ft.Node n := ft.Node
for _, a := range n.Addresses { for _, a := range n.Addresses {
if a.IP != ip { if a.IP() != ip {
continue continue
} }
if n.LastSeen != nil { if n.LastSeen != nil {
@ -301,7 +301,7 @@ func runCpTargets(ctx context.Context, args []string) error {
if detail != "" { if detail != "" {
detail = "\t" + detail detail = "\t" + detail
} }
fmt.Printf("%s\t%s%s\n", n.Addresses[0].IP, n.ComputedName, detail) fmt.Printf("%s\t%s%s\n", n.Addresses[0].IP(), n.ComputedName, detail)
} }
return nil return nil
} }

@ -164,10 +164,10 @@ func prefsFromUpArgs(upArgs upArgsT, warnf logger.Logf, st *ipnstate.Status, goo
routes = append(routes, r) routes = append(routes, r)
} }
sort.Slice(routes, func(i, j int) bool { sort.Slice(routes, func(i, j int) bool {
if routes[i].Bits != routes[j].Bits { if routes[i].Bits() != routes[j].Bits() {
return routes[i].Bits < routes[j].Bits return routes[i].Bits() < routes[j].Bits()
} }
return routes[i].IP.Less(routes[j].IP) return routes[i].IP().Less(routes[j].IP())
}) })
var exitNodeIP netaddr.IP var exitNodeIP netaddr.IP
@ -723,10 +723,10 @@ func fmtFlagValueArg(flagName string, val interface{}) string {
func hasExitNodeRoutes(rr []netaddr.IPPrefix) bool { func hasExitNodeRoutes(rr []netaddr.IPPrefix) bool {
var v4, v6 bool var v4, v6 bool
for _, r := range rr { for _, r := range rr {
if r.Bits == 0 { if r.Bits() == 0 {
if r.IP.Is4() { if r.IP().Is4() {
v4 = true v4 = true
} else if r.IP.Is6() { } else if r.IP().Is6() {
v6 = true v6 = true
} }
} }
@ -743,7 +743,7 @@ func withoutExitNodes(rr []netaddr.IPPrefix) []netaddr.IPPrefix {
} }
var out []netaddr.IPPrefix var out []netaddr.IPPrefix
for _, r := range rr { for _, r := range rr {
if r.Bits > 0 { if r.Bits() > 0 {
out = append(out, r) out = append(out, r)
} }
} }

@ -266,7 +266,7 @@ func run() error {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if ns != nil && useNetstackForIP(ipp.IP) { if ns != nil && useNetstackForIP(ipp.IP()) {
return ns.DialContextTCP(ctx, addr) return ns.DialContextTCP(ctx, addr)
} }
var d net.Dialer var d net.Dialer

@ -1091,7 +1091,7 @@ func ipForwardingBroken(routes []netaddr.IPPrefix, state *interfaces.State) bool
localIPs := map[netaddr.IP]bool{} localIPs := map[netaddr.IP]bool{}
for _, addrs := range state.InterfaceIPs { for _, addrs := range state.InterfaceIPs {
for _, pfx := range addrs { for _, pfx := range addrs {
localIPs[pfx.IP] = true localIPs[pfx.IP()] = true
} }
} }
@ -1100,10 +1100,10 @@ func ipForwardingBroken(routes []netaddr.IPPrefix, state *interfaces.State) bool
// It's possible to advertise a route to one of the local // It's possible to advertise a route to one of the local
// machine's local IPs. IP forwarding isn't required for this // machine's local IPs. IP forwarding isn't required for this
// to work, so we shouldn't warn for such exports. // to work, so we shouldn't warn for such exports.
if r.IsSingleIP() && localIPs[r.IP] { if r.IsSingleIP() && localIPs[r.IP()] {
continue continue
} }
if r.IP.Is4() { if r.IP().Is4() {
v4Routes = true v4Routes = true
} else { } else {
v6Routes = true v6Routes = true

@ -86,7 +86,7 @@ func TestNewDirect(t *testing.T) {
func fakeEndpoints(ports ...uint16) (ret []tailcfg.Endpoint) { func fakeEndpoints(ports ...uint16) (ret []tailcfg.Endpoint) {
for _, port := range ports { for _, port := range ports {
ret = append(ret, tailcfg.Endpoint{ ret = append(ret, tailcfg.Endpoint{
Addr: netaddr.IPPort{Port: port}, Addr: netaddr.IPPortFrom(netaddr.IP{}, port),
}) })
} }
return return

@ -147,9 +147,9 @@ const epLength = 16 + 2 // 16 byte IP address + 2 byte port
func (m *CallMeMaybe) AppendMarshal(b []byte) []byte { func (m *CallMeMaybe) AppendMarshal(b []byte) []byte {
ret, p := appendMsgHeader(b, TypeCallMeMaybe, v0, epLength*len(m.MyNumber)) ret, p := appendMsgHeader(b, TypeCallMeMaybe, v0, epLength*len(m.MyNumber))
for _, ipp := range m.MyNumber { for _, ipp := range m.MyNumber {
a := ipp.IP.As16() a := ipp.IP().As16()
copy(p[:], a[:]) copy(p[:], a[:])
binary.BigEndian.PutUint16(p[16:], ipp.Port) binary.BigEndian.PutUint16(p[16:], ipp.Port())
p = p[epLength:] p = p[epLength:]
} }
return ret return ret
@ -164,10 +164,9 @@ func parseCallMeMaybe(ver uint8, p []byte) (m *CallMeMaybe, err error) {
for len(p) > 0 { for len(p) > 0 {
var a [16]byte var a [16]byte
copy(a[:], p) copy(a[:], p)
m.MyNumber = append(m.MyNumber, netaddr.IPPort{ m.MyNumber = append(m.MyNumber, netaddr.IPPortFrom(
IP: netaddr.IPFrom16(a), netaddr.IPFrom16(a),
Port: binary.BigEndian.Uint16(p[16:18]), binary.BigEndian.Uint16(p[16:18])))
})
p = p[epLength:] p = p[epLength:]
} }
return m, nil return m, nil
@ -187,9 +186,9 @@ const pongLen = 12 + 16 + 2
func (m *Pong) AppendMarshal(b []byte) []byte { func (m *Pong) AppendMarshal(b []byte) []byte {
ret, d := appendMsgHeader(b, TypePong, v0, pongLen) ret, d := appendMsgHeader(b, TypePong, v0, pongLen)
d = d[copy(d, m.TxID[:]):] d = d[copy(d, m.TxID[:]):]
ip16 := m.Src.IP.As16() ip16 := m.Src.IP().As16()
d = d[copy(d, ip16[:]):] d = d[copy(d, ip16[:]):]
binary.BigEndian.PutUint16(d, m.Src.Port) binary.BigEndian.PutUint16(d, m.Src.Port())
return ret return ret
} }
@ -201,10 +200,10 @@ func parsePong(ver uint8, p []byte) (m *Pong, err error) {
copy(m.TxID[:], p) copy(m.TxID[:], p)
p = p[12:] p = p[12:]
m.Src.IP, _ = netaddr.FromStdIP(net.IP(p[:16])) srcIP, _ := netaddr.FromStdIP(net.IP(p[:16]))
p = p[16:] p = p[16:]
port := binary.BigEndian.Uint16(p)
m.Src.Port = binary.BigEndian.Uint16(p) m.Src = netaddr.IPPortFrom(srcIP, port)
return m, nil return m, nil
} }

@ -40,10 +40,10 @@ require (
golang.zx2c4.com/wireguard/windows v0.1.2-0.20201113162609-9b85be97fdf8 golang.zx2c4.com/wireguard/windows v0.1.2-0.20201113162609-9b85be97fdf8
gopkg.in/yaml.v2 v2.2.8 // indirect gopkg.in/yaml.v2 v2.2.8 // indirect
honnef.co/go/tools v0.1.0 honnef.co/go/tools v0.1.0
inet.af/netaddr v0.0.0-20210511181906-37180328850c inet.af/netaddr v0.0.0-20210515010201-ad03edc7c841
inet.af/netstack v0.0.0-20210317161235-a1bf4e56ef22 inet.af/netstack v0.0.0-20210317161235-a1bf4e56ef22
inet.af/peercred v0.0.0-20210302202138-56e694897155 inet.af/peercred v0.0.0-20210302202138-56e694897155
inet.af/wf v0.0.0-20210424212123-eaa011a774a4 inet.af/wf v0.0.0-20210516214145-a5343001b756
rsc.io/goversion v1.2.0 rsc.io/goversion v1.2.0
) )

@ -258,11 +258,17 @@ inet.af/netaddr v0.0.0-20210508014949-da1c2a70a83d h1:9tuJMxDV7THGfXWirKBD/v9rbs
inet.af/netaddr v0.0.0-20210508014949-da1c2a70a83d/go.mod h1:z0nx+Dh+7N7CC8V5ayHtHGpZpxLQZZxkIaaz6HN65Ls= inet.af/netaddr v0.0.0-20210508014949-da1c2a70a83d/go.mod h1:z0nx+Dh+7N7CC8V5ayHtHGpZpxLQZZxkIaaz6HN65Ls=
inet.af/netaddr v0.0.0-20210511181906-37180328850c h1:rzDy/tC8LjEdN94+i0Bu22tTo/qE9cvhKyfD0HMU0NU= inet.af/netaddr v0.0.0-20210511181906-37180328850c h1:rzDy/tC8LjEdN94+i0Bu22tTo/qE9cvhKyfD0HMU0NU=
inet.af/netaddr v0.0.0-20210511181906-37180328850c/go.mod h1:z0nx+Dh+7N7CC8V5ayHtHGpZpxLQZZxkIaaz6HN65Ls= inet.af/netaddr v0.0.0-20210511181906-37180328850c/go.mod h1:z0nx+Dh+7N7CC8V5ayHtHGpZpxLQZZxkIaaz6HN65Ls=
inet.af/netaddr v0.0.0-20210515010201-ad03edc7c841 h1:2HpK+rC0Arcu98JukIlyVfEaE2OsvtmBFc8rs/2SJYs=
inet.af/netaddr v0.0.0-20210515010201-ad03edc7c841/go.mod h1:z0nx+Dh+7N7CC8V5ayHtHGpZpxLQZZxkIaaz6HN65Ls=
inet.af/netstack v0.0.0-20210317161235-a1bf4e56ef22 h1:DNtszwGa6w76qlIr+PbPEnlBJdiRV8SaxeigOy0q1gg= inet.af/netstack v0.0.0-20210317161235-a1bf4e56ef22 h1:DNtszwGa6w76qlIr+PbPEnlBJdiRV8SaxeigOy0q1gg=
inet.af/netstack v0.0.0-20210317161235-a1bf4e56ef22/go.mod h1:GVx+5OZtbG4TVOW5ilmyRZAZXr1cNwfqUEkTOtWK0PM= inet.af/netstack v0.0.0-20210317161235-a1bf4e56ef22/go.mod h1:GVx+5OZtbG4TVOW5ilmyRZAZXr1cNwfqUEkTOtWK0PM=
inet.af/peercred v0.0.0-20210302202138-56e694897155 h1:KojYNEYqDkZ2O3LdyTstR1l13L3ePKTIEM2h7ONkfkE= inet.af/peercred v0.0.0-20210302202138-56e694897155 h1:KojYNEYqDkZ2O3LdyTstR1l13L3ePKTIEM2h7ONkfkE=
inet.af/peercred v0.0.0-20210302202138-56e694897155/go.mod h1:FjawnflS/udxX+SvpsMgZfdqx2aykOlkISeAsADi5IU= inet.af/peercred v0.0.0-20210302202138-56e694897155/go.mod h1:FjawnflS/udxX+SvpsMgZfdqx2aykOlkISeAsADi5IU=
inet.af/wf v0.0.0-20210424212123-eaa011a774a4 h1:g1VVXY1xRKoO17aKY3g9KeJxDW0lGx1n2Y+WPSWkOL8= inet.af/wf v0.0.0-20210424212123-eaa011a774a4 h1:g1VVXY1xRKoO17aKY3g9KeJxDW0lGx1n2Y+WPSWkOL8=
inet.af/wf v0.0.0-20210424212123-eaa011a774a4/go.mod h1:56/0QVlZ4NmPRh1QuU2OfrKqjSgt5P39R534gD2JMpQ= inet.af/wf v0.0.0-20210424212123-eaa011a774a4/go.mod h1:56/0QVlZ4NmPRh1QuU2OfrKqjSgt5P39R534gD2JMpQ=
inet.af/wf v0.0.0-20210515021317-09f8efa8ac30 h1:TLxVVv7rmErJW7l81tbbR2BkOIYBI3YdxbJbEs/HJt8=
inet.af/wf v0.0.0-20210515021317-09f8efa8ac30/go.mod h1:ViGMZRA6+RA318D7GCncrjv5gHUrPYrNDejjU12tikA=
inet.af/wf v0.0.0-20210516214145-a5343001b756 h1:muIT3C1rH3/xpvIH8blKkMvhctV7F+OtZqs7kcwHDBQ=
inet.af/wf v0.0.0-20210516214145-a5343001b756/go.mod h1:ViGMZRA6+RA318D7GCncrjv5gHUrPYrNDejjU12tikA=
rsc.io/goversion v1.2.0 h1:SPn+NLTiAG7w30IRK/DKp1BjvpWabYgxlLp/+kx5J8w= rsc.io/goversion v1.2.0 h1:SPn+NLTiAG7w30IRK/DKp1BjvpWabYgxlLp/+kx5J8w=
rsc.io/goversion v1.2.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo= rsc.io/goversion v1.2.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo=

@ -33,7 +33,7 @@ func getVal() []interface{} {
return []interface{}{ return []interface{}{
&wgcfg.Config{ &wgcfg.Config{
Name: "foo", Name: "foo",
Addresses: []netaddr.IPPrefix{{Bits: 5, IP: netaddr.IPFrom16([16]byte{3: 3})}}, Addresses: []netaddr.IPPrefix{netaddr.IPPrefixFrom(netaddr.IPFrom16([16]byte{3: 3}), 5)},
Peers: []wgcfg.Peer{ Peers: []wgcfg.Peer{
{ {
Endpoints: wgcfg.Endpoints{ Endpoints: wgcfg.Endpoints{

@ -356,14 +356,14 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
var tailAddr4 string var tailAddr4 string
var tailscaleIPs = make([]netaddr.IP, 0, len(p.Addresses)) var tailscaleIPs = make([]netaddr.IP, 0, len(p.Addresses))
for _, addr := range p.Addresses { for _, addr := range p.Addresses {
if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.IP) { if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.IP()) {
if addr.IP.Is4() && tailAddr4 == "" { if addr.IP().Is4() && tailAddr4 == "" {
// The peer struct previously only allowed a single // The peer struct previously only allowed a single
// Tailscale IP address. For compatibility for a few releases starting // Tailscale IP address. For compatibility for a few releases starting
// with 1.8, keep it pulled out as IPv4-only for a bit. // with 1.8, keep it pulled out as IPv4-only for a bit.
tailAddr4 = addr.IP.String() tailAddr4 = addr.IP().String()
} }
tailscaleIPs = append(tailscaleIPs, addr.IP) tailscaleIPs = append(tailscaleIPs, addr.IP())
} }
} }
sb.AddPeer(key.Public(p.Key), &ipnstate.PeerStatus{ sb.AddPeer(key.Public(p.Key), &ipnstate.PeerStatus{
@ -390,10 +390,10 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
func (b *LocalBackend) WhoIs(ipp netaddr.IPPort) (n *tailcfg.Node, u tailcfg.UserProfile, ok bool) { func (b *LocalBackend) WhoIs(ipp netaddr.IPPort) (n *tailcfg.Node, u tailcfg.UserProfile, ok bool) {
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()
n, ok = b.nodeByAddr[ipp.IP] n, ok = b.nodeByAddr[ipp.IP()]
if !ok { if !ok {
var ip netaddr.IP var ip netaddr.IP
if ipp.Port != 0 { if ipp.Port() != 0 {
ip, ok = b.e.WhoIsIPPort(ipp) ip, ok = b.e.WhoIsIPPort(ipp)
} }
if !ok { if !ok {
@ -552,7 +552,7 @@ func (b *LocalBackend) findExitNodeIDLocked(nm *netmap.NetworkMap) (prefsChanged
for _, peer := range nm.Peers { for _, peer := range nm.Peers {
for _, addr := range peer.Addresses { for _, addr := range peer.Addresses {
if !addr.IsSingleIP() || addr.IP != b.prefs.ExitNodeIP { if !addr.IsSingleIP() || addr.IP() != b.prefs.ExitNodeIP {
continue continue
} }
// Found the node being referenced, upgrade prefs to // Found the node being referenced, upgrade prefs to
@ -891,7 +891,7 @@ func (b *LocalBackend) updateFilter(netMap *netmap.NetworkMap, prefs *ipn.Prefs)
} }
if prefs != nil { if prefs != nil {
for _, r := range prefs.AdvertiseRoutes { for _, r := range prefs.AdvertiseRoutes {
if r.Bits == 0 { if r.Bits() == 0 {
// When offering a default route to the world, we // When offering a default route to the world, we
// filter out locally reachable LANs, so that the // filter out locally reachable LANs, so that the
// default route effectively appears to be a "guest // default route effectively appears to be a "guest
@ -959,13 +959,13 @@ var removeFromDefaultRoute = []netaddr.IPPrefix{
func interfaceRoutes() (ips *netaddr.IPSet, hostIPs []netaddr.IP, err error) { func interfaceRoutes() (ips *netaddr.IPSet, hostIPs []netaddr.IP, err error) {
var b netaddr.IPSetBuilder var b netaddr.IPSetBuilder
if err := interfaces.ForeachInterfaceAddress(func(_ interfaces.Interface, pfx netaddr.IPPrefix) { if err := interfaces.ForeachInterfaceAddress(func(_ interfaces.Interface, pfx netaddr.IPPrefix) {
if tsaddr.IsTailscaleIP(pfx.IP) { if tsaddr.IsTailscaleIP(pfx.IP()) {
return return
} }
if pfx.IsSingleIP() { if pfx.IsSingleIP() {
return return
} }
hostIPs = append(hostIPs, pfx.IP) hostIPs = append(hostIPs, pfx.IP())
b.AddPrefix(pfx) b.AddPrefix(pfx)
}); err != nil { }); err != nil {
return nil, nil, err return nil, nil, err
@ -1751,10 +1751,10 @@ func (b *LocalBackend) authReconfig() {
// https://github.com/tailscale/tailscale/issues/1152 // https://github.com/tailscale/tailscale/issues/1152
// tracks adding the right capability reporting to // tracks adding the right capability reporting to
// enable AAAA in MagicDNS. // enable AAAA in MagicDNS.
if addr.IP.Is6() { if addr.IP().Is6() {
continue continue
} }
ips = append(ips, addr.IP) ips = append(ips, addr.IP())
} }
dcfg.Hosts[fqdn] = ips dcfg.Hosts[fqdn] = ips
} }
@ -1809,10 +1809,7 @@ func parseResolver(cfg tailcfg.DNSResolver) (netaddr.IPPort, error) {
if err != nil { if err != nil {
return netaddr.IPPort{}, fmt.Errorf("[unexpected] non-IP resolver %q", cfg.Addr) return netaddr.IPPort{}, fmt.Errorf("[unexpected] non-IP resolver %q", cfg.Addr)
} }
return netaddr.IPPort{ return netaddr.IPPortFrom(ip, 53), nil
IP: ip,
Port: 53,
}, nil
} }
// tailscaleVarRoot returns the root directory of Tailscale's writable // tailscaleVarRoot returns the root directory of Tailscale's writable
@ -1870,7 +1867,7 @@ func (b *LocalBackend) initPeerAPIListener() {
if len(b.netMap.Addresses) == len(b.peerAPIListeners) { if len(b.netMap.Addresses) == len(b.peerAPIListeners) {
allSame := true allSame := true
for i, pln := range b.peerAPIListeners { for i, pln := range b.peerAPIListeners {
if pln.ip != b.netMap.Addresses[i].IP { if pln.ip != b.netMap.Addresses[i].IP() {
allSame = false allSame = false
break break
} }
@ -1915,7 +1912,7 @@ func (b *LocalBackend) initPeerAPIListener() {
var err error var err error
skipListen := i > 0 && isNetstack skipListen := i > 0 && isNetstack
if !skipListen { if !skipListen {
ln, err = ps.listen(a.IP, b.prevIfState) ln, err = ps.listen(a.IP(), b.prevIfState)
if err != nil { if err != nil {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
// Expected for now. See Issue 1620. // Expected for now. See Issue 1620.
@ -1929,7 +1926,7 @@ func (b *LocalBackend) initPeerAPIListener() {
} }
pln := &peerAPIListener{ pln := &peerAPIListener{
ps: ps, ps: ps,
ip: a.IP, ip: a.IP(),
ln: ln, // nil for 2nd+ on netstack ln: ln, // nil for 2nd+ on netstack
lb: b, lb: b,
} }
@ -1938,7 +1935,7 @@ func (b *LocalBackend) initPeerAPIListener() {
} else { } else {
pln.port = ln.Addr().(*net.TCPAddr).Port 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.IP().String(), strconv.Itoa(pln.port))
b.logf("peerapi: serving on %s", pln.urlStr) b.logf("peerapi: serving on %s", pln.urlStr)
go pln.serve() go pln.serve()
b.peerAPIListeners = append(b.peerAPIListeners, pln) b.peerAPIListeners = append(b.peerAPIListeners, pln)
@ -1989,14 +1986,14 @@ func peerRoutes(peers []wgcfg.Peer, cgnatThreshold int) (routes []netaddr.IPPref
for _, aip := range peer.AllowedIPs { for _, aip := range peer.AllowedIPs {
aip = unmapIPPrefix(aip) aip = unmapIPPrefix(aip)
// Only add the Tailscale IPv6 ULA once, if we see anybody using part of it. // 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.IP().Is6() && aip.IsSingleIP() && tsULA.Contains(aip.IP()) {
if !didULA { if !didULA {
didULA = true didULA = true
routes = append(routes, tsULA) routes = append(routes, tsULA)
} }
continue continue
} }
if aip.IsSingleIP() && cgNAT.Contains(aip.IP) { if aip.IsSingleIP() && cgNAT.Contains(aip.IP()) {
cgNATIPs = append(cgNATIPs, aip) cgNATIPs = append(cgNATIPs, aip)
} else { } else {
routes = append(routes, aip) routes = append(routes, aip)
@ -2063,16 +2060,13 @@ func (b *LocalBackend) routerConfig(cfg *wgcfg.Config, prefs *ipn.Prefs) *router
} }
} }
rs.Routes = append(rs.Routes, netaddr.IPPrefix{ rs.Routes = append(rs.Routes, netaddr.IPPrefixFrom(tsaddr.TailscaleServiceIP(), 32))
IP: tsaddr.TailscaleServiceIP(),
Bits: 32,
})
return rs return rs
} }
func unmapIPPrefix(ipp netaddr.IPPrefix) netaddr.IPPrefix { func unmapIPPrefix(ipp netaddr.IPPrefix) netaddr.IPPrefix {
return netaddr.IPPrefix{IP: ipp.IP.Unmap(), Bits: ipp.Bits} return netaddr.IPPrefixFrom(ipp.IP().Unmap(), ipp.Bits())
} }
func unmapIPPrefixes(ippsList ...[]netaddr.IPPrefix) (ret []netaddr.IPPrefix) { func unmapIPPrefixes(ippsList ...[]netaddr.IPPrefix) (ret []netaddr.IPPrefix) {
@ -2156,7 +2150,7 @@ func (b *LocalBackend) enterState(newState ipn.State) {
case ipn.Running: case ipn.Running:
var addrs []string var addrs []string
for _, addr := range b.netMap.Addresses { for _, addr := range b.netMap.Addresses {
addrs = append(addrs, addr.IP.String()) addrs = append(addrs, addr.IP().String())
} }
systemd.Status("Connected; %s; %s", activeLogin, strings.Join(addrs, " ")) systemd.Status("Connected; %s; %s", activeLogin, strings.Join(addrs, " "))
default: default:
@ -2424,7 +2418,7 @@ func (b *LocalBackend) setNetMapLocked(nm *netmap.NetworkMap) {
addNode := func(n *tailcfg.Node) { addNode := func(n *tailcfg.Node) {
for _, ipp := range n.Addresses { for _, ipp := range n.Addresses {
if ipp.IsSingleIP() { if ipp.IsSingleIP() {
b.nodeByAddr[ipp.IP] = n b.nodeByAddr[ipp.IP()] = n
} }
} }
} }
@ -2576,9 +2570,9 @@ func peerAPIBase(nm *netmap.NetworkMap, peer *tailcfg.Node) string {
continue continue
} }
switch { switch {
case a.IP.Is4(): case a.IP().Is4():
have4 = true have4 = true
case a.IP.Is6(): case a.IP().Is6():
have6 = true have6 = true
} }
} }
@ -2594,11 +2588,11 @@ func peerAPIBase(nm *netmap.NetworkMap, peer *tailcfg.Node) string {
var ipp netaddr.IPPort var ipp netaddr.IPPort
switch { switch {
case have4 && p4 != 0: case have4 && p4 != 0:
ipp = netaddr.IPPort{IP: nodeIP(peer, netaddr.IP.Is4), Port: p4} ipp = netaddr.IPPortFrom(nodeIP(peer, netaddr.IP.Is4), p4)
case have6 && p6 != 0: case have6 && p6 != 0:
ipp = netaddr.IPPort{IP: nodeIP(peer, netaddr.IP.Is6), Port: p6} ipp = netaddr.IPPortFrom(nodeIP(peer, netaddr.IP.Is6), p6)
} }
if ipp.IP.IsZero() { if ipp.IP().IsZero() {
return "" return ""
} }
return fmt.Sprintf("http://%v", ipp) return fmt.Sprintf("http://%v", ipp)
@ -2606,8 +2600,8 @@ func peerAPIBase(nm *netmap.NetworkMap, peer *tailcfg.Node) string {
func nodeIP(n *tailcfg.Node, pred func(netaddr.IP) bool) netaddr.IP { func nodeIP(n *tailcfg.Node, pred func(netaddr.IP) bool) netaddr.IP {
for _, a := range n.Addresses { for _, a := range n.Addresses {
if a.IsSingleIP() && pred(a.IP) { if a.IsSingleIP() && pred(a.IP()) {
return a.IP return a.IP()
} }
} }
return netaddr.IP{} return netaddr.IP{}

@ -171,7 +171,7 @@ func TestShrinkDefaultRoute(t *testing.T) {
out: []string{ out: []string{
"fe80::1", "fe80::1",
"ff00::1", "ff00::1",
tsaddr.TailscaleULARange().IP.String(), tsaddr.TailscaleULARange().IP().String(),
}, },
localIPFn: func(ip netaddr.IP) bool { return !inRemove(ip) && ip.Is6() }, localIPFn: func(ip netaddr.IP) bool { return !inRemove(ip) && ip.Is6() },
}, },

@ -510,7 +510,7 @@ func (h *peerAPIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
<body> <body>
<h1>Hello, %s (%v)</h1> <h1>Hello, %s (%v)</h1>
This is my Tailscale device. Your device is %v. 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.IP(), html.EscapeString(h.peerNode.ComputedName))
if h.isSelf { if h.isSelf {
fmt.Fprintf(w, "<p>You are the owner of this node.\n") fmt.Fprintf(w, "<p>You are the owner of this node.\n")

@ -147,7 +147,7 @@ func (s *server) getConnIdentity(c net.Conn) (ci connIdentity, err error) {
if err != nil { if err != nil {
return ci, fmt.Errorf("parsing local remote: %w", err) return ci, fmt.Errorf("parsing local remote: %w", err)
} }
if !la.IP.IsLoopback() || !ra.IP.IsLoopback() { if !la.IP().IsLoopback() || !ra.IP().IsLoopback() {
return ci, errors.New("non-loopback connection") return ci, errors.New("non-loopback connection")
} }
tab, err := netstat.Get() tab, err := netstat.Get()

@ -211,7 +211,7 @@ func (m *Manager) compileConfig(cfg Config) (resolver.Config, OSConfig, error) {
func toIPsOnly(ipps []netaddr.IPPort) (ret []netaddr.IP) { func toIPsOnly(ipps []netaddr.IPPort) (ret []netaddr.IP) {
ret = make([]netaddr.IP, 0, len(ipps)) ret = make([]netaddr.IP, 0, len(ipps))
for _, ipp := range ipps { for _, ipp := range ipps {
ret = append(ret, ipp.IP) ret = append(ret, ipp.IP())
} }
return ret return ret
} }
@ -219,7 +219,7 @@ func toIPsOnly(ipps []netaddr.IPPort) (ret []netaddr.IP) {
func toIPPorts(ips []netaddr.IP) (ret []netaddr.IPPort) { func toIPPorts(ips []netaddr.IP) (ret []netaddr.IPPort) {
ret = make([]netaddr.IPPort, 0, len(ips)) ret = make([]netaddr.IPPort, 0, len(ips))
for _, ip := range ips { for _, ip := range ips {
ret = append(ret, netaddr.IPPort{IP: ip, Port: 53}) ret = append(ret, netaddr.IPPortFrom(ip, 53))
} }
return ret return ret
} }

@ -368,11 +368,12 @@ func TestManager(t *testing.T) {
if err := m.Set(test.in); err != nil { if err := m.Set(test.in); err != nil {
t.Fatalf("m.Set: %v", err) t.Fatalf("m.Set: %v", err)
} }
tr := cmp.Transformer("ipStr", func(ip netaddr.IP) string { return ip.String() }) trIP := cmp.Transformer("ipStr", func(ip netaddr.IP) string { return ip.String() })
if diff := cmp.Diff(f.OSConfig, test.os, tr, cmpopts.EquateEmpty()); diff != "" { trIPPort := cmp.Transformer("ippStr", func(ipp netaddr.IPPort) string { return ipp.String() })
if diff := cmp.Diff(f.OSConfig, test.os, trIP, trIPPort, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("wrong OSConfig (-got+want)\n%s", diff) t.Errorf("wrong OSConfig (-got+want)\n%s", diff)
} }
if diff := cmp.Diff(f.ResolverConfig, test.rs, tr, cmpopts.EquateEmpty()); diff != "" { if diff := cmp.Diff(f.ResolverConfig, test.rs, trIP, trIPPort, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("wrong resolver.Config (-got+want)\n%s", diff) t.Errorf("wrong resolver.Config (-got+want)\n%s", diff)
} }
}) })

@ -433,8 +433,8 @@ func TestDelegateCollision(t *testing.T) {
qtype dns.Type qtype dns.Type
addr netaddr.IPPort addr netaddr.IPPort
}{ }{
{"test.site.", dns.TypeA, netaddr.IPPort{IP: netaddr.IPv4(1, 1, 1, 1), Port: 1001}}, {"test.site.", dns.TypeA, netaddr.IPPortFrom(netaddr.IPv4(1, 1, 1, 1), 1001)},
{"test.site.", dns.TypeAAAA, netaddr.IPPort{IP: netaddr.IPv4(1, 1, 1, 1), Port: 1002}}, {"test.site.", dns.TypeAAAA, netaddr.IPPortFrom(netaddr.IPv4(1, 1, 1, 1), 1002)},
} }
// packets will have the same dns txid. // packets will have the same dns txid.

@ -195,7 +195,7 @@ func ForeachInterface(fn func(Interface, []netaddr.IPPrefix)) error {
} }
} }
sort.Slice(pfxs, func(i, j int) bool { sort.Slice(pfxs, func(i, j int) bool {
return pfxs[i].IP.Less(pfxs[j].IP) return pfxs[i].IP().Less(pfxs[j].IP())
}) })
fn(Interface{iface}, pfxs) fn(Interface{iface}, pfxs)
} }
@ -264,7 +264,7 @@ func (s *State) String() string {
fmt.Fprintf(&sb, "%s:[", ifName) fmt.Fprintf(&sb, "%s:[", ifName)
needSpace := false needSpace := false
for _, pfx := range s.InterfaceIPs[ifName] { for _, pfx := range s.InterfaceIPs[ifName] {
if !isInterestingIP(pfx.IP) { if !isInterestingIP(pfx.IP()) {
continue continue
} }
if needSpace { if needSpace {
@ -367,7 +367,7 @@ func (s *State) AnyInterfaceUp() bool {
func hasTailscaleIP(pfxs []netaddr.IPPrefix) bool { func hasTailscaleIP(pfxs []netaddr.IPPrefix) bool {
for _, pfx := range pfxs { for _, pfx := range pfxs {
if tsaddr.IsTailscaleIP(pfx.IP) { if tsaddr.IsTailscaleIP(pfx.IP()) {
return true return true
} }
} }
@ -407,11 +407,11 @@ func GetState() (*State, error) {
return return
} }
for _, pfx := range pfxs { for _, pfx := range pfxs {
if pfx.IP.IsLoopback() || pfx.IP.IsLinkLocalUnicast() { if pfx.IP().IsLoopback() || pfx.IP().IsLinkLocalUnicast() {
continue continue
} }
s.HaveV6Global = s.HaveV6Global || isGlobalV6(pfx.IP) s.HaveV6Global = s.HaveV6Global || isGlobalV6(pfx.IP())
s.HaveV4 = s.HaveV4 || pfx.IP.Is4() s.HaveV4 = s.HaveV4 || pfx.IP().Is4()
} }
}); err != nil { }); err != nil {
return nil, err return nil, err
@ -447,7 +447,7 @@ func HTTPOfListener(ln net.Listener) string {
var goodIP string var goodIP string
var privateIP string var privateIP string
ForeachInterfaceAddress(func(i Interface, pfx netaddr.IPPrefix) { ForeachInterfaceAddress(func(i Interface, pfx netaddr.IPPrefix) {
ip := pfx.IP ip := pfx.IP()
if isPrivateIP(ip) { if isPrivateIP(ip) {
if privateIP == "" { if privateIP == "" {
privateIP = ip.String() privateIP = ip.String()
@ -484,7 +484,7 @@ func LikelyHomeRouterIP() (gateway, myIP netaddr.IP, ok bool) {
return return
} }
ForeachInterfaceAddress(func(i Interface, pfx netaddr.IPPrefix) { ForeachInterfaceAddress(func(i Interface, pfx netaddr.IPPrefix) {
ip := pfx.IP ip := pfx.IP()
if !i.IsUp() || ip.IsZero() || !myIP.IsZero() { if !i.IsUp() || ip.IsZero() || !myIP.IsZero() {
return return
} }
@ -528,7 +528,7 @@ var (
// isInterestingIP. // isInterestingIP.
func anyInterestingIP(pfxs []netaddr.IPPrefix) bool { func anyInterestingIP(pfxs []netaddr.IPPrefix) bool {
for _, pfx := range pfxs { for _, pfx := range pfxs {
if isInterestingIP(pfx.IP) { if isInterestingIP(pfx.IP()) {
return true return true
} }
} }

@ -625,7 +625,7 @@ func (rs *reportState) stopTimers() {
func (rs *reportState) addNodeLatency(node *tailcfg.DERPNode, ipp netaddr.IPPort, d time.Duration) { func (rs *reportState) addNodeLatency(node *tailcfg.DERPNode, ipp netaddr.IPPort, d time.Duration) {
var ipPortStr string var ipPortStr string
if ipp != (netaddr.IPPort{}) { if ipp != (netaddr.IPPort{}) {
ipPortStr = net.JoinHostPort(ipp.IP.String(), fmt.Sprint(ipp.Port)) ipPortStr = net.JoinHostPort(ipp.IP().String(), fmt.Sprint(ipp.Port()))
} }
rs.mu.Lock() rs.mu.Lock()
@ -650,13 +650,13 @@ func (rs *reportState) addNodeLatency(node *tailcfg.DERPNode, ipp netaddr.IPPort
} }
switch { switch {
case ipp.IP.Is6(): case ipp.IP().Is6():
updateLatency(ret.RegionV6Latency, node.RegionID, d) updateLatency(ret.RegionV6Latency, node.RegionID, d)
ret.IPv6 = true ret.IPv6 = true
ret.GlobalV6 = ipPortStr ret.GlobalV6 = ipPortStr
// TODO: track MappingVariesByDestIP for IPv6 // TODO: track MappingVariesByDestIP for IPv6
// too? Would be sad if so, but who knows. // too? Would be sad if so, but who knows.
case ipp.IP.Is4(): case ipp.IP().Is4():
updateLatency(ret.RegionV4Latency, node.RegionID, d) updateLatency(ret.RegionV4Latency, node.RegionID, d)
ret.IPv4 = true ret.IPv4 = true
if rs.gotEP4 == "" { if rs.gotEP4 == "" {
@ -1172,7 +1172,7 @@ func (c *Client) nodeAddr(ctx context.Context, n *tailcfg.DERPNode, proto probeP
if proto == probeIPv6 && ip.Is4() { if proto == probeIPv6 && ip.Is4() {
return nil return nil
} }
return netaddr.IPPort{IP: ip, Port: uint16(port)}.UDPAddr() return netaddr.IPPortFrom(ip, uint16(port)).UDPAddr()
} }
switch proto { switch proto {
@ -1182,7 +1182,7 @@ func (c *Client) nodeAddr(ctx context.Context, n *tailcfg.DERPNode, proto probeP
if !ip.Is4() { if !ip.Is4() {
return nil return nil
} }
return netaddr.IPPort{IP: ip, Port: uint16(port)}.UDPAddr() return netaddr.IPPortFrom(ip, uint16(port)).UDPAddr()
} }
case probeIPv6: case probeIPv6:
if n.IPv6 != "" { if n.IPv6 != "" {
@ -1190,7 +1190,7 @@ func (c *Client) nodeAddr(ctx context.Context, n *tailcfg.DERPNode, proto probeP
if !ip.Is6() { if !ip.Is6() {
return nil return nil
} }
return netaddr.IPPort{IP: ip, Port: uint16(port)}.UDPAddr() return netaddr.IPPortFrom(ip, uint16(port)).UDPAddr()
} }
default: default:
return nil return nil

@ -157,10 +157,9 @@ func ipport4(addr uint32, port uint16) netaddr.IPPort {
if !endian.Big { if !endian.Big {
addr = bits.ReverseBytes32(addr) addr = bits.ReverseBytes32(addr)
} }
return netaddr.IPPort{ return netaddr.IPPortFrom(
IP: netaddr.IPv4(byte(addr>>24), byte(addr>>16), byte(addr>>8), byte(addr)), netaddr.IPv4(byte(addr>>24), byte(addr>>16), byte(addr>>8), byte(addr)),
Port: port, port)
}
} }
func ipport6(addr [16]byte, scope uint32, port uint16) netaddr.IPPort { func ipport6(addr [16]byte, scope uint32, port uint16) netaddr.IPPort {
@ -169,10 +168,7 @@ func ipport6(addr [16]byte, scope uint32, port uint16) netaddr.IPPort {
// TODO: something better here? // TODO: something better here?
ip = ip.WithZone(fmt.Sprint(scope)) ip = ip.WithZone(fmt.Sprint(scope))
} }
return netaddr.IPPort{ return netaddr.IPPortFrom(ip, port)
IP: ip,
Port: port,
}
} }
func port(v *uint32) uint16 { func port(v *uint32) uint16 {

@ -76,8 +76,8 @@ func (p *Parsed) String() string {
// //
// TODO: make netaddr more efficient in this area, and retire this func. // TODO: make netaddr more efficient in this area, and retire this func.
func writeIPPort(sb *strbuilder.Builder, ipp netaddr.IPPort) { func writeIPPort(sb *strbuilder.Builder, ipp netaddr.IPPort) {
if ipp.IP.Is4() { if ipp.IP().Is4() {
raw := ipp.IP.As4() raw := ipp.IP().As4()
sb.WriteUint(uint64(raw[0])) sb.WriteUint(uint64(raw[0]))
sb.WriteByte('.') sb.WriteByte('.')
sb.WriteUint(uint64(raw[1])) sb.WriteUint(uint64(raw[1]))
@ -88,10 +88,10 @@ func writeIPPort(sb *strbuilder.Builder, ipp netaddr.IPPort) {
sb.WriteByte(':') sb.WriteByte(':')
} else { } else {
sb.WriteByte('[') sb.WriteByte('[')
sb.WriteString(ipp.IP.String()) // TODO: faster? sb.WriteString(ipp.IP().String()) // TODO: faster?
sb.WriteString("]:") sb.WriteString("]:")
} }
sb.WriteUint(uint64(ipp.Port)) sb.WriteUint(uint64(ipp.Port()))
} }
// Decode extracts data from the packet in b into q. // Decode extracts data from the packet in b into q.
@ -142,8 +142,8 @@ func (q *Parsed) decode4(b []byte) {
} }
// If it's valid IPv4, then the IP addresses are valid // If it's valid IPv4, then the IP addresses are valid
q.Src.IP = netaddr.IPv4(b[12], b[13], b[14], b[15]) q.Src = q.Src.WithIP(netaddr.IPv4(b[12], b[13], b[14], b[15]))
q.Dst.IP = netaddr.IPv4(b[16], b[17], b[18], b[19]) q.Dst = q.Dst.WithIP(netaddr.IPv4(b[16], b[17], b[18], b[19]))
q.subofs = int((b[0] & 0x0F) << 2) q.subofs = int((b[0] & 0x0F) << 2)
if q.subofs > q.length { if q.subofs > q.length {
@ -185,8 +185,8 @@ func (q *Parsed) decode4(b []byte) {
q.IPProto = unknown q.IPProto = unknown
return return
} }
q.Src.Port = 0 q.Src = q.Src.WithPort(0)
q.Dst.Port = 0 q.Dst = q.Dst.WithPort(0)
q.dataofs = q.subofs + icmp4HeaderLength q.dataofs = q.subofs + icmp4HeaderLength
return return
case ipproto.IGMP: case ipproto.IGMP:
@ -198,8 +198,8 @@ func (q *Parsed) decode4(b []byte) {
q.IPProto = unknown q.IPProto = unknown
return return
} }
q.Src.Port = binary.BigEndian.Uint16(sub[0:2]) q.Src = q.Src.WithPort(binary.BigEndian.Uint16(sub[0:2]))
q.Dst.Port = binary.BigEndian.Uint16(sub[2:4]) q.Dst = q.Dst.WithPort(binary.BigEndian.Uint16(sub[2:4]))
q.TCPFlags = TCPFlag(sub[13]) & 0x3F q.TCPFlags = TCPFlag(sub[13]) & 0x3F
headerLength := (sub[12] & 0xF0) >> 2 headerLength := (sub[12] & 0xF0) >> 2
q.dataofs = q.subofs + int(headerLength) q.dataofs = q.subofs + int(headerLength)
@ -209,8 +209,8 @@ func (q *Parsed) decode4(b []byte) {
q.IPProto = unknown q.IPProto = unknown
return return
} }
q.Src.Port = binary.BigEndian.Uint16(sub[0:2]) q.Src = q.Src.WithPort(binary.BigEndian.Uint16(sub[0:2]))
q.Dst.Port = binary.BigEndian.Uint16(sub[2:4]) q.Dst = q.Dst.WithPort(binary.BigEndian.Uint16(sub[2:4]))
q.dataofs = q.subofs + udpHeaderLength q.dataofs = q.subofs + udpHeaderLength
return return
case ipproto.SCTP: case ipproto.SCTP:
@ -218,8 +218,8 @@ func (q *Parsed) decode4(b []byte) {
q.IPProto = unknown q.IPProto = unknown
return return
} }
q.Src.Port = binary.BigEndian.Uint16(sub[0:2]) q.Src = q.Src.WithPort(binary.BigEndian.Uint16(sub[0:2]))
q.Dst.Port = binary.BigEndian.Uint16(sub[2:4]) q.Dst = q.Dst.WithPort(binary.BigEndian.Uint16(sub[2:4]))
return return
case ipproto.TSMP: case ipproto.TSMP:
// Inter-tailscale messages. // Inter-tailscale messages.
@ -265,8 +265,10 @@ func (q *Parsed) decode6(b []byte) {
// okay to ignore `ok` here, because IPs pulled from packets are // okay to ignore `ok` here, because IPs pulled from packets are
// always well-formed stdlib IPs. // always well-formed stdlib IPs.
q.Src.IP, _ = netaddr.FromStdIP(net.IP(b[8:24])) srcIP, _ := netaddr.FromStdIP(net.IP(b[8:24]))
q.Dst.IP, _ = netaddr.FromStdIP(net.IP(b[24:40])) dstIP, _ := netaddr.FromStdIP(net.IP(b[24:40]))
q.Src = q.Src.WithIP(srcIP)
q.Dst = q.Dst.WithIP(dstIP)
// We don't support any IPv6 extension headers. Don't try to // We don't support any IPv6 extension headers. Don't try to
// be clever. Therefore, the IP subprotocol always starts at // be clever. Therefore, the IP subprotocol always starts at
@ -290,16 +292,16 @@ func (q *Parsed) decode6(b []byte) {
q.IPProto = unknown q.IPProto = unknown
return return
} }
q.Src.Port = 0 q.Src = q.Src.WithPort(0)
q.Dst.Port = 0 q.Dst = q.Dst.WithPort(0)
q.dataofs = q.subofs + icmp6HeaderLength q.dataofs = q.subofs + icmp6HeaderLength
case ipproto.TCP: case ipproto.TCP:
if len(sub) < tcpHeaderLength { if len(sub) < tcpHeaderLength {
q.IPProto = unknown q.IPProto = unknown
return return
} }
q.Src.Port = binary.BigEndian.Uint16(sub[0:2]) q.Src = q.Src.WithPort(binary.BigEndian.Uint16(sub[0:2]))
q.Dst.Port = binary.BigEndian.Uint16(sub[2:4]) q.Dst = q.Dst.WithPort(binary.BigEndian.Uint16(sub[2:4]))
q.TCPFlags = TCPFlag(sub[13]) & 0x3F q.TCPFlags = TCPFlag(sub[13]) & 0x3F
headerLength := (sub[12] & 0xF0) >> 2 headerLength := (sub[12] & 0xF0) >> 2
q.dataofs = q.subofs + int(headerLength) q.dataofs = q.subofs + int(headerLength)
@ -309,16 +311,16 @@ func (q *Parsed) decode6(b []byte) {
q.IPProto = unknown q.IPProto = unknown
return return
} }
q.Src.Port = binary.BigEndian.Uint16(sub[0:2]) q.Src = q.Src.WithPort(binary.BigEndian.Uint16(sub[0:2]))
q.Dst.Port = binary.BigEndian.Uint16(sub[2:4]) q.Dst = q.Dst.WithPort(binary.BigEndian.Uint16(sub[2:4]))
q.dataofs = q.subofs + udpHeaderLength q.dataofs = q.subofs + udpHeaderLength
case ipproto.SCTP: case ipproto.SCTP:
if len(sub) < sctpHeaderLength { if len(sub) < sctpHeaderLength {
q.IPProto = unknown q.IPProto = unknown
return return
} }
q.Src.Port = binary.BigEndian.Uint16(sub[0:2]) q.Src = q.Src.WithPort(binary.BigEndian.Uint16(sub[0:2]))
q.Dst.Port = binary.BigEndian.Uint16(sub[2:4]) q.Dst = q.Dst.WithPort(binary.BigEndian.Uint16(sub[2:4]))
return return
case ipproto.TSMP: case ipproto.TSMP:
// Inter-tailscale messages. // Inter-tailscale messages.
@ -338,8 +340,8 @@ func (q *Parsed) IP4Header() IP4Header {
return IP4Header{ return IP4Header{
IPID: ipid, IPID: ipid,
IPProto: q.IPProto, IPProto: q.IPProto,
Src: q.Src.IP, Src: q.Src.IP(),
Dst: q.Dst.IP, Dst: q.Dst.IP(),
} }
} }
@ -351,8 +353,8 @@ func (q *Parsed) IP6Header() IP6Header {
return IP6Header{ return IP6Header{
IPID: ipid, IPID: ipid,
IPProto: q.IPProto, IPProto: q.IPProto,
Src: q.Src.IP, Src: q.Src.IP(),
Dst: q.Dst.IP, Dst: q.Dst.IP(),
} }
} }
@ -373,8 +375,8 @@ func (q *Parsed) UDP4Header() UDP4Header {
} }
return UDP4Header{ return UDP4Header{
IP4Header: q.IP4Header(), IP4Header: q.IP4Header(),
SrcPort: q.Src.Port, SrcPort: q.Src.Port(),
DstPort: q.Dst.Port, DstPort: q.Dst.Port(),
} }
} }

@ -143,7 +143,7 @@ func (h TailscaleRejectedHeader) Marshal(buf []byte) error {
if len(buf) > maxPacketLength { if len(buf) > maxPacketLength {
return errLargePacket return errLargePacket
} }
if h.Src.IP.Is4() { if h.Src.IP().Is4() {
iph := IP4Header{ iph := IP4Header{
IPProto: ipproto.TSMP, IPProto: ipproto.TSMP,
Src: h.IPSrc, Src: h.IPSrc,
@ -151,7 +151,7 @@ func (h TailscaleRejectedHeader) Marshal(buf []byte) error {
} }
iph.Marshal(buf) iph.Marshal(buf)
buf = buf[ip4HeaderLength:] buf = buf[ip4HeaderLength:]
} else if h.Src.IP.Is6() { } else if h.Src.IP().Is6() {
iph := IP6Header{ iph := IP6Header{
IPProto: ipproto.TSMP, IPProto: ipproto.TSMP,
Src: h.IPSrc, Src: h.IPSrc,
@ -165,8 +165,8 @@ func (h TailscaleRejectedHeader) Marshal(buf []byte) error {
buf[0] = byte(TSMPTypeRejectedConn) buf[0] = byte(TSMPTypeRejectedConn)
buf[1] = byte(h.Proto) buf[1] = byte(h.Proto)
buf[2] = byte(h.Reason) buf[2] = byte(h.Reason)
binary.BigEndian.PutUint16(buf[3:5], h.Src.Port) binary.BigEndian.PutUint16(buf[3:5], h.Src.Port())
binary.BigEndian.PutUint16(buf[5:7], h.Dst.Port) binary.BigEndian.PutUint16(buf[5:7], h.Dst.Port())
if h.hasFlags() { if h.hasFlags() {
var flags byte var flags byte
@ -190,10 +190,10 @@ func (pp *Parsed) AsTailscaleRejectedHeader() (h TailscaleRejectedHeader, ok boo
h = TailscaleRejectedHeader{ h = TailscaleRejectedHeader{
Proto: ipproto.Proto(p[1]), Proto: ipproto.Proto(p[1]),
Reason: TailscaleRejectReason(p[2]), Reason: TailscaleRejectReason(p[2]),
IPSrc: pp.Src.IP, IPSrc: pp.Src.IP(),
IPDst: pp.Dst.IP, IPDst: pp.Dst.IP(),
Src: netaddr.IPPort{IP: pp.Dst.IP, Port: binary.BigEndian.Uint16(p[3:5])}, Src: netaddr.IPPortFrom(pp.Dst.IP(), binary.BigEndian.Uint16(p[3:5])),
Dst: netaddr.IPPort{IP: pp.Src.IP, Port: binary.BigEndian.Uint16(p[5:7])}, Dst: netaddr.IPPortFrom(pp.Src.IP(), binary.BigEndian.Uint16(p[5:7])),
} }
if len(p) > 7 { if len(p) > 7 {
flags := p[7] flags := p[7]

@ -84,7 +84,7 @@ type pmpMapping struct {
// externalValid reports whether m.external is valid, with both its IP and Port populated. // externalValid reports whether m.external is valid, with both its IP and Port populated.
func (m *pmpMapping) externalValid() bool { func (m *pmpMapping) externalValid() bool {
return !m.external.IP.IsZero() && m.external.Port != 0 return !m.external.IP().IsZero() && m.external.Port() != 0
} }
// release does a best effort fire-and-forget release of the PMP mapping m. // release does a best effort fire-and-forget release of the PMP mapping m.
@ -94,8 +94,8 @@ func (m *pmpMapping) release() {
return return
} }
defer uc.Close() defer uc.Close()
pkt := buildPMPRequestMappingPacket(m.internal.Port, m.external.Port, pmpMapLifetimeDelete) pkt := buildPMPRequestMappingPacket(m.internal.Port(), m.external.Port(), pmpMapLifetimeDelete)
uc.WriteTo(pkt, netaddr.IPPort{IP: m.gw, Port: pmpPort}.UDPAddr()) uc.WriteTo(pkt, netaddr.IPPortFrom(m.gw, pmpPort).UDPAddr())
} }
// NewClient returns a new portmapping client. // NewClient returns a new portmapping client.
@ -256,7 +256,7 @@ func (c *Client) CreateOrGetMapping(ctx context.Context) (external netaddr.IPPor
localPort := c.localPort localPort := c.localPort
m := &pmpMapping{ m := &pmpMapping{
gw: gw, gw: gw,
internal: netaddr.IPPort{IP: myIP, Port: localPort}, internal: netaddr.IPPortFrom(myIP, localPort),
} }
// prevPort is the port we had most previously, if any. We try // prevPort is the port we had most previously, if any. We try
@ -271,7 +271,7 @@ func (c *Client) CreateOrGetMapping(ctx context.Context) (external netaddr.IPPor
return m.external, nil return m.external, nil
} }
// The mapping might still be valid, so just try to renew it. // The mapping might still be valid, so just try to renew it.
prevPort = m.external.Port prevPort = m.external.Port()
} }
// If we just did a Probe (e.g. via netchecker) but didn't // If we just did a Probe (e.g. via netchecker) but didn't
@ -279,7 +279,7 @@ func (c *Client) CreateOrGetMapping(ctx context.Context) (external netaddr.IPPor
// again. Cuts down latency for most clients. // again. Cuts down latency for most clients.
haveRecentPMP := c.sawPMPRecentlyLocked() haveRecentPMP := c.sawPMPRecentlyLocked()
if haveRecentPMP { if haveRecentPMP {
m.external.IP = c.pmpPubIP m.external = m.external.WithIP(c.pmpPubIP)
} }
if c.lastProbe.After(now.Add(-5*time.Second)) && !haveRecentPMP { if c.lastProbe.After(now.Add(-5*time.Second)) && !haveRecentPMP {
c.mu.Unlock() c.mu.Unlock()
@ -297,11 +297,11 @@ func (c *Client) CreateOrGetMapping(ctx context.Context) (external netaddr.IPPor
uc.SetReadDeadline(time.Now().Add(portMapServiceTimeout)) uc.SetReadDeadline(time.Now().Add(portMapServiceTimeout))
defer closeCloserOnContextDone(ctx, uc)() defer closeCloserOnContextDone(ctx, uc)()
pmpAddr := netaddr.IPPort{IP: gw, Port: pmpPort} pmpAddr := netaddr.IPPortFrom(gw, pmpPort)
pmpAddru := pmpAddr.UDPAddr() pmpAddru := pmpAddr.UDPAddr()
// Ask for our external address if needed. // Ask for our external address if needed.
if m.external.IP.IsZero() { if m.external.IP().IsZero() {
if _, err := uc.WriteTo(pmpReqExternalAddrPacket, pmpAddru); err != nil { if _, err := uc.WriteTo(pmpReqExternalAddrPacket, pmpAddru); err != nil {
return netaddr.IPPort{}, err return netaddr.IPPort{}, err
} }
@ -337,10 +337,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)} return netaddr.IPPort{}, NoMappingError{fmt.Errorf("PMP response Op=0x%x,Res=0x%x", pres.OpCode, pres.ResultCode)}
} }
if pres.OpCode == pmpOpReply|pmpOpMapPublicAddr { if pres.OpCode == pmpOpReply|pmpOpMapPublicAddr {
m.external.IP = pres.PublicAddr m.external = m.external.WithIP(pres.PublicAddr)
} }
if pres.OpCode == pmpOpReply|pmpOpMapUDP { if pres.OpCode == pmpOpReply|pmpOpMapUDP {
m.external.Port = pres.ExternalPort m.external = m.external.WithPort(pres.ExternalPort)
d := time.Duration(pres.MappingValidSeconds) * time.Second d := time.Duration(pres.MappingValidSeconds) * time.Second
d /= 2 // renew in half the time d /= 2 // renew in half the time
m.useUntil = time.Now().Add(d) m.useUntil = time.Now().Add(d)
@ -468,9 +468,9 @@ func (c *Client) Probe(ctx context.Context) (res ProbeResult, err error) {
defer cancel() defer cancel()
defer closeCloserOnContextDone(ctx, uc)() defer closeCloserOnContextDone(ctx, uc)()
pcpAddr := netaddr.IPPort{IP: gw, Port: pcpPort}.UDPAddr() pcpAddr := netaddr.IPPortFrom(gw, pcpPort).UDPAddr()
pmpAddr := netaddr.IPPort{IP: gw, Port: pmpPort}.UDPAddr() pmpAddr := netaddr.IPPortFrom(gw, pmpPort).UDPAddr()
upnpAddr := netaddr.IPPort{IP: gw, Port: upnpPort}.UDPAddr() upnpAddr := netaddr.IPPortFrom(gw, upnpPort).UDPAddr()
// Don't send probes to services that we recently learned (for // Don't send probes to services that we recently learned (for
// the same gw/myIP) are available. See // the same gw/myIP) are available. See

@ -92,7 +92,7 @@ func TailscaleEphemeral6Range() netaddr.IPPrefix {
// Currently used to work around a Windows limitation when programming // Currently used to work around a Windows limitation when programming
// IPv6 routes in corner cases. // IPv6 routes in corner cases.
func Tailscale4To6Placeholder() netaddr.IP { func Tailscale4To6Placeholder() netaddr.IP {
return Tailscale4To6Range().IP return Tailscale4To6Range().IP()
} }
// Tailscale4To6 returns a Tailscale IPv6 address that maps 1:1 to the // Tailscale4To6 returns a Tailscale IPv6 address that maps 1:1 to the
@ -102,7 +102,7 @@ func Tailscale4To6(ipv4 netaddr.IP) netaddr.IP {
if !ipv4.Is4() || !IsTailscaleIP(ipv4) { if !ipv4.Is4() || !IsTailscaleIP(ipv4) {
return netaddr.IP{} return netaddr.IP{}
} }
ret := Tailscale4To6Range().IP.As16() ret := Tailscale4To6Range().IP().As16()
v4 := ipv4.As4() v4 := ipv4.As4()
copy(ret[13:], v4[1:]) copy(ret[13:], v4[1:])
return netaddr.IPFrom16(ret) return netaddr.IPFrom16(ret)
@ -172,16 +172,16 @@ func NewContainsIPFunc(addrs []netaddr.IPPrefix) func(ip netaddr.IP) bool {
// Fast paths for 1 and 2 IPs: // Fast paths for 1 and 2 IPs:
if len(addrs) == 1 { if len(addrs) == 1 {
a := addrs[0] a := addrs[0]
return func(ip netaddr.IP) bool { return ip == a.IP } return func(ip netaddr.IP) bool { return ip == a.IP() }
} }
if len(addrs) == 2 { if len(addrs) == 2 {
a, b := addrs[0], addrs[1] a, b := addrs[0], addrs[1]
return func(ip netaddr.IP) bool { return ip == a.IP || ip == b.IP } return func(ip netaddr.IP) bool { return ip == a.IP() || ip == b.IP() }
} }
// General case: // General case:
m := map[netaddr.IP]bool{} m := map[netaddr.IP]bool{}
for _, a := range addrs { for _, a := range addrs {
m[a.IP] = true m[a.IP()] = true
} }
return func(ip netaddr.IP) bool { return m[ip] } return func(ip netaddr.IP) bool { return m[ip] }
} }

@ -352,7 +352,7 @@ func (t *Wrapper) Read(buf []byte, offset int) (int, error) {
p.Decode(buf[offset : offset+n]) p.Decode(buf[offset : offset+n])
if m, ok := t.destIPActivity.Load().(map[netaddr.IP]func()); ok { if m, ok := t.destIPActivity.Load().(map[netaddr.IP]func()); ok {
if fn := m[p.Dst.IP]; fn != nil { if fn := m[p.Dst.IP()]; fn != nil {
fn() fn()
} }
} }
@ -412,7 +412,7 @@ func (t *Wrapper) filterIn(buf []byte) filter.Response {
p.IPProto == ipproto.TCP && p.IPProto == ipproto.TCP &&
p.TCPFlags&packet.TCPSyn != 0 && p.TCPFlags&packet.TCPSyn != 0 &&
t.PeerAPIPort != nil { t.PeerAPIPort != nil {
if port, ok := t.PeerAPIPort(p.Dst.IP); ok && port == p.Dst.Port { if port, ok := t.PeerAPIPort(p.Dst.IP()); ok && port == p.Dst.Port() {
outcome = filter.Accept outcome = filter.Accept
} }
} }
@ -425,8 +425,8 @@ func (t *Wrapper) filterIn(buf []byte) filter.Response {
// can show them a rejection history with reasons. // can show them a rejection history with reasons.
if p.IPVersion == 4 && p.IPProto == ipproto.TCP && p.TCPFlags&packet.TCPSyn != 0 && !t.disableTSMPRejected { if p.IPVersion == 4 && p.IPProto == ipproto.TCP && p.TCPFlags&packet.TCPSyn != 0 && !t.disableTSMPRejected {
rj := packet.TailscaleRejectedHeader{ rj := packet.TailscaleRejectedHeader{
IPSrc: p.Dst.IP, IPSrc: p.Dst.IP(),
IPDst: p.Src.IP, IPDst: p.Src.IP(),
Src: p.Src, Src: p.Src,
Dst: p.Dst, Dst: p.Dst,
Proto: p.IPProto, Proto: p.IPProto,
@ -536,7 +536,7 @@ func (t *Wrapper) injectOutboundPong(pp *packet.Parsed, req packet.TSMPPingReque
Data: req.Data, Data: req.Data,
} }
if t.PeerAPIPort != nil { if t.PeerAPIPort != nil {
pong.PeerAPIPort, _ = t.PeerAPIPort(pp.Dst.IP) pong.PeerAPIPort, _ = t.PeerAPIPort(pp.Dst.IP())
} }
switch pp.IPVersion { switch pp.IPVersion {
case 4: case 4:

@ -82,7 +82,7 @@ func nets(nets ...string) (ret []netaddr.IPPrefix) {
if ip.Is6() { if ip.Is6() {
bits = 128 bits = 128
} }
ret = append(ret, netaddr.IPPrefix{IP: ip, Bits: bits}) ret = append(ret, netaddr.IPPrefixFrom(ip, bits))
} else { } else {
pfx, err := netaddr.ParseIPPrefix(s) pfx, err := netaddr.ParseIPPrefix(s)
if err != nil { if err != nil {

@ -70,7 +70,7 @@ func (s *Server) WhoIs(addr string) (w *apitype.WhoIsResponse, ok bool) {
if err != nil { if err != nil {
return nil, false return nil, false
} }
ipp.IP = ip ipp = ipp.WithIP(ip)
} }
n, up, ok := s.lb.WhoIs(ipp) n, up, ok := s.lb.WhoIs(ipp)
if !ok { if !ok {

@ -650,7 +650,7 @@ func keepClientEndpoint(ep string) bool {
// the incoming JSON response. // the incoming JSON response.
return false return false
} }
ip := ipp.IP ip := ipp.IP()
if ip.Zone() != "" { if ip.Zone() != "" {
return false return false
} }

@ -52,7 +52,7 @@ func (s FirewallType) key(src, dst netaddr.IPPort) fwKey {
switch s { switch s {
case EndpointIndependentFirewall: case EndpointIndependentFirewall:
case AddressDependentFirewall: case AddressDependentFirewall:
k.dst.IP = dst.IP k.dst = k.dst.WithIP(dst.IP())
case AddressAndPortDependentFirewall: case AddressAndPortDependentFirewall:
k.dst = dst k.dst = dst
default: default:

@ -62,7 +62,7 @@ func (t NATType) key(src, dst netaddr.IPPort) natKey {
switch t { switch t {
case EndpointIndependentNAT: case EndpointIndependentNAT:
case AddressDependentNAT: case AddressDependentNAT:
k.dst.IP = dst.IP k.dst = k.dst.WithIP(dst.IP())
case AddressAndPortDependentNAT: case AddressAndPortDependentNAT:
k.dst = dst k.dst = dst
default: default:
@ -171,7 +171,7 @@ func (n *SNAT44) HandleIn(p *Packet, iif *Interface) *Packet {
func (n *SNAT44) HandleForward(p *Packet, iif, oif *Interface) *Packet { func (n *SNAT44) HandleForward(p *Packet, iif, oif *Interface) *Packet {
switch { switch {
case oif == n.ExternalInterface: case oif == n.ExternalInterface:
if p.Src.IP == oif.V4() { if p.Src.IP() == oif.V4() {
// Packet already NATed and is just retraversing Forward, // Packet already NATed and is just retraversing Forward,
// don't touch it again. // don't touch it again.
return p return p
@ -237,10 +237,7 @@ func (n *SNAT44) allocateMappedPort() (net.PacketConn, netaddr.IPPort) {
if err != nil { if err != nil {
panic(fmt.Sprintf("ran out of NAT ports: %v", err)) panic(fmt.Sprintf("ran out of NAT ports: %v", err))
} }
addr := netaddr.IPPort{ addr := netaddr.IPPortFrom(ip, uint16(pc.LocalAddr().(*net.UDPAddr).Port))
IP: ip,
Port: uint16(pc.LocalAddr().(*net.UDPAddr).Port),
}
return pc, addr return pc, addr
} }

@ -138,7 +138,7 @@ func (n *Network) allocIPv4(iface *Interface) netaddr.IP {
return netaddr.IP{} return netaddr.IP{}
} }
if n.lastV4.IsZero() { if n.lastV4.IsZero() {
n.lastV4 = n.Prefix4.IP n.lastV4 = n.Prefix4.IP()
} }
a := n.lastV4.As16() a := n.lastV4.As16()
addOne(&a, 15) addOne(&a, 15)
@ -157,7 +157,7 @@ func (n *Network) allocIPv6(iface *Interface) netaddr.IP {
return netaddr.IP{} return netaddr.IP{}
} }
if n.lastV6.IsZero() { if n.lastV6.IsZero() {
n.lastV6 = n.Prefix6.IP n.lastV6 = n.Prefix6.IP()
} }
a := n.lastV6.As16() a := n.lastV6.As16()
addOne(&a, 15) addOne(&a, 15)
@ -183,15 +183,15 @@ func (n *Network) write(p *Packet) (num int, err error) {
n.mu.Lock() n.mu.Lock()
defer n.mu.Unlock() defer n.mu.Unlock()
iface, ok := n.machine[p.Dst.IP] iface, ok := n.machine[p.Dst.IP()]
if !ok { if !ok {
// If the destination is within the network's authoritative // If the destination is within the network's authoritative
// range, no route to host. // range, no route to host.
if p.Dst.IP.Is4() && n.Prefix4.Contains(p.Dst.IP) { if p.Dst.IP().Is4() && n.Prefix4.Contains(p.Dst.IP()) {
p.Trace("no route to %v", p.Dst.IP) p.Trace("no route to %v", p.Dst.IP)
return len(p.Payload), nil return len(p.Payload), nil
} }
if p.Dst.IP.Is6() && n.Prefix6.Contains(p.Dst.IP) { if p.Dst.IP().Is6() && n.Prefix6.Contains(p.Dst.IP()) {
p.Trace("no route to %v", p.Dst.IP) p.Trace("no route to %v", p.Dst.IP)
return len(p.Payload), nil return len(p.Payload), nil
} }
@ -363,7 +363,7 @@ func (m *Machine) isLocalIP(ip netaddr.IP) bool {
func (m *Machine) deliverIncomingPacket(p *Packet, iface *Interface) { func (m *Machine) deliverIncomingPacket(p *Packet, iface *Interface) {
p.setLocator("mach=%s if=%s", m.Name, iface.name) p.setLocator("mach=%s if=%s", m.Name, iface.name)
if m.isLocalIP(p.Dst.IP) { if m.isLocalIP(p.Dst.IP()) {
m.deliverLocalPacket(p, iface) m.deliverLocalPacket(p, iface)
} else { } else {
m.forwardPacket(p, iface) m.forwardPacket(p, iface)
@ -391,13 +391,13 @@ func (m *Machine) deliverLocalPacket(p *Packet, iface *Interface) {
defer m.mu.Unlock() defer m.mu.Unlock()
conns := m.conns4 conns := m.conns4
if p.Dst.IP.Is6() { if p.Dst.IP().Is6() {
conns = m.conns6 conns = m.conns6
} }
possibleDsts := []netaddr.IPPort{ possibleDsts := []netaddr.IPPort{
p.Dst, p.Dst,
netaddr.IPPort{IP: v6unspec, Port: p.Dst.Port}, netaddr.IPPortFrom(v6unspec, p.Dst.Port()),
netaddr.IPPort{IP: v4unspec, Port: p.Dst.Port}, netaddr.IPPortFrom(v4unspec, p.Dst.Port()),
} }
for _, dest := range possibleDsts { for _, dest := range possibleDsts {
c, ok := conns[dest] c, ok := conns[dest]
@ -417,7 +417,7 @@ func (m *Machine) deliverLocalPacket(p *Packet, iface *Interface) {
} }
func (m *Machine) forwardPacket(p *Packet, iif *Interface) { func (m *Machine) forwardPacket(p *Packet, iif *Interface) {
oif, err := m.interfaceForIP(p.Dst.IP) oif, err := m.interfaceForIP(p.Dst.IP())
if err != nil { if err != nil {
p.Trace("%v", err) p.Trace("%v", err)
return return
@ -501,7 +501,7 @@ func (m *Machine) Attach(interfaceName string, n *Network) *Interface {
} }
} }
sort.Slice(m.routes, func(i, j int) bool { sort.Slice(m.routes, func(i, j int) bool {
return m.routes[i].prefix.Bits > m.routes[j].prefix.Bits return m.routes[i].prefix.Bits() > m.routes[j].prefix.Bits()
}) })
return f return f
@ -515,33 +515,33 @@ var (
func (m *Machine) writePacket(p *Packet) (n int, err error) { func (m *Machine) writePacket(p *Packet) (n int, err error) {
p.setLocator("mach=%s", m.Name) p.setLocator("mach=%s", m.Name)
iface, err := m.interfaceForIP(p.Dst.IP) iface, err := m.interfaceForIP(p.Dst.IP())
if err != nil { if err != nil {
p.Trace("%v", err) p.Trace("%v", err)
return 0, err return 0, err
} }
origSrcIP := p.Src.IP origSrcIP := p.Src.IP()
switch { switch {
case p.Src.IP == v4unspec: case p.Src.IP() == v4unspec:
p.Trace("assigning srcIP=%s", iface.V4()) p.Trace("assigning srcIP=%s", iface.V4())
p.Src.IP = iface.V4() p.Src = p.Src.WithIP(iface.V4())
case p.Src.IP == v6unspec: case p.Src.IP() == v6unspec:
// v6unspec in Go means "any src, but match address families" // v6unspec in Go means "any src, but match address families"
if p.Dst.IP.Is6() { if p.Dst.IP().Is6() {
p.Trace("assigning srcIP=%s", iface.V6()) p.Trace("assigning srcIP=%s", iface.V6())
p.Src.IP = iface.V6() p.Src = p.Src.WithIP(iface.V6())
} else if p.Dst.IP.Is4() { } else if p.Dst.IP().Is4() {
p.Trace("assigning srcIP=%s", iface.V4()) p.Trace("assigning srcIP=%s", iface.V4())
p.Src.IP = iface.V4() p.Src = p.Src.WithIP(iface.V4())
} }
default: default:
if !iface.Contains(p.Src.IP) { if !iface.Contains(p.Src.IP()) {
err := fmt.Errorf("can't send to %v with src %v on interface %v", p.Dst.IP, p.Src.IP, iface) err := fmt.Errorf("can't send to %v with src %v on interface %v", p.Dst.IP(), p.Src.IP(), iface)
p.Trace("%v", err) p.Trace("%v", err)
return 0, err return 0, err
} }
} }
if p.Src.IP.IsZero() { if p.Src.IP().IsZero() {
err := fmt.Errorf("no matching address for address family for %v", origSrcIP) err := fmt.Errorf("no matching address for address family for %v", origSrcIP)
p.Trace("%v", err) p.Trace("%v", err)
return 0, err return 0, err
@ -602,12 +602,12 @@ func (m *Machine) pickEphemPort() (port uint16, err error) {
func (m *Machine) portInUseLocked(port uint16) bool { func (m *Machine) portInUseLocked(port uint16) bool {
for ipp := range m.conns4 { for ipp := range m.conns4 {
if ipp.Port == port { if ipp.Port() == port {
return true return true
} }
} }
for ipp := range m.conns6 { for ipp := range m.conns6 {
if ipp.Port == port { if ipp.Port() == port {
return true return true
} }
} }
@ -617,7 +617,7 @@ func (m *Machine) portInUseLocked(port uint16) bool {
func (m *Machine) registerConn4(c *conn) error { func (m *Machine) registerConn4(c *conn) error {
m.mu.Lock() m.mu.Lock()
defer m.mu.Unlock() defer m.mu.Unlock()
if c.ipp.IP.Is6() && c.ipp.IP != v6unspec { if c.ipp.IP().Is6() && c.ipp.IP() != v6unspec {
return fmt.Errorf("registerConn4 got IPv6 %s", c.ipp) return fmt.Errorf("registerConn4 got IPv6 %s", c.ipp)
} }
return registerConn(&m.conns4, c) return registerConn(&m.conns4, c)
@ -632,7 +632,7 @@ func (m *Machine) unregisterConn4(c *conn) {
func (m *Machine) registerConn6(c *conn) error { func (m *Machine) registerConn6(c *conn) error {
m.mu.Lock() m.mu.Lock()
defer m.mu.Unlock() defer m.mu.Unlock()
if c.ipp.IP.Is4() { if c.ipp.IP().Is4() {
return fmt.Errorf("registerConn6 got IPv4 %s", c.ipp) return fmt.Errorf("registerConn6 got IPv4 %s", c.ipp)
} }
return registerConn(&m.conns6, c) return registerConn(&m.conns6, c)
@ -707,7 +707,7 @@ func (m *Machine) ListenPacket(ctx context.Context, network, address string) (ne
return nil, nil return nil, nil
} }
} }
ipp := netaddr.IPPort{IP: ip, Port: port} ipp := netaddr.IPPortFrom(ip, port)
c := &conn{ c := &conn{
m: m, m: m,

@ -49,8 +49,8 @@ func TestSendPacket(t *testing.T) {
ifFoo := foo.Attach("eth0", internet) ifFoo := foo.Attach("eth0", internet)
ifBar := bar.Attach("enp0s1", internet) ifBar := bar.Attach("enp0s1", internet)
fooAddr := netaddr.IPPort{IP: ifFoo.V4(), Port: 123} fooAddr := netaddr.IPPortFrom(ifFoo.V4(), 123)
barAddr := netaddr.IPPort{IP: ifBar.V4(), Port: 456} barAddr := netaddr.IPPortFrom(ifBar.V4(), 456)
ctx := context.Background() ctx := context.Background()
fooPC, err := foo.ListenPacket(ctx, "udp4", fooAddr.String()) fooPC, err := foo.ListenPacket(ctx, "udp4", fooAddr.String())
@ -111,10 +111,10 @@ func TestMultiNetwork(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
clientAddr := netaddr.IPPort{IP: ifClient.V4(), Port: 123} clientAddr := netaddr.IPPortFrom(ifClient.V4(), 123)
natLANAddr := netaddr.IPPort{IP: ifNATLAN.V4(), Port: 456} natLANAddr := netaddr.IPPortFrom(ifNATLAN.V4(), 456)
natWANAddr := netaddr.IPPort{IP: ifNATWAN.V4(), Port: 456} natWANAddr := netaddr.IPPortFrom(ifNATWAN.V4(), 456)
serverAddr := netaddr.IPPort{IP: ifServer.V4(), Port: 789} serverAddr := netaddr.IPPortFrom(ifServer.V4(), 789)
const msg1, msg2 = "hello", "world" const msg1, msg2 = "hello", "world"
if _, err := natPC.WriteTo([]byte(msg1), clientAddr.UDPAddr()); err != nil { if _, err := natPC.WriteTo([]byte(msg1), clientAddr.UDPAddr()); err != nil {
@ -154,8 +154,8 @@ type trivialNAT struct {
} }
func (n *trivialNAT) HandleIn(p *Packet, iface *Interface) *Packet { func (n *trivialNAT) HandleIn(p *Packet, iface *Interface) *Packet {
if iface == n.wanIf && p.Dst.IP == n.wanIf.V4() { if iface == n.wanIf && p.Dst.IP() == n.wanIf.V4() {
p.Dst.IP = n.clientIP p.Dst = p.Dst.WithIP(n.clientIP)
} }
return p return p
} }
@ -167,13 +167,13 @@ func (n trivialNAT) HandleOut(p *Packet, iface *Interface) *Packet {
func (n *trivialNAT) HandleForward(p *Packet, iif, oif *Interface) *Packet { func (n *trivialNAT) HandleForward(p *Packet, iif, oif *Interface) *Packet {
// Outbound from LAN -> apply NAT, continue // Outbound from LAN -> apply NAT, continue
if iif == n.lanIf && oif == n.wanIf { if iif == n.lanIf && oif == n.wanIf {
if p.Src.IP == n.clientIP { if p.Src.IP() == n.clientIP {
p.Src.IP = n.wanIf.V4() p.Src = p.Src.WithIP(n.wanIf.V4())
} }
return p return p
} }
// Return traffic to LAN, allow if right dst. // Return traffic to LAN, allow if right dst.
if iif == n.wanIf && oif == n.lanIf && p.Dst.IP == n.clientIP { if iif == n.wanIf && oif == n.lanIf && p.Dst.IP() == n.clientIP {
return p return p
} }
// Else drop. // Else drop.
@ -216,7 +216,7 @@ func TestPacketHandler(t *testing.T) {
} }
const msg = "some message" const msg = "some message"
serverAddr := netaddr.IPPort{IP: ifServer.V4(), Port: 456} serverAddr := netaddr.IPPortFrom(ifServer.V4(), 456)
if _, err := clientPC.WriteTo([]byte(msg), serverAddr.UDPAddr()); err != nil { if _, err := clientPC.WriteTo([]byte(msg), serverAddr.UDPAddr()); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -230,7 +230,7 @@ func TestPacketHandler(t *testing.T) {
if string(buf) != msg { if string(buf) != msg {
t.Errorf("read %q; want %q", buf, msg) t.Errorf("read %q; want %q", buf, msg)
} }
mappedAddr := netaddr.IPPort{IP: ifNATWAN.V4(), Port: 123} mappedAddr := netaddr.IPPortFrom(ifNATWAN.V4(), 123)
if addr.String() != mappedAddr.String() { if addr.String() != mappedAddr.String() {
t.Errorf("addr = %q; want %q", addr, mappedAddr) t.Errorf("addr = %q; want %q", addr, mappedAddr)
} }

@ -250,7 +250,7 @@ func TestConciseDiffFrom(t *testing.T) {
DERP: "127.3.3.40:2", DERP: "127.3.3.40:2",
Endpoints: []string{"192.168.0.100:41641", "1.1.1.1:41641"}, Endpoints: []string{"192.168.0.100:41641", "1.1.1.1:41641"},
DiscoKey: testDiscoKey("f00f00f00f"), DiscoKey: testDiscoKey("f00f00f00f"),
AllowedIPs: []netaddr.IPPrefix{{IP: netaddr.IPv4(100, 102, 103, 104), Bits: 32}}, AllowedIPs: []netaddr.IPPrefix{netaddr.IPPrefixFrom(netaddr.IPv4(100, 102, 103, 104), 32)},
}, },
}, },
}, },
@ -263,7 +263,7 @@ func TestConciseDiffFrom(t *testing.T) {
DERP: "127.3.3.40:2", DERP: "127.3.3.40:2",
Endpoints: []string{"192.168.0.100:41641", "1.1.1.1:41641"}, Endpoints: []string{"192.168.0.100:41641", "1.1.1.1:41641"},
DiscoKey: testDiscoKey("ba4ba4ba4b"), DiscoKey: testDiscoKey("ba4ba4ba4b"),
AllowedIPs: []netaddr.IPPrefix{{IP: netaddr.IPv4(100, 102, 103, 104), Bits: 32}}, AllowedIPs: []netaddr.IPPrefix{netaddr.IPPrefixFrom(netaddr.IPv4(100, 102, 103, 104), 32)},
}, },
}, },
}, },

@ -218,7 +218,7 @@ func (f *Firewall) UpdatePermittedRoutes(newRoutes []netaddr.IPPrefix) error {
}, },
} }
var p protocol var p protocol
if r.IP.Is4() { if r.IP().Is4() {
p = protocolV4 p = protocolV4
} else { } else {
p = protocolV6 p = protocolV6

@ -87,7 +87,7 @@ func main() {
} }
logf("initialized ok.") logf("initialized ok.")
traf.Start(Addr1.IP, Addr2.IP, PayloadSize+ICMPMinSize, 0) traf.Start(Addr1.IP(), Addr2.IP(), PayloadSize+ICMPMinSize, 0)
var cur, prev Snapshot var cur, prev Snapshot
var pps int64 var pps int64

@ -78,7 +78,7 @@ func runOnce(b *testing.B, setup SetupFunc, payload int) {
logf("initialized. (n=%v)", b.N) logf("initialized. (n=%v)", b.N)
b.SetBytes(int64(payload)) b.SetBytes(int64(payload))
traf.Start(Addr1.IP, Addr2.IP, payload, int64(b.N)) traf.Start(Addr1.IP(), Addr2.IP(), payload, int64(b.N))
var cur, prev Snapshot var cur, prev Snapshot
var pps int64 var pps int64

@ -98,8 +98,8 @@ const (
// everything. Use in tests only, as it permits some kinds of spoofing // everything. Use in tests only, as it permits some kinds of spoofing
// attacks to reach the OS network stack. // attacks to reach the OS network stack.
func NewAllowAllForTest(logf logger.Logf) *Filter { func NewAllowAllForTest(logf logger.Logf) *Filter {
any4 := netaddr.IPPrefix{IP: netaddr.IPv4(0, 0, 0, 0), Bits: 0} any4 := netaddr.IPPrefixFrom(netaddr.IPv4(0, 0, 0, 0), 0)
any6 := netaddr.IPPrefix{IP: netaddr.IPFrom16([16]byte{}), Bits: 0} any6 := netaddr.IPPrefixFrom(netaddr.IPFrom16([16]byte{}), 0)
ms := []Match{ ms := []Match{
{ {
Srcs: []netaddr.IPPrefix{any4}, Srcs: []netaddr.IPPrefix{any4},
@ -185,12 +185,12 @@ func matchesFamily(ms matches, keep func(netaddr.IP) bool) matches {
var retm Match var retm Match
retm.IPProto = m.IPProto retm.IPProto = m.IPProto
for _, src := range m.Srcs { for _, src := range m.Srcs {
if keep(src.IP) { if keep(src.IP()) {
retm.Srcs = append(retm.Srcs, src) retm.Srcs = append(retm.Srcs, src)
} }
} }
for _, dst := range m.Dsts { for _, dst := range m.Dsts {
if keep(dst.Net.IP) { if keep(dst.Net.IP()) {
retm.Dsts = append(retm.Dsts, dst) retm.Dsts = append(retm.Dsts, dst)
} }
} }
@ -266,12 +266,10 @@ func (f *Filter) CheckTCP(srcIP, dstIP netaddr.IP, dstPort uint16) Response {
default: default:
panic("unreachable") panic("unreachable")
} }
pkt.Src.IP = srcIP pkt.Src = netaddr.IPPortFrom(srcIP, 0)
pkt.Dst.IP = dstIP pkt.Dst = netaddr.IPPortFrom(dstIP, dstPort)
pkt.IPProto = ipproto.TCP pkt.IPProto = ipproto.TCP
pkt.TCPFlags = packet.TCPSyn pkt.TCPFlags = packet.TCPSyn
pkt.Src.Port = 0
pkt.Dst.Port = dstPort
return f.RunIn(pkt, 0) return f.RunIn(pkt, 0)
} }
@ -321,7 +319,7 @@ func (f *Filter) runIn4(q *packet.Parsed) (r Response, why string) {
// A compromised peer could try to send us packets for // A compromised peer could try to send us packets for
// destinations we didn't explicitly advertise. This check is to // destinations we didn't explicitly advertise. This check is to
// prevent that. // prevent that.
if !f.local.Contains(q.Dst.IP) { if !f.local.Contains(q.Dst.IP()) {
return Drop, "destination not allowed" return Drop, "destination not allowed"
} }
@ -378,7 +376,7 @@ func (f *Filter) runIn6(q *packet.Parsed) (r Response, why string) {
// A compromised peer could try to send us packets for // A compromised peer could try to send us packets for
// destinations we didn't explicitly advertise. This check is to // destinations we didn't explicitly advertise. This check is to
// prevent that. // prevent that.
if !f.local.Contains(q.Dst.IP) { if !f.local.Contains(q.Dst.IP()) {
return Drop, "destination not allowed" return Drop, "destination not allowed"
} }
@ -480,11 +478,11 @@ func (f *Filter) pre(q *packet.Parsed, rf RunFlags, dir direction) Response {
return Drop return Drop
} }
if q.Dst.IP.IsMulticast() { if q.Dst.IP().IsMulticast() {
f.logRateLimit(rf, q, dir, Drop, "multicast") f.logRateLimit(rf, q, dir, Drop, "multicast")
return Drop return Drop
} }
if q.Dst.IP.IsLinkLocalUnicast() && q.Dst.IP != gcpDNSAddr { if q.Dst.IP().IsLinkLocalUnicast() && q.Dst.IP() != gcpDNSAddr {
f.logRateLimit(rf, q, dir, Drop, "link-local-unicast") f.logRateLimit(rf, q, dir, Drop, "link-local-unicast")
return Drop return Drop
} }
@ -506,7 +504,7 @@ func (f *Filter) pre(q *packet.Parsed, rf RunFlags, dir direction) Response {
// loggingAllowed reports whether p can appear in logs at all. // loggingAllowed reports whether p can appear in logs at all.
func (f *Filter) loggingAllowed(p *packet.Parsed) bool { func (f *Filter) loggingAllowed(p *packet.Parsed) bool {
return f.logIPs.Contains(p.Src.IP) && f.logIPs.Contains(p.Dst.IP) return f.logIPs.Contains(p.Src.IP()) && f.logIPs.Contains(p.Dst.IP())
} }
// omitDropLogging reports whether packet p, which has already been // omitDropLogging reports whether packet p, which has already been
@ -518,5 +516,5 @@ func omitDropLogging(p *packet.Parsed, dir direction) bool {
return false return false
} }
return p.Dst.IP.IsMulticast() || (p.Dst.IP.IsLinkLocalUnicast() && p.Dst.IP != gcpDNSAddr) || p.IPProto == ipproto.IGMP return p.Dst.IP().IsMulticast() || (p.Dst.IP().IsLinkLocalUnicast() && p.Dst.IP() != gcpDNSAddr) || p.IPProto == ipproto.IGMP
} }

@ -120,9 +120,9 @@ func TestFilter(t *testing.T) {
if test.p.IPProto == ipproto.TCP { if test.p.IPProto == ipproto.TCP {
var got Response var got Response
if test.p.IPVersion == 4 { if test.p.IPVersion == 4 {
got = acl.CheckTCP(test.p.Src.IP, test.p.Dst.IP, test.p.Dst.Port) got = acl.CheckTCP(test.p.Src.IP(), test.p.Dst.IP(), test.p.Dst.Port())
} else { } else {
got = acl.CheckTCP(test.p.Src.IP, test.p.Dst.IP, test.p.Dst.Port) got = acl.CheckTCP(test.p.Src.IP(), test.p.Dst.IP(), test.p.Dst.Port())
} }
if test.want != got { if test.want != got {
t.Errorf("#%d CheckTCP got=%v want=%v packet:%v", i, got, test.want, test.p) t.Errorf("#%d CheckTCP got=%v want=%v packet:%v", i, got, test.want, test.p)
@ -254,7 +254,9 @@ func TestParseIPSet(t *testing.T) {
} }
t.Errorf("parseIPSet(%q, %v) error: %v; want error %q", tt.host, tt.bits, err, tt.wantErr) t.Errorf("parseIPSet(%q, %v) error: %v; want error %q", tt.host, tt.bits, err, tt.wantErr)
} }
if diff := cmp.Diff(got, tt.want, cmp.Comparer(func(a, b netaddr.IP) bool { return a == b })); diff != "" { compareIP := cmp.Comparer(func(a, b netaddr.IP) bool { return a == b })
compareIPPrefix := cmp.Comparer(func(a, b netaddr.IPPrefix) bool { return a == b })
if diff := cmp.Diff(got, tt.want, compareIP, compareIPPrefix); diff != "" {
t.Errorf("parseIPSet(%q, %v) = %s; want %s", tt.host, tt.bits, got, tt.want) t.Errorf("parseIPSet(%q, %v) = %s; want %s", tt.host, tt.bits, got, tt.want)
continue continue
} }
@ -425,10 +427,10 @@ func TestLoggingPrivacy(t *testing.T) {
f.logIPs = logB.IPSet() f.logIPs = logB.IPSet()
var ( var (
ts4 = netaddr.IPPort{IP: tsaddr.CGNATRange().IP.Next(), Port: 1234} ts4 = netaddr.IPPortFrom(tsaddr.CGNATRange().IP().Next(), 1234)
internet4 = netaddr.IPPort{IP: netaddr.MustParseIP("8.8.8.8"), Port: 1234} internet4 = netaddr.IPPortFrom(netaddr.MustParseIP("8.8.8.8"), 1234)
ts6 = netaddr.IPPort{IP: tsaddr.TailscaleULARange().IP.Next(), Port: 1234} ts6 = netaddr.IPPortFrom(tsaddr.TailscaleULARange().IP().Next(), 1234)
internet6 = netaddr.IPPort{IP: netaddr.MustParseIP("2001::1"), Port: 1234} internet6 = netaddr.IPPortFrom(netaddr.MustParseIP("2001::1"), 1234)
) )
tests := []struct { tests := []struct {
@ -545,10 +547,8 @@ func parsed(proto ipproto.Proto, src, dst string, sport, dport uint16) packet.Pa
var ret packet.Parsed var ret packet.Parsed
ret.Decode(dummyPacket) ret.Decode(dummyPacket)
ret.IPProto = proto ret.IPProto = proto
ret.Src.IP = sip ret.Src = netaddr.IPPortFrom(sip, sport)
ret.Src.Port = sport ret.Dst = netaddr.IPPortFrom(dip, dport)
ret.Dst.IP = dip
ret.Dst.Port = dport
ret.TCPFlags = packet.TCPSyn ret.TCPFlags = packet.TCPSyn
if sip.Is4() { if sip.Is4() {
@ -674,7 +674,7 @@ func nets(nets ...string) (ret []netaddr.IPPrefix) {
if ip.Is6() { if ip.Is6() {
bits = 128 bits = 128
} }
ret = append(ret, netaddr.IPPrefix{IP: ip, Bits: bits}) ret = append(ret, netaddr.IPPrefixFrom(ip, bits))
} else { } else {
pfx, err := netaddr.ParseIPPrefix(s) pfx, err := netaddr.ParseIPPrefix(s)
if err != nil { if err != nil {

@ -85,14 +85,14 @@ func (ms matches) match(q *packet.Parsed) bool {
if !protoInList(q.IPProto, m.IPProto) { if !protoInList(q.IPProto, m.IPProto) {
continue continue
} }
if !ipInList(q.Src.IP, m.Srcs) { if !ipInList(q.Src.IP(), m.Srcs) {
continue continue
} }
for _, dst := range m.Dsts { for _, dst := range m.Dsts {
if !dst.Net.Contains(q.Dst.IP) { if !dst.Net.Contains(q.Dst.IP()) {
continue continue
} }
if !dst.Ports.contains(q.Dst.Port) { if !dst.Ports.contains(q.Dst.Port()) {
continue continue
} }
return true return true
@ -103,11 +103,11 @@ func (ms matches) match(q *packet.Parsed) bool {
func (ms matches) matchIPsOnly(q *packet.Parsed) bool { func (ms matches) matchIPsOnly(q *packet.Parsed) bool {
for _, m := range ms { for _, m := range ms {
if !ipInList(q.Src.IP, m.Srcs) { if !ipInList(q.Src.IP(), m.Srcs) {
continue continue
} }
for _, dst := range m.Dsts { for _, dst := range m.Dsts {
if dst.Net.Contains(q.Dst.IP) { if dst.Net.Contains(q.Dst.IP()) {
return true return true
} }
} }

@ -99,8 +99,8 @@ func parseIPSet(arg string, bits *int) ([]netaddr.IPPrefix, error) {
if arg == "*" { if arg == "*" {
// User explicitly requested wildcard. // User explicitly requested wildcard.
return []netaddr.IPPrefix{ return []netaddr.IPPrefix{
{IP: zeroIP4, Bits: 0}, netaddr.IPPrefixFrom(zeroIP4, 0),
{IP: zeroIP6, Bits: 0}, netaddr.IPPrefixFrom(zeroIP6, 0),
}, nil }, nil
} }
if strings.Contains(arg, "/") { if strings.Contains(arg, "/") {
@ -124,7 +124,7 @@ func parseIPSet(arg string, bits *int) ([]netaddr.IPPrefix, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
r := netaddr.IPRange{From: ip1, To: ip2} r := netaddr.IPRangeFrom(ip1, ip2)
if !r.Valid() { if !r.Valid() {
return nil, fmt.Errorf("invalid IP range %q", arg) return nil, fmt.Errorf("invalid IP range %q", arg)
} }
@ -141,5 +141,5 @@ func parseIPSet(arg string, bits *int) ([]netaddr.IPPrefix, error) {
} }
bits8 = uint8(*bits) bits8 = uint8(*bits)
} }
return []netaddr.IPPrefix{{IP: ip, Bits: bits8}}, nil return []netaddr.IPPrefix{netaddr.IPPrefixFrom(ip, bits8)}, nil
} }

@ -62,7 +62,7 @@ func (c *Conn) createLegacyEndpointLocked(pk key.Public, addrs wgcfg.IPPortSet,
// Add entries to c.addrsByUDP. // Add entries to c.addrsByUDP.
for _, ipp := range a.ipPorts { for _, ipp := range a.ipPorts {
if ipp.IP == derpMagicIPAddr { if ipp.IP() == derpMagicIPAddr {
continue continue
} }
c.addrsByUDP[ipp] = a c.addrsByUDP[ipp] = a
@ -70,7 +70,7 @@ func (c *Conn) createLegacyEndpointLocked(pk key.Public, addrs wgcfg.IPPortSet,
// Remove previous c.addrsByUDP entries that are no longer in the new set. // Remove previous c.addrsByUDP entries that are no longer in the new set.
for _, ipp := range oldIPP { for _, ipp := range oldIPP {
if ipp.IP != derpMagicIPAddr && c.addrsByUDP[ipp] != a { if ipp.IP() != derpMagicIPAddr && c.addrsByUDP[ipp] != a {
delete(c.addrsByUDP, ipp) delete(c.addrsByUDP, ipp)
} }
} }
@ -388,8 +388,8 @@ type addrSet struct {
// derpID returns this addrSet's home DERP node, or 0 if none is found. // derpID returns this addrSet's home DERP node, or 0 if none is found.
func (as *addrSet) derpID() int { func (as *addrSet) derpID() int {
for _, ua := range as.ipPorts { for _, ua := range as.ipPorts {
if ua.IP == derpMagicIPAddr { if ua.IP() == derpMagicIPAddr {
return int(ua.Port) return int(ua.Port())
} }
} }
return 0 return 0
@ -428,7 +428,7 @@ func (a *addrSet) DstToString() string {
return a.rawdst return a.rawdst
} }
func (a *addrSet) DstIP() net.IP { func (a *addrSet) DstIP() net.IP {
return a.dst().IP.IPAddr().IP // TODO: add netaddr accessor to cut an alloc here? return a.dst().IP().IPAddr().IP // TODO: add netaddr accessor to cut an alloc here?
} }
func (a *addrSet) SrcIP() net.IP { return nil } func (a *addrSet) SrcIP() net.IP { return nil }
func (a *addrSet) SrcToString() string { return "" } func (a *addrSet) SrcToString() string { return "" }
@ -437,7 +437,7 @@ func (a *addrSet) ClearSrc() {}
// updateDst records receipt of a packet from new. This is used to // updateDst records receipt of a packet from new. This is used to
// potentially update the transmit address used for this addrSet. // potentially update the transmit address used for this addrSet.
func (a *addrSet) updateDst(new netaddr.IPPort) error { func (a *addrSet) updateDst(new netaddr.IPPort) error {
if new.IP == derpMagicIPAddr { if new.IP() == derpMagicIPAddr {
// Never consider DERP addresses as a viable candidate for // Never consider DERP addresses as a viable candidate for
// either curAddr or roamAddr. It's only ever a last resort // either curAddr or roamAddr. It's only ever a last resort
// choice, never a preferred choice. // choice, never a preferred choice.
@ -539,7 +539,7 @@ func (as *addrSet) populatePeerStatus(ps *ipnstate.PeerStatus) {
ps.LastWrite = as.lastSend ps.LastWrite = as.lastSend
for i, ua := range as.ipPorts { for i, ua := range as.ipPorts {
if ua.IP == derpMagicIPAddr { if ua.IP() == derpMagicIPAddr {
continue continue
} }
uaStr := ua.String() uaStr := ua.String()

@ -832,7 +832,7 @@ func (c *Conn) Ping(peer *tailcfg.Node, res *ipnstate.PingResult, cb func(*ipnst
return return
} }
if len(peer.Addresses) > 0 { if len(peer.Addresses) > 0 {
res.NodeIP = peer.Addresses[0].IP.String() res.NodeIP = peer.Addresses[0].IP().String()
} }
res.NodeName = peer.Name // prefer DNS name res.NodeName = peer.Name // prefer DNS name
if res.NodeName == "" { if res.NodeName == "" {
@ -878,11 +878,11 @@ func (c *Conn) Ping(peer *tailcfg.Node, res *ipnstate.PingResult, cb func(*ipnst
// c.mu must be held // c.mu must be held
func (c *Conn) populateCLIPingResponseLocked(res *ipnstate.PingResult, latency time.Duration, ep netaddr.IPPort) { func (c *Conn) populateCLIPingResponseLocked(res *ipnstate.PingResult, latency time.Duration, ep netaddr.IPPort) {
res.LatencySeconds = latency.Seconds() res.LatencySeconds = latency.Seconds()
if ep.IP != derpMagicIPAddr { if ep.IP() != derpMagicIPAddr {
res.Endpoint = ep.String() res.Endpoint = ep.String()
return return
} }
regionID := int(ep.Port) regionID := int(ep.Port())
res.DERPRegionID = regionID res.DERPRegionID = regionID
if c.derpMap != nil { if c.derpMap != nil {
if dr, ok := c.derpMap.Regions[regionID]; ok { if dr, ok := c.derpMap.Regions[regionID]; ok {
@ -965,7 +965,7 @@ func (c *Conn) goDerpConnect(node int) {
if node == 0 { if node == 0 {
return return
} }
go c.derpWriteChanOfAddr(netaddr.IPPort{IP: derpMagicIPAddr, Port: uint16(node)}, key.Public{}) go c.derpWriteChanOfAddr(netaddr.IPPortFrom(derpMagicIPAddr, uint16(node)), key.Public{})
} }
// determineEndpoints returns the machine's endpoint addresses. It // determineEndpoints returns the machine's endpoint addresses. It
@ -1037,7 +1037,7 @@ func (c *Conn) determineEndpoints(ctx context.Context) ([]tailcfg.Endpoint, erro
ips = loopback ips = loopback
} }
for _, ip := range ips { for _, ip := range ips {
addAddr(netaddr.IPPort{IP: ip, Port: uint16(localAddr.Port)}, tailcfg.EndpointLocal) addAddr(netaddr.IPPortFrom(ip, uint16(localAddr.Port)), tailcfg.EndpointLocal)
} }
} else { } else {
// Our local endpoint is bound to a particular address. // Our local endpoint is bound to a particular address.
@ -1169,7 +1169,7 @@ func (c *Conn) sendUDPStd(addr *net.UDPAddr, b []byte) (sent bool, err error) {
// IPv6 address when the local machine doesn't have IPv6 support // IPv6 address when the local machine doesn't have IPv6 support
// returns (false, nil); it's not an error, but nothing was sent. // returns (false, nil); it's not an error, but nothing was sent.
func (c *Conn) sendAddr(addr netaddr.IPPort, pubKey key.Public, b []byte) (sent bool, err error) { func (c *Conn) sendAddr(addr netaddr.IPPort, pubKey key.Public, b []byte) (sent bool, err error) {
if addr.IP != derpMagicIPAddr { if addr.IP() != derpMagicIPAddr {
return c.sendUDP(addr, b) return c.sendUDP(addr, b)
} }
@ -1211,10 +1211,10 @@ const bufferedDerpWritesBeforeDrop = 32
// If peer is non-zero, it can be used to find an active reverse // If peer is non-zero, it can be used to find an active reverse
// path, without using addr. // path, without using addr.
func (c *Conn) derpWriteChanOfAddr(addr netaddr.IPPort, peer key.Public) chan<- derpWriteRequest { func (c *Conn) derpWriteChanOfAddr(addr netaddr.IPPort, peer key.Public) chan<- derpWriteRequest {
if addr.IP != derpMagicIPAddr { if addr.IP() != derpMagicIPAddr {
return nil return nil
} }
regionID := int(addr.Port) regionID := int(addr.Port())
if c.networkDown() { if c.networkDown() {
return nil return nil
@ -1402,7 +1402,7 @@ func (c *Conn) runDerpReader(ctx context.Context, derpFakeAddr netaddr.IPPort, d
} }
didCopy := make(chan struct{}, 1) didCopy := make(chan struct{}, 1)
regionID := int(derpFakeAddr.Port) regionID := int(derpFakeAddr.Port())
res := derpReadResult{regionID: regionID} res := derpReadResult{regionID: regionID}
var pkt derp.ReceivedPacket var pkt derp.ReceivedPacket
res.copyBuf = func(dst []byte) int { res.copyBuf = func(dst []byte) int {
@ -1676,7 +1676,7 @@ func (c *Conn) processDERPReadResult(dm derpReadResult, b []byte) (n int, ep con
return 0, nil return 0, nil
} }
ipp := netaddr.IPPort{IP: derpMagicIPAddr, Port: uint16(regionID)} ipp := netaddr.IPPortFrom(derpMagicIPAddr, uint16(regionID))
if c.handleDiscoMessage(b[:n], ipp) { if c.handleDiscoMessage(b[:n], ipp) {
return 0, nil return 0, nil
} }
@ -1922,7 +1922,7 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netaddr.IPPort) (isDiscoMsg bo
} }
de.handlePongConnLocked(dm, src) de.handlePongConnLocked(dm, src)
case *disco.CallMeMaybe: case *disco.CallMeMaybe:
if src.IP != derpMagicIPAddr { if src.IP() != derpMagicIPAddr {
// CallMeMaybe messages should only come via DERP. // CallMeMaybe messages should only come via DERP.
c.logf("[unexpected] CallMeMaybe packets should only come via DERP") c.logf("[unexpected] CallMeMaybe packets should only come via DERP")
return return
@ -2722,7 +2722,7 @@ func (c *Conn) resetEndpointStates() {
// packIPPort packs an IPPort into the form wanted by WireGuard. // packIPPort packs an IPPort into the form wanted by WireGuard.
func packIPPort(ua netaddr.IPPort) []byte { func packIPPort(ua netaddr.IPPort) []byte {
ip := ua.IP.Unmap() ip := ua.IP().Unmap()
a := ip.As16() a := ip.As16()
ipb := a[:] ipb := a[:]
if ip.Is4() { if ip.Is4() {
@ -2730,8 +2730,8 @@ func packIPPort(ua netaddr.IPPort) []byte {
} }
b := make([]byte, 0, len(ipb)+2) b := make([]byte, 0, len(ipb)+2)
b = append(b, ipb...) b = append(b, ipb...)
b = append(b, byte(ua.Port)) b = append(b, byte(ua.Port()))
b = append(b, byte(ua.Port>>8)) b = append(b, byte(ua.Port()>>8))
return b return b
} }
@ -2972,15 +2972,15 @@ func peerShort(k key.Public) string {
} }
func sbPrintAddr(sb *strings.Builder, a netaddr.IPPort) { func sbPrintAddr(sb *strings.Builder, a netaddr.IPPort) {
is6 := a.IP.Is6() is6 := a.IP().Is6()
if is6 { if is6 {
sb.WriteByte('[') sb.WriteByte('[')
} }
fmt.Fprintf(sb, "%s", a.IP) fmt.Fprintf(sb, "%s", a.IP())
if is6 { if is6 {
sb.WriteByte(']') sb.WriteByte(']')
} }
fmt.Fprintf(sb, ":%d", a.Port) fmt.Fprintf(sb, ":%d", a.Port())
} }
func (c *Conn) derpRegionCodeOfAddrLocked(ipPort string) string { func (c *Conn) derpRegionCodeOfAddrLocked(ipPort string) string {
@ -3017,15 +3017,15 @@ func (c *Conn) UpdateStatus(sb *ipnstate.StatusBuilder) {
if !addr.IsSingleIP() { if !addr.IsSingleIP() {
continue continue
} }
sb.AddTailscaleIP(addr.IP) sb.AddTailscaleIP(addr.IP())
// TailAddr previously only allowed for a // TailAddr previously only allowed for a
// single Tailscale IP. For compatibility for // single Tailscale IP. For compatibility for
// a couple releases starting with 1.8, keep // a couple releases starting with 1.8, keep
// that field pulled out separately. // that field pulled out separately.
if addr.IP.Is4() { if addr.IP().Is4() {
tailAddr4 = addr.IP.String() tailAddr4 = addr.IP().String()
} }
tailscaleIPs = append(tailscaleIPs, addr.IP) tailscaleIPs = append(tailscaleIPs, addr.IP())
} }
} }
@ -3084,8 +3084,8 @@ func (c *Conn) UpdateStatus(sb *ipnstate.StatusBuilder) {
} }
func ippDebugString(ua netaddr.IPPort) string { func ippDebugString(ua netaddr.IPPort) string {
if ua.IP == derpMagicIPAddr { if ua.IP() == derpMagicIPAddr {
return fmt.Sprintf("derp-%d", ua.Port) return fmt.Sprintf("derp-%d", ua.Port())
} }
return ua.String() return ua.String()
} }
@ -3254,10 +3254,7 @@ func (de *discoEndpoint) initFakeUDPAddr() {
addr[0] = 0xfd addr[0] = 0xfd
addr[1] = 0x00 addr[1] = 0x00
binary.BigEndian.PutUint64(addr[2:], uint64(reflect.ValueOf(de).Pointer())) binary.BigEndian.PutUint64(addr[2:], uint64(reflect.ValueOf(de).Pointer()))
de.fakeWGAddr = netaddr.IPPort{ de.fakeWGAddr = netaddr.IPPortFrom(netaddr.IPFrom16(addr), 12345)
IP: netaddr.IPFrom16(addr),
Port: 12345,
}
} }
// isFirstRecvActivityInAwhile notes that receive activity has occured for this // isFirstRecvActivityInAwhile notes that receive activity has occured for this
@ -3632,7 +3629,7 @@ func (de *discoEndpoint) handlePongConnLocked(m *disco.Pong, src netaddr.IPPort)
de.mu.Lock() de.mu.Lock()
defer de.mu.Unlock() defer de.mu.Unlock()
isDerp := src.IP == derpMagicIPAddr isDerp := src.IP() == derpMagicIPAddr
sp, ok := de.sentPing[m.TxID] sp, ok := de.sentPing[m.TxID]
if !ok { if !ok {
@ -3708,13 +3705,13 @@ func betterAddr(a, b addrLatency) bool {
if a.IsZero() { if a.IsZero() {
return false return false
} }
if a.IP.Is6() && b.IP.Is4() { if a.IP().Is6() && b.IP().Is4() {
// Prefer IPv6 for being a bit more robust, as long as // Prefer IPv6 for being a bit more robust, as long as
// the latencies are roughly equivalent. // the latencies are roughly equivalent.
if a.latency/10*9 < b.latency { if a.latency/10*9 < b.latency {
return true return true
} }
} else if a.IP.Is4() && b.IP.Is6() { } else if a.IP().Is4() && b.IP().Is6() {
if betterAddr(b, a) { if betterAddr(b, a) {
return false return false
} }
@ -3754,7 +3751,7 @@ func (de *discoEndpoint) handleCallMeMaybe(m *disco.CallMeMaybe) {
} }
var newEPs []netaddr.IPPort var newEPs []netaddr.IPPort
for _, ep := range m.MyNumber { for _, ep := range m.MyNumber {
if ep.IP.Is6() && ep.IP.IsLinkLocalUnicast() { if ep.IP().Is6() && ep.IP().IsLinkLocalUnicast() {
// We send these out, but ignore them for now. // We send these out, but ignore them for now.
// TODO: teach the ping code to ping on all interfaces // TODO: teach the ping code to ping on all interfaces
// for these. // for these.

@ -252,13 +252,13 @@ func meshStacks(logf logger.Logf, ms []*magicStack) (cleanup func()) {
nm := &netmap.NetworkMap{ nm := &netmap.NetworkMap{
PrivateKey: me.privateKey, PrivateKey: me.privateKey,
NodeKey: tailcfg.NodeKey(me.privateKey.Public()), NodeKey: tailcfg.NodeKey(me.privateKey.Public()),
Addresses: []netaddr.IPPrefix{{IP: netaddr.IPv4(1, 0, 0, byte(myIdx+1)), Bits: 32}}, Addresses: []netaddr.IPPrefix{netaddr.IPPrefixFrom(netaddr.IPv4(1, 0, 0, byte(myIdx+1)), 32)},
} }
for i, peer := range ms { for i, peer := range ms {
if i == myIdx { if i == myIdx {
continue continue
} }
addrs := []netaddr.IPPrefix{{IP: netaddr.IPv4(1, 0, 0, byte(i+1)), Bits: 32}} addrs := []netaddr.IPPrefix{netaddr.IPPrefixFrom(netaddr.IPv4(1, 0, 0, byte(i+1)), 32)}
peer := &tailcfg.Node{ peer := &tailcfg.Node{
ID: tailcfg.NodeID(i + 1), ID: tailcfg.NodeID(i + 1),
Name: fmt.Sprintf("node%d", i+1), Name: fmt.Sprintf("node%d", i+1),
@ -433,7 +433,7 @@ func TestPickDERPFallback(t *testing.T) {
// But move if peers are elsewhere. // But move if peers are elsewhere.
const otherNode = 789 const otherNode = 789
c.addrsByKey = map[key.Public]*addrSet{ c.addrsByKey = map[key.Public]*addrSet{
{1}: {ipPorts: []netaddr.IPPort{{IP: derpMagicIPAddr, Port: otherNode}}}, {1}: {ipPorts: []netaddr.IPPort{netaddr.IPPortFrom(derpMagicIPAddr, otherNode)}},
} }
if got := c.pickDERPFallback(); got != otherNode { if got := c.pickDERPFallback(); got != otherNode {
t.Errorf("didn't join peers: got %v; want %v", got, someNode) t.Errorf("didn't join peers: got %v; want %v", got, someNode)
@ -887,8 +887,8 @@ func testTwoDevicePing(t *testing.T, d *devices) {
defer m2.Close() defer m2.Close()
addrs := []netaddr.IPPort{ addrs := []netaddr.IPPort{
{IP: d.m1IP, Port: m1.conn.LocalPort()}, netaddr.IPPortFrom(d.m1IP, m1.conn.LocalPort()),
{IP: d.m2IP, Port: m2.conn.LocalPort()}, netaddr.IPPortFrom(d.m2IP, m2.conn.LocalPort()),
} }
cfgs := makeConfigs(t, addrs) cfgs := makeConfigs(t, addrs)
@ -1555,7 +1555,7 @@ func TestEndpointSetsEqual(t *testing.T) {
s := func(ports ...uint16) (ret []tailcfg.Endpoint) { s := func(ports ...uint16) (ret []tailcfg.Endpoint) {
for _, port := range ports { for _, port := range ports {
ret = append(ret, tailcfg.Endpoint{ ret = append(ret, tailcfg.Endpoint{
Addr: netaddr.IPPort{Port: port}, Addr: netaddr.IPPortFrom(netaddr.IP{}, port),
}) })
} }
return return

@ -130,11 +130,11 @@ func netaddrIP(std net.IP) netaddr.IP {
func netaddrIPPrefix(std net.IP, bits uint8) netaddr.IPPrefix { func netaddrIPPrefix(std net.IP, bits uint8) netaddr.IPPrefix {
ip, _ := netaddr.FromStdIP(std) ip, _ := netaddr.FromStdIP(std)
return netaddr.IPPrefix{IP: ip, Bits: bits} return netaddr.IPPrefixFrom(ip, bits)
} }
func condNetAddrPrefix(ipp netaddr.IPPrefix) string { func condNetAddrPrefix(ipp netaddr.IPPrefix) string {
if ipp.IP.IsZero() { if ipp.IP().IsZero() {
return "" return ""
} }
return ipp.String() return ipp.String()
@ -157,7 +157,7 @@ type newRouteMessage struct {
const tsTable = 52 const tsTable = 52
func (m *newRouteMessage) ignore() bool { func (m *newRouteMessage) ignore() bool {
return m.Table == tsTable || tsaddr.IsTailscaleIP(m.Dst.IP) return m.Table == tsTable || tsaddr.IsTailscaleIP(m.Dst.IP())
} }
// newAddrMessage is a message for a new address being added. // newAddrMessage is a message for a new address being added.

@ -179,7 +179,7 @@ func DNSMapFromNetworkMap(nm *netmap.NetworkMap) DNSMap {
suffix := nm.MagicDNSSuffix() suffix := nm.MagicDNSSuffix()
if nm.Name != "" && len(nm.Addresses) > 0 { if nm.Name != "" && len(nm.Addresses) > 0 {
ip := nm.Addresses[0].IP ip := nm.Addresses[0].IP()
ret[strings.TrimRight(nm.Name, ".")] = ip ret[strings.TrimRight(nm.Name, ".")] = ip
if dnsname.HasSuffix(nm.Name, suffix) { if dnsname.HasSuffix(nm.Name, suffix) {
ret[dnsname.TrimSuffix(nm.Name, suffix)] = ip ret[dnsname.TrimSuffix(nm.Name, suffix)] = ip
@ -187,7 +187,7 @@ func DNSMapFromNetworkMap(nm *netmap.NetworkMap) DNSMap {
} }
for _, p := range nm.Peers { for _, p := range nm.Peers {
if p.Name != "" && len(p.Addresses) > 0 { if p.Name != "" && len(p.Addresses) > 0 {
ip := p.Addresses[0].IP ip := p.Addresses[0].IP()
ret[strings.TrimRight(p.Name, ".")] = ip ret[strings.TrimRight(p.Name, ".")] = ip
if dnsname.HasSuffix(p.Name, suffix) { if dnsname.HasSuffix(p.Name, suffix) {
ret[dnsname.TrimSuffix(p.Name, suffix)] = ip ret[dnsname.TrimSuffix(p.Name, suffix)] = ip
@ -227,8 +227,8 @@ func (ns *Impl) removeSubnetAddress(ip netaddr.IP) {
func ipPrefixToAddressWithPrefix(ipp netaddr.IPPrefix) tcpip.AddressWithPrefix { func ipPrefixToAddressWithPrefix(ipp netaddr.IPPrefix) tcpip.AddressWithPrefix {
return tcpip.AddressWithPrefix{ return tcpip.AddressWithPrefix{
Address: tcpip.Address(ipp.IP.IPAddr().IP), Address: tcpip.Address(ipp.IP().IPAddr().IP),
PrefixLen: int(ipp.Bits), PrefixLen: int(ipp.Bits()),
} }
} }
@ -322,7 +322,7 @@ func (m DNSMap) Resolve(ctx context.Context, addr string) (netaddr.IPPort, error
// Try MagicDNS first, else otherwise a real DNS lookup. // Try MagicDNS first, else otherwise a real DNS lookup.
ip := m[host] ip := m[host]
if !ip.IsZero() { if !ip.IsZero() {
return netaddr.IPPort{IP: ip, Port: uint16(port16)}, nil return netaddr.IPPortFrom(ip, uint16(port16)), nil
} }
// No MagicDNS name so try real DNS. // No MagicDNS name so try real DNS.
@ -335,7 +335,7 @@ func (m DNSMap) Resolve(ctx context.Context, addr string) (netaddr.IPPort, error
return netaddr.IPPort{}, fmt.Errorf("DNS lookup returned no results for %q", host) return netaddr.IPPort{}, fmt.Errorf("DNS lookup returned no results for %q", host)
} }
ip, _ = netaddr.FromStdIP(ips[0]) ip, _ = netaddr.FromStdIP(ips[0])
return netaddr.IPPort{IP: ip, Port: uint16(port16)}, nil return netaddr.IPPortFrom(ip, uint16(port16)), nil
} }
func (ns *Impl) DialContextTCP(ctx context.Context, addr string) (*gonet.TCPConn, error) { func (ns *Impl) DialContextTCP(ctx context.Context, addr string) (*gonet.TCPConn, error) {
@ -349,11 +349,11 @@ func (ns *Impl) DialContextTCP(ctx context.Context, addr string) (*gonet.TCPConn
} }
remoteAddress := tcpip.FullAddress{ remoteAddress := tcpip.FullAddress{
NIC: nicID, NIC: nicID,
Addr: tcpip.Address(remoteIPPort.IP.IPAddr().IP), Addr: tcpip.Address(remoteIPPort.IP().IPAddr().IP),
Port: remoteIPPort.Port, Port: remoteIPPort.Port(),
} }
var ipType tcpip.NetworkProtocolNumber var ipType tcpip.NetworkProtocolNumber
if remoteIPPort.IP.Is4() { if remoteIPPort.IP().Is4() {
ipType = ipv4.ProtocolNumber ipType = ipv4.ProtocolNumber
} else { } else {
ipType = ipv6.ProtocolNumber ipType = ipv6.ProtocolNumber
@ -395,7 +395,7 @@ func (ns *Impl) isLocalIP(ip netaddr.IP) bool {
} }
func (ns *Impl) injectInbound(p *packet.Parsed, t *tstun.Wrapper) filter.Response { func (ns *Impl) injectInbound(p *packet.Parsed, t *tstun.Wrapper) filter.Response {
if ns.onlySubnets && ns.isLocalIP(p.Dst.IP) { if ns.onlySubnets && ns.isLocalIP(p.Dst.IP()) {
// In hybrid ("only subnets") mode, bail out early if // In hybrid ("only subnets") mode, bail out early if
// the traffic is destined for an actual Tailscale // the traffic is destined for an actual Tailscale
// address. The real host OS interface will handle it. // address. The real host OS interface will handle it.

@ -115,8 +115,8 @@ func (e *userspaceEngine) trackOpenPostFilterOut(pp *packet.Parsed, t *tstun.Wra
// Don't start timers tracking those. They won't succeed anyway. Avoids log spam // Don't start timers tracking those. They won't succeed anyway. Avoids log spam
// like: // like:
// open-conn-track: timeout opening (100.115.73.60:52501 => 17.125.252.5:443); no associated peer node // open-conn-track: timeout opening (100.115.73.60:52501 => 17.125.252.5:443); no associated peer node
if runtime.GOOS == "ios" && flow.Dst.Port == 443 && !tsaddr.IsTailscaleIP(flow.Dst.IP) { if runtime.GOOS == "ios" && flow.Dst.Port() == 443 && !tsaddr.IsTailscaleIP(flow.Dst.IP()) {
if _, err := e.peerForIP(flow.Dst.IP); err != nil { if _, err := e.peerForIP(flow.Dst.IP()); err != nil {
return return
} }
} }
@ -156,7 +156,7 @@ func (e *userspaceEngine) onOpenTimeout(flow flowtrack.Tuple) {
} }
// Diagnose why it might've timed out. // Diagnose why it might've timed out.
n, err := e.peerForIP(flow.Dst.IP) n, err := e.peerForIP(flow.Dst.IP())
if err != nil { if err != nil {
e.logf("open-conn-track: timeout opening %v; peerForIP: %v", flow, err) e.logf("open-conn-track: timeout opening %v; peerForIP: %v", flow, err)
return return
@ -193,7 +193,7 @@ func (e *userspaceEngine) onOpenTimeout(flow flowtrack.Tuple) {
if ps == nil { if ps == nil {
onlyZeroRoute := true // whether peerForIP returned n only because its /0 route matched onlyZeroRoute := true // whether peerForIP returned n only because its /0 route matched
for _, r := range n.AllowedIPs { for _, r := range n.AllowedIPs {
if r.Bits != 0 && r.Contains(flow.Dst.IP) { if r.Bits() != 0 && r.Contains(flow.Dst.IP()) {
onlyZeroRoute = false onlyZeroRoute = false
break break
} }

@ -324,16 +324,16 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) (retErr error) {
var firstGateway6 *net.IP var firstGateway6 *net.IP
addresses := make([]*net.IPNet, 0, len(cfg.LocalAddrs)) addresses := make([]*net.IPNet, 0, len(cfg.LocalAddrs))
for _, addr := range cfg.LocalAddrs { for _, addr := range cfg.LocalAddrs {
if (addr.IP.Is4() && ipif4 == nil) || (addr.IP.Is6() && ipif6 == nil) { if (addr.IP().Is4() && ipif4 == nil) || (addr.IP().Is6() && ipif6 == nil) {
// Can't program addresses for disabled protocol. // Can't program addresses for disabled protocol.
continue continue
} }
ipnet := addr.IPNet() ipnet := addr.IPNet()
addresses = append(addresses, ipnet) addresses = append(addresses, ipnet)
gateway := ipnet.IP gateway := ipnet.IP
if addr.IP.Is4() && firstGateway4 == nil { if addr.IP().Is4() && firstGateway4 == nil {
firstGateway4 = &gateway firstGateway4 = &gateway
} else if addr.IP.Is6() && firstGateway6 == nil { } else if addr.IP().Is6() && firstGateway6 == nil {
firstGateway6 = &gateway firstGateway6 = &gateway
} }
} }
@ -342,12 +342,12 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) (retErr error) {
foundDefault4 := false foundDefault4 := false
foundDefault6 := false foundDefault6 := false
for _, route := range cfg.Routes { for _, route := range cfg.Routes {
if (route.IP.Is4() && ipif4 == nil) || (route.IP.Is6() && ipif6 == nil) { if (route.IP().Is4() && ipif4 == nil) || (route.IP().Is6() && ipif6 == nil) {
// Can't program routes for disabled protocol. // Can't program routes for disabled protocol.
continue continue
} }
if route.IP.Is6() && firstGateway6 == nil { if route.IP().Is6() && firstGateway6 == nil {
// Windows won't let us set IPv6 routes without having an // Windows won't let us set IPv6 routes without having an
// IPv6 local address set. However, when we've configured // IPv6 local address set. However, when we've configured
// a default route, we want to forcibly grab IPv6 traffic // a default route, we want to forcibly grab IPv6 traffic
@ -357,16 +357,16 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) (retErr error) {
ipnet := &net.IPNet{tsaddr.Tailscale4To6Placeholder().IPAddr().IP, net.CIDRMask(128, 128)} ipnet := &net.IPNet{tsaddr.Tailscale4To6Placeholder().IPAddr().IP, net.CIDRMask(128, 128)}
addresses = append(addresses, ipnet) addresses = append(addresses, ipnet)
firstGateway6 = &ipnet.IP firstGateway6 = &ipnet.IP
} else if route.IP.Is4() && firstGateway4 == nil { } else if route.IP().Is4() && firstGateway4 == nil {
// TODO: do same dummy behavior as v6? // TODO: do same dummy behavior as v6?
return errors.New("due to a Windows limitation, one cannot have interface routes without an interface address") return errors.New("due to a Windows limitation, one cannot have interface routes without an interface address")
} }
ipn := route.IPNet() ipn := route.IPNet()
var gateway net.IP var gateway net.IP
if route.IP.Is4() { if route.IP().Is4() {
gateway = *firstGateway4 gateway = *firstGateway4
} else if route.IP.Is6() { } else if route.IP().Is6() {
gateway = *firstGateway6 gateway = *firstGateway6
} }
r := winipcfg.RouteData{ r := winipcfg.RouteData{
@ -385,13 +385,13 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) (retErr error) {
// then the interface's IP won't be pingable. // then the interface's IP won't be pingable.
continue continue
} }
if route.IP.Is4() { if route.IP().Is4() {
if route.Bits == 0 { if route.Bits() == 0 {
foundDefault4 = true foundDefault4 = true
} }
r.NextHop = *firstGateway4 r.NextHop = *firstGateway4
} else if route.IP.Is6() { } else if route.IP().Is6() {
if route.Bits == 0 { if route.Bits() == 0 {
foundDefault6 = true foundDefault6 = true
} }
r.NextHop = *firstGateway6 r.NextHop = *firstGateway6
@ -760,11 +760,8 @@ func filterRoutes(routes []*winipcfg.RouteData, dontDelete []netaddr.IPPrefix) [
if nr.IsSingleIP() { if nr.IsSingleIP() {
continue continue
} }
lastIP := nr.Range().To lastIP := nr.Range().To()
ddm[netaddr.IPPrefix{ ddm[netaddr.IPPrefixFrom(lastIP, lastIP.BitLen())] = true
IP: lastIP,
Bits: lastIP.BitLen(),
}] = true
} }
filtered := make([]*winipcfg.RouteData, 0, len(routes)) filtered := make([]*winipcfg.RouteData, 0, len(routes))
for _, r := range routes { for _, r := range routes {

@ -360,7 +360,7 @@ func (r *linuxRouter) setNetfilterMode(mode preftype.NetfilterMode) error {
} }
for cidr := range r.addrs { for cidr := range r.addrs {
if err := r.addLoopbackRule(cidr.IP); err != nil { if err := r.addLoopbackRule(cidr.IP()); err != nil {
return err return err
} }
} }
@ -372,13 +372,13 @@ func (r *linuxRouter) setNetfilterMode(mode preftype.NetfilterMode) error {
// address is already assigned to the interface, or if the addition // address is already assigned to the interface, or if the addition
// fails. // fails.
func (r *linuxRouter) addAddress(addr netaddr.IPPrefix) error { func (r *linuxRouter) addAddress(addr netaddr.IPPrefix) error {
if !r.v6Available && addr.IP.Is6() { if !r.v6Available && addr.IP().Is6() {
return nil return nil
} }
if err := r.cmd.run("ip", "addr", "add", addr.String(), "dev", r.tunname); err != nil { if err := r.cmd.run("ip", "addr", "add", addr.String(), "dev", r.tunname); err != nil {
return fmt.Errorf("adding address %q to tunnel interface: %w", addr, err) return fmt.Errorf("adding address %q to tunnel interface: %w", addr, err)
} }
if err := r.addLoopbackRule(addr.IP); err != nil { if err := r.addLoopbackRule(addr.IP()); err != nil {
return err return err
} }
return nil return nil
@ -388,10 +388,10 @@ func (r *linuxRouter) addAddress(addr netaddr.IPPrefix) error {
// the address is not assigned to the interface, or if the removal // the address is not assigned to the interface, or if the removal
// fails. // fails.
func (r *linuxRouter) delAddress(addr netaddr.IPPrefix) error { func (r *linuxRouter) delAddress(addr netaddr.IPPrefix) error {
if !r.v6Available && addr.IP.Is6() { if !r.v6Available && addr.IP().Is6() {
return nil return nil
} }
if err := r.delLoopbackRule(addr.IP); err != nil { if err := r.delLoopbackRule(addr.IP()); err != nil {
return err return err
} }
if err := r.cmd.run("ip", "addr", "del", addr.String(), "dev", r.tunname); err != nil { if err := r.cmd.run("ip", "addr", "del", addr.String(), "dev", r.tunname); err != nil {
@ -463,7 +463,7 @@ func (r *linuxRouter) addThrowRoute(cidr netaddr.IPPrefix) error {
} }
func (r *linuxRouter) addRouteDef(routeDef []string, cidr netaddr.IPPrefix) error { func (r *linuxRouter) addRouteDef(routeDef []string, cidr netaddr.IPPrefix) error {
if !r.v6Available && cidr.IP.Is6() { if !r.v6Available && cidr.IP().Is6() {
return nil return nil
} }
args := append([]string{"ip", "route", "add"}, routeDef...) args := append([]string{"ip", "route", "add"}, routeDef...)
@ -490,7 +490,7 @@ func (r *linuxRouter) delThrowRoute(cidr netaddr.IPPrefix) error {
} }
func (r *linuxRouter) delRouteDef(routeDef []string, cidr netaddr.IPPrefix) error { func (r *linuxRouter) delRouteDef(routeDef []string, cidr netaddr.IPPrefix) error {
if !r.v6Available && cidr.IP.Is6() { if !r.v6Available && cidr.IP().Is6() {
return nil return nil
} }
args := append([]string{"ip", "route", "del"}, routeDef...) args := append([]string{"ip", "route", "del"}, routeDef...)
@ -520,7 +520,7 @@ func dashFam(ip netaddr.IP) string {
} }
func (r *linuxRouter) hasRoute(routeDef []string, cidr netaddr.IPPrefix) (bool, error) { func (r *linuxRouter) hasRoute(routeDef []string, cidr netaddr.IPPrefix) (bool, error) {
args := append([]string{"ip", dashFam(cidr.IP), "route", "show"}, routeDef...) args := append([]string{"ip", dashFam(cidr.IP()), "route", "show"}, routeDef...)
if r.ipRuleAvailable { if r.ipRuleAvailable {
args = append(args, "table", tailscaleRouteTable) args = append(args, "table", tailscaleRouteTable)
} }

@ -69,11 +69,11 @@ func (r *openbsdRouter) Set(cfg *Config) error {
localAddr4 := netaddr.IPPrefix{} localAddr4 := netaddr.IPPrefix{}
localAddr6 := netaddr.IPPrefix{} localAddr6 := netaddr.IPPrefix{}
for _, addr := range cfg.LocalAddrs { for _, addr := range cfg.LocalAddrs {
if addr.IP.Is4() { if addr.IP().Is4() {
numIPv4++ numIPv4++
localAddr4 = addr localAddr4 = addr
} }
if addr.IP.Is6() { if addr.IP().Is6() {
numIPv6++ numIPv6++
localAddr6 = addr localAddr6 = addr
} }
@ -98,7 +98,7 @@ func (r *openbsdRouter) Set(cfg *Config) error {
routedel := []string{"route", "-q", "-n", routedel := []string{"route", "-q", "-n",
"del", "-inet", r.local4.String(), "del", "-inet", r.local4.String(),
"-iface", r.local4.IP.String()} "-iface", r.local4.IP().String()}
if out, err := cmd(routedel...).CombinedOutput(); err != nil { if out, err := cmd(routedel...).CombinedOutput(); err != nil {
r.logf("route del failed: %v: %v\n%s", routedel, err, out) r.logf("route del failed: %v: %v\n%s", routedel, err, out)
if errq == nil { if errq == nil {
@ -120,7 +120,7 @@ func (r *openbsdRouter) Set(cfg *Config) error {
routeadd := []string{"route", "-q", "-n", routeadd := []string{"route", "-q", "-n",
"add", "-inet", localAddr4.String(), "add", "-inet", localAddr4.String(),
"-iface", localAddr4.IP.String()} "-iface", localAddr4.IP().String()}
if out, err := cmd(routeadd...).CombinedOutput(); err != nil { if out, err := cmd(routeadd...).CombinedOutput(); err != nil {
r.logf("route add failed: %v: %v\n%s", routeadd, err, out) r.logf("route add failed: %v: %v\n%s", routeadd, err, out)
if errq == nil { if errq == nil {
@ -134,7 +134,7 @@ func (r *openbsdRouter) Set(cfg *Config) error {
// in https://github.com/tailscale/tailscale/issues/1307 we made // in https://github.com/tailscale/tailscale/issues/1307 we made
// FreeBSD use a /48 for IPv6 addresses, which is nice because we // FreeBSD use a /48 for IPv6 addresses, which is nice because we
// don't need to additionally add routing entries. Do that here too. // don't need to additionally add routing entries. Do that here too.
localAddr6 = netaddr.IPPrefix{localAddr6.IP, 48} localAddr6 = netaddr.IPPrefixFrom(localAddr6.IP(), 48)
} }
if localAddr6 != r.local6 { if localAddr6 != r.local6 {
@ -171,10 +171,10 @@ func (r *openbsdRouter) Set(cfg *Config) error {
if _, keep := newRoutes[route]; !keep { if _, keep := newRoutes[route]; !keep {
net := route.IPNet() net := route.IPNet()
nip := net.IP.Mask(net.Mask) nip := net.IP.Mask(net.Mask)
nstr := fmt.Sprintf("%v/%d", nip, route.Bits) nstr := fmt.Sprintf("%v/%d", nip, route.Bits())
routedel := []string{"route", "-q", "-n", routedel := []string{"route", "-q", "-n",
"del", "-inet", nstr, "del", "-inet", nstr,
"-iface", localAddr4.IP.String()} "-iface", localAddr4.IP().String()}
out, err := cmd(routedel...).CombinedOutput() out, err := cmd(routedel...).CombinedOutput()
if err != nil { if err != nil {
r.logf("route del failed: %v: %v\n%s", routedel, err, out) r.logf("route del failed: %v: %v\n%s", routedel, err, out)
@ -188,10 +188,10 @@ func (r *openbsdRouter) Set(cfg *Config) error {
if _, exists := r.routes[route]; !exists { if _, exists := r.routes[route]; !exists {
net := route.IPNet() net := route.IPNet()
nip := net.IP.Mask(net.Mask) nip := net.IP.Mask(net.Mask)
nstr := fmt.Sprintf("%v/%d", nip, route.Bits) nstr := fmt.Sprintf("%v/%d", nip, route.Bits())
routeadd := []string{"route", "-q", "-n", routeadd := []string{"route", "-q", "-n",
"add", "-inet", nstr, "add", "-inet", nstr,
"-iface", localAddr4.IP.String()} "-iface", localAddr4.IP().String()}
out, err := cmd(routeadd...).CombinedOutput() out, err := cmd(routeadd...).CombinedOutput()
if err != nil { if err != nil {
r.logf("addr add failed: %v: %v\n%s", routeadd, err, out) r.logf("addr add failed: %v: %v\n%s", routeadd, err, out)

@ -87,7 +87,7 @@ func (r *userspaceBSDRouter) Up() error {
} }
func inet(p netaddr.IPPrefix) string { func inet(p netaddr.IPPrefix) string {
if p.IP.Is6() { if p.IP().Is6() {
return "inet6" return "inet6"
} }
return "inet" return "inet"
@ -116,15 +116,15 @@ func (r *userspaceBSDRouter) Set(cfg *Config) (reterr error) {
} }
for _, addr := range r.addrsToAdd(cfg.LocalAddrs) { for _, addr := range r.addrsToAdd(cfg.LocalAddrs) {
var arg []string var arg []string
if runtime.GOOS == "freebsd" && addr.IP.Is6() && addr.Bits == 128 { if runtime.GOOS == "freebsd" && addr.IP().Is6() && addr.Bits() == 128 {
// FreeBSD rejects tun addresses of the form fc00::1/128 -> fc00::1, // FreeBSD rejects tun addresses of the form fc00::1/128 -> fc00::1,
// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218508 // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218508
// Instead add our whole /48, which works because we use a /48 route. // Instead add our whole /48, which works because we use a /48 route.
// Full history: https://github.com/tailscale/tailscale/issues/1307 // Full history: https://github.com/tailscale/tailscale/issues/1307
tmp := netaddr.IPPrefix{IP: addr.IP, Bits: 48} tmp := netaddr.IPPrefixFrom(addr.IP(), 48)
arg = []string{"ifconfig", r.tunname, inet(tmp), tmp.String()} arg = []string{"ifconfig", r.tunname, inet(tmp), tmp.String()}
} else { } else {
arg = []string{"ifconfig", r.tunname, inet(addr), addr.String(), addr.IP.String()} arg = []string{"ifconfig", r.tunname, inet(addr), addr.String(), addr.IP().String()}
} }
out, err := cmd(arg...).CombinedOutput() out, err := cmd(arg...).CombinedOutput()
if err != nil { if err != nil {
@ -148,7 +148,7 @@ func (r *userspaceBSDRouter) Set(cfg *Config) (reterr error) {
if _, keep := newRoutes[route]; !keep { if _, keep := newRoutes[route]; !keep {
net := route.IPNet() net := route.IPNet()
nip := net.IP.Mask(net.Mask) nip := net.IP.Mask(net.Mask)
nstr := fmt.Sprintf("%v/%d", nip, route.Bits) nstr := fmt.Sprintf("%v/%d", nip, route.Bits())
del := "del" del := "del"
if version.OS() == "macOS" { if version.OS() == "macOS" {
del = "delete" del = "delete"
@ -168,7 +168,7 @@ func (r *userspaceBSDRouter) Set(cfg *Config) (reterr error) {
if _, exists := r.routes[route]; !exists { if _, exists := r.routes[route]; !exists {
net := route.IPNet() net := route.IPNet()
nip := net.IP.Mask(net.Mask) nip := net.IP.Mask(net.Mask)
nstr := fmt.Sprintf("%v/%d", nip, route.Bits) nstr := fmt.Sprintf("%v/%d", nip, route.Bits())
routeadd := []string{"route", "-q", "-n", routeadd := []string{"route", "-q", "-n",
"add", "-" + inet(route), nstr, "add", "-" + inet(route), nstr,
"-iface", r.tunname} "-iface", r.tunname}

@ -91,7 +91,7 @@ func (r *winRouter) Set(cfg *Config) error {
func hasDefaultRoute(routes []netaddr.IPPrefix) bool { func hasDefaultRoute(routes []netaddr.IPPrefix) bool {
for _, route := range routes { for _, route := range routes {
if route.Bits == 0 { if route.Bits() == 0 {
return true return true
} }
} }

@ -399,7 +399,7 @@ func (e *userspaceEngine) handleLocalPackets(p *packet.Parsed, t *tstun.Wrapper)
isLocalAddr, ok := e.isLocalAddr.Load().(func(netaddr.IP) bool) isLocalAddr, ok := e.isLocalAddr.Load().(func(netaddr.IP) bool)
if !ok { if !ok {
e.logf("[unexpected] e.isLocalAddr was nil, can't check for loopback packet") e.logf("[unexpected] e.isLocalAddr was nil, can't check for loopback packet")
} else if isLocalAddr(p.Dst.IP) { } else if isLocalAddr(p.Dst.IP()) {
// macOS NetworkExtension directs packets destined to the // macOS NetworkExtension directs packets destined to the
// tunnel's local IP address into the tunnel, instead of // tunnel's local IP address into the tunnel, instead of
// looping back within the kernel network stack. We have to // looping back within the kernel network stack. We have to
@ -415,7 +415,7 @@ func (e *userspaceEngine) handleLocalPackets(p *packet.Parsed, t *tstun.Wrapper)
// handleDNS is an outbound pre-filter resolving Tailscale domains. // handleDNS is an outbound pre-filter resolving Tailscale domains.
func (e *userspaceEngine) handleDNS(p *packet.Parsed, t *tstun.Wrapper) filter.Response { func (e *userspaceEngine) handleDNS(p *packet.Parsed, t *tstun.Wrapper) filter.Response {
if p.Dst.IP == magicDNSIP && p.Dst.Port == magicDNSPort && p.IPProto == ipproto.UDP { if p.Dst.IP() == magicDNSIP && p.Dst.Port() == magicDNSPort && p.IPProto == ipproto.UDP {
err := e.dns.EnqueueRequest(append([]byte(nil), p.Payload()...), p.Src) err := e.dns.EnqueueRequest(append([]byte(nil), p.Payload()...), p.Src)
if err != nil { if err != nil {
e.logf("dns: enqueue: %v", err) e.logf("dns: enqueue: %v", err)
@ -440,10 +440,10 @@ func (e *userspaceEngine) pollResolver() {
h := packet.UDP4Header{ h := packet.UDP4Header{
IP4Header: packet.IP4Header{ IP4Header: packet.IP4Header{
Src: magicDNSIP, Src: magicDNSIP,
Dst: to.IP, Dst: to.IP(),
}, },
SrcPort: magicDNSPort, SrcPort: magicDNSPort,
DstPort: to.Port, DstPort: to.Port(),
} }
hlen := h.Len() hlen := h.Len()
@ -620,8 +620,8 @@ func (e *userspaceEngine) maybeReconfigWireguardLocked(discoChanged map[key.Publ
trackDisco = append(trackDisco, dk) trackDisco = append(trackDisco, dk)
recentlyActive := false recentlyActive := false
for _, cidr := range p.AllowedIPs { for _, cidr := range p.AllowedIPs {
trackIPs = append(trackIPs, cidr.IP) trackIPs = append(trackIPs, cidr.IP())
recentlyActive = recentlyActive || e.isActiveSince(dk, cidr.IP, activeCutoff) recentlyActive = recentlyActive || e.isActiveSince(dk, cidr.IP(), activeCutoff)
} }
if recentlyActive { if recentlyActive {
min.Peers = append(min.Peers, *p) min.Peers = append(min.Peers, *p)
@ -1156,8 +1156,8 @@ func (e *userspaceEngine) mySelfIPMatchingFamily(dst netaddr.IP) (src netaddr.IP
return netaddr.IP{}, errors.New("no netmap") return netaddr.IP{}, errors.New("no netmap")
} }
for _, a := range e.netMap.Addresses { for _, a := range e.netMap.Addresses {
if a.IsSingleIP() && a.IP.BitLen() == dst.BitLen() { if a.IsSingleIP() && a.IP().BitLen() == dst.BitLen() {
return a.IP, nil return a.IP(), nil
} }
} }
if len(e.netMap.Addresses) == 0 { if len(e.netMap.Addresses) == 0 {
@ -1293,7 +1293,7 @@ func (e *userspaceEngine) peerForIP(ip netaddr.IP) (n *tailcfg.Node, err error)
var bestInNM *tailcfg.Node var bestInNM *tailcfg.Node
for _, p := range nm.Peers { for _, p := range nm.Peers {
for _, a := range p.Addresses { for _, a := range p.Addresses {
if a.IP == ip && a.IsSingleIP() && tsaddr.IsTailscaleIP(ip) { if a.IP() == ip && a.IsSingleIP() && tsaddr.IsTailscaleIP(ip) {
return p, nil return p, nil
} }
} }
@ -1301,7 +1301,7 @@ func (e *userspaceEngine) peerForIP(ip netaddr.IP) (n *tailcfg.Node, err error)
if !cidr.Contains(ip) { if !cidr.Contains(ip) {
continue continue
} }
if bestInNMPrefix.IsZero() || cidr.Bits > bestInNMPrefix.Bits { if bestInNMPrefix.IsZero() || cidr.Bits() > bestInNMPrefix.Bits() {
bestInNMPrefix = cidr bestInNMPrefix = cidr
bestInNM = p bestInNM = p
} }
@ -1319,7 +1319,7 @@ func (e *userspaceEngine) peerForIP(ip netaddr.IP) (n *tailcfg.Node, err error)
if !cidr.Contains(ip) { if !cidr.Contains(ip) {
continue continue
} }
if best.IsZero() || cidr.Bits > best.Bits { if best.IsZero() || cidr.Bits() > best.Bits() {
best = cidr best = cidr
bestKey = tailcfg.NodeKey(p.PublicKey) bestKey = tailcfg.NodeKey(p.PublicKey)
} }
@ -1337,7 +1337,7 @@ func (e *userspaceEngine) peerForIP(ip netaddr.IP) (n *tailcfg.Node, err error)
if bestInNM == nil { if bestInNM == nil {
return nil, nil return nil, nil
} }
if bestInNMPrefix.Bits == 0 { if bestInNMPrefix.Bits() == 0 {
return nil, errors.New("exit node found but not enabled") return nil, errors.New("exit node found but not enabled")
} }
return nil, fmt.Errorf("node %q found, but not using its %v route", bestInNM.ComputedNameWithHost, bestInNMPrefix) return nil, fmt.Errorf("node %q found, but not using its %v route", bestInNM.ComputedNameWithHost, bestInNMPrefix)

@ -102,7 +102,7 @@ func TestUserspaceEngineReconfig(t *testing.T) {
Peers: []wgcfg.Peer{ Peers: []wgcfg.Peer{
{ {
AllowedIPs: []netaddr.IPPrefix{ AllowedIPs: []netaddr.IPPrefix{
{IP: netaddr.IPv4(100, 100, 99, 1), Bits: 32}, netaddr.IPPrefixFrom(netaddr.IPv4(100, 100, 99, 1), 32),
}, },
Endpoints: wgcfg.Endpoints{DiscoKey: dkFromHex(discoHex)}, Endpoints: wgcfg.Endpoints{DiscoKey: dkFromHex(discoHex)},
}, },

@ -37,7 +37,7 @@ func nodeDebugName(n *tailcfg.Node) string {
// cidrIsSubnet reports whether cidr is a non-default-route subnet // cidrIsSubnet reports whether cidr is a non-default-route subnet
// exported by node that is not one of its own self addresses. // exported by node that is not one of its own self addresses.
func cidrIsSubnet(node *tailcfg.Node, cidr netaddr.IPPrefix) bool { func cidrIsSubnet(node *tailcfg.Node, cidr netaddr.IPPrefix) bool {
if cidr.Bits == 0 { if cidr.Bits() == 0 {
return false return false
} }
if !cidr.IsSingleIP() { if !cidr.IsSingleIP() {
@ -93,7 +93,7 @@ func WGCfg(nm *netmap.NetworkMap, logf logger.Logf, flags netmap.WGConfigFlags,
} }
didExitNodeWarn := false didExitNodeWarn := false
for _, allowedIP := range peer.AllowedIPs { for _, allowedIP := range peer.AllowedIPs {
if allowedIP.Bits == 0 && peer.StableID != exitNode { if allowedIP.Bits() == 0 && peer.StableID != exitNode {
if didExitNodeWarn { if didExitNodeWarn {
// Don't log about both the IPv4 /0 and IPv6 /0. // Don't log about both the IPv4 /0 and IPv6 /0.
continue continue
@ -104,11 +104,11 @@ func WGCfg(nm *netmap.NetworkMap, logf logger.Logf, flags netmap.WGConfigFlags,
} }
fmt.Fprintf(skippedUnselected, "%q (%v)", nodeDebugName(peer), peer.Key.ShortString()) fmt.Fprintf(skippedUnselected, "%q (%v)", nodeDebugName(peer), peer.Key.ShortString())
continue continue
} else if allowedIP.IsSingleIP() && tsaddr.IsTailscaleIP(allowedIP.IP) && (flags&netmap.AllowSingleHosts) == 0 { } else if allowedIP.IsSingleIP() && tsaddr.IsTailscaleIP(allowedIP.IP()) && (flags&netmap.AllowSingleHosts) == 0 {
if skippedIPs.Len() > 0 { if skippedIPs.Len() > 0 {
skippedIPs.WriteString(", ") skippedIPs.WriteString(", ")
} }
fmt.Fprintf(skippedIPs, "%v from %q (%v)", allowedIP.IP, nodeDebugName(peer), peer.Key.ShortString()) fmt.Fprintf(skippedIPs, "%v from %q (%v)", allowedIP.IP(), nodeDebugName(peer), peer.Key.ShortString())
continue continue
} else if cidrIsSubnet(peer, allowedIP) { } else if cidrIsSubnet(peer, allowedIP) {
if (flags & netmap.AllowSubnetRoutes) == 0 { if (flags & netmap.AllowSubnetRoutes) == 0 {

Loading…
Cancel
Save