wireguard.go 6.9 KB

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