wireguard.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. //go:build with_wireguard
  2. package outbound
  3. import (
  4. "context"
  5. "encoding/base64"
  6. "encoding/hex"
  7. "fmt"
  8. "net"
  9. "net/netip"
  10. "strings"
  11. "github.com/sagernet/sing-box/adapter"
  12. "github.com/sagernet/sing-box/common/dialer"
  13. C "github.com/sagernet/sing-box/constant"
  14. "github.com/sagernet/sing-box/log"
  15. "github.com/sagernet/sing-box/option"
  16. "github.com/sagernet/sing-box/transport/wireguard"
  17. "github.com/sagernet/sing-dns"
  18. "github.com/sagernet/sing-tun"
  19. E "github.com/sagernet/sing/common/exceptions"
  20. M "github.com/sagernet/sing/common/metadata"
  21. N "github.com/sagernet/sing/common/network"
  22. "github.com/sagernet/sing/common/x/list"
  23. "github.com/sagernet/sing/service"
  24. "github.com/sagernet/sing/service/pause"
  25. "github.com/sagernet/wireguard-go/conn"
  26. "github.com/sagernet/wireguard-go/device"
  27. )
  28. var (
  29. _ adapter.Outbound = (*WireGuard)(nil)
  30. _ adapter.InterfaceUpdateListener = (*WireGuard)(nil)
  31. )
  32. type WireGuard struct {
  33. myOutboundAdapter
  34. ctx context.Context
  35. workers int
  36. peers []wireguard.PeerConfig
  37. useStdNetBind bool
  38. listener N.Dialer
  39. ipcConf string
  40. pauseManager pause.Manager
  41. pauseCallback *list.Element[pause.Callback]
  42. bind conn.Bind
  43. device *device.Device
  44. tunDevice wireguard.Device
  45. }
  46. func NewWireGuard(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.WireGuardOutboundOptions) (*WireGuard, error) {
  47. outbound := &WireGuard{
  48. myOutboundAdapter: myOutboundAdapter{
  49. protocol: C.TypeWireGuard,
  50. network: options.Network.Build(),
  51. router: router,
  52. logger: logger,
  53. tag: tag,
  54. dependencies: withDialerDependency(options.DialerOptions),
  55. },
  56. ctx: ctx,
  57. workers: options.Workers,
  58. pauseManager: service.FromContext[pause.Manager](ctx),
  59. }
  60. peers, err := wireguard.ParsePeers(options)
  61. if err != nil {
  62. return nil, err
  63. }
  64. outbound.peers = peers
  65. if len(options.LocalAddress) == 0 {
  66. return nil, E.New("missing local address")
  67. }
  68. if options.GSO {
  69. if options.GSO && options.Detour != "" {
  70. return nil, E.New("gso is conflict with detour")
  71. }
  72. options.IsWireGuardListener = true
  73. outbound.useStdNetBind = true
  74. }
  75. listener, err := dialer.New(router, options.DialerOptions)
  76. if err != nil {
  77. return nil, err
  78. }
  79. outbound.listener = listener
  80. var privateKey string
  81. {
  82. bytes, err := base64.StdEncoding.DecodeString(options.PrivateKey)
  83. if err != nil {
  84. return nil, E.Cause(err, "decode private key")
  85. }
  86. privateKey = hex.EncodeToString(bytes)
  87. }
  88. outbound.ipcConf = "private_key=" + privateKey
  89. mtu := options.MTU
  90. if mtu == 0 {
  91. mtu = 1408
  92. }
  93. var wireTunDevice wireguard.Device
  94. if !options.SystemInterface && tun.WithGVisor {
  95. wireTunDevice, err = wireguard.NewStackDevice(options.LocalAddress, mtu)
  96. } else {
  97. wireTunDevice, err = wireguard.NewSystemDevice(router, options.InterfaceName, options.LocalAddress, mtu, options.GSO)
  98. }
  99. if err != nil {
  100. return nil, E.Cause(err, "create WireGuard device")
  101. }
  102. outbound.tunDevice = wireTunDevice
  103. return outbound, nil
  104. }
  105. func (w *WireGuard) Start() error {
  106. err := wireguard.ResolvePeers(w.ctx, w.router, w.peers)
  107. if err != nil {
  108. return err
  109. }
  110. var bind conn.Bind
  111. if w.useStdNetBind {
  112. bind = conn.NewStdNetBind(w.listener.(dialer.WireGuardListener))
  113. } else {
  114. var (
  115. isConnect bool
  116. connectAddr netip.AddrPort
  117. reserved [3]uint8
  118. )
  119. peerLen := len(w.peers)
  120. if peerLen == 1 {
  121. isConnect = true
  122. connectAddr = w.peers[0].Endpoint
  123. reserved = w.peers[0].Reserved
  124. }
  125. bind = wireguard.NewClientBind(w.ctx, w, w.listener, isConnect, connectAddr, reserved)
  126. }
  127. wgDevice := device.NewDevice(w.tunDevice, bind, &device.Logger{
  128. Verbosef: func(format string, args ...interface{}) {
  129. w.logger.Debug(fmt.Sprintf(strings.ToLower(format), args...))
  130. },
  131. Errorf: func(format string, args ...interface{}) {
  132. w.logger.Error(fmt.Sprintf(strings.ToLower(format), args...))
  133. },
  134. }, w.workers)
  135. ipcConf := w.ipcConf
  136. for _, peer := range w.peers {
  137. ipcConf += peer.GenerateIpcLines()
  138. }
  139. err = wgDevice.IpcSet(ipcConf)
  140. if err != nil {
  141. return E.Cause(err, "setup wireguard: \n", ipcConf)
  142. }
  143. w.device = wgDevice
  144. w.pauseCallback = w.pauseManager.RegisterCallback(w.onPauseUpdated)
  145. return w.tunDevice.Start()
  146. }
  147. func (w *WireGuard) Close() error {
  148. if w.device != nil {
  149. w.device.Close()
  150. }
  151. if w.pauseCallback != nil {
  152. w.pauseManager.UnregisterCallback(w.pauseCallback)
  153. }
  154. w.tunDevice.Close()
  155. return nil
  156. }
  157. func (w *WireGuard) InterfaceUpdated() {
  158. w.device.BindUpdate()
  159. return
  160. }
  161. func (w *WireGuard) onPauseUpdated(event int) {
  162. switch event {
  163. case pause.EventDevicePaused:
  164. w.device.Down()
  165. case pause.EventDeviceWake:
  166. w.device.Up()
  167. }
  168. }
  169. func (w *WireGuard) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
  170. switch network {
  171. case N.NetworkTCP:
  172. w.logger.InfoContext(ctx, "outbound connection to ", destination)
  173. case N.NetworkUDP:
  174. w.logger.InfoContext(ctx, "outbound packet connection to ", destination)
  175. }
  176. if destination.IsFqdn() {
  177. destinationAddresses, err := w.router.LookupDefault(ctx, destination.Fqdn)
  178. if err != nil {
  179. return nil, err
  180. }
  181. return N.DialSerial(ctx, w.tunDevice, network, destination, destinationAddresses)
  182. }
  183. return w.tunDevice.DialContext(ctx, network, destination)
  184. }
  185. func (w *WireGuard) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
  186. w.logger.InfoContext(ctx, "outbound packet connection to ", destination)
  187. if destination.IsFqdn() {
  188. destinationAddresses, err := w.router.LookupDefault(ctx, destination.Fqdn)
  189. if err != nil {
  190. return nil, err
  191. }
  192. packetConn, _, err := N.ListenSerial(ctx, w.tunDevice, destination, destinationAddresses)
  193. if err != nil {
  194. return nil, err
  195. }
  196. return packetConn, err
  197. }
  198. return w.tunDevice.ListenPacket(ctx, destination)
  199. }
  200. func (w *WireGuard) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
  201. return NewDirectConnection(ctx, w.router, w, conn, metadata, dns.DomainStrategyAsIS)
  202. }
  203. func (w *WireGuard) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
  204. return NewDirectPacketConnection(ctx, w.router, w, conn, metadata, dns.DomainStrategyAsIS)
  205. }