123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- //go:build !android
- package ebpf
- import (
- "fmt"
- "net/netip"
- "github.com/metacubex/mihomo/common/cmd"
- "github.com/metacubex/mihomo/component/dialer"
- "github.com/metacubex/mihomo/component/ebpf/redir"
- "github.com/metacubex/mihomo/component/ebpf/tc"
- C "github.com/metacubex/mihomo/constant"
- "github.com/sagernet/netlink"
- )
- func GetAutoDetectInterface() (string, error) {
- routes, err := netlink.RouteList(nil, netlink.FAMILY_V4)
- if err != nil {
- return "", err
- }
- for _, route := range routes {
- if route.Dst == nil {
- lk, err := netlink.LinkByIndex(route.LinkIndex)
- if err != nil {
- return "", err
- }
- if lk.Type() == "tuntap" {
- continue
- }
- return lk.Attrs().Name, nil
- }
- }
- return "", fmt.Errorf("interface not found")
- }
- // NewTcEBpfProgram new redirect to tun ebpf program
- func NewTcEBpfProgram(ifaceNames []string, tunName string) (*TcEBpfProgram, error) {
- tunIface, err := netlink.LinkByName(tunName)
- if err != nil {
- return nil, fmt.Errorf("lookup network iface %q: %w", tunName, err)
- }
- tunIndex := uint32(tunIface.Attrs().Index)
- dialer.DefaultRoutingMark.Store(C.MihomoTrafficMark)
- ifMark := uint32(dialer.DefaultRoutingMark.Load())
- var pros []C.EBpf
- for _, ifaceName := range ifaceNames {
- iface, err := netlink.LinkByName(ifaceName)
- if err != nil {
- return nil, fmt.Errorf("lookup network iface %q: %w", ifaceName, err)
- }
- if iface.Attrs().OperState != netlink.OperUp {
- return nil, fmt.Errorf("network iface %q is down", ifaceName)
- }
- attrs := iface.Attrs()
- index := attrs.Index
- tcPro := tc.NewEBpfTc(ifaceName, index, ifMark, tunIndex)
- if err = tcPro.Start(); err != nil {
- return nil, err
- }
- pros = append(pros, tcPro)
- }
- systemSetting(ifaceNames...)
- return &TcEBpfProgram{pros: pros, rawNICs: ifaceNames}, nil
- }
- // NewRedirEBpfProgram new auto redirect ebpf program
- func NewRedirEBpfProgram(ifaceNames []string, redirPort uint16, defaultRouteInterfaceName string) (*TcEBpfProgram, error) {
- defaultRouteInterface, err := netlink.LinkByName(defaultRouteInterfaceName)
- if err != nil {
- return nil, fmt.Errorf("lookup network iface %q: %w", defaultRouteInterfaceName, err)
- }
- defaultRouteIndex := uint32(defaultRouteInterface.Attrs().Index)
- var pros []C.EBpf
- for _, ifaceName := range ifaceNames {
- iface, err := netlink.LinkByName(ifaceName)
- if err != nil {
- return nil, fmt.Errorf("lookup network iface %q: %w", ifaceName, err)
- }
- attrs := iface.Attrs()
- index := attrs.Index
- addrs, err := netlink.AddrList(iface, netlink.FAMILY_V4)
- if err != nil {
- return nil, fmt.Errorf("lookup network iface %q address: %w", ifaceName, err)
- }
- if len(addrs) == 0 {
- return nil, fmt.Errorf("network iface %q does not contain any ipv4 addresses", ifaceName)
- }
- address, _ := netip.AddrFromSlice(addrs[0].IP)
- redirAddrPort := netip.AddrPortFrom(address, redirPort)
- redirPro := redir.NewEBpfRedirect(ifaceName, index, 0, defaultRouteIndex, redirAddrPort)
- if err = redirPro.Start(); err != nil {
- return nil, err
- }
- pros = append(pros, redirPro)
- }
- systemSetting(ifaceNames...)
- return &TcEBpfProgram{pros: pros, rawNICs: ifaceNames}, nil
- }
- func systemSetting(ifaceNames ...string) {
- _, _ = cmd.ExecCmd("sysctl -w net.ipv4.ip_forward=1")
- _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.forwarding=1")
- _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.accept_local=1")
- _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.accept_redirects=1")
- _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.rp_filter=0")
- for _, ifaceName := range ifaceNames {
- _, _ = cmd.ExecCmd(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.forwarding=1", ifaceName))
- _, _ = cmd.ExecCmd(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.accept_local=1", ifaceName))
- _, _ = cmd.ExecCmd(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.accept_redirects=1", ifaceName))
- _, _ = cmd.ExecCmd(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.rp_filter=0", ifaceName))
- }
- }
|