@ -29,6 +29,7 @@ import (
"tailscale.com/types/logger"
"tailscale.com/types/logger"
"tailscale.com/types/opt"
"tailscale.com/types/opt"
"tailscale.com/types/preftype"
"tailscale.com/types/preftype"
"tailscale.com/util/eventbus"
"tailscale.com/util/linuxfw"
"tailscale.com/util/linuxfw"
"tailscale.com/util/multierr"
"tailscale.com/util/multierr"
"tailscale.com/version/distro"
"tailscale.com/version/distro"
@ -48,6 +49,9 @@ type linuxRouter struct {
tunname string
tunname string
netMon * netmon . Monitor
netMon * netmon . Monitor
health * health . Tracker
health * health . Tracker
eventClient * eventbus . Client
ruleDeletedSub * eventbus . Subscriber [ netmon . RuleDeleted ]
rulesAddedPub * eventbus . Publisher [ AddIPRules ]
unregNetMon func ( )
unregNetMon func ( )
addrs map [ netip . Prefix ] bool
addrs map [ netip . Prefix ] bool
routes map [ netip . Prefix ] bool
routes map [ netip . Prefix ] bool
@ -77,7 +81,7 @@ type linuxRouter struct {
magicsockPortV6 uint16
magicsockPortV6 uint16
}
}
func newUserspaceRouter ( logf logger . Logf , tunDev tun . Device , netMon * netmon . Monitor , health * health . Tracker ) ( Router , error ) {
func newUserspaceRouter ( logf logger . Logf , tunDev tun . Device , netMon * netmon . Monitor , health * health . Tracker , bus * eventbus . Bus ) ( Router , error ) {
tunname , err := tunDev . Name ( )
tunname , err := tunDev . Name ( )
if err != nil {
if err != nil {
return nil , err
return nil , err
@ -87,15 +91,16 @@ func newUserspaceRouter(logf logger.Logf, tunDev tun.Device, netMon *netmon.Moni
ambientCapNetAdmin : useAmbientCaps ( ) ,
ambientCapNetAdmin : useAmbientCaps ( ) ,
}
}
return newUserspaceRouterAdvanced ( logf , tunname , netMon , cmd , health )
return newUserspaceRouterAdvanced ( logf , tunname , netMon , cmd , health , bus )
}
}
func newUserspaceRouterAdvanced ( logf logger . Logf , tunname string , netMon * netmon . Monitor , cmd commandRunner , health * health . Tracker ) ( Router , error ) {
func newUserspaceRouterAdvanced ( logf logger . Logf , tunname string , netMon * netmon . Monitor , cmd commandRunner , health * health . Tracker , bus * eventbus . Bus ) ( Router , error ) {
r := & linuxRouter {
r := & linuxRouter {
logf : logf ,
logf : logf ,
tunname : tunname ,
tunname : tunname ,
netfilterMode : netfilterOff ,
netfilterMode : netfilterOff ,
netMon : netMon ,
netMon : netMon ,
eventClient : bus . Client ( "router-linux" ) ,
health : health ,
health : health ,
cmd : cmd ,
cmd : cmd ,
@ -103,6 +108,10 @@ func newUserspaceRouterAdvanced(logf logger.Logf, tunname string, netMon *netmon
ipRuleFixLimiter : rate . NewLimiter ( rate . Every ( 5 * time . Second ) , 10 ) ,
ipRuleFixLimiter : rate . NewLimiter ( rate . Every ( 5 * time . Second ) , 10 ) ,
ipPolicyPrefBase : 5200 ,
ipPolicyPrefBase : 5200 ,
}
}
r . ruleDeletedSub = eventbus . Subscribe [ netmon . RuleDeleted ] ( r . eventClient )
r . rulesAddedPub = eventbus . Publish [ AddIPRules ] ( r . eventClient )
go r . consumeEventbusTopics ( )
if r . useIPCommand ( ) {
if r . useIPCommand ( ) {
r . ipRuleAvailable = ( cmd . run ( "ip" , "rule" ) == nil )
r . ipRuleAvailable = ( cmd . run ( "ip" , "rule" ) == nil )
} else {
} else {
@ -145,6 +154,24 @@ func newUserspaceRouterAdvanced(logf logger.Logf, tunname string, netMon *netmon
return r , nil
return r , nil
}
}
// consumeEventbusTopics consumes events from all [Conn]-relevant
// [eventbus.Subscriber]'s and passes them to their related handler. Events are
// always handled in the order they are received, i.e. the next event is not
// read until the previous event's handler has returned. It returns when the
// [portmapper.Mapping] subscriber is closed, which is interpreted to be the
// same as the [eventbus.Client] closing ([eventbus.Subscribers] are either
// all open or all closed).
func ( r * linuxRouter ) consumeEventbusTopics ( ) {
for {
select {
case <- r . ruleDeletedSub . Done ( ) :
return
case rulesDeleted := <- r . ruleDeletedSub . Events ( ) :
r . onIPRuleDeleted ( rulesDeleted . Table , rulesDeleted . Priority )
}
}
}
// ipCmdSupportsFwmask returns true if the system 'ip' binary supports using a
// ipCmdSupportsFwmask returns true if the system 'ip' binary supports using a
// fwmark stanza with a mask specified. To our knowledge, everything except busybox
// fwmark stanza with a mask specified. To our knowledge, everything except busybox
// pre-1.33 supports this.
// pre-1.33 supports this.
@ -276,6 +303,10 @@ func (r *linuxRouter) fwmaskWorks() bool {
return v
return v
}
}
// AddIPRules is used as an event signal to signify that rules have been added.
// It is added to aid testing, but could be extended if there's a reason for it.
type AddIPRules struct { }
// onIPRuleDeleted is the callback from the network monitor for when an IP
// onIPRuleDeleted is the callback from the network monitor for when an IP
// policy rule is deleted. See Issue 1591.
// policy rule is deleted. See Issue 1591.
//
//
@ -303,6 +334,9 @@ func (r *linuxRouter) onIPRuleDeleted(table uint8, priority uint32) {
r . ruleRestorePending . Swap ( false )
r . ruleRestorePending . Swap ( false )
return
return
}
}
r . rulesAddedPub . Publish ( AddIPRules { } )
time . AfterFunc ( rr . Delay ( ) + 250 * time . Millisecond , func ( ) {
time . AfterFunc ( rr . Delay ( ) + 250 * time . Millisecond , func ( ) {
if r . ruleRestorePending . Swap ( false ) && ! r . closed . Load ( ) {
if r . ruleRestorePending . Swap ( false ) && ! r . closed . Load ( ) {
r . logf ( "somebody (likely systemd-networkd) deleted ip rules; restoring Tailscale's" )
r . logf ( "somebody (likely systemd-networkd) deleted ip rules; restoring Tailscale's" )
@ -312,9 +346,6 @@ func (r *linuxRouter) onIPRuleDeleted(table uint8, priority uint32) {
}
}
func ( r * linuxRouter ) Up ( ) error {
func ( r * linuxRouter ) Up ( ) error {
if r . unregNetMon == nil && r . netMon != nil {
r . unregNetMon = r . netMon . RegisterRuleDeleteCallback ( r . onIPRuleDeleted )
}
if err := r . setNetfilterMode ( netfilterOff ) ; err != nil {
if err := r . setNetfilterMode ( netfilterOff ) ; err != nil {
return fmt . Errorf ( "setting netfilter mode: %w" , err )
return fmt . Errorf ( "setting netfilter mode: %w" , err )
}
}
@ -333,6 +364,7 @@ func (r *linuxRouter) Close() error {
if r . unregNetMon != nil {
if r . unregNetMon != nil {
r . unregNetMon ( )
r . unregNetMon ( )
}
}
r . eventClient . Close ( )
if err := r . downInterface ( ) ; err != nil {
if err := r . downInterface ( ) ; err != nil {
return err
return err
}
}
@ -1276,7 +1308,6 @@ func (r *linuxRouter) justAddIPRules() error {
}
}
var errAcc error
var errAcc error
for _ , family := range r . addrFamilies ( ) {
for _ , family := range r . addrFamilies ( ) {
for _ , ru := range ipRules ( ) {
for _ , ru := range ipRules ( ) {
// Note: r is a value type here; safe to mutate it.
// Note: r is a value type here; safe to mutate it.
ru . Family = family . netlinkInt ( )
ru . Family = family . netlinkInt ( )