fix: set accept_ra=2 to fix missing ipv6 address on WAN interface if necessary (#504)

This commit is contained in:
mzz 2024-06-11 21:33:21 +08:00 committed by GitHub
parent ec7cf06de4
commit 3d68dbafdc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 61 additions and 9 deletions

View File

@ -208,6 +208,7 @@ func NewControlPlane(
if len(global.LanInterface) > 0 {
if global.AutoConfigKernelParameter {
_ = SetIpv4forward("1")
_ = setForwarding("all", consts.IpVersionStr_6, "1")
}
global.LanInterface = common.Deduplicate(global.LanInterface)
for _, ifname := range global.LanInterface {
@ -227,6 +228,19 @@ func NewControlPlane(
}
}
for _, ifname := range global.WanInterface {
if len(global.LanInterface) > 0 {
// FIXME: Code is not elegant here.
// bindLan setting conf.ipv6.all.forwarding=1 suppresses accept_ra=1,
// thus we set it 2 as a workaround.
// See https://sysctl-explorer.net/net/ipv6/accept_ra/ for more information.
if global.AutoConfigKernelParameter {
acceptRa := sysctl.Keyf("net.ipv6.conf.%v.accept_ra", ifname)
val, _ := acceptRa.Get()
if val == "1" {
_ = acceptRa.Set("2", false)
}
}
}
if err = core.bindWan(ifname, global.AutoConfigKernelParameter); err != nil {
return nil, fmt.Errorf("bindWan: %v: %w", ifname, err)
}

View File

@ -247,7 +247,6 @@ func (c *controlPlaneCore) bindLan(ifname string, autoConfigKernelParameter bool
if autoConfigKernelParameter {
SetSendRedirects(ifname, "0")
SetForwarding(ifname, "1")
setForwarding("all", consts.IpVersionStr_6, "1")
}
if err := c._bindLan(ifname); err != nil {
var notFoundErr netlink.LinkNotFoundError

View File

@ -281,11 +281,11 @@ func (ns *DaeNetns) setupNetns() (err error) {
func (ns *DaeNetns) setupSysctl() (err error) {
// sysctl net.ipv6.conf.dae0.disable_ipv6=0
if err = sysctl.Set(fmt.Sprintf("net.ipv6.conf.%s.disable_ipv6", HostVethName), "0", true); err != nil {
if err = sysctl.Keyf("net.ipv6.conf.%s.disable_ipv6", HostVethName).Set("0", true); err != nil {
return fmt.Errorf("failed to set disable_ipv6 for dae0: %v", err)
}
// sysctl net.ipv6.conf.dae0.forwarding=1
if err = sysctl.Set(fmt.Sprintf("net.ipv6.conf.%s.forwarding", HostVethName), "1", true); err != nil {
if err = sysctl.Keyf("net.ipv6.conf.%s.forwarding", HostVethName).Set("1", true); err != nil {
return fmt.Errorf("failed to set forwarding for dae0: %v", err)
}
@ -295,12 +295,12 @@ func (ns *DaeNetns) setupSysctl() (err error) {
defer netns.Set(ns.hostNs)
// *_early_demux is not mandatory, but it's recommended to enable it for better performance
sysctl.Set("net.ipv4.tcp_early_demux", "1", false)
sysctl.Set("net.ipv4.ip_early_demux", "1", false)
sysctl.Keyf("net.ipv4.tcp_early_demux").Set("1", false)
sysctl.Keyf("net.ipv4.ip_early_demux").Set("1", false)
// (ip net e daens) sysctl net.ipv4.conf.dae0peer.accept_local=1
// This is to prevent kernel from dropping skb due to "martian source" check: https://elixir.bootlin.com/linux/v6.6/source/net/ipv4/fib_frontend.c#L381
if err = sysctl.Set(fmt.Sprintf("net.ipv4.conf.%s.accept_local", NsVethName), "1", false); err != nil {
if err = sysctl.Keyf("net.ipv4.conf.%s.accept_local", NsVethName).Set("1", false); err != nil {
return fmt.Errorf("failed to set accept_local for dae0peer: %v", err)
}
return

View File

@ -1,6 +1,7 @@
package control
import (
"fmt"
"os"
"strings"
"sync"
@ -76,8 +77,29 @@ func (s *SysctlManager) startWatch() {
}
}
func (s *SysctlManager) Set(key string, value string, watch bool) (err error) {
path := SysctlPrefixPath + strings.Replace(key, ".", "/", -1)
type SysctlKey string
func (s *SysctlManager) Keyf(format string, a ...any) SysctlKey {
return SysctlKey(SysctlPrefixPath + fmt.Sprintf(strings.ReplaceAll(format, ".", "/"), a...))
}
func (k SysctlKey) Get() (value string, err error) {
return sysctl.get(string(k))
}
func (k SysctlKey) Set(value string, watch bool) (err error) {
return sysctl.set(string(k), value, watch)
}
func (s *SysctlManager) get(path string) (value string, err error) {
val, err := os.ReadFile(path)
if err != nil {
return "", err
}
return strings.TrimSpace(string(val)), nil
}
func (s *SysctlManager) set(path string, value string, watch bool) (err error) {
if watch {
s.mux.Lock()
s.expectations[path] = value

View File

@ -10,7 +10,7 @@ For every LAN interfaces you want to proxy:
```shell
export lan_ifname=docker0
sudo tee /etc/sysctl.d/60-dae-$lan_ifname.conf << EOF
sudo tee /etc/sysctl.d/60-dae-lan-$lan_ifname.conf << EOF
net.ipv4.conf.$lan_ifname.forwarding = 1
net.ipv6.conf.$lan_ifname.forwarding = 1
net.ipv4.conf.$lan_ifname.send_redirects = 0
@ -27,3 +27,20 @@ sudo sysctl --system
```
Please modify `docker0` to your LAN interface.
For your WAN interfaces that accept RA:
```shell
export wan_ifname=eth0
if [ "$(cat /proc/sys/net/ipv6/conf/$wan_ifname/accept_ra)" == "1" ]; then
sudo tee /etc/sysctl.d/60-dae-wan-$wan_ifname.conf << EOF
net.ipv6.conf.$wan_ifname.accept_ra = 2
EOF
sudo sysctl --system
fi
```
Please modify `eth0` to your WAN interface.
Setting accept_ra to 2 if it is 1 because `net.ipv6.conf.all.forwarding = 1` will suppress it. See <https://sysctl-explorer.net/net/ipv6/accept_ra/> for more information.