ebpf_linux.go 3.8 KB

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