wgengine/router: probe better for v6 policy routing support.

Previously we disabled v6 support if the disable_policy knob was
missing in /proc, but some kernels support policy routing without
exposing the toggle. So instead, treat disable_policy absence as a
"maybe", and make the direct `ip -6 rule` probing a bit more
elaborate to compensate.

Fixes #1241.

Signed-off-by: David Anderson <danderson@tailscale.com>
pull/1253/head
David Anderson 3 years ago committed by Dave Anderson
parent 717c715c96
commit 267531e4f8

@ -1045,18 +1045,22 @@ func checkIPv6() error {
return errors.New("disable_ipv6 is set")
}
// Older kernels don't support IPv6 policy routing.
// Older kernels don't support IPv6 policy routing. Some kernels
// support policy routing but don't have this knob, so absence of
// the knob is not fatal.
bs, err = ioutil.ReadFile("/proc/sys/net/ipv6/conf/all/disable_policy")
if err != nil {
// Absent knob means policy routing is unsupported.
return err
}
disabled, err = strconv.ParseBool(strings.TrimSpace(string(bs)))
if err != nil {
return errors.New("disable_policy has invalid bool")
if err == nil {
disabled, err = strconv.ParseBool(strings.TrimSpace(string(bs)))
if err != nil {
return errors.New("disable_policy has invalid bool")
}
if disabled {
return errors.New("disable_policy is set")
}
}
if disabled {
return errors.New("disable_policy is set")
if err := checkIPRuleSupportsV6(); err != nil {
return fmt.Errorf("kernel doesn't support IPv6 policy routing: %w", err)
}
// Some distros ship ip6tables separately from iptables.
@ -1064,10 +1068,6 @@ func checkIPv6() error {
return err
}
if err := checkIPRuleSupportsV6(); err != nil {
return err
}
return nil
}
@ -1088,13 +1088,17 @@ func supportsV6NAT() bool {
}
func checkIPRuleSupportsV6() error {
// First add a rule for "ip rule del" to delete.
// We ignore the "add" operation's error because it can also
// fail if the rule already exists.
exec.Command("ip", "-6", "rule", "add",
"pref", "123", "fwmark", tailscaleBypassMark, "table", fmt.Sprint(tailscaleRouteTable)).Run()
out, err := exec.Command("ip", "-6", "rule", "del",
"pref", "123", "fwmark", tailscaleBypassMark, "table", fmt.Sprint(tailscaleRouteTable)).CombinedOutput()
add := []string{"-6", "rule", "add", "pref", "1234", "fwmark", tailscaleBypassMark, "table", tailscaleRouteTable}
del := []string{"-6", "rule", "del", "pref", "1234", "fwmark", tailscaleBypassMark, "table", tailscaleRouteTable}
// First delete the rule unconditionally, and don't check for
// errors. This is just cleaning up anything that might be already
// there.
exec.Command("ip", del...).Run()
// Try adding the rule. This will fail on systems that support
// IPv6, but not IPv6 policy routing.
out, err := exec.Command("ip", add...).CombinedOutput()
if err != nil {
out = bytes.TrimSpace(out)
var detail interface{} = out
@ -1103,5 +1107,8 @@ func checkIPRuleSupportsV6() error {
}
return fmt.Errorf("ip -6 rule failed: %s", detail)
}
// Delete again.
exec.Command("ip", del...).Run()
return nil
}

Loading…
Cancel
Save