github.com/yaling888/clash@v1.53.0/component/ebpf/ebpf_linux.go (about) 1 package ebpf 2 3 import ( 4 "fmt" 5 "net/netip" 6 7 "github.com/vishvananda/netlink" 8 9 "github.com/yaling888/clash/common/cmd" 10 "github.com/yaling888/clash/component/dialer" 11 "github.com/yaling888/clash/component/ebpf/redir" 12 "github.com/yaling888/clash/component/ebpf/tc" 13 C "github.com/yaling888/clash/constant" 14 ) 15 16 // NewTcEBpfProgram new redirect to tun ebpf program 17 func NewTcEBpfProgram(ifaceNames []string, tunName string) (*TcEBpfProgram, error) { 18 tunIface, err := netlink.LinkByName(tunName) 19 if err != nil { 20 return nil, fmt.Errorf("lookup network iface %q: %w", tunName, err) 21 } 22 23 tunIndex := uint32(tunIface.Attrs().Index) 24 25 dialer.DefaultRoutingMark.Store(C.ClashTrafficMark) 26 27 ifMark := uint32(dialer.DefaultRoutingMark.Load()) 28 29 var pros []C.EBpf 30 for _, ifaceName := range ifaceNames { 31 iface, err := netlink.LinkByName(ifaceName) 32 if err != nil { 33 return nil, fmt.Errorf("lookup network iface %q: %w", ifaceName, err) 34 } 35 if iface.Attrs().OperState != netlink.OperUp { 36 return nil, fmt.Errorf("network iface %q is down", ifaceName) 37 } 38 39 attrs := iface.Attrs() 40 index := attrs.Index 41 42 tcPro := tc.NewEBpfTc(ifaceName, index, ifMark, tunIndex) 43 if err = tcPro.Start(); err != nil { 44 return nil, err 45 } 46 47 pros = append(pros, tcPro) 48 } 49 50 systemSetting(ifaceNames...) 51 52 return &TcEBpfProgram{pros: pros, rawNICs: ifaceNames}, nil 53 } 54 55 // NewRedirEBpfProgram new auto redirect ebpf program 56 func NewRedirEBpfProgram(ifaceNames []string, redirPort uint16, defaultRouteInterfaceName string) (*TcEBpfProgram, error) { 57 defaultRouteInterface, err := netlink.LinkByName(defaultRouteInterfaceName) 58 if err != nil { 59 return nil, fmt.Errorf("lookup network iface %q: %w", defaultRouteInterfaceName, err) 60 } 61 62 defaultRouteIndex := uint32(defaultRouteInterface.Attrs().Index) 63 64 var pros []C.EBpf 65 for _, ifaceName := range ifaceNames { 66 iface, err := netlink.LinkByName(ifaceName) 67 if err != nil { 68 return nil, fmt.Errorf("lookup network iface %q: %w", ifaceName, err) 69 } 70 71 attrs := iface.Attrs() 72 index := attrs.Index 73 74 addrs, err := netlink.AddrList(iface, netlink.FAMILY_V4) 75 if err != nil { 76 return nil, fmt.Errorf("lookup network iface %q address: %w", ifaceName, err) 77 } 78 79 if len(addrs) == 0 { 80 return nil, fmt.Errorf("network iface %q does not contain any ipv4 addresses", ifaceName) 81 } 82 83 address, _ := netip.AddrFromSlice(addrs[0].IP) 84 redirAddrPort := netip.AddrPortFrom(address, redirPort) 85 86 redirPro := redir.NewEBpfRedirect(ifaceName, index, 0, defaultRouteIndex, redirAddrPort) 87 if err = redirPro.Start(); err != nil { 88 return nil, err 89 } 90 91 pros = append(pros, redirPro) 92 } 93 94 systemSetting(ifaceNames...) 95 96 return NewAutoRedirProgram(pros, ifaceNames, defaultRouteInterfaceName), nil 97 } 98 99 func systemSetting(ifaceNames ...string) { 100 _, _ = cmd.ExecCmd("sysctl -w net.ipv4.ip_forward=1") 101 _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.forwarding=1") 102 _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.accept_local=1") 103 _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.accept_redirects=1") 104 _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.rp_filter=0") 105 _, _ = cmd.ExecCmd("iptables -t filter -P FORWARD ACCEPT") 106 107 for _, ifaceName := range ifaceNames { 108 _, _ = cmd.ExecCmd(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.forwarding=1", ifaceName)) 109 _, _ = cmd.ExecCmd(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.accept_local=1", ifaceName)) 110 _, _ = cmd.ExecCmd(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.accept_redirects=1", ifaceName)) 111 _, _ = cmd.ExecCmd(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.rp_filter=0", ifaceName)) 112 } 113 }