cmd/tailscaled, wgengine/netstack: always wire up netstack

Even if not in use. We plan to use it for more stuff later.

(not for iOS or macOS-GUIs yet; only tailscaled)

Change-Id: Idaef719d2a009be6a39f158fd8f57f8cca68e0ee
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/3218/head
Brad Fitzpatrick 3 years ago committed by Brad Fitzpatrick
parent ff597e773e
commit 5dc5bd8d20

@ -289,10 +289,14 @@ func run() error {
return err return err
} }
var ns *netstack.Impl ns, err := newNetstack(logf, e)
if useNetstack || wrapNetstack { if err != nil {
onlySubnets := wrapNetstack && !useNetstack return fmt.Errorf("newNetstack: %w", err)
ns = mustStartNetstack(logf, e, onlySubnets) }
ns.ProcessLocalIPs = useNetstack
ns.ProcessSubnets = useNetstack || wrapNetstack
if err := ns.Start(); err != nil {
log.Fatalf("failed to start netstack: %v", err)
} }
if socksListener != nil || httpProxyListener != nil { if socksListener != nil || httpProxyListener != nil {
@ -453,19 +457,12 @@ func runDebugServer(mux *http.ServeMux, addr string) {
} }
} }
func mustStartNetstack(logf logger.Logf, e wgengine.Engine, onlySubnets bool) *netstack.Impl { func newNetstack(logf logger.Logf, e wgengine.Engine) (*netstack.Impl, error) {
tunDev, magicConn, ok := e.(wgengine.InternalsGetter).GetInternals() tunDev, magicConn, ok := e.(wgengine.InternalsGetter).GetInternals()
if !ok { if !ok {
log.Fatalf("%T is not a wgengine.InternalsGetter", e) return nil, fmt.Errorf("%T is not a wgengine.InternalsGetter", e)
}
ns, err := netstack.Create(logf, tunDev, e, magicConn, onlySubnets)
if err != nil {
log.Fatalf("netstack.Create: %v", err)
}
if err := ns.Start(); err != nil {
log.Fatalf("failed to start netstack: %v", err)
} }
return ns return netstack.Create(logf, tunDev, e, magicConn)
} }
func mustStartTCPListener(name, addr string) net.Listener { func mustStartTCPListener(name, addr string) net.Listener {

@ -202,9 +202,14 @@ func startIPNServer(ctx context.Context, logid string) error {
dev.Close() dev.Close()
return nil, fmt.Errorf("engine: %w", err) return nil, fmt.Errorf("engine: %w", err)
} }
onlySubnets := true ns, err := newNetstack(logf, eng)
if wrapNetstack { if err != nil {
mustStartNetstack(logf, eng, onlySubnets) return nil, fmt.Errorf("newNetstack: %w", err)
}
ns.ProcessLocalIPs = false
ns.ProcessSubnets = wrapNetstack
if err := ns.Start(); err != nil {
return nil, fmt.Errorf("failed to start netstack: %w", err)
} }
return wgengine.NewWatchdog(eng), nil return wgengine.NewWatchdog(eng), nil
} }

@ -127,10 +127,11 @@ func (s *Server) start() error {
return fmt.Errorf("%T is not a wgengine.InternalsGetter", eng) return fmt.Errorf("%T is not a wgengine.InternalsGetter", eng)
} }
ns, err := netstack.Create(logf, tunDev, eng, magicConn, false) ns, err := netstack.Create(logf, tunDev, eng, magicConn)
if err != nil { if err != nil {
return fmt.Errorf("netstack.Create: %w", err) return fmt.Errorf("netstack.Create: %w", err)
} }
ns.ProcessLocalIPs = true
ns.ForwardTCPIn = s.forwardTCP ns.ForwardTCPIn = s.forwardTCP
if err := ns.Start(); err != nil { if err := ns.Start(); err != nil {
return fmt.Errorf("failed to start netstack: %w", err) return fmt.Errorf("failed to start netstack: %w", err)

@ -54,13 +54,23 @@ type Impl struct {
// port other than accepting it and closing it. // port other than accepting it and closing it.
ForwardTCPIn func(c net.Conn, port uint16) ForwardTCPIn func(c net.Conn, port uint16)
// ProcessLocalIPs is whether netstack should handle incoming
// traffic directed at the Node.Addresses (local IPs).
// It can only be set before calling Start.
ProcessLocalIPs bool
// ProcessSubnets is whether netstack should handle incoming
// traffic destined to non-local IPs (i.e. whether it should
// be a subnet router).
// It can only be set before calling Start.
ProcessSubnets bool
ipstack *stack.Stack ipstack *stack.Stack
linkEP *channel.Endpoint linkEP *channel.Endpoint
tundev *tstun.Wrapper tundev *tstun.Wrapper
e wgengine.Engine e wgengine.Engine
mc *magicsock.Conn mc *magicsock.Conn
logf logger.Logf logf logger.Logf
onlySubnets bool // whether we only want to handle subnet relaying
// atomicIsLocalIPFunc holds a func that reports whether an IP // atomicIsLocalIPFunc holds a func that reports whether an IP
// is a local (non-subnet) Tailscale IP address of this // is a local (non-subnet) Tailscale IP address of this
@ -81,7 +91,7 @@ const nicID = 1
const mtu = 1500 const mtu = 1500
// Create creates and populates a new Impl. // Create creates and populates a new Impl.
func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magicsock.Conn, onlySubnets bool) (*Impl, error) { func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magicsock.Conn) (*Impl, error) {
if mc == nil { if mc == nil {
return nil, errors.New("nil magicsock.Conn") return nil, errors.New("nil magicsock.Conn")
} }
@ -130,7 +140,6 @@ func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magi
e: e, e: e,
mc: mc, mc: mc,
connsOpenBySubnetIP: make(map[netaddr.IP]int), connsOpenBySubnetIP: make(map[netaddr.IP]int),
onlySubnets: onlySubnets,
} }
ns.atomicIsLocalIPFunc.Store(tsaddr.NewContainsIPFunc(nil)) ns.atomicIsLocalIPFunc.Store(tsaddr.NewContainsIPFunc(nil))
return ns, nil return ns, nil
@ -275,11 +284,11 @@ func (ns *Impl) updateIPs(nm *netmap.NetworkMap) {
isAddr[ipp] = true isAddr[ipp] = true
} }
for _, ipp := range nm.SelfNode.AllowedIPs { for _, ipp := range nm.SelfNode.AllowedIPs {
if ns.onlySubnets && isAddr[ipp] { local := isAddr[ipp]
continue if local && ns.ProcessLocalIPs || !local && ns.ProcessSubnets {
}
newIPs[ipPrefixToAddressWithPrefix(ipp)] = true newIPs[ipPrefixToAddressWithPrefix(ipp)] = true
} }
}
ipsToBeAdded := make(map[tcpip.AddressWithPrefix]bool) ipsToBeAdded := make(map[tcpip.AddressWithPrefix]bool)
for ipp := range newIPs { for ipp := range newIPs {
@ -446,11 +455,27 @@ func (ns *Impl) isLocalIP(ip netaddr.IP) bool {
return ns.atomicIsLocalIPFunc.Load().(func(netaddr.IP) bool)(ip) return ns.atomicIsLocalIPFunc.Load().(func(netaddr.IP) bool)(ip)
} }
// shouldProcessInbound reports whether an inbound packet should be
// handled by netstack.
func (ns *Impl) shouldProcessInbound(p *packet.Parsed, t *tstun.Wrapper) bool {
if !ns.ProcessLocalIPs && !ns.ProcessSubnets {
// Fast path for common case (e.g. Linux server in TUN mode) where
// netstack isn't used at all; don't even do an isLocalIP lookup.
return false
}
isLocal := ns.isLocalIP(p.Dst.IP())
if ns.ProcessLocalIPs && isLocal {
return true
}
if ns.ProcessSubnets && !isLocal {
return true
}
return false
}
func (ns *Impl) injectInbound(p *packet.Parsed, t *tstun.Wrapper) filter.Response { func (ns *Impl) injectInbound(p *packet.Parsed, t *tstun.Wrapper) filter.Response {
if ns.onlySubnets && ns.isLocalIP(p.Dst.IP()) { if !ns.shouldProcessInbound(p, t) {
// In hybrid ("only subnets") mode, bail out early if // Let the host network stack (if any) deal with it.
// the traffic is destined for an actual Tailscale
// address. The real host OS interface will handle it.
return filter.Accept return filter.Accept
} }
var pn tcpip.NetworkProtocolNumber var pn tcpip.NetworkProtocolNumber

Loading…
Cancel
Save