tun_linux.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. //go:build linux && !android
  2. package wireguard
  3. import (
  4. "context"
  5. "errors"
  6. "fmt"
  7. "net"
  8. "net/netip"
  9. "os"
  10. "golang.org/x/sys/unix"
  11. "github.com/sagernet/sing/common/control"
  12. "github.com/vishvananda/netlink"
  13. wgtun "golang.zx2c4.com/wireguard/tun"
  14. )
  15. type deviceNet struct {
  16. tunnel
  17. dialer net.Dialer
  18. handle *netlink.Handle
  19. linkAddrs []netlink.Addr
  20. routes []*netlink.Route
  21. rules []*netlink.Rule
  22. }
  23. func newDeviceNet(interfaceName string) *deviceNet {
  24. var dialer net.Dialer
  25. bindControl := control.BindToInterface(control.DefaultInterfaceFinder(), interfaceName, -1)
  26. dialer.Control = control.Append(dialer.Control, bindControl)
  27. return &deviceNet{dialer: dialer}
  28. }
  29. func (d *deviceNet) DialContextTCPAddrPort(ctx context.Context, addr netip.AddrPort) (
  30. net.Conn, error,
  31. ) {
  32. return d.dialer.DialContext(ctx, "tcp", addr.String())
  33. }
  34. func (d *deviceNet) DialUDPAddrPort(laddr, raddr netip.AddrPort) (net.Conn, error) {
  35. dialer := d.dialer
  36. dialer.LocalAddr = &net.UDPAddr{IP: laddr.Addr().AsSlice(), Port: int(laddr.Port())}
  37. return dialer.DialContext(context.Background(), "udp", raddr.String())
  38. }
  39. func (d *deviceNet) Close() (err error) {
  40. var errs []error
  41. for _, rule := range d.rules {
  42. if err = d.handle.RuleDel(rule); err != nil {
  43. errs = append(errs, fmt.Errorf("failed to delete rule: %w", err))
  44. }
  45. }
  46. for _, route := range d.routes {
  47. if err = d.handle.RouteDel(route); err != nil {
  48. errs = append(errs, fmt.Errorf("failed to delete route: %w", err))
  49. }
  50. }
  51. if err = d.tunnel.Close(); err != nil {
  52. errs = append(errs, fmt.Errorf("failed to close tunnel: %w", err))
  53. }
  54. if d.handle != nil {
  55. d.handle.Close()
  56. d.handle = nil
  57. }
  58. if len(errs) == 0 {
  59. return nil
  60. }
  61. return errors.Join(errs...)
  62. }
  63. func createKernelTun(localAddresses []netip.Addr, mtu int, handler promiscuousModeHandler) (t Tunnel, err error) {
  64. if handler != nil {
  65. return nil, newError("TODO: support promiscuous mode")
  66. }
  67. var v4, v6 *netip.Addr
  68. for _, prefixes := range localAddresses {
  69. if v4 == nil && prefixes.Is4() {
  70. x := prefixes
  71. v4 = &x
  72. }
  73. if v6 == nil && prefixes.Is6() {
  74. x := prefixes
  75. v6 = &x
  76. }
  77. }
  78. writeSysctlZero := func(path string) error {
  79. _, err := os.Stat(path)
  80. if os.IsNotExist(err) {
  81. return nil
  82. }
  83. if err != nil {
  84. return err
  85. }
  86. return os.WriteFile(path, []byte("0"), 0o644)
  87. }
  88. // system configs.
  89. if v4 != nil {
  90. if err = writeSysctlZero("/proc/sys/net/ipv4/conf/all/rp_filter"); err != nil {
  91. return nil, fmt.Errorf("failed to disable ipv4 rp_filter for all: %w", err)
  92. }
  93. }
  94. if v6 != nil {
  95. if err = writeSysctlZero("/proc/sys/net/ipv6/conf/all/disable_ipv6"); err != nil {
  96. return nil, fmt.Errorf("failed to enable ipv6: %w", err)
  97. }
  98. if err = writeSysctlZero("/proc/sys/net/ipv6/conf/all/rp_filter"); err != nil {
  99. return nil, fmt.Errorf("failed to disable ipv6 rp_filter for all: %w", err)
  100. }
  101. }
  102. n := CalculateInterfaceName("wg")
  103. wgt, err := wgtun.CreateTUN(n, mtu)
  104. if err != nil {
  105. return nil, err
  106. }
  107. defer func() {
  108. if err != nil {
  109. _ = wgt.Close()
  110. }
  111. }()
  112. // disable linux rp_filter for tunnel device to avoid packet drop.
  113. // the operation require root privilege on container require '--privileged' flag.
  114. if v4 != nil {
  115. if err = writeSysctlZero("/proc/sys/net/ipv4/conf/" + n + "/rp_filter"); err != nil {
  116. return nil, fmt.Errorf("failed to disable ipv4 rp_filter for tunnel: %w", err)
  117. }
  118. }
  119. if v6 != nil {
  120. if err = writeSysctlZero("/proc/sys/net/ipv6/conf/" + n + "/rp_filter"); err != nil {
  121. return nil, fmt.Errorf("failed to disable ipv6 rp_filter for tunnel: %w", err)
  122. }
  123. }
  124. ipv6TableIndex := 1023
  125. if v6 != nil {
  126. r := &netlink.Route{Table: ipv6TableIndex}
  127. for {
  128. routeList, fErr := netlink.RouteListFiltered(netlink.FAMILY_V6, r, netlink.RT_FILTER_TABLE)
  129. if len(routeList) == 0 || fErr != nil {
  130. break
  131. }
  132. ipv6TableIndex--
  133. if ipv6TableIndex < 0 {
  134. return nil, fmt.Errorf("failed to find available ipv6 table index")
  135. }
  136. }
  137. }
  138. out := newDeviceNet(n)
  139. out.handle, err = netlink.NewHandle()
  140. if err != nil {
  141. return nil, err
  142. }
  143. defer func() {
  144. if err != nil {
  145. _ = out.Close()
  146. }
  147. }()
  148. l, err := netlink.LinkByName(n)
  149. if err != nil {
  150. return nil, err
  151. }
  152. if v4 != nil {
  153. addr := netlink.Addr{
  154. IPNet: &net.IPNet{
  155. IP: v4.AsSlice(),
  156. Mask: net.CIDRMask(v4.BitLen(), v4.BitLen()),
  157. },
  158. }
  159. out.linkAddrs = append(out.linkAddrs, addr)
  160. }
  161. if v6 != nil {
  162. addr := netlink.Addr{
  163. IPNet: &net.IPNet{
  164. IP: v6.AsSlice(),
  165. Mask: net.CIDRMask(v6.BitLen(), v6.BitLen()),
  166. },
  167. }
  168. out.linkAddrs = append(out.linkAddrs, addr)
  169. rt := &netlink.Route{
  170. LinkIndex: l.Attrs().Index,
  171. Dst: &net.IPNet{
  172. IP: net.IPv6zero,
  173. Mask: net.CIDRMask(0, 128),
  174. },
  175. Table: ipv6TableIndex,
  176. }
  177. out.routes = append(out.routes, rt)
  178. r := netlink.NewRule()
  179. r.Table, r.Family, r.Src = ipv6TableIndex, unix.AF_INET6, addr.IPNet
  180. out.rules = append(out.rules, r)
  181. }
  182. for _, addr := range out.linkAddrs {
  183. if err = out.handle.AddrAdd(l, &addr); err != nil {
  184. return nil, fmt.Errorf("failed to add address %s to %s: %w", addr, n, err)
  185. }
  186. }
  187. if err = out.handle.LinkSetMTU(l, mtu); err != nil {
  188. return nil, err
  189. }
  190. if err = out.handle.LinkSetUp(l); err != nil {
  191. return nil, err
  192. }
  193. for _, route := range out.routes {
  194. if err = out.handle.RouteAdd(route); err != nil {
  195. return nil, fmt.Errorf("failed to add route %s: %w", route, err)
  196. }
  197. }
  198. for _, rule := range out.rules {
  199. if err = out.handle.RuleAdd(rule); err != nil {
  200. return nil, fmt.Errorf("failed to add rule %s: %w", rule, err)
  201. }
  202. }
  203. out.tun = wgt
  204. return out, nil
  205. }
  206. func KernelTunSupported() bool {
  207. // run a superuser permission check to check
  208. // if the current user has the sufficient permission
  209. // to create a tun device.
  210. return unix.Geteuid() == 0 // 0 means root
  211. }