Compare commits

..

1 Commits

Author SHA1 Message Date
Josh Bleecher Snyder
920145a836 netaddr.NewIPPort 2021-05-12 16:25:04 -07:00
76 changed files with 506 additions and 1674 deletions

View File

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

View File

@@ -194,7 +194,7 @@ func discoverPeerAPIBase(ctx context.Context, ipStr string) (base string, lastSe
for _, ft := range fts {
n := ft.Node
for _, a := range n.Addresses {
if a.IP() != ip {
if a.IP != ip {
continue
}
if n.LastSeen != nil {
@@ -301,7 +301,7 @@ func runCpTargets(ctx context.Context, args []string) error {
if 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
}

View File

@@ -139,9 +139,6 @@ func runPing(ctx context.Context, args []string) error {
if !anyPong {
return errors.New("no reply")
}
if pingArgs.untilDirect {
return errors.New("direct connection not established")
}
return nil
}
}

View File

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

View File

@@ -4,7 +4,7 @@
// The tailscale command is the Tailscale command-line client. It interacts
// with the tailscaled node agent.
package main // import "tailscale.com/cmd/tailscaled"
package main // import "tailscale.com/cmd/tailscale"
import (
"fmt"
@@ -12,10 +12,10 @@ import (
"path/filepath"
"strings"
"tailscale.com/cmd/tailscaled/cli"
"tailscale.com/cmd/tailscale/cli"
)
func tailscale_main() {
func main() {
args := os.Args[1:]
if name, _ := os.Executable(); strings.HasSuffix(filepath.Base(name), ".cgi") {
args = []string{"web", "-cgi"}

View File

@@ -1,16 +0,0 @@
package main
import (
"os"
"strings"
)
func main() {
if strings.HasSuffix(os.Args[0], "tailscaled") {
tailscaled_main()
} else if strings.HasSuffix(os.Args[0], "tailscale") {
tailscale_main()
} else {
panic(os.Args[0])
}
}

View File

@@ -101,7 +101,7 @@ var subCommands = map[string]*func([]string) error{
"debug": &debugModeFunc,
}
func tailscaled_main() {
func main() {
// We aren't very performance sensitive, and the parts that are
// performance sensitive (wireguard) try hard not to do any memory
// allocations. So let's be aggressive about garbage collection,
@@ -266,7 +266,7 @@ func run() error {
if err != nil {
return nil, err
}
if ns != nil && useNetstackForIP(ipp.IP()) {
if ns != nil && useNetstackForIP(ipp.IP) {
return ns.DialContextTCP(ctx, addr)
}
var d net.Dialer

View File

@@ -460,10 +460,10 @@ func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, new
request.NodeKey.ShortString())
return true, "", nil
}
if resp.Login.Provider != "" {
if persist.Provider == "" {
persist.Provider = resp.Login.Provider
}
if resp.Login.LoginName != "" {
if persist.LoginName == "" {
persist.LoginName = resp.Login.LoginName
}
@@ -1091,7 +1091,7 @@ func ipForwardingBroken(routes []netaddr.IPPrefix, state *interfaces.State) bool
localIPs := map[netaddr.IP]bool{}
for _, addrs := range state.InterfaceIPs {
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
// machine's local IPs. IP forwarding isn't required for this
// to work, so we shouldn't warn for such exports.
if r.IsSingleIP() && localIPs[r.IP()] {
if r.IsSingleIP() && localIPs[r.IP] {
continue
}
if r.IP().Is4() {
if r.IP.Is4() {
v4Routes = true
} else {
v6Routes = true

View File

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

View File

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

4
go.mod
View File

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

6
go.sum
View File

@@ -258,17 +258,11 @@ 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-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-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/go.mod h1:GVx+5OZtbG4TVOW5ilmyRZAZXr1cNwfqUEkTOtWK0PM=
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/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-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/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo=

View File

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

View File

@@ -356,14 +356,14 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
var tailAddr4 string
var tailscaleIPs = make([]netaddr.IP, 0, len(p.Addresses))
for _, addr := range p.Addresses {
if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.IP()) {
if addr.IP().Is4() && tailAddr4 == "" {
if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.IP) {
if addr.IP.Is4() && tailAddr4 == "" {
// The peer struct previously only allowed a single
// Tailscale IP address. For compatibility for a few releases starting
// 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{
@@ -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) {
b.mu.Lock()
defer b.mu.Unlock()
n, ok = b.nodeByAddr[ipp.IP()]
n, ok = b.nodeByAddr[ipp.IP]
if !ok {
var ip netaddr.IP
if ipp.Port() != 0 {
if ipp.Port != 0 {
ip, ok = b.e.WhoIsIPPort(ipp)
}
if !ok {
@@ -434,15 +434,14 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
}
return
}
b.mu.Lock()
wasBlocked := b.blocked
b.mu.Unlock()
if st.LoginFinished != nil && wasBlocked {
if st.LoginFinished != nil {
// Auth completed, unblock the engine
b.blockEngineUpdates(false)
b.authReconfig()
b.EditPrefs(&ipn.MaskedPrefs{
LoggedOutSet: true,
Prefs: ipn.Prefs{LoggedOut: false},
})
b.send(ipn.Notify{LoginFinished: &empty.Message{}})
}
@@ -481,15 +480,11 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
b.authURL = st.URL
b.authURLSticky = st.URL
}
if wasBlocked && st.LoginFinished != nil {
// Interactive login finished successfully (URL visited).
// After an interactive login, the user always wants
// WantRunning.
if !b.prefs.WantRunning || b.prefs.LoggedOut {
if b.state == ipn.NeedsLogin {
if !b.prefs.WantRunning {
prefsChanged = true
}
b.prefs.WantRunning = true
b.prefs.LoggedOut = false
}
// Prefs will be written out; this is not safe unless locked or cloned.
if prefsChanged {
@@ -552,7 +547,7 @@ func (b *LocalBackend) findExitNodeIDLocked(nm *netmap.NetworkMap) (prefsChanged
for _, peer := range nm.Peers {
for _, addr := range peer.Addresses {
if !addr.IsSingleIP() || addr.IP() != b.prefs.ExitNodeIP {
if !addr.IsSingleIP() || addr.IP != b.prefs.ExitNodeIP {
continue
}
// Found the node being referenced, upgrade prefs to
@@ -571,18 +566,10 @@ func (b *LocalBackend) findExitNodeIDLocked(nm *netmap.NetworkMap) (prefsChanged
func (b *LocalBackend) setWgengineStatus(s *wgengine.Status, err error) {
if err != nil {
b.logf("wgengine status error: %v", err)
b.statusLock.Lock()
b.statusChanged.Broadcast()
b.statusLock.Unlock()
return
}
if s == nil {
b.logf("[unexpected] non-error wgengine update with status=nil: %v", s)
b.statusLock.Lock()
b.statusChanged.Broadcast()
b.statusLock.Unlock()
return
}
@@ -891,7 +878,7 @@ func (b *LocalBackend) updateFilter(netMap *netmap.NetworkMap, prefs *ipn.Prefs)
}
if prefs != nil {
for _, r := range prefs.AdvertiseRoutes {
if r.Bits() == 0 {
if r.Bits == 0 {
// When offering a default route to the world, we
// filter out locally reachable LANs, so that the
// default route effectively appears to be a "guest
@@ -959,13 +946,13 @@ var removeFromDefaultRoute = []netaddr.IPPrefix{
func interfaceRoutes() (ips *netaddr.IPSet, hostIPs []netaddr.IP, err error) {
var b netaddr.IPSetBuilder
if err := interfaces.ForeachInterfaceAddress(func(_ interfaces.Interface, pfx netaddr.IPPrefix) {
if tsaddr.IsTailscaleIP(pfx.IP()) {
if tsaddr.IsTailscaleIP(pfx.IP) {
return
}
if pfx.IsSingleIP() {
return
}
hostIPs = append(hostIPs, pfx.IP())
hostIPs = append(hostIPs, pfx.IP)
b.AddPrefix(pfx)
}); err != nil {
return nil, nil, err
@@ -1751,10 +1738,10 @@ func (b *LocalBackend) authReconfig() {
// https://github.com/tailscale/tailscale/issues/1152
// tracks adding the right capability reporting to
// enable AAAA in MagicDNS.
if addr.IP().Is6() {
if addr.IP.Is6() {
continue
}
ips = append(ips, addr.IP())
ips = append(ips, addr.IP)
}
dcfg.Hosts[fqdn] = ips
}
@@ -1809,7 +1796,7 @@ func parseResolver(cfg tailcfg.DNSResolver) (netaddr.IPPort, error) {
if err != nil {
return netaddr.IPPort{}, fmt.Errorf("[unexpected] non-IP resolver %q", cfg.Addr)
}
return netaddr.IPPortFrom(ip, 53), nil
return netaddr.NewIPPort(ip, 53), nil
}
// tailscaleVarRoot returns the root directory of Tailscale's writable
@@ -1867,7 +1854,7 @@ func (b *LocalBackend) initPeerAPIListener() {
if len(b.netMap.Addresses) == len(b.peerAPIListeners) {
allSame := true
for i, pln := range b.peerAPIListeners {
if pln.ip != b.netMap.Addresses[i].IP() {
if pln.ip != b.netMap.Addresses[i].IP {
allSame = false
break
}
@@ -1912,7 +1899,7 @@ func (b *LocalBackend) initPeerAPIListener() {
var err error
skipListen := i > 0 && isNetstack
if !skipListen {
ln, err = ps.listen(a.IP(), b.prevIfState)
ln, err = ps.listen(a.IP, b.prevIfState)
if err != nil {
if runtime.GOOS == "windows" {
// Expected for now. See Issue 1620.
@@ -1926,7 +1913,7 @@ func (b *LocalBackend) initPeerAPIListener() {
}
pln := &peerAPIListener{
ps: ps,
ip: a.IP(),
ip: a.IP,
ln: ln, // nil for 2nd+ on netstack
lb: b,
}
@@ -1935,7 +1922,7 @@ func (b *LocalBackend) initPeerAPIListener() {
} else {
pln.port = ln.Addr().(*net.TCPAddr).Port
}
pln.urlStr = "http://" + net.JoinHostPort(a.IP().String(), strconv.Itoa(pln.port))
pln.urlStr = "http://" + net.JoinHostPort(a.IP.String(), strconv.Itoa(pln.port))
b.logf("peerapi: serving on %s", pln.urlStr)
go pln.serve()
b.peerAPIListeners = append(b.peerAPIListeners, pln)
@@ -1986,14 +1973,14 @@ func peerRoutes(peers []wgcfg.Peer, cgnatThreshold int) (routes []netaddr.IPPref
for _, aip := range peer.AllowedIPs {
aip = unmapIPPrefix(aip)
// Only add the Tailscale IPv6 ULA once, if we see anybody using part of it.
if aip.IP().Is6() && aip.IsSingleIP() && tsULA.Contains(aip.IP()) {
if aip.IP.Is6() && aip.IsSingleIP() && tsULA.Contains(aip.IP) {
if !didULA {
didULA = true
routes = append(routes, tsULA)
}
continue
}
if aip.IsSingleIP() && cgNAT.Contains(aip.IP()) {
if aip.IsSingleIP() && cgNAT.Contains(aip.IP) {
cgNATIPs = append(cgNATIPs, aip)
} else {
routes = append(routes, aip)
@@ -2060,13 +2047,16 @@ func (b *LocalBackend) routerConfig(cfg *wgcfg.Config, prefs *ipn.Prefs) *router
}
}
rs.Routes = append(rs.Routes, netaddr.IPPrefixFrom(tsaddr.TailscaleServiceIP(), 32))
rs.Routes = append(rs.Routes, netaddr.IPPrefix{
IP: tsaddr.TailscaleServiceIP(),
Bits: 32,
})
return rs
}
func unmapIPPrefix(ipp netaddr.IPPrefix) netaddr.IPPrefix {
return netaddr.IPPrefixFrom(ipp.IP().Unmap(), ipp.Bits())
return netaddr.IPPrefix{IP: ipp.IP.Unmap(), Bits: ipp.Bits}
}
func unmapIPPrefixes(ippsList ...[]netaddr.IPPrefix) (ret []netaddr.IPPrefix) {
@@ -2120,8 +2110,8 @@ func (b *LocalBackend) enterState(newState ipn.State) {
if oldState == newState {
return
}
b.logf("Switching ipn state %v -> %v (WantRunning=%v, nm=%v)",
oldState, newState, prefs.WantRunning, netMap != nil)
b.logf("Switching ipn state %v -> %v (WantRunning=%v)",
oldState, newState, prefs.WantRunning)
health.SetIPNState(newState.String(), prefs.WantRunning)
b.send(ipn.Notify{State: &newState})
@@ -2150,7 +2140,7 @@ func (b *LocalBackend) enterState(newState ipn.State) {
case ipn.Running:
var addrs []string
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, " "))
default:
@@ -2177,14 +2167,13 @@ func (b *LocalBackend) nextState() ipn.State {
cc = b.cc
netMap = b.netMap
state = b.state
blocked = b.blocked
wantRunning = b.prefs.WantRunning
loggedOut = b.prefs.LoggedOut
)
b.mu.Unlock()
switch {
case !wantRunning && !loggedOut && !blocked && b.hasNodeKey():
case !wantRunning && !loggedOut && b.hasNodeKey():
return ipn.Stopped
case netMap == nil:
if cc.AuthCantContinue() || loggedOut {
@@ -2418,7 +2407,7 @@ func (b *LocalBackend) setNetMapLocked(nm *netmap.NetworkMap) {
addNode := func(n *tailcfg.Node) {
for _, ipp := range n.Addresses {
if ipp.IsSingleIP() {
b.nodeByAddr[ipp.IP()] = n
b.nodeByAddr[ipp.IP] = n
}
}
}
@@ -2570,9 +2559,9 @@ func peerAPIBase(nm *netmap.NetworkMap, peer *tailcfg.Node) string {
continue
}
switch {
case a.IP().Is4():
case a.IP.Is4():
have4 = true
case a.IP().Is6():
case a.IP.Is6():
have6 = true
}
}
@@ -2588,11 +2577,11 @@ func peerAPIBase(nm *netmap.NetworkMap, peer *tailcfg.Node) string {
var ipp netaddr.IPPort
switch {
case have4 && p4 != 0:
ipp = netaddr.IPPortFrom(nodeIP(peer, netaddr.IP.Is4), p4)
ipp = netaddr.NewIPPort(nodeIP(peer, netaddr.IP.Is4), p4)
case have6 && p6 != 0:
ipp = netaddr.IPPortFrom(nodeIP(peer, netaddr.IP.Is6), p6)
ipp = netaddr.NewIPPort(nodeIP(peer, netaddr.IP.Is6), p6)
}
if ipp.IP().IsZero() {
if ipp.IP.IsZero() {
return ""
}
return fmt.Sprintf("http://%v", ipp)
@@ -2600,8 +2589,8 @@ func peerAPIBase(nm *netmap.NetworkMap, peer *tailcfg.Node) string {
func nodeIP(n *tailcfg.Node, pred func(netaddr.IP) bool) netaddr.IP {
for _, a := range n.Addresses {
if a.IsSingleIP() && pred(a.IP()) {
return a.IP()
if a.IsSingleIP() && pred(a.IP) {
return a.IP
}
}
return netaddr.IP{}

View File

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

View File

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

View File

@@ -368,11 +368,13 @@ func TestStateMachine(t *testing.T) {
{
c.Assert(cc.getCalls(), qt.DeepEquals, []string{"Login"})
notifies.drain(0)
// Note: WantRunning isn't true yet. It'll switch to true
// after a successful login finishes.
// (This behaviour is needed so that b.Login() won't
// start connecting to an old account right away, if one
// exists when you launch another login.)
// BUG: this should immediately set WantRunning to true.
// Users don't log in if they don't want to also connect.
// (Generally, we're inconsistent about who is supposed to
// update Prefs at what time. But the overall philosophy is:
// update it when the user's intent changes. This is clearly
// at the time the user *requests* Login, not at the time
// the login finishes.)
}
// Attempted non-interactive login with no key; indicate that
@@ -382,16 +384,18 @@ func TestStateMachine(t *testing.T) {
url1 := "http://localhost:1/1"
cc.send(nil, url1, false, nil)
{
c.Assert(cc.getCalls(), qt.DeepEquals, []string{})
c.Assert(cc.getCalls(), qt.HasLen, 0)
// ...but backend eats that notification, because the user
// didn't explicitly request interactive login yet, and
// we're already in NeedsLogin state.
nn := notifies.drain(1)
// Trying to log in automatically sets WantRunning.
// BUG: that should have happened right after Login().
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsFalse)
c.Assert(nn[0].Prefs.WantRunning, qt.IsFalse)
c.Assert(nn[0].Prefs.WantRunning, qt.IsTrue)
}
// Now we'll try an interactive login.
@@ -447,12 +451,11 @@ func TestStateMachine(t *testing.T) {
// same time.
// The backend should propagate this upward for the UI.
t.Logf("\n\nLoginFinished")
notifies.expect(3)
notifies.expect(2)
cc.setAuthBlocked(false)
cc.persist.LoginName = "user1"
cc.send(nil, "", true, &netmap.NetworkMap{})
{
nn := notifies.drain(3)
nn := notifies.drain(2)
// BUG: still too soon for UpdateEndpoints.
//
// Arguably it makes sense to unpause now, since the machine
@@ -465,12 +468,15 @@ func TestStateMachine(t *testing.T) {
// it's visible in the logs)
c.Assert([]string{"unpause", "UpdateEndpoints"}, qt.DeepEquals, cc.getCalls())
c.Assert(nn[0].LoginFinished, qt.Not(qt.IsNil))
c.Assert(nn[1].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[2].State, qt.Not(qt.IsNil))
c.Assert(nn[1].Prefs.Persist.LoginName, qt.Equals, "user1")
c.Assert(ipn.NeedsMachineAuth, qt.Equals, *nn[2].State)
c.Assert(nn[1].State, qt.Not(qt.IsNil))
c.Assert(ipn.NeedsMachineAuth, qt.Equals, *nn[1].State)
}
// TODO: check that the logged-in username propagates from control
// through to the UI notifications. I think it's used as a hint
// for future logins, to pre-fill the username box? Not really sure
// how it works.
// Pretend that the administrator has authorized our machine.
t.Logf("\n\nMachineAuthorized")
notifies.expect(1)
@@ -575,72 +581,77 @@ func TestStateMachine(t *testing.T) {
// Let's make the logout succeed.
t.Logf("\n\nLogout (async) - succeed")
notifies.expect(0)
notifies.expect(1)
cc.setAuthBlocked(true)
cc.send(nil, "", false, nil)
{
notifies.drain(0)
nn := notifies.drain(1)
c.Assert(cc.getCalls(), qt.HasLen, 0)
c.Assert(b.Prefs().LoggedOut, qt.IsTrue)
c.Assert(b.Prefs().WantRunning, qt.IsFalse)
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsTrue)
// BUG: WantRunning should be false after manual logout.
c.Assert(nn[0].Prefs.WantRunning, qt.IsTrue)
c.Assert(ipn.NeedsLogin, qt.Equals, b.State())
}
// A second logout should do nothing, since the prefs haven't changed.
t.Logf("\n\nLogout2 (async)")
notifies.expect(0)
notifies.expect(1)
b.Logout()
{
notifies.drain(0)
nn := notifies.drain(1)
// BUG: the backend has already called StartLogout, and we're
// still logged out. So it shouldn't call it again.
c.Assert([]string{"StartLogout"}, qt.DeepEquals, cc.getCalls())
c.Assert(cc.getCalls(), qt.HasLen, 0)
c.Assert(b.Prefs().LoggedOut, qt.IsTrue)
c.Assert(b.Prefs().WantRunning, qt.IsFalse)
// BUG: Prefs should not change here. Already logged out.
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsTrue)
c.Assert(nn[0].Prefs.WantRunning, qt.IsFalse)
c.Assert(ipn.NeedsLogin, qt.Equals, b.State())
}
// Let's acknowledge the second logout too.
t.Logf("\n\nLogout2 (async) - succeed")
notifies.expect(0)
notifies.expect(1)
cc.setAuthBlocked(true)
cc.send(nil, "", false, nil)
{
notifies.drain(0)
nn := notifies.drain(1)
c.Assert(cc.getCalls(), qt.HasLen, 0)
c.Assert(cc.getCalls(), qt.HasLen, 0)
c.Assert(b.Prefs().LoggedOut, qt.IsTrue)
c.Assert(b.Prefs().WantRunning, qt.IsFalse)
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsTrue)
// BUG: second logout shouldn't cause WantRunning->true !!
c.Assert(nn[0].Prefs.WantRunning, qt.IsTrue)
c.Assert(ipn.NeedsLogin, qt.Equals, b.State())
}
// Try the synchronous logout feature.
t.Logf("\n\nLogout3 (sync)")
notifies.expect(0)
notifies.expect(1)
b.LogoutSync(context.Background())
// NOTE: This returns as soon as cc.Logout() returns, which is okay
// I guess, since that's supposed to be synchronous.
{
notifies.drain(0)
nn := notifies.drain(1)
c.Assert([]string{"Logout"}, qt.DeepEquals, cc.getCalls())
c.Assert(cc.getCalls(), qt.HasLen, 0)
c.Assert(b.Prefs().LoggedOut, qt.IsTrue)
c.Assert(b.Prefs().WantRunning, qt.IsFalse)
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsTrue)
c.Assert(nn[0].Prefs.WantRunning, qt.IsFalse)
c.Assert(ipn.NeedsLogin, qt.Equals, b.State())
}
// Generate the third logout event.
t.Logf("\n\nLogout3 (sync) - succeed")
notifies.expect(0)
notifies.expect(1)
cc.setAuthBlocked(true)
cc.send(nil, "", false, nil)
{
notifies.drain(0)
nn := notifies.drain(1)
c.Assert(cc.getCalls(), qt.HasLen, 0)
c.Assert(cc.getCalls(), qt.HasLen, 0)
c.Assert(b.Prefs().LoggedOut, qt.IsTrue)
c.Assert(b.Prefs().WantRunning, qt.IsFalse)
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsTrue)
// BUG: third logout shouldn't cause WantRunning->true !!
c.Assert(nn[0].Prefs.WantRunning, qt.IsTrue)
c.Assert(ipn.NeedsLogin, qt.Equals, b.State())
}
@@ -658,6 +669,10 @@ func TestStateMachine(t *testing.T) {
// happens if the user exits and restarts while logged out.
// Note that it's explicitly okay to call b.Start() over and over
// again, every time the frontend reconnects.
//
// BUG: WantRunning is true here (because of the bug above).
// We'll have to adjust the following test's expectations if we
// fix that.
// TODO: test user switching between statekeys.
@@ -676,7 +691,7 @@ func TestStateMachine(t *testing.T) {
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[1].State, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs.LoggedOut, qt.IsTrue)
c.Assert(nn[0].Prefs.WantRunning, qt.IsFalse)
c.Assert(nn[0].Prefs.WantRunning, qt.IsTrue)
c.Assert(ipn.NeedsLogin, qt.Equals, *nn[1].State)
c.Assert(ipn.NeedsLogin, qt.Equals, b.State())
}
@@ -688,20 +703,16 @@ func TestStateMachine(t *testing.T) {
t.Logf("\n\nLoginFinished3")
notifies.expect(3)
cc.setAuthBlocked(false)
cc.persist.LoginName = "user2"
cc.send(nil, "", true, &netmap.NetworkMap{
MachineStatus: tailcfg.MachineAuthorized,
})
{
nn := notifies.drain(3)
c.Assert([]string{"unpause"}, qt.DeepEquals, cc.getCalls())
c.Assert(nn[0].LoginFinished, qt.Not(qt.IsNil))
c.Assert(nn[1].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[0].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[1].LoginFinished, qt.Not(qt.IsNil))
c.Assert(nn[2].State, qt.Not(qt.IsNil))
// Prefs after finishing the login, so LoginName updated.
c.Assert(nn[1].Prefs.Persist.LoginName, qt.Equals, "user2")
c.Assert(nn[1].Prefs.LoggedOut, qt.IsFalse)
c.Assert(nn[1].Prefs.WantRunning, qt.IsTrue)
c.Assert(nn[0].Prefs.LoggedOut, qt.IsFalse)
c.Assert(ipn.Starting, qt.Equals, *nn[2].State)
}
@@ -762,63 +773,6 @@ func TestStateMachine(t *testing.T) {
c.Assert(ipn.Starting, qt.Equals, *nn[0].State)
}
// Disconnect.
t.Logf("\n\nStop")
notifies.expect(2)
b.EditPrefs(&ipn.MaskedPrefs{
WantRunningSet: true,
Prefs: ipn.Prefs{WantRunning: false},
})
{
nn := notifies.drain(2)
c.Assert([]string{"unpause"}, qt.DeepEquals, cc.getCalls())
// BUG: I would expect Prefs to change first, and state after.
c.Assert(nn[0].State, qt.Not(qt.IsNil))
c.Assert(nn[1].Prefs, qt.Not(qt.IsNil))
c.Assert(ipn.Stopped, qt.Equals, *nn[0].State)
}
// We want to try logging in as a different user, while Stopped.
// First, start the login process (without logging out first).
t.Logf("\n\nLoginDifferent")
notifies.expect(2)
b.StartLoginInteractive()
url3 := "http://localhost:1/3"
cc.send(nil, url3, false, nil)
{
nn := notifies.drain(2)
// It might seem like WantRunning should switch to true here,
// but that would be risky since we already have a valid
// user account. It might try to reconnect to the old account
// before the new one is ready. So no change yet.
c.Assert([]string{"Login", "unpause"}, qt.DeepEquals, cc.getCalls())
c.Assert(nn[0].BrowseToURL, qt.Not(qt.IsNil))
c.Assert(nn[1].State, qt.Not(qt.IsNil))
c.Assert(*nn[0].BrowseToURL, qt.Equals, url3)
c.Assert(ipn.NeedsLogin, qt.Equals, *nn[1].State)
}
// Now, let's say the interactive login completed, using a different
// user account than before.
t.Logf("\n\nLoginDifferent URL visited")
notifies.expect(3)
cc.persist.LoginName = "user3"
cc.send(nil, "", true, &netmap.NetworkMap{
MachineStatus: tailcfg.MachineAuthorized,
})
{
nn := notifies.drain(3)
c.Assert([]string{"unpause"}, qt.DeepEquals, cc.getCalls())
c.Assert(nn[0].LoginFinished, qt.Not(qt.IsNil))
c.Assert(nn[1].Prefs, qt.Not(qt.IsNil))
c.Assert(nn[2].State, qt.Not(qt.IsNil))
// Prefs after finishing the login, so LoginName updated.
c.Assert(nn[1].Prefs.Persist.LoginName, qt.Equals, "user3")
c.Assert(nn[1].Prefs.LoggedOut, qt.IsFalse)
c.Assert(nn[1].Prefs.WantRunning, qt.IsTrue)
c.Assert(ipn.Starting, qt.Equals, *nn[2].State)
}
// The last test case is the most common one: restarting when both
// logged in and WantRunning.
t.Logf("\n\nStart5")
@@ -839,18 +793,17 @@ func TestStateMachine(t *testing.T) {
// Control server accepts our valid key from before.
t.Logf("\n\nLoginFinished5")
notifies.expect(1)
notifies.expect(2)
cc.setAuthBlocked(false)
cc.send(nil, "", true, &netmap.NetworkMap{
MachineStatus: tailcfg.MachineAuthorized,
})
{
nn := notifies.drain(1)
nn := notifies.drain(2)
c.Assert([]string{"unpause"}, qt.DeepEquals, cc.getCalls())
// NOTE: No LoginFinished message since no interactive
// login was needed.
c.Assert(nn[0].State, qt.Not(qt.IsNil))
c.Assert(ipn.Starting, qt.Equals, *nn[0].State)
c.Assert(nn[0].LoginFinished, qt.Not(qt.IsNil))
c.Assert(nn[1].State, qt.Not(qt.IsNil))
c.Assert(ipn.Starting, qt.Equals, *nn[1].State)
// NOTE: No prefs change this time. WantRunning stays true.
// We were in Starting in the first place, so that doesn't
// change either.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -84,7 +84,7 @@ type pmpMapping struct {
// externalValid reports whether m.external is valid, with both its IP and Port populated.
func (m *pmpMapping) externalValid() bool {
return !m.external.IP().IsZero() && m.external.Port() != 0
return !m.external.IP.IsZero() && m.external.Port != 0
}
// release does a best effort fire-and-forget release of the PMP mapping m.
@@ -94,8 +94,8 @@ func (m *pmpMapping) release() {
return
}
defer uc.Close()
pkt := buildPMPRequestMappingPacket(m.internal.Port(), m.external.Port(), pmpMapLifetimeDelete)
uc.WriteTo(pkt, netaddr.IPPortFrom(m.gw, pmpPort).UDPAddr())
pkt := buildPMPRequestMappingPacket(m.internal.Port, m.external.Port, pmpMapLifetimeDelete)
uc.WriteTo(pkt, netaddr.NewIPPort(m.gw, pmpPort).UDPAddr())
}
// NewClient returns a new portmapping client.
@@ -256,7 +256,7 @@ func (c *Client) CreateOrGetMapping(ctx context.Context) (external netaddr.IPPor
localPort := c.localPort
m := &pmpMapping{
gw: gw,
internal: netaddr.IPPortFrom(myIP, localPort),
internal: netaddr.NewIPPort(myIP, localPort),
}
// 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
}
// 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
@@ -279,7 +279,7 @@ func (c *Client) CreateOrGetMapping(ctx context.Context) (external netaddr.IPPor
// again. Cuts down latency for most clients.
haveRecentPMP := c.sawPMPRecentlyLocked()
if haveRecentPMP {
m.external = m.external.WithIP(c.pmpPubIP)
m.external.IP = c.pmpPubIP
}
if c.lastProbe.After(now.Add(-5*time.Second)) && !haveRecentPMP {
c.mu.Unlock()
@@ -297,11 +297,11 @@ func (c *Client) CreateOrGetMapping(ctx context.Context) (external netaddr.IPPor
uc.SetReadDeadline(time.Now().Add(portMapServiceTimeout))
defer closeCloserOnContextDone(ctx, uc)()
pmpAddr := netaddr.IPPortFrom(gw, pmpPort)
pmpAddr := netaddr.NewIPPort(gw, pmpPort)
pmpAddru := pmpAddr.UDPAddr()
// 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 {
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)}
}
if pres.OpCode == pmpOpReply|pmpOpMapPublicAddr {
m.external = m.external.WithIP(pres.PublicAddr)
m.external.IP = pres.PublicAddr
}
if pres.OpCode == pmpOpReply|pmpOpMapUDP {
m.external = m.external.WithPort(pres.ExternalPort)
m.external.Port = pres.ExternalPort
d := time.Duration(pres.MappingValidSeconds) * time.Second
d /= 2 // renew in half the time
m.useUntil = time.Now().Add(d)
@@ -468,9 +468,9 @@ func (c *Client) Probe(ctx context.Context) (res ProbeResult, err error) {
defer cancel()
defer closeCloserOnContextDone(ctx, uc)()
pcpAddr := netaddr.IPPortFrom(gw, pcpPort).UDPAddr()
pmpAddr := netaddr.IPPortFrom(gw, pmpPort).UDPAddr()
upnpAddr := netaddr.IPPortFrom(gw, upnpPort).UDPAddr()
pcpAddr := netaddr.NewIPPort(gw, pcpPort).UDPAddr()
pmpAddr := netaddr.NewIPPort(gw, pmpPort).UDPAddr()
upnpAddr := netaddr.NewIPPort(gw, upnpPort).UDPAddr()
// Don't send probes to services that we recently learned (for
// the same gw/myIP) are available. See

View File

@@ -92,7 +92,7 @@ func TailscaleEphemeral6Range() netaddr.IPPrefix {
// Currently used to work around a Windows limitation when programming
// IPv6 routes in corner cases.
func Tailscale4To6Placeholder() netaddr.IP {
return Tailscale4To6Range().IP()
return Tailscale4To6Range().IP
}
// 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) {
return netaddr.IP{}
}
ret := Tailscale4To6Range().IP().As16()
ret := Tailscale4To6Range().IP.As16()
v4 := ipv4.As4()
copy(ret[13:], v4[1:])
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:
if len(addrs) == 1 {
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 {
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:
m := map[netaddr.IP]bool{}
for _, a := range addrs {
m[a.IP()] = true
m[a.IP] = true
}
return func(ip netaddr.IP) bool { return m[ip] }
}

View File

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

View File

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

View File

@@ -1,399 +0,0 @@
#!/bin/sh
# Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
#
# This script detects the current operating system, and installs
# Tailscale according to that OS's conventions.
set -eu
# All the code is wrapped in a main function that gets called at the
# bottom of the file, so that a truncated partial download doesn't end
# up executing half a script.
main() {
# Step 1: detect the current linux distro, version, and packaging system.
#
# We rely on a combination of 'uname' and /etc/os-release to find
# an OS name and version, and from there work out what
# installation method we should be using.
#
# The end result of this step is that the following three
# variables are populated, if detection was successful.
OS=""
VERSION=""
PACKAGETYPE=""
if [ -f /etc/os-release ]; then
# /etc/os-release populates a number of shell variables. We care about the following:
# - ID: the short name of the OS (e.g. "debian", "freebsd")
# - VERSION_ID: the numeric release version for the OS, if any (e.g. "18.04")
# - VERSION_CODENAME: the codename of the OS release, if any (e.g. "buster")
. /etc/os-release
case "$ID" in
ubuntu)
OS="$ID"
VERSION="$VERSION_CODENAME"
PACKAGETYPE="apt"
;;
debian)
OS="$ID"
VERSION="$VERSION_CODENAME"
PACKAGETYPE="apt"
;;
raspbian)
OS="$ID"
VERSION="$VERSION_CODENAME"
PACKAGETYPE="apt"
;;
centos)
OS="$ID"
VERSION="$VERSION_ID"
PACKAGETYPE="dnf"
if [ "$VERSION" = "7" ]; then
PACKAGETYPE="yum"
fi
;;
rhel)
OS="$ID"
VERSION="$(echo "$VERSION_ID" | cut -f1 -d.)"
PACKAGETYPE="dnf"
;;
fedora)
OS="$ID"
VERSION=""
PACKAGETYPE="dnf"
;;
amzn)
OS="amazon-linux"
VERSION="$VERSION_ID"
PACKAGETYPE="yum"
;;
opensuse-leap)
OS="opensuse"
VERSION="leap/$VERSION_ID"
PACKAGETYPE="zypper"
;;
opensuse-tumbleweed)
OS="opensuse"
VERSION="tumbleweed"
PACKAGETYPE="zypper"
;;
arch)
OS="$ID"
VERSION="" # rolling release
PACKAGETYPE="pacman"
;;
manjaro)
OS="$ID"
VERSION="" # rolling release
PACKAGETYPE="pacman"
;;
alpine)
OS="$ID"
VERSION="$VERSION_ID"
PACKAGETYPE="apk"
;;
nixos)
echo "Please add Tailscale to your NixOS configuration directly:"
echo
echo "services.tailscale.enable = true;"
exit 1
;;
void)
OS="$ID"
VERSION="" # rolling release
PACKAGETYPE="xbps"
;;
gentoo)
OS="$ID"
VERSION="" # rolling release
PACKAGETYPE="emerge"
;;
freebsd)
OS="$ID"
VERSION="$(echo "$VERSION_ID" | cut -f1 -d.)"
PACKAGETYPE="pkg"
;;
# TODO: wsl?
# TODO: synology? qnap?
esac
fi
# If we failed to detect something through os-release, consult
# uname and try to infer things from that.
if [ -z "$OS" ]; then
if type uname >/dev/null 2>&1; then
case "$(uname)" in
FreeBSD)
# FreeBSD before 12.2 doesn't have
# /etc/os-release, so we wouldn't have found it in
# the os-release probing above.
OS="freebsd"
VERSION="$(freebsd-version | cut -f1 -d.)"
PACKAGETYPE="pkg"
;;
OpenBSD)
OS="openbsd"
VERSION="$(uname -r)"
PACKAGETYPE=""
;;
Darwin)
OS="macos"
VERSION="$(sw_vers -productVersion | cut -f1-2 -d.)"
PACKAGETYPE="appstore"
;;
Linux)
OS="other-linux"
VERSION=""
PACKAGETYPE=""
;;
esac
fi
fi
# Step 2: having detected an OS we support, is it one of the
# versions we support?
OS_UNSUPPORTED=
case "$OS" in
ubuntu)
if [ "$VERSION" != "xenial" ] && \
[ "$VERSION" != "bionic" ] && \
[ "$VERSION" != "eoan" ] && \
[ "$VERSION" != "focal" ] && \
[ "$VERSION" != "groovy" ] && \
[ "$VERSION" != "hirsute" ]
then
OS_UNSUPPORTED=1
fi
;;
debian)
if [ "$VERSION" != "stretch" ] && \
[ "$VERSION" != "buster" ] && \
[ "$VERSION" != "bullseye" ] && \
[ "$VERSION" != "sid" ]
then
OS_UNSUPPORTED=1
fi
;;
raspbian)
if [ "$VERSION" != "buster" ]
then
OS_UNSUPPORTED=1
fi
;;
centos)
if [ "$VERSION" != "7" ] && \
[ "$VERSION" != "8" ]
then
OS_UNSUPPORTED=1
fi
;;
rhel)
if [ "$VERSION" != "8" ]
then
OS_UNSUPPORTED=1
fi
;;
amazon-linux)
if [ "$VERSION" != "2" ]
then
OS_UNSUPPORTED=1
fi
;;
opensuse)
if [ "$VERSION" != "leap/15.1" ] && \
[ "$VERSION" != "leap/15.2" ] && \
[ "$VERSION" != "tumbleweed" ]
then
OS_UNSUPPORTED=1
fi
;;
arch)
# Rolling release, no version checking needed.
;;
manjaro)
# Rolling release, no version checking needed.
;;
alpine)
# All versions supported, no version checking needed.
# TODO: is that true? When was tailscale packaged?
;;
void)
# Rolling release, no version checking needed.
;;
gentoo)
# Rolling release, no version checking needed.
;;
freebsd)
if [ "$VERSION" != "12" ] && \
[ "$VERSION" != "13" ]
then
OS_UNSUPPORTED=1
fi
;;
openbsd)
OS_UNSUPPORTED=1
;;
macos)
# We delegate macOS installation to the app store, it will
# perform version checks for us.
;;
other-linux)
OS_UNSUPPORTED=1
;;
*)
OS_UNSUPPORTED=1
;;
esac
if [ "$OS_UNSUPPORTED" = "1" ]; then
case "$OS" in
other-linux)
echo "Couldn't determine what kind of Linux is running."
echo "You could try the static binaries at:"
echo "https://pkgs.tailscale.com/stable/#static"
;;
"")
echo "Couldn't determine what operating system you're running."
;;
*)
echo "$OS $VERSION isn't supported by this script yet."
;;
esac
echo
echo "If you'd like us to support your system better, please email support@tailscale.com"
echo "and tell us what OS you're running."
echo
echo "Please include the following information we gathered from your system:"
echo
echo "OS=$OS"
echo "VERSION=$VERSION"
echo "PACKAGETYPE=$PACKAGETYPE"
if type uname >/dev/null 2>&1; then
echo "UNAME=$(uname -a)"
else
echo "UNAME="
fi
echo
if [ -f /etc/os-release ]; then
cat /etc/os-release
else
echo "No /etc/os-release"
fi
exit 1
fi
# Step 3: work out if we can run privileged commands, and if so,
# how.
CAN_ROOT=
SUDO=
if [ "$(id -u)" = 0 ]; then
CAN_ROOT=1
SUDO=""
elif type sudo >/dev/null; then
CAN_ROOT=1
SUDO="sudo"
elif type doas >/dev/null; then
CAN_ROOT=1
SUDO="doas"
fi
if [ "$CAN_ROOT" != "1" ]; then
echo "This installer needs to run commands as root."
echo "We tried looking for 'sudo' and 'doas', but couldn't find them."
echo "Either re-run this script as root, or set up sudo/doas."
exit 1
fi
# Step 4: run the installation.
echo "Installing Tailscale for $OS $VERSION, using method $PACKAGETYPE"
case "$PACKAGETYPE" in
apt)
# Ideally we want to use curl, but on some installs we
# only have wget. Detect and use what's available.
CURL=
if type curl >/dev/null; then
CURL="curl -fsSL"
elif type wget >/dev/null; then
CURL="wget -q -O-"
fi
if [ -z "$CURL" ]; then
echo "The installer needs either curl or wget to download files."
echo "Please install either curl or wget to proceed."
exit 1
fi
# TODO: use newfangled per-repo signature scheme
set -x
$CURL "https://pkgs.tailscale.com/stable/$OS/$VERSION.gpg" | $SUDO apt-key add -
$CURL "https://pkgs.tailscale.com/stable/$OS/$VERSION.list" | $SUDO tee /etc/apt/sources.list.d/tailscale.list
$SUDO apt-get update
$SUDO apt-get install tailscale
set +x
;;
yum)
set -x
$SUDO yum install yum-utils
$SUDO yum-config-manager --add-repo "https://pkgs.tailscale.com/stable/$OS/$VERSION/tailscale.repo"
$SUDO yum install tailscale
$SUDO systemctl enable --now tailscaled
set +x
;;
dnf)
set -x
$SUDO dnf config-manager --add-repo "https://pkgs.tailscale.com/stable/$OS/$VERSION/tailscale.repo"
$SUDO dnf install tailscale
$SUDO systemctl enable --now tailscaled
set +x
;;
zypper)
set -x
$SUDO zypper ar -g -r "https://pkgs.tailscale.com/stable/$OS/$VERSION/tailscale.repo"
$SUDO zypper ref
$SUDO zypper in tailscale
$SUDO systemctl enable --now tailscaled
set +x
;;
pacman)
set -x
$SUDO pacman -S tailscale
$SUDO systemctl enable --now tailscaled
set +x
;;
apk)
set -x
$SUDO apk add tailscale
$SUDO rc-update add tailscale
set +x
;;
xbps)
set -x
$SUDO xbps-install tailscale
set +x
;;
emerge)
set -x
$SUDO emerge net-vpn/tailscale
set +x
;;
appstore)
set -x
open "https://apps.apple.com/us/app/tailscale/id1475387142"
set +x
;;
*)
echo "unexpected: unknown package type $PACKAGETYPE"
exit 1
;;
esac
echo "Installation complete! Log in to start using Tailscale by running:"
echo
if [ -z "$SUDO" ]; then
echo "tailscale up"
else
echo "$SUDO tailscale up"
fi
}
main

View File

@@ -1,43 +0,0 @@
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The tshello server demonstrates how to use Tailscale as a library.
package main
import (
"fmt"
"html"
"log"
"net/http"
"strings"
"tailscale.com/tsnet"
)
func main() {
s := new(tsnet.Server)
ln, err := s.Listen("tcp", ":80")
if err != nil {
log.Fatal(err)
}
log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
who, ok := s.WhoIs(r.RemoteAddr)
if !ok {
http.Error(w, "WhoIs failed", 500)
return
}
fmt.Fprintf(w, "<html><body><h1>Hello, world!</h1>\n")
fmt.Fprintf(w, "<p>You are <b>%s</b> from <b>%s</b> (%s)</p>",
html.EscapeString(who.UserProfile.LoginName),
html.EscapeString(firstLabel(who.Node.ComputedName)),
r.RemoteAddr)
})))
}
func firstLabel(s string) string {
if i := strings.Index(s, "."); i != -1 {
return s[:i]
}
return s
}

View File

@@ -1,274 +0,0 @@
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package tsnet provides Tailscale as a library.
//
// It is an experimental work in progress.
package tsnet
import (
"errors"
"fmt"
"log"
"net"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
"inet.af/netaddr"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/control/controlclient"
"tailscale.com/ipn"
"tailscale.com/ipn/ipnlocal"
"tailscale.com/smallzstd"
"tailscale.com/types/logger"
"tailscale.com/wgengine"
"tailscale.com/wgengine/monitor"
"tailscale.com/wgengine/netstack"
)
// Server is an embedded Tailscale server.
//
// Its exported fields may be changed until the first call to Listen.
type Server struct {
// Dir specifies the name of the directory to use for
// state. If empty, a directory is selected automatically
// under os.UserConfigDir (https://golang.org/pkg/os/#UserConfigDir).
// based on the name of the binary.
Dir string
// Hostname is the hostname to present to the control server.
// If empty, the binary name is used.l
Hostname string
// Logf, if non-nil, specifies the logger to use. By default,
// log.Printf is used.
Logf logger.Logf
initOnce sync.Once
initErr error
lb *ipnlocal.LocalBackend
// the state directory
dir string
hostname string
mu sync.Mutex
listeners map[listenKey]*listener
}
// WhoIs reports the node and user who owns the node with the given
// address. The addr may be an ip:port (as from an
// http.Request.RemoteAddr) or just an IP address.
func (s *Server) WhoIs(addr string) (w *apitype.WhoIsResponse, ok bool) {
ipp, err := netaddr.ParseIPPort(addr)
if err != nil {
ip, err := netaddr.ParseIP(addr)
if err != nil {
return nil, false
}
ipp = ipp.WithIP(ip)
}
n, up, ok := s.lb.WhoIs(ipp)
if !ok {
return nil, false
}
return &apitype.WhoIsResponse{
Node: n,
UserProfile: &up,
}, true
}
func (s *Server) doInit() {
if err := s.start(); err != nil {
s.initErr = fmt.Errorf("tsnet: %w", err)
}
}
func (s *Server) start() error {
if v, _ := strconv.ParseBool(os.Getenv("TAILSCALE_USE_WIP_CODE")); !v {
return errors.New("code disabled without environment variable TAILSCALE_USE_WIP_CODE set true")
}
exe, err := os.Executable()
if err != nil {
return err
}
prog := strings.TrimSuffix(strings.ToLower(filepath.Base(exe)), ".exe")
s.hostname = s.Hostname
if s.hostname == "" {
s.hostname = prog
}
s.dir = s.Dir
if s.dir == "" {
confDir, err := os.UserConfigDir()
if err != nil {
return err
}
s.dir = filepath.Join(confDir, "tslib-"+prog)
if err := os.MkdirAll(s.dir, 0700); err != nil {
return err
}
}
if fi, err := os.Stat(s.dir); err != nil {
return err
} else if !fi.IsDir() {
return fmt.Errorf("%v is not a directory", s.dir)
}
logf := s.Logf
if logf == nil {
logf = log.Printf
}
// TODO(bradfitz): start logtail? don't use filch, perhaps?
// only upload plumbed Logf?
linkMon, err := monitor.New(logf)
if err != nil {
return err
}
eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{
ListenPort: 0,
LinkMonitor: linkMon,
})
if err != nil {
return err
}
tunDev, magicConn, ok := eng.(wgengine.InternalsGetter).GetInternals()
if !ok {
return fmt.Errorf("%T is not a wgengine.InternalsGetter", eng)
}
ns, err := netstack.Create(logf, tunDev, eng, magicConn, false)
if err != nil {
return fmt.Errorf("netstack.Create: %w", err)
}
ns.ForwardTCPIn = s.forwardTCP
if err := ns.Start(); err != nil {
return fmt.Errorf("failed to start netstack: %w", err)
}
statePath := filepath.Join(s.dir, "tailscaled.state")
store, err := ipn.NewFileStore(statePath)
if err != nil {
return err
}
logid := "tslib-TODO"
lb, err := ipnlocal.NewLocalBackend(logf, logid, store, eng)
if err != nil {
return fmt.Errorf("NewLocalBackend: %v", err)
}
s.lb = lb
lb.SetDecompressor(func() (controlclient.Decompressor, error) {
return smallzstd.NewDecoder(nil)
})
prefs := ipn.NewPrefs()
prefs.Hostname = s.hostname
prefs.WantRunning = true
err = lb.Start(ipn.Options{
StateKey: ipn.GlobalDaemonStateKey,
UpdatePrefs: prefs,
})
if err != nil {
return fmt.Errorf("starting backend: %w", err)
}
if os.Getenv("TS_LOGIN") == "1" {
s.lb.StartLoginInteractive()
}
return nil
}
func (s *Server) forwardTCP(c net.Conn, port uint16) {
s.mu.Lock()
ln, ok := s.listeners[listenKey{"tcp", "", fmt.Sprint(port)}]
s.mu.Unlock()
if !ok {
c.Close()
return
}
t := time.NewTimer(time.Second)
defer t.Stop()
select {
case ln.conn <- c:
case <-t.C:
c.Close()
}
}
func (s *Server) Listen(network, addr string) (net.Listener, error) {
host, port, err := net.SplitHostPort(addr)
if err != nil {
return nil, fmt.Errorf("tsnet: %w", err)
}
s.initOnce.Do(s.doInit)
if s.initErr != nil {
return nil, s.initErr
}
key := listenKey{network, host, port}
ln := &listener{
s: s,
key: key,
addr: addr,
conn: make(chan net.Conn),
}
s.mu.Lock()
if s.listeners == nil {
s.listeners = map[listenKey]*listener{}
}
if _, ok := s.listeners[key]; ok {
s.mu.Unlock()
return nil, fmt.Errorf("tsnet: listener already open for %s, %s", network, addr)
}
s.listeners[key] = ln
s.mu.Unlock()
return ln, nil
}
type listenKey struct {
network string
host string
port string
}
type listener struct {
s *Server
key listenKey
addr string
conn chan net.Conn
}
func (ln *listener) Accept() (net.Conn, error) {
c, ok := <-ln.conn
if !ok {
return nil, fmt.Errorf("tsnet: %w", net.ErrClosed)
}
return c, nil
}
func (ln *listener) Addr() net.Addr { return addr{ln} }
func (ln *listener) Close() error {
ln.s.mu.Lock()
defer ln.s.mu.Unlock()
if v, ok := ln.s.listeners[ln.key]; ok && v == ln {
delete(ln.s.listeners, ln.key)
close(ln.conn)
}
return nil
}
type addr struct{ ln *listener }
func (a addr) Network() string { return a.ln.key.network }
func (a addr) String() string { return a.ln.addr }

View File

@@ -10,8 +10,6 @@ import (
crand "crypto/rand"
"crypto/tls"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
@@ -23,7 +21,6 @@ import (
"os/exec"
"path"
"path/filepath"
"regexp"
"runtime"
"strings"
"sync"
@@ -44,11 +41,8 @@ import (
"tailscale.com/types/key"
"tailscale.com/types/logger"
"tailscale.com/types/nettype"
"tailscale.com/version"
)
var verbose = flag.Bool("verbose", false, "verbose debug logs")
var mainError atomic.Value // of error
func TestMain(m *testing.M) {
@@ -63,8 +57,11 @@ func TestMain(m *testing.M) {
os.Exit(0)
}
func TestOneNodeUp_NoAuth(t *testing.T) {
t.Parallel()
func TestIntegration(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("not tested/working on Windows yet")
}
bins := buildTestBinaries(t)
env := newTestEnv(t, bins)
@@ -72,8 +69,8 @@ func TestOneNodeUp_NoAuth(t *testing.T) {
n1 := newTestNode(t, env)
d1 := n1.StartDaemon(t)
defer d1.Kill()
dcmd := n1.StartDaemon(t)
defer dcmd.Process.Kill()
n1.AwaitListening(t)
@@ -90,110 +87,44 @@ func TestOneNodeUp_NoAuth(t *testing.T) {
t.Error(err)
}
n1.MustUp()
t.Logf("Running up --login-server=%s ...", env.ControlServer.URL)
if err := n1.Tailscale("up", "--login-server="+env.ControlServer.URL).Run(); err != nil {
t.Fatalf("up: %v", err)
}
if d, _ := time.ParseDuration(os.Getenv("TS_POST_UP_SLEEP")); d > 0 {
t.Logf("Sleeping for %v to give 'up' time to misbehave (https://github.com/tailscale/tailscale/issues/1840) ...", d)
time.Sleep(d)
}
t.Logf("Got IP: %v", n1.AwaitIP(t))
n1.AwaitRunning(t)
d1.MustCleanShutdown(t)
t.Logf("number of HTTP logcatcher requests: %v", env.LogCatcher.numRequests())
}
func TestOneNodeUp_Auth(t *testing.T) {
t.Parallel()
bins := buildTestBinaries(t)
env := newTestEnv(t, bins)
defer env.Close()
env.Control.RequireAuth = true
n1 := newTestNode(t, env)
d1 := n1.StartDaemon(t)
defer d1.Kill()
n1.AwaitListening(t)
st := n1.MustStatus(t)
t.Logf("Status: %s", st.BackendState)
t.Logf("Running up --login-server=%s ...", env.ControlServer.URL)
cmd := n1.Tailscale("up", "--login-server="+env.ControlServer.URL)
var authCountAtomic int32
cmd.Stdout = &authURLParserWriter{fn: func(urlStr string) error {
if env.Control.CompleteAuth(urlStr) {
atomic.AddInt32(&authCountAtomic, 1)
t.Logf("completed auth path %s", urlStr)
return nil
}
err := fmt.Errorf("Failed to complete auth path to %q", urlStr)
t.Log(err)
return err
}}
cmd.Stderr = cmd.Stdout
if err := cmd.Run(); err != nil {
t.Fatalf("up: %v", err)
}
t.Logf("Got IP: %v", n1.AwaitIP(t))
n1.AwaitRunning(t)
if n := atomic.LoadInt32(&authCountAtomic); n != 1 {
t.Errorf("Auth URLs completed = %d; want 1", n)
}
d1.MustCleanShutdown(t)
}
func TestTwoNodes(t *testing.T) {
t.Parallel()
bins := buildTestBinaries(t)
env := newTestEnv(t, bins)
defer env.Close()
// Create two nodes:
n1 := newTestNode(t, env)
d1 := n1.StartDaemon(t)
defer d1.Kill()
n2 := newTestNode(t, env)
d2 := n2.StartDaemon(t)
defer d2.Kill()
n1.AwaitListening(t)
n2.AwaitListening(t)
n1.MustUp()
n2.MustUp()
n1.AwaitRunning(t)
n2.AwaitRunning(t)
if err := tstest.WaitFor(2*time.Second, func() error {
st := n1.MustStatus(t)
if len(st.Peer) == 0 {
return errors.New("no peers")
}
if len(st.Peer) > 1 {
return fmt.Errorf("got %d peers; want 1", len(st.Peer))
}
peer := st.Peer[st.Peers()[0]]
if peer.ID == st.Self.ID {
return errors.New("peer is self")
var ip string
if err := tstest.WaitFor(20*time.Second, func() error {
out, err := n1.Tailscale("ip").Output()
if err != nil {
return err
}
ip = string(out)
return nil
}); err != nil {
t.Error(err)
}
t.Logf("Got IP: %v", ip)
d1.MustCleanShutdown(t)
d2.MustCleanShutdown(t)
dcmd.Process.Signal(os.Interrupt)
ps, err := dcmd.Process.Wait()
if err != nil {
t.Fatalf("tailscaled Wait: %v", err)
}
if ps.ExitCode() != 0 {
t.Errorf("tailscaled ExitCode = %d; want 0", ps.ExitCode())
}
t.Logf("number of HTTP logcatcher requests: %v", env.LogCatcher.numRequests())
if err := env.TrafficTrap.Err(); err != nil {
t.Errorf("traffic trap: %v", err)
t.Logf("logs: %s", env.LogCatcher.logsString())
}
}
// testBinaries are the paths to a tailscaled and tailscale binary.
@@ -208,18 +139,16 @@ type testBinaries struct {
// if they fail to compile.
func buildTestBinaries(t testing.TB) *testBinaries {
td := t.TempDir()
build(t, td, "tailscale.com/cmd/tailscaled", "tailscale.com/cmd/tailscale")
return &testBinaries{
dir: td,
daemon: filepath.Join(td, "tailscaled"+exe()),
cli: filepath.Join(td, "tailscale"+exe()),
daemon: build(t, td, "tailscale.com/cmd/tailscaled"),
cli: build(t, td, "tailscale.com/cmd/tailscale"),
}
}
// testEnv contains the test environment (set of servers) used by one
// or more nodes.
type testEnv struct {
t testing.TB
Binaries *testBinaries
LogCatcher *logCatcher
@@ -239,9 +168,6 @@ type testEnv struct {
//
// Call Close to shut everything down.
func newTestEnv(t testing.TB, bins *testBinaries) *testEnv {
if runtime.GOOS == "windows" {
t.Skip("not tested/working on Windows yet")
}
derpMap, derpShutdown := runDERPAndStun(t, logger.Discard)
logc := new(logCatcher)
control := &testcontrol.Server{
@@ -249,7 +175,6 @@ func newTestEnv(t testing.TB, bins *testBinaries) *testEnv {
}
trafficTrap := new(trafficTrap)
e := &testEnv{
t: t,
Binaries: bins,
LogCatcher: logc,
LogCatcherServer: httptest.NewServer(logc),
@@ -259,16 +184,10 @@ func newTestEnv(t testing.TB, bins *testBinaries) *testEnv {
TrafficTrapServer: httptest.NewServer(trafficTrap),
derpShutdown: derpShutdown,
}
e.Control.BaseURL = e.ControlServer.URL
return e
}
func (e *testEnv) Close() error {
if err := e.TrafficTrap.Err(); err != nil {
e.t.Errorf("traffic trap: %v", err)
e.t.Logf("logs: %s", e.LogCatcher.logsString())
}
e.LogCatcherServer.Close()
e.TrafficTrapServer.Close()
e.ControlServer.Close()
@@ -299,28 +218,9 @@ func newTestNode(t *testing.T, env *testEnv) *testNode {
}
}
type Daemon struct {
Process *os.Process
}
func (d *Daemon) Kill() {
d.Process.Kill()
}
func (d *Daemon) MustCleanShutdown(t testing.TB) {
d.Process.Signal(os.Interrupt)
ps, err := d.Process.Wait()
if err != nil {
t.Fatalf("tailscaled Wait: %v", err)
}
if ps.ExitCode() != 0 {
t.Errorf("tailscaled ExitCode = %d; want 0", ps.ExitCode())
}
}
// StartDaemon starts the node's tailscaled, failing if it fails to
// start.
func (n *testNode) StartDaemon(t testing.TB) *Daemon {
func (n *testNode) StartDaemon(t testing.TB) *exec.Cmd {
cmd := exec.Command(n.env.Binaries.daemon,
"--tun=userspace-networking",
"--state="+n.stateFile,
@@ -334,17 +234,7 @@ func (n *testNode) StartDaemon(t testing.TB) *Daemon {
if err := cmd.Start(); err != nil {
t.Fatalf("starting tailscaled: %v", err)
}
return &Daemon{
Process: cmd.Process,
}
}
func (n *testNode) MustUp() {
t := n.env.t
t.Logf("Running up --login-server=%s ...", n.env.ControlServer.URL)
if err := n.Tailscale("up", "--login-server="+n.env.ControlServer.URL).Run(); err != nil {
t.Fatalf("up: %v", err)
}
return cmd
}
// AwaitListening waits for the tailscaled to be serving local clients
@@ -362,40 +252,6 @@ func (n *testNode) AwaitListening(t testing.TB) {
}
}
func (n *testNode) AwaitIP(t testing.TB) (ips string) {
t.Helper()
if err := tstest.WaitFor(20*time.Second, func() error {
out, err := n.Tailscale("ip").Output()
if err != nil {
return err
}
ips = string(out)
return nil
}); err != nil {
t.Fatalf("awaiting an IP address: %v", err)
}
if ips == "" {
t.Fatalf("returned IP address was blank")
}
return ips
}
func (n *testNode) AwaitRunning(t testing.TB) {
t.Helper()
if err := tstest.WaitFor(20*time.Second, func() error {
st, err := n.Status()
if err != nil {
return err
}
if st.BackendState != "Running" {
return fmt.Errorf("in state %q", st.BackendState)
}
return nil
}); err != nil {
t.Fatalf("failure/timeout waiting for transition to Running status: %v", err)
}
}
// Tailscale returns a command that runs the tailscale CLI with the provided arguments.
// It does not start the process.
func (n *testNode) Tailscale(arg ...string) *exec.Cmd {
@@ -405,23 +261,15 @@ func (n *testNode) Tailscale(arg ...string) *exec.Cmd {
return cmd
}
func (n *testNode) Status() (*ipnstate.Status, error) {
func (n *testNode) MustStatus(tb testing.TB) *ipnstate.Status {
tb.Helper()
out, err := n.Tailscale("status", "--json").CombinedOutput()
if err != nil {
return nil, fmt.Errorf("running tailscale status: %v, %s", err, out)
tb.Fatalf("getting status: %v, %s", err, out)
}
st := new(ipnstate.Status)
if err := json.Unmarshal(out, st); err != nil {
return nil, fmt.Errorf("decoding tailscale status JSON: %w", err)
}
return st, nil
}
func (n *testNode) MustStatus(tb testing.TB) *ipnstate.Status {
tb.Helper()
st, err := n.Status()
if err != nil {
tb.Fatal(err)
tb.Fatalf("parsing status json: %v, from: %s", err, out)
}
return st
}
@@ -443,44 +291,21 @@ func findGo(t testing.TB) string {
} else if !fi.Mode().IsRegular() {
t.Fatalf("%v is unexpected %v", goBin, fi.Mode())
}
t.Logf("using go binary %v", goBin)
return goBin
}
// buildMu limits our use of "go build" to one at a time, so we don't
// fight Go's built-in caching trying to do the same build concurrently.
var buildMu sync.Mutex
func build(t testing.TB, outDir string, targets ...string) {
buildMu.Lock()
defer buildMu.Unlock()
t0 := time.Now()
defer func() { t.Logf("built %s in %v", targets, time.Since(t0).Round(time.Millisecond)) }()
goBin := findGo(t)
cmd := exec.Command(goBin, "install")
if version.IsRace() {
cmd.Args = append(cmd.Args, "-race")
func build(t testing.TB, outDir, target string) string {
exe := ""
if runtime.GOOS == "windows" {
exe = ".exe"
}
cmd.Args = append(cmd.Args, targets...)
cmd.Env = append(os.Environ(), "GOARCH="+runtime.GOARCH, "GOBIN="+outDir)
errOut, err := cmd.CombinedOutput()
if err == nil {
return
bin := filepath.Join(outDir, path.Base(target)) + exe
errOut, err := exec.Command(findGo(t), "build", "-o", bin, target).CombinedOutput()
if err != nil {
t.Fatalf("failed to build %v: %v, %s", target, err, errOut)
}
if strings.Contains(string(errOut), "when GOBIN is set") {
// Fallback slow path for cross-compiled binaries.
for _, target := range targets {
outFile := filepath.Join(outDir, path.Base(target)+exe())
cmd := exec.Command(goBin, "build", "-o", outFile, target)
cmd.Env = append(os.Environ(), "GOARCH="+runtime.GOARCH)
if errOut, err := cmd.CombinedOutput(); err != nil {
t.Fatalf("failed to build %v with %v: %v, %s", target, goBin, err, errOut)
}
}
return
}
t.Fatalf("failed to build %v with %v: %v, %s", targets, goBin, err, errOut)
return bin
}
// logCatcher is a minimal logcatcher for the logtail upload client.
@@ -553,9 +378,6 @@ func (lc *logCatcher) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} else {
for _, ent := range jreq {
fmt.Fprintf(&lc.buf, "%s\n", strings.TrimSpace(ent.Text))
if *verbose {
fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(ent.Text))
}
}
}
w.WriteHeader(200) // must have no content, but not a 204
@@ -632,23 +454,3 @@ func runDERPAndStun(t testing.TB, logf logger.Logf) (derpMap *tailcfg.DERPMap, c
return m, cleanup
}
type authURLParserWriter struct {
buf bytes.Buffer
fn func(urlStr string) error
}
var authURLRx = regexp.MustCompile(`(https?://\S+/auth/\S+)`)
func (w *authURLParserWriter) Write(p []byte) (n int, err error) {
n, err = w.buf.Write(p)
m := authURLRx.FindSubmatch(w.buf.Bytes())
if m != nil {
urlStr := string(m[1])
w.buf.Reset() // so it's not matched again
if err := w.fn(urlStr); err != nil {
return 0, err
}
}
return n, err
}

View File

@@ -17,8 +17,6 @@ import (
"log"
"math/rand"
"net/http"
"net/url"
"sort"
"strings"
"sync"
"time"
@@ -36,43 +34,19 @@ import (
// Server is a control plane server. Its zero value is ready for use.
// Everything is stored in-memory in one tailnet.
type Server struct {
Logf logger.Logf // nil means to use the log package
DERPMap *tailcfg.DERPMap // nil means to use prod DERP map
RequireAuth bool
BaseURL string // must be set to e.g. "http://127.0.0.1:1234" with no trailing URL
Verbose bool
Logf logger.Logf // nil means to use the log package
DERPMap *tailcfg.DERPMap // nil means to use prod DERP map
initMuxOnce sync.Once
mux *http.ServeMux
mu sync.Mutex
pubKey wgkey.Key
privKey wgkey.Private
nodes map[tailcfg.NodeKey]*tailcfg.Node
users map[tailcfg.NodeKey]*tailcfg.User
logins map[tailcfg.NodeKey]*tailcfg.Login
updates map[tailcfg.NodeID]chan updateType
authPath map[string]*AuthPath
nodeKeyAuthed map[tailcfg.NodeKey]bool // key => true once authenticated
}
type AuthPath struct {
nodeKey tailcfg.NodeKey
closeOnce sync.Once
ch chan struct{}
success bool
}
func (ap *AuthPath) completeSuccessfully() {
ap.success = true
close(ap.ch)
}
// CompleteSuccessfully completes the login path successfully, as if
// the user did the whole auth dance.
func (ap *AuthPath) CompleteSuccessfully() {
ap.closeOnce.Do(ap.completeSuccessfully)
mu sync.Mutex
pubKey wgkey.Key
privKey wgkey.Private
nodes map[tailcfg.NodeKey]*tailcfg.Node
users map[tailcfg.NodeKey]*tailcfg.User
logins map[tailcfg.NodeKey]*tailcfg.Login
updates map[tailcfg.NodeID]chan updateType
}
func (s *Server) logf(format string, a ...interface{}) {
@@ -168,18 +142,6 @@ func (s *Server) Node(nodeKey tailcfg.NodeKey) *tailcfg.Node {
return s.nodes[nodeKey].Clone()
}
func (s *Server) AllNodes() (nodes []*tailcfg.Node) {
s.mu.Lock()
defer s.mu.Unlock()
for _, n := range s.nodes {
nodes = append(nodes, n.Clone())
}
sort.Slice(nodes, func(i, j int) bool {
return nodes[i].StableID < nodes[j].StableID
})
return nodes
}
func (s *Server) getUser(nodeKey tailcfg.NodeKey) (*tailcfg.User, *tailcfg.Login) {
s.mu.Lock()
defer s.mu.Unlock()
@@ -216,56 +178,6 @@ func (s *Server) getUser(nodeKey tailcfg.NodeKey) (*tailcfg.User, *tailcfg.Login
return user, login
}
// authPathDone returns a close-only struct that's closed when the
// authPath ("/auth/XXXXXX") has authenticated.
func (s *Server) authPathDone(authPath string) <-chan struct{} {
s.mu.Lock()
defer s.mu.Unlock()
if a, ok := s.authPath[authPath]; ok {
return a.ch
}
return nil
}
func (s *Server) addAuthPath(authPath string, nodeKey tailcfg.NodeKey) {
s.mu.Lock()
defer s.mu.Unlock()
if s.authPath == nil {
s.authPath = map[string]*AuthPath{}
}
s.authPath[authPath] = &AuthPath{
ch: make(chan struct{}),
nodeKey: nodeKey,
}
}
// CompleteAuth marks the provided path or URL (containing
// "/auth/...") as successfully authenticated, unblocking any
// requests blocked on that in serveRegister.
func (s *Server) CompleteAuth(authPathOrURL string) bool {
i := strings.Index(authPathOrURL, "/auth/")
if i == -1 {
return false
}
authPath := authPathOrURL[i:]
s.mu.Lock()
defer s.mu.Unlock()
ap, ok := s.authPath[authPath]
if !ok {
return false
}
if ap.nodeKey.IsZero() {
panic("zero AuthPath.NodeKey")
}
if s.nodeKeyAuthed == nil {
s.nodeKeyAuthed = map[tailcfg.NodeKey]bool{}
}
s.nodeKeyAuthed[ap.nodeKey] = true
ap.CompleteSuccessfully()
return true
}
func (s *Server) serveRegister(w http.ResponseWriter, r *http.Request, mkey tailcfg.MachineKey) {
var req tailcfg.RegisterRequest
if err := s.decode(mkey, r.Body, &req); err != nil {
@@ -277,65 +189,28 @@ func (s *Server) serveRegister(w http.ResponseWriter, r *http.Request, mkey tail
if req.NodeKey.IsZero() {
panic("serveRegister: request has zero node key")
}
if s.Verbose {
j, _ := json.MarshalIndent(req, "", "\t")
log.Printf("Got %T: %s", req, j)
}
// If this is a followup request, wait until interactive followup URL visit complete.
if req.Followup != "" {
followupURL, err := url.Parse(req.Followup)
if err != nil {
panic(err)
}
doneCh := s.authPathDone(followupURL.Path)
select {
case <-r.Context().Done():
return
case <-doneCh:
}
// TODO(bradfitz): support a side test API to mark an
// auth as failued so we can send an error response in
// some follow-ups? For now all are successes.
}
user, login := s.getUser(req.NodeKey)
s.mu.Lock()
if s.nodes == nil {
s.nodes = map[tailcfg.NodeKey]*tailcfg.Node{}
}
machineAuthorized := true // TODO: add Server.RequireMachineAuth
s.nodes[req.NodeKey] = &tailcfg.Node{
ID: tailcfg.NodeID(user.ID),
StableID: tailcfg.StableNodeID(fmt.Sprintf("TESTCTRL%08x", int(user.ID))),
User: user.ID,
Machine: mkey,
Key: req.NodeKey,
MachineAuthorized: machineAuthorized,
}
requireAuth := s.RequireAuth
if requireAuth && s.nodeKeyAuthed[req.NodeKey] {
requireAuth = false
MachineAuthorized: true,
}
s.mu.Unlock()
authURL := ""
if requireAuth {
randHex := make([]byte, 10)
crand.Read(randHex)
authPath := fmt.Sprintf("/auth/%x", randHex)
s.addAuthPath(authPath, req.NodeKey)
authURL = s.BaseURL + authPath
}
res, err := s.encode(mkey, false, tailcfg.RegisterResponse{
User: *user,
Login: *login,
NodeKeyExpired: false,
MachineAuthorized: machineAuthorized,
AuthURL: authURL,
MachineAuthorized: true,
AuthURL: "", // all good; TODO(bradfitz): add ways to not start all good.
})
if err != nil {
go panic(fmt.Sprintf("serveRegister: encode: %v", err))
@@ -379,21 +254,6 @@ func sendUpdate(dst chan<- updateType, updateType updateType) {
}
}
func (s *Server) UpdateNode(n *tailcfg.Node) (peersToUpdate []tailcfg.NodeID) {
s.mu.Lock()
defer s.mu.Unlock()
if n.Key.IsZero() {
panic("zero nodekey")
}
s.nodes[n.Key] = n.Clone()
for _, n2 := range s.nodes {
if n.ID != n2.ID {
peersToUpdate = append(peersToUpdate, n2.ID)
}
}
return peersToUpdate
}
func (s *Server) serveMap(w http.ResponseWriter, r *http.Request, mkey tailcfg.MachineKey) {
ctx := r.Context()
@@ -419,8 +279,10 @@ func (s *Server) serveMap(w http.ResponseWriter, r *http.Request, mkey tailcfg.M
if !req.ReadOnly {
endpoints := filterInvalidIPv6Endpoints(req.Endpoints)
node.Endpoints = endpoints
node.DiscoKey = req.DiscoKey
peersToUpdate = s.UpdateNode(node)
// TODO: more
// TODO: register node,
//s.UpdateEndpoint(mkey, req.NodeKey,
// XXX
}
nodeID := node.ID
@@ -527,12 +389,6 @@ func (s *Server) MapResponse(req *tailcfg.MapRequest) (res *tailcfg.MapResponse,
CollectServices: "true",
PacketFilter: tailcfg.FilterAllowAll,
}
for _, p := range s.AllNodes() {
if p.StableID != node.StableID {
res.Peers = append(res.Peers, p)
}
}
res.Node.Addresses = []netaddr.IPPrefix{
netaddr.MustParseIPPrefix(fmt.Sprintf("100.64.%d.%d/32", uint8(node.ID>>8), uint8(node.ID))),
}
@@ -650,7 +506,7 @@ func keepClientEndpoint(ep string) bool {
// the incoming JSON response.
return false
}
ip := ipp.IP()
ip := ipp.IP
if ip.Zone() != "" {
return false
}

View File

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

View File

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

View File

@@ -138,7 +138,7 @@ func (n *Network) allocIPv4(iface *Interface) netaddr.IP {
return netaddr.IP{}
}
if n.lastV4.IsZero() {
n.lastV4 = n.Prefix4.IP()
n.lastV4 = n.Prefix4.IP
}
a := n.lastV4.As16()
addOne(&a, 15)
@@ -157,7 +157,7 @@ func (n *Network) allocIPv6(iface *Interface) netaddr.IP {
return netaddr.IP{}
}
if n.lastV6.IsZero() {
n.lastV6 = n.Prefix6.IP()
n.lastV6 = n.Prefix6.IP
}
a := n.lastV6.As16()
addOne(&a, 15)
@@ -183,15 +183,15 @@ func (n *Network) write(p *Packet) (num int, err error) {
n.mu.Lock()
defer n.mu.Unlock()
iface, ok := n.machine[p.Dst.IP()]
iface, ok := n.machine[p.Dst.IP]
if !ok {
// If the destination is within the network's authoritative
// 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)
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)
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) {
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)
} else {
m.forwardPacket(p, iface)
@@ -391,13 +391,13 @@ func (m *Machine) deliverLocalPacket(p *Packet, iface *Interface) {
defer m.mu.Unlock()
conns := m.conns4
if p.Dst.IP().Is6() {
if p.Dst.IP.Is6() {
conns = m.conns6
}
possibleDsts := []netaddr.IPPort{
p.Dst,
netaddr.IPPortFrom(v6unspec, p.Dst.Port()),
netaddr.IPPortFrom(v4unspec, p.Dst.Port()),
netaddr.NewIPPort(v6unspec, p.Dst.Port),
netaddr.NewIPPort(v4unspec, p.Dst.Port),
}
for _, dest := range possibleDsts {
c, ok := conns[dest]
@@ -417,7 +417,7 @@ func (m *Machine) deliverLocalPacket(p *Packet, iface *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 {
p.Trace("%v", err)
return
@@ -501,7 +501,7 @@ func (m *Machine) Attach(interfaceName string, n *Network) *Interface {
}
}
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
@@ -515,33 +515,33 @@ var (
func (m *Machine) writePacket(p *Packet) (n int, err error) {
p.setLocator("mach=%s", m.Name)
iface, err := m.interfaceForIP(p.Dst.IP())
iface, err := m.interfaceForIP(p.Dst.IP)
if err != nil {
p.Trace("%v", err)
return 0, err
}
origSrcIP := p.Src.IP()
origSrcIP := p.Src.IP
switch {
case p.Src.IP() == v4unspec:
case p.Src.IP == v4unspec:
p.Trace("assigning srcIP=%s", iface.V4())
p.Src = p.Src.WithIP(iface.V4())
case p.Src.IP() == v6unspec:
p.Src.IP = iface.V4()
case p.Src.IP == v6unspec:
// 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.Src = p.Src.WithIP(iface.V6())
} else if p.Dst.IP().Is4() {
p.Src.IP = iface.V6()
} else if p.Dst.IP.Is4() {
p.Trace("assigning srcIP=%s", iface.V4())
p.Src = p.Src.WithIP(iface.V4())
p.Src.IP = iface.V4()
}
default:
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)
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)
p.Trace("%v", 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)
p.Trace("%v", err)
return 0, err
@@ -602,12 +602,12 @@ func (m *Machine) pickEphemPort() (port uint16, err error) {
func (m *Machine) portInUseLocked(port uint16) bool {
for ipp := range m.conns4 {
if ipp.Port() == port {
if ipp.Port == port {
return true
}
}
for ipp := range m.conns6 {
if ipp.Port() == port {
if ipp.Port == port {
return true
}
}
@@ -617,7 +617,7 @@ func (m *Machine) portInUseLocked(port uint16) bool {
func (m *Machine) registerConn4(c *conn) error {
m.mu.Lock()
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 registerConn(&m.conns4, c)
@@ -632,7 +632,7 @@ func (m *Machine) unregisterConn4(c *conn) {
func (m *Machine) registerConn6(c *conn) error {
m.mu.Lock()
defer m.mu.Unlock()
if c.ipp.IP().Is4() {
if c.ipp.IP.Is4() {
return fmt.Errorf("registerConn6 got IPv4 %s", c.ipp)
}
return registerConn(&m.conns6, c)
@@ -707,7 +707,7 @@ func (m *Machine) ListenPacket(ctx context.Context, network, address string) (ne
return nil, nil
}
}
ipp := netaddr.IPPortFrom(ip, port)
ipp := netaddr.NewIPPort(ip, port)
c := &conn{
m: m,

View File

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

View File

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

View File

@@ -1,11 +0,0 @@
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build race
package version
// IsRace reports whether the current binary was built with the Go
// race detector enabled.
func IsRace() bool { return true }

View File

@@ -1,11 +0,0 @@
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !race
package version
// IsRace reports whether the current binary was built with the Go
// race detector enabled.
func IsRace() bool { return false }

View File

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

View File

@@ -87,7 +87,7 @@ func main() {
}
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 pps int64

View File

@@ -78,7 +78,7 @@ func runOnce(b *testing.B, setup SetupFunc, payload int) {
logf("initialized. (n=%v)", b.N)
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 pps int64

View File

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

View File

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

View File

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

View File

@@ -99,8 +99,8 @@ func parseIPSet(arg string, bits *int) ([]netaddr.IPPrefix, error) {
if arg == "*" {
// User explicitly requested wildcard.
return []netaddr.IPPrefix{
netaddr.IPPrefixFrom(zeroIP4, 0),
netaddr.IPPrefixFrom(zeroIP6, 0),
{IP: zeroIP4, Bits: 0},
{IP: zeroIP6, Bits: 0},
}, nil
}
if strings.Contains(arg, "/") {
@@ -124,7 +124,7 @@ func parseIPSet(arg string, bits *int) ([]netaddr.IPPrefix, error) {
if err != nil {
return nil, err
}
r := netaddr.IPRangeFrom(ip1, ip2)
r := netaddr.IPRange{From: ip1, To: ip2}
if !r.Valid() {
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)
}
return []netaddr.IPPrefix{netaddr.IPPrefixFrom(ip, bits8)}, nil
return []netaddr.IPPrefix{{IP: ip, Bits: bits8}}, nil
}

View File

@@ -62,7 +62,7 @@ func (c *Conn) createLegacyEndpointLocked(pk key.Public, addrs wgcfg.IPPortSet,
// Add entries to c.addrsByUDP.
for _, ipp := range a.ipPorts {
if ipp.IP() == derpMagicIPAddr {
if ipp.IP == derpMagicIPAddr {
continue
}
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.
for _, ipp := range oldIPP {
if ipp.IP() != derpMagicIPAddr && c.addrsByUDP[ipp] != a {
if ipp.IP != derpMagicIPAddr && c.addrsByUDP[ipp] != a {
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.
func (as *addrSet) derpID() int {
for _, ua := range as.ipPorts {
if ua.IP() == derpMagicIPAddr {
return int(ua.Port())
if ua.IP == derpMagicIPAddr {
return int(ua.Port)
}
}
return 0
@@ -428,7 +428,7 @@ func (a *addrSet) DstToString() string {
return a.rawdst
}
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) SrcToString() string { return "" }
@@ -437,7 +437,7 @@ func (a *addrSet) ClearSrc() {}
// updateDst records receipt of a packet from new. This is used to
// potentially update the transmit address used for this addrSet.
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
// either curAddr or roamAddr. It's only ever a last resort
// choice, never a preferred choice.
@@ -539,7 +539,7 @@ func (as *addrSet) populatePeerStatus(ps *ipnstate.PeerStatus) {
ps.LastWrite = as.lastSend
for i, ua := range as.ipPorts {
if ua.IP() == derpMagicIPAddr {
if ua.IP == derpMagicIPAddr {
continue
}
uaStr := ua.String()

View File

@@ -832,7 +832,7 @@ func (c *Conn) Ping(peer *tailcfg.Node, res *ipnstate.PingResult, cb func(*ipnst
return
}
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
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
func (c *Conn) populateCLIPingResponseLocked(res *ipnstate.PingResult, latency time.Duration, ep netaddr.IPPort) {
res.LatencySeconds = latency.Seconds()
if ep.IP() != derpMagicIPAddr {
if ep.IP != derpMagicIPAddr {
res.Endpoint = ep.String()
return
}
regionID := int(ep.Port())
regionID := int(ep.Port)
res.DERPRegionID = regionID
if c.derpMap != nil {
if dr, ok := c.derpMap.Regions[regionID]; ok {
@@ -965,7 +965,7 @@ func (c *Conn) goDerpConnect(node int) {
if node == 0 {
return
}
go c.derpWriteChanOfAddr(netaddr.IPPortFrom(derpMagicIPAddr, uint16(node)), key.Public{})
go c.derpWriteChanOfAddr(netaddr.NewIPPort(derpMagicIPAddr, uint16(node)), key.Public{})
}
// determineEndpoints returns the machine's endpoint addresses. It
@@ -1037,7 +1037,7 @@ func (c *Conn) determineEndpoints(ctx context.Context) ([]tailcfg.Endpoint, erro
ips = loopback
}
for _, ip := range ips {
addAddr(netaddr.IPPortFrom(ip, uint16(localAddr.Port)), tailcfg.EndpointLocal)
addAddr(netaddr.NewIPPort(ip, uint16(localAddr.Port)), tailcfg.EndpointLocal)
}
} else {
// 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
// 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) {
if addr.IP() != derpMagicIPAddr {
if addr.IP != derpMagicIPAddr {
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
// path, without using addr.
func (c *Conn) derpWriteChanOfAddr(addr netaddr.IPPort, peer key.Public) chan<- derpWriteRequest {
if addr.IP() != derpMagicIPAddr {
if addr.IP != derpMagicIPAddr {
return nil
}
regionID := int(addr.Port())
regionID := int(addr.Port)
if c.networkDown() {
return nil
@@ -1402,7 +1402,7 @@ func (c *Conn) runDerpReader(ctx context.Context, derpFakeAddr netaddr.IPPort, d
}
didCopy := make(chan struct{}, 1)
regionID := int(derpFakeAddr.Port())
regionID := int(derpFakeAddr.Port)
res := derpReadResult{regionID: regionID}
var pkt derp.ReceivedPacket
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
}
ipp := netaddr.IPPortFrom(derpMagicIPAddr, uint16(regionID))
ipp := netaddr.NewIPPort(derpMagicIPAddr, uint16(regionID))
if c.handleDiscoMessage(b[:n], ipp) {
return 0, nil
}
@@ -1922,7 +1922,7 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netaddr.IPPort) (isDiscoMsg bo
}
de.handlePongConnLocked(dm, src)
case *disco.CallMeMaybe:
if src.IP() != derpMagicIPAddr {
if src.IP != derpMagicIPAddr {
// CallMeMaybe messages should only come via DERP.
c.logf("[unexpected] CallMeMaybe packets should only come via DERP")
return
@@ -2722,7 +2722,7 @@ func (c *Conn) resetEndpointStates() {
// packIPPort packs an IPPort into the form wanted by WireGuard.
func packIPPort(ua netaddr.IPPort) []byte {
ip := ua.IP().Unmap()
ip := ua.IP.Unmap()
a := ip.As16()
ipb := a[:]
if ip.Is4() {
@@ -2730,8 +2730,8 @@ func packIPPort(ua netaddr.IPPort) []byte {
}
b := make([]byte, 0, len(ipb)+2)
b = append(b, ipb...)
b = append(b, byte(ua.Port()))
b = append(b, byte(ua.Port()>>8))
b = append(b, byte(ua.Port))
b = append(b, byte(ua.Port>>8))
return b
}
@@ -2972,15 +2972,15 @@ func peerShort(k key.Public) string {
}
func sbPrintAddr(sb *strings.Builder, a netaddr.IPPort) {
is6 := a.IP().Is6()
is6 := a.IP.Is6()
if is6 {
sb.WriteByte('[')
}
fmt.Fprintf(sb, "%s", a.IP())
fmt.Fprintf(sb, "%s", a.IP)
if is6 {
sb.WriteByte(']')
}
fmt.Fprintf(sb, ":%d", a.Port())
fmt.Fprintf(sb, ":%d", a.Port)
}
func (c *Conn) derpRegionCodeOfAddrLocked(ipPort string) string {
@@ -3017,15 +3017,15 @@ func (c *Conn) UpdateStatus(sb *ipnstate.StatusBuilder) {
if !addr.IsSingleIP() {
continue
}
sb.AddTailscaleIP(addr.IP())
sb.AddTailscaleIP(addr.IP)
// TailAddr previously only allowed for a
// single Tailscale IP. For compatibility for
// a couple releases starting with 1.8, keep
// that field pulled out separately.
if addr.IP().Is4() {
tailAddr4 = addr.IP().String()
if addr.IP.Is4() {
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 {
if ua.IP() == derpMagicIPAddr {
return fmt.Sprintf("derp-%d", ua.Port())
if ua.IP == derpMagicIPAddr {
return fmt.Sprintf("derp-%d", ua.Port)
}
return ua.String()
}
@@ -3254,7 +3254,7 @@ func (de *discoEndpoint) initFakeUDPAddr() {
addr[0] = 0xfd
addr[1] = 0x00
binary.BigEndian.PutUint64(addr[2:], uint64(reflect.ValueOf(de).Pointer()))
de.fakeWGAddr = netaddr.IPPortFrom(netaddr.IPFrom16(addr), 12345)
de.fakeWGAddr = netaddr.NewIPPort(netaddr.IPFrom16(addr), 12345)
}
// isFirstRecvActivityInAwhile notes that receive activity has occured for this
@@ -3629,7 +3629,7 @@ func (de *discoEndpoint) handlePongConnLocked(m *disco.Pong, src netaddr.IPPort)
de.mu.Lock()
defer de.mu.Unlock()
isDerp := src.IP() == derpMagicIPAddr
isDerp := src.IP == derpMagicIPAddr
sp, ok := de.sentPing[m.TxID]
if !ok {
@@ -3705,13 +3705,13 @@ func betterAddr(a, b addrLatency) bool {
if a.IsZero() {
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
// the latencies are roughly equivalent.
if a.latency/10*9 < b.latency {
return true
}
} else if a.IP().Is4() && b.IP().Is6() {
} else if a.IP.Is4() && b.IP.Is6() {
if betterAddr(b, a) {
return false
}
@@ -3751,7 +3751,7 @@ func (de *discoEndpoint) handleCallMeMaybe(m *disco.CallMeMaybe) {
}
var newEPs []netaddr.IPPort
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.
// TODO: teach the ping code to ping on all interfaces
// for these.

View File

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

View File

@@ -130,11 +130,11 @@ func netaddrIP(std net.IP) netaddr.IP {
func netaddrIPPrefix(std net.IP, bits uint8) netaddr.IPPrefix {
ip, _ := netaddr.FromStdIP(std)
return netaddr.IPPrefixFrom(ip, bits)
return netaddr.IPPrefix{IP: ip, Bits: bits}
}
func condNetAddrPrefix(ipp netaddr.IPPrefix) string {
if ipp.IP().IsZero() {
if ipp.IP.IsZero() {
return ""
}
return ipp.String()
@@ -157,7 +157,7 @@ type newRouteMessage struct {
const tsTable = 52
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.

View File

@@ -48,12 +48,6 @@ const debugNetstack = false
// and implements wgengine.FakeImpl to act as a userspace network
// stack when Tailscale is running in fake mode.
type Impl struct {
// ForwardTCPIn, if non-nil, handles forwarding an inbound TCP
// connection.
// TODO(bradfitz): provide mechanism for tsnet to reject a
// port other than accepting it and closing it.
ForwardTCPIn func(c net.Conn, port uint16)
ipstack *stack.Stack
linkEP *channel.Endpoint
tundev *tstun.Wrapper
@@ -179,7 +173,7 @@ func DNSMapFromNetworkMap(nm *netmap.NetworkMap) DNSMap {
suffix := nm.MagicDNSSuffix()
if nm.Name != "" && len(nm.Addresses) > 0 {
ip := nm.Addresses[0].IP()
ip := nm.Addresses[0].IP
ret[strings.TrimRight(nm.Name, ".")] = ip
if dnsname.HasSuffix(nm.Name, suffix) {
ret[dnsname.TrimSuffix(nm.Name, suffix)] = ip
@@ -187,7 +181,7 @@ func DNSMapFromNetworkMap(nm *netmap.NetworkMap) DNSMap {
}
for _, p := range nm.Peers {
if p.Name != "" && len(p.Addresses) > 0 {
ip := p.Addresses[0].IP()
ip := p.Addresses[0].IP
ret[strings.TrimRight(p.Name, ".")] = ip
if dnsname.HasSuffix(p.Name, suffix) {
ret[dnsname.TrimSuffix(p.Name, suffix)] = ip
@@ -227,8 +221,8 @@ func (ns *Impl) removeSubnetAddress(ip netaddr.IP) {
func ipPrefixToAddressWithPrefix(ipp netaddr.IPPrefix) tcpip.AddressWithPrefix {
return tcpip.AddressWithPrefix{
Address: tcpip.Address(ipp.IP().IPAddr().IP),
PrefixLen: int(ipp.Bits()),
Address: tcpip.Address(ipp.IP.IPAddr().IP),
PrefixLen: int(ipp.Bits),
}
}
@@ -322,7 +316,7 @@ func (m DNSMap) Resolve(ctx context.Context, addr string) (netaddr.IPPort, error
// Try MagicDNS first, else otherwise a real DNS lookup.
ip := m[host]
if !ip.IsZero() {
return netaddr.IPPortFrom(ip, uint16(port16)), nil
return netaddr.NewIPPort(ip, uint16(port16)), nil
}
// No MagicDNS name so try real DNS.
@@ -335,7 +329,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)
}
ip, _ = netaddr.FromStdIP(ips[0])
return netaddr.IPPortFrom(ip, uint16(port16)), nil
return netaddr.NewIPPort(ip, uint16(port16)), nil
}
func (ns *Impl) DialContextTCP(ctx context.Context, addr string) (*gonet.TCPConn, error) {
@@ -349,11 +343,11 @@ func (ns *Impl) DialContextTCP(ctx context.Context, addr string) (*gonet.TCPConn
}
remoteAddress := tcpip.FullAddress{
NIC: nicID,
Addr: tcpip.Address(remoteIPPort.IP().IPAddr().IP),
Port: remoteIPPort.Port(),
Addr: tcpip.Address(remoteIPPort.IP.IPAddr().IP),
Port: remoteIPPort.Port,
}
var ipType tcpip.NetworkProtocolNumber
if remoteIPPort.IP().Is4() {
if remoteIPPort.IP.Is4() {
ipType = ipv4.ProtocolNumber
} else {
ipType = ipv6.ProtocolNumber
@@ -395,7 +389,7 @@ func (ns *Impl) isLocalIP(ip netaddr.IP) bool {
}
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
// the traffic is destined for an actual Tailscale
// address. The real host OS interface will handle it.
@@ -447,15 +441,11 @@ func (ns *Impl) acceptTCP(r *tcp.ForwarderRequest) {
r.Complete(true)
return
}
r.Complete(false)
c := gonet.NewTCPConn(&wq, ep)
if ns.ForwardTCPIn != nil {
ns.ForwardTCPIn(c, reqDetails.LocalPort)
return
}
if isTailscaleIP {
dialAddr = tcpip.Address(net.ParseIP("127.0.0.1")).To4()
}
r.Complete(false)
c := gonet.NewTCPConn(&wq, ep)
ns.forwardTCP(c, &wq, dialAddr, reqDetails.LocalPort)
}

View File

@@ -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
// like:
// 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 _, err := e.peerForIP(flow.Dst.IP()); err != nil {
if runtime.GOOS == "ios" && flow.Dst.Port == 443 && !tsaddr.IsTailscaleIP(flow.Dst.IP) {
if _, err := e.peerForIP(flow.Dst.IP); err != nil {
return
}
}
@@ -156,7 +156,7 @@ func (e *userspaceEngine) onOpenTimeout(flow flowtrack.Tuple) {
}
// Diagnose why it might've timed out.
n, err := e.peerForIP(flow.Dst.IP())
n, err := e.peerForIP(flow.Dst.IP)
if err != nil {
e.logf("open-conn-track: timeout opening %v; peerForIP: %v", flow, err)
return
@@ -193,7 +193,7 @@ func (e *userspaceEngine) onOpenTimeout(flow flowtrack.Tuple) {
if ps == nil {
onlyZeroRoute := true // whether peerForIP returned n only because its /0 route matched
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
break
}

View File

@@ -324,16 +324,16 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) (retErr error) {
var firstGateway6 *net.IP
addresses := make([]*net.IPNet, 0, len(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.
continue
}
ipnet := addr.IPNet()
addresses = append(addresses, ipnet)
gateway := ipnet.IP
if addr.IP().Is4() && firstGateway4 == nil {
if addr.IP.Is4() && firstGateway4 == nil {
firstGateway4 = &gateway
} else if addr.IP().Is6() && firstGateway6 == nil {
} else if addr.IP.Is6() && firstGateway6 == nil {
firstGateway6 = &gateway
}
}
@@ -342,12 +342,12 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) (retErr error) {
foundDefault4 := false
foundDefault6 := false
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.
continue
}
if route.IP().Is6() && firstGateway6 == nil {
if route.IP.Is6() && firstGateway6 == nil {
// Windows won't let us set IPv6 routes without having an
// IPv6 local address set. However, when we've configured
// 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)}
addresses = append(addresses, ipnet)
firstGateway6 = &ipnet.IP
} else if route.IP().Is4() && firstGateway4 == nil {
} else if route.IP.Is4() && firstGateway4 == nil {
// TODO: do same dummy behavior as v6?
return errors.New("due to a Windows limitation, one cannot have interface routes without an interface address")
}
ipn := route.IPNet()
var gateway net.IP
if route.IP().Is4() {
if route.IP.Is4() {
gateway = *firstGateway4
} else if route.IP().Is6() {
} else if route.IP.Is6() {
gateway = *firstGateway6
}
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.
continue
}
if route.IP().Is4() {
if route.Bits() == 0 {
if route.IP.Is4() {
if route.Bits == 0 {
foundDefault4 = true
}
r.NextHop = *firstGateway4
} else if route.IP().Is6() {
if route.Bits() == 0 {
} else if route.IP.Is6() {
if route.Bits == 0 {
foundDefault6 = true
}
r.NextHop = *firstGateway6
@@ -760,8 +760,11 @@ func filterRoutes(routes []*winipcfg.RouteData, dontDelete []netaddr.IPPrefix) [
if nr.IsSingleIP() {
continue
}
lastIP := nr.Range().To()
ddm[netaddr.IPPrefixFrom(lastIP, lastIP.BitLen())] = true
lastIP := nr.Range().To
ddm[netaddr.IPPrefix{
IP: lastIP,
Bits: lastIP.BitLen(),
}] = true
}
filtered := make([]*winipcfg.RouteData, 0, len(routes))
for _, r := range routes {

View File

@@ -360,7 +360,7 @@ func (r *linuxRouter) setNetfilterMode(mode preftype.NetfilterMode) error {
}
for cidr := range r.addrs {
if err := r.addLoopbackRule(cidr.IP()); err != nil {
if err := r.addLoopbackRule(cidr.IP); err != nil {
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
// fails.
func (r *linuxRouter) addAddress(addr netaddr.IPPrefix) error {
if !r.v6Available && addr.IP().Is6() {
if !r.v6Available && addr.IP.Is6() {
return 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)
}
if err := r.addLoopbackRule(addr.IP()); err != nil {
if err := r.addLoopbackRule(addr.IP); err != nil {
return err
}
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
// fails.
func (r *linuxRouter) delAddress(addr netaddr.IPPrefix) error {
if !r.v6Available && addr.IP().Is6() {
if !r.v6Available && addr.IP.Is6() {
return nil
}
if err := r.delLoopbackRule(addr.IP()); err != nil {
if err := r.delLoopbackRule(addr.IP); err != nil {
return err
}
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 {
if !r.v6Available && cidr.IP().Is6() {
if !r.v6Available && cidr.IP.Is6() {
return nil
}
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 {
if !r.v6Available && cidr.IP().Is6() {
if !r.v6Available && cidr.IP.Is6() {
return nil
}
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) {
args := append([]string{"ip", dashFam(cidr.IP()), "route", "show"}, routeDef...)
args := append([]string{"ip", dashFam(cidr.IP), "route", "show"}, routeDef...)
if r.ipRuleAvailable {
args = append(args, "table", tailscaleRouteTable)
}

View File

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

View File

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

View File

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

View File

@@ -399,7 +399,7 @@ func (e *userspaceEngine) handleLocalPackets(p *packet.Parsed, t *tstun.Wrapper)
isLocalAddr, ok := e.isLocalAddr.Load().(func(netaddr.IP) bool)
if !ok {
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
// tunnel's local IP address into the tunnel, instead of
// 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.
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)
if err != nil {
e.logf("dns: enqueue: %v", err)
@@ -440,10 +440,10 @@ func (e *userspaceEngine) pollResolver() {
h := packet.UDP4Header{
IP4Header: packet.IP4Header{
Src: magicDNSIP,
Dst: to.IP(),
Dst: to.IP,
},
SrcPort: magicDNSPort,
DstPort: to.Port(),
DstPort: to.Port,
}
hlen := h.Len()
@@ -620,8 +620,8 @@ func (e *userspaceEngine) maybeReconfigWireguardLocked(discoChanged map[key.Publ
trackDisco = append(trackDisco, dk)
recentlyActive := false
for _, cidr := range p.AllowedIPs {
trackIPs = append(trackIPs, cidr.IP())
recentlyActive = recentlyActive || e.isActiveSince(dk, cidr.IP(), activeCutoff)
trackIPs = append(trackIPs, cidr.IP)
recentlyActive = recentlyActive || e.isActiveSince(dk, cidr.IP, activeCutoff)
}
if recentlyActive {
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")
}
for _, a := range e.netMap.Addresses {
if a.IsSingleIP() && a.IP().BitLen() == dst.BitLen() {
return a.IP(), nil
if a.IsSingleIP() && a.IP.BitLen() == dst.BitLen() {
return a.IP, nil
}
}
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
for _, p := range nm.Peers {
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
}
}
@@ -1301,7 +1301,7 @@ func (e *userspaceEngine) peerForIP(ip netaddr.IP) (n *tailcfg.Node, err error)
if !cidr.Contains(ip) {
continue
}
if bestInNMPrefix.IsZero() || cidr.Bits() > bestInNMPrefix.Bits() {
if bestInNMPrefix.IsZero() || cidr.Bits > bestInNMPrefix.Bits {
bestInNMPrefix = cidr
bestInNM = p
}
@@ -1319,7 +1319,7 @@ func (e *userspaceEngine) peerForIP(ip netaddr.IP) (n *tailcfg.Node, err error)
if !cidr.Contains(ip) {
continue
}
if best.IsZero() || cidr.Bits() > best.Bits() {
if best.IsZero() || cidr.Bits > best.Bits {
best = cidr
bestKey = tailcfg.NodeKey(p.PublicKey)
}
@@ -1337,7 +1337,7 @@ func (e *userspaceEngine) peerForIP(ip netaddr.IP) (n *tailcfg.Node, err error)
if bestInNM == nil {
return nil, nil
}
if bestInNMPrefix.Bits() == 0 {
if bestInNMPrefix.Bits == 0 {
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)

View File

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

View File

@@ -37,7 +37,7 @@ func nodeDebugName(n *tailcfg.Node) string {
// cidrIsSubnet reports whether cidr is a non-default-route subnet
// exported by node that is not one of its own self addresses.
func cidrIsSubnet(node *tailcfg.Node, cidr netaddr.IPPrefix) bool {
if cidr.Bits() == 0 {
if cidr.Bits == 0 {
return false
}
if !cidr.IsSingleIP() {
@@ -93,7 +93,7 @@ func WGCfg(nm *netmap.NetworkMap, logf logger.Logf, flags netmap.WGConfigFlags,
}
didExitNodeWarn := false
for _, allowedIP := range peer.AllowedIPs {
if allowedIP.Bits() == 0 && peer.StableID != exitNode {
if allowedIP.Bits == 0 && peer.StableID != exitNode {
if didExitNodeWarn {
// Don't log about both the IPv4 /0 and IPv6 /0.
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())
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 {
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
} else if cidrIsSubnet(peer, allowedIP) {
if (flags & netmap.AllowSubnetRoutes) == 0 {