@ -70,6 +70,7 @@ type netfilterRunner interface {
type linuxRouter struct {
type linuxRouter struct {
logf func ( fmt string , args ... interface { } )
logf func ( fmt string , args ... interface { } )
ipRuleAvailable bool
tunname string
tunname string
addrs map [ netaddr . IPPrefix ] bool
addrs map [ netaddr . IPPrefix ] bool
routes map [ netaddr . IPPrefix ] bool
routes map [ netaddr . IPPrefix ] bool
@ -96,12 +97,16 @@ func newUserspaceRouter(logf logger.Logf, _ *device.Device, tunDev tun.Device) (
}
}
func newUserspaceRouterAdvanced ( logf logger . Logf , tunname string , netfilter netfilterRunner , cmd commandRunner ) ( Router , error ) {
func newUserspaceRouterAdvanced ( logf logger . Logf , tunname string , netfilter netfilterRunner , cmd commandRunner ) ( Router , error ) {
_ , err := exec . Command ( "ip" , "rule" ) . Output ( )
ipRuleAvailable := ( err == nil )
return & linuxRouter {
return & linuxRouter {
logf : logf ,
logf : logf ,
tunname : tunname ,
ipRuleAvailable : ipRuleAvailable ,
netfilterMode : NetfilterOff ,
tunname : tunname ,
ipt4 : netfilter ,
netfilterMode : NetfilterOff ,
cmd : cmd ,
ipt4 : netfilter ,
cmd : cmd ,
} , nil
} , nil
}
}
@ -109,10 +114,10 @@ func (r *linuxRouter) Up() error {
if err := r . delLegacyNetfilter ( ) ; err != nil {
if err := r . delLegacyNetfilter ( ) ; err != nil {
return err
return err
}
}
if err := r . setNetfilterMode( NetfilterOff ) ; err != nil {
if err := r . addIPRules( ) ; err != nil {
return err
return err
}
}
if err := r . addBypassRule( ) ; err != nil {
if err := r . setNetfilterMode( NetfilterOff ) ; err != nil {
return err
return err
}
}
if err := r . upInterface ( ) ; err != nil {
if err := r . upInterface ( ) ; err != nil {
@ -126,7 +131,7 @@ func (r *linuxRouter) down() error {
if err := r . downInterface ( ) ; err != nil {
if err := r . downInterface ( ) ; err != nil {
return err
return err
}
}
if err := r . del BypassRule ( ) ; err != nil {
if err := r . del IPRules ( ) ; err != nil {
return err
return err
}
}
if err := r . setNetfilterMode ( NetfilterOff ) ; err != nil {
if err := r . setNetfilterMode ( NetfilterOff ) ; err != nil {
@ -477,24 +482,30 @@ func (r *linuxRouter) delLoopbackRule(addr netaddr.IP) error {
// interface. Fails if the route already exists, or if adding the
// interface. Fails if the route already exists, or if adding the
// route fails.
// route fails.
func ( r * linuxRouter ) addRoute ( cidr netaddr . IPPrefix ) error {
func ( r * linuxRouter ) addRoute ( cidr netaddr . IPPrefix ) error {
return r . cmd . run (
args := [ ] string {
"ip" , "route" , "add" ,
"ip" , "route" , "add" ,
normalizeCIDR ( cidr ) ,
normalizeCIDR ( cidr ) ,
"dev" , r . tunname ,
"dev" , r . tunname ,
"table" , "88" ,
}
)
if r . ipRuleAvailable {
args = append ( args , "table" , "88" )
}
return r . cmd . run ( args ... )
}
}
// delRoute removes the route for cidr pointing to the tunnel
// delRoute removes the route for cidr pointing to the tunnel
// interface. Fails if the route doesn't exist, or if removing the
// interface. Fails if the route doesn't exist, or if removing the
// route fails.
// route fails.
func ( r * linuxRouter ) delRoute ( cidr netaddr . IPPrefix ) error {
func ( r * linuxRouter ) delRoute ( cidr netaddr . IPPrefix ) error {
return r . cmd . run (
args := [ ] string {
"ip" , "route" , "del" ,
"ip" , "route" , "del" ,
normalizeCIDR ( cidr ) ,
normalizeCIDR ( cidr ) ,
"dev" , r . tunname ,
"dev" , r . tunname ,
"table" , "88" ,
}
)
if r . ipRuleAvailable {
args = append ( args , "table" , "88" )
}
return r . cmd . run ( args ... )
}
}
// addSubnetRule adds a netfilter rule that allows traffic to flow
// addSubnetRule adds a netfilter rule that allows traffic to flow
@ -540,13 +551,17 @@ func (r *linuxRouter) downInterface() error {
return r . cmd . run ( "ip" , "link" , "set" , "dev" , r . tunname , "down" )
return r . cmd . run ( "ip" , "link" , "set" , "dev" , r . tunname , "down" )
}
}
// add BypassRule adds the policy routing rule that avoids tailscaled
// add IPRules adds the policy routing rule that avoids tailscaled
// routing loops. If the rule exists and appears to be a
// routing loops. If the rule exists and appears to be a
// tailscale-managed rule, it is gracefully replaced.
// tailscale-managed rule, it is gracefully replaced.
func ( r * linuxRouter ) addBypassRule ( ) error {
func ( r * linuxRouter ) addIPRules ( ) error {
if ! r . ipRuleAvailable {
return nil
}
// Clear out old rules. After that, any error adding a rule is fatal,
// Clear out old rules. After that, any error adding a rule is fatal,
// because there should be no reason we add a duplicate.
// because there should be no reason we add a duplicate.
if err := r . delBypassRule ( ) ; err != nil {
if err := r . del IPRules ( ) ; err != nil {
return err
return err
}
}
@ -611,7 +626,11 @@ func (r *linuxRouter) addBypassRule() error {
// delBypassrule removes the policy routing rules that avoid
// delBypassrule removes the policy routing rules that avoid
// tailscaled routing loops, if it exists.
// tailscaled routing loops, if it exists.
func ( r * linuxRouter ) delBypassRule ( ) error {
func ( r * linuxRouter ) delIPRules ( ) error {
if ! r . ipRuleAvailable {
return nil
}
// Error codes: 'ip rule' returns error code 2 if the rule is a
// Error codes: 'ip rule' returns error code 2 if the rule is a
// duplicate (add) or not found (del). It returns a different code
// duplicate (add) or not found (del). It returns a different code
// for syntax errors. This is also true of busybox.
// for syntax errors. This is also true of busybox.