diff --git a/cmd/tailscaled/tailscaled.go b/cmd/tailscaled/tailscaled.go index 33da24e04..e0aaa72e8 100644 --- a/cmd/tailscaled/tailscaled.go +++ b/cmd/tailscaled/tailscaled.go @@ -308,8 +308,6 @@ func run() error { socksListener, httpProxyListener := mustStartProxyListeners(args.socksAddr, args.httpProxyAddr) dialer := new(tsdial.Dialer) // mutated below (before used) - dialer.SetLinkMonitor(linkMon) - e, useNetstack, err := createEngine(logf, linkMon, dialer) if err != nil { logf("wgengine.New: %v", err) diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 3951f46a7..2ebb3e18d 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -22,7 +22,6 @@ import ( "strings" "sync" "sync/atomic" - "syscall" "time" "inet.af/netaddr" @@ -192,7 +191,6 @@ func NewLocalBackend(logf logger.Logf, logid string, store ipn.StateStore, diale portpoll: portpoll, gotPortPollRes: make(chan struct{}), } - dialer.SetPeerDialControlFuncGetter(b.peerDialControlFunc) // Default filter blocks everything and logs nothing, until Start() is called. b.setFilter(filter.NewAllowNone(logf, &netaddr.IPSet{})) @@ -3041,19 +3039,6 @@ func disabledSysctls(sysctls ...string) (disabled []string, err error) { return disabled, nil } -// peerDialControlFunc is non-nil on platforms that require a way to -// bind to dial out to other peers. -var peerDialControlFunc func(*LocalBackend) func(network, address string, c syscall.RawConn) error - -// peerDialControlFunc returns a net.Dialer.Control func (possibly nil) to use to -// dial other Tailscale peers from the current environment. -func (b *LocalBackend) peerDialControlFunc() func(network, address string, c syscall.RawConn) error { - if peerDialControlFunc != nil { - return peerDialControlFunc(b) - } - return nil -} - // DERPMap returns the current DERPMap in use, or nil if not connected. func (b *LocalBackend) DERPMap() *tailcfg.DERPMap { b.mu.Lock() diff --git a/ipn/ipnlocal/peerapi_macios_ext.go b/ipn/ipnlocal/peerapi_macios_ext.go index 8267b03e3..ff1839a43 100644 --- a/ipn/ipnlocal/peerapi_macios_ext.go +++ b/ipn/ipnlocal/peerapi_macios_ext.go @@ -9,10 +9,8 @@ package ipnlocal import ( - "errors" "fmt" "net" - "syscall" "inet.af/netaddr" "tailscale.com/net/interfaces" @@ -21,7 +19,6 @@ import ( func init() { initListenConfig = initListenConfigNetworkExtension - peerDialControlFunc = peerDialControlFuncNetworkExtension } // initListenConfigNetworkExtension configures nc for listening on IP @@ -34,24 +31,3 @@ func initListenConfigNetworkExtension(nc *net.ListenConfig, ip netaddr.IP, st *i } return netns.SetListenConfigInterfaceIndex(nc, tunIf.Index) } - -func peerDialControlFuncNetworkExtension(b *LocalBackend) func(network, address string, c syscall.RawConn) error { - b.mu.Lock() - defer b.mu.Unlock() - st := b.prevIfState - pas := b.peerAPIServer - index := -1 - if st != nil && pas != nil && pas.tunName != "" { - if tunIf, ok := st.Interface[pas.tunName]; ok { - index = tunIf.Index - } - } - var lc net.ListenConfig - netns.SetListenConfigInterfaceIndex(&lc, index) - return func(network, address string, c syscall.RawConn) error { - if index == -1 { - return errors.New("failed to find TUN interface to bind to") - } - return lc.Control(network, address, c) - } -} diff --git a/ipn/ipnserver/server.go b/ipn/ipnserver/server.go index 49134e00c..6c5f5c173 100644 --- a/ipn/ipnserver/server.go +++ b/ipn/ipnserver/server.go @@ -739,12 +739,11 @@ func Run(ctx context.Context, logf logger.Logf, ln net.Listener, store ipn.State } dialer := new(tsdial.Dialer) - dialer.SetLinkMonitor(linkMon) eng.AddNetworkMapCallback(func(nm *netmap.NetworkMap) { dialer.SetDNSMap(tsdial.DNSMapFromNetworkMap(nm)) }) - server, err := New(logf, logid, store, eng, nil, serverModeUser, opts) + server, err := New(logf, logid, store, eng, dialer, serverModeUser, opts) if err != nil { return err } diff --git a/net/tsdial/peerapi_macios_ext.go b/net/tsdial/peerapi_macios_ext.go new file mode 100644 index 000000000..523ddc16d --- /dev/null +++ b/net/tsdial/peerapi_macios_ext.go @@ -0,0 +1,43 @@ +// 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 file's built on iOS and on two of three macOS build variants: +// the two GUI variants that both use Extensions (Network Extension +// and System Extension). It's not used on tailscaled-on-macOS. + +//go:build ts_macext && (darwin || ios) +// +build ts_macext +// +build darwin ios + +package tsdial + +import ( + "errors" + "net" + "syscall" + + "tailscale.com/net/netns" +) + +func init() { + peerDialControlFunc = peerDialControlFuncNetworkExtension +} + +func peerDialControlFuncNetworkExtension(d *Dialer) func(network, address string, c syscall.RawConn) error { + d.mu.Lock() + defer d.mu.Unlock() + + index := -1 + if x, ok := d.interfaceIndexLocked(d.tunName); ok { + index = x + } + var lc net.ListenConfig + netns.SetListenConfigInterfaceIndex(&lc, index) + return func(network, address string, c syscall.RawConn) error { + if index == -1 { + return errors.New("failed to find TUN interface to bind to") + } + return lc.Control(network, address, c) + } +} diff --git a/net/tsdial/tsdial.go b/net/tsdial/tsdial.go index cd5002f75..aa1f18ea8 100644 --- a/net/tsdial/tsdial.go +++ b/net/tsdial/tsdial.go @@ -67,6 +67,22 @@ func (d *Dialer) SetLinkMonitor(mon *monitor.Mon) { d.linkMon = mon } +func (d *Dialer) interfaceIndexLocked(ifName string) (index int, ok bool) { + if d.linkMon == nil { + return 0, false + } + st := d.linkMon.InterfaceState() + iface, ok := st.Interface[ifName] + if !ok { + return 0, false + } + return iface.Index, true +} + +// peerDialControlFunc is non-nil on platforms that require a way to +// bind to dial out to other peers. +var peerDialControlFunc func(*Dialer) func(network, address string, c syscall.RawConn) error + // PeerDialControlFunc returns a function // that can assigned to net.Dialer.Control to set sockopts or whatnot // to make a dial escape the current platform's network sandbox. @@ -76,19 +92,10 @@ func (d *Dialer) SetLinkMonitor(mon *monitor.Mon) { // Notably, this is non-nil on iOS and macOS when run as a Network or // System Extension (the GUI variants). func (d *Dialer) PeerDialControlFunc() func(network, address string, c syscall.RawConn) error { - gf, _ := d.peerDialControlFuncAtomic.Load().(func() func(network, address string, c syscall.RawConn) error) - if gf == nil { + if peerDialControlFunc == nil { return nil } - return gf() -} - -// SetPeerDialControlFuncGetter sets a function that returns, for the -// current network configuration at the time it's called, a function -// that can assigned to net.Dialer.Control to set sockopts or whatnot -// to make a dial escape the current platform's network sandbox. -func (d *Dialer) SetPeerDialControlFuncGetter(getFunc func() func(network, address string, c syscall.RawConn) error) { - d.peerDialControlFuncAtomic.Store(getFunc) + return peerDialControlFunc(d) } // SetDNSMap sets the current map of DNS names learned from the netmap. diff --git a/wgengine/userspace.go b/wgengine/userspace.go index 16034ea2d..17868c79c 100644 --- a/wgengine/userspace.go +++ b/wgengine/userspace.go @@ -319,6 +319,7 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error) tunName, _ := conf.Tun.Name() conf.Dialer.SetTUNName(tunName) + conf.Dialer.SetLinkMonitor(e.linkMon) e.dns = dns.NewManager(logf, conf.DNS, e.linkMon, conf.Dialer, fwdDNSLinkSelector{e, tunName}) logf("link state: %+v", e.linkMon.InterfaceState())