hysteria.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. //go:build with_quic
  2. package outbound
  3. import (
  4. "context"
  5. "net"
  6. "sync"
  7. "github.com/sagernet/quic-go"
  8. "github.com/sagernet/quic-go/congestion"
  9. "github.com/sagernet/sing-box/adapter"
  10. "github.com/sagernet/sing-box/common/dialer"
  11. "github.com/sagernet/sing-box/common/tls"
  12. C "github.com/sagernet/sing-box/constant"
  13. "github.com/sagernet/sing-box/log"
  14. "github.com/sagernet/sing-box/option"
  15. "github.com/sagernet/sing-box/transport/hysteria"
  16. "github.com/sagernet/sing/common"
  17. "github.com/sagernet/sing/common/bufio"
  18. E "github.com/sagernet/sing/common/exceptions"
  19. M "github.com/sagernet/sing/common/metadata"
  20. N "github.com/sagernet/sing/common/network"
  21. )
  22. var (
  23. _ adapter.Outbound = (*Hysteria)(nil)
  24. _ adapter.InterfaceUpdateListener = (*Hysteria)(nil)
  25. )
  26. type Hysteria struct {
  27. myOutboundAdapter
  28. ctx context.Context
  29. dialer N.Dialer
  30. serverAddr M.Socksaddr
  31. tlsConfig *tls.STDConfig
  32. quicConfig *quic.Config
  33. authKey []byte
  34. xplusKey []byte
  35. sendBPS uint64
  36. recvBPS uint64
  37. connAccess sync.Mutex
  38. conn quic.Connection
  39. rawConn net.Conn
  40. udpAccess sync.RWMutex
  41. udpSessions map[uint32]chan *hysteria.UDPMessage
  42. udpDefragger hysteria.Defragger
  43. }
  44. func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HysteriaOutboundOptions) (*Hysteria, error) {
  45. options.UDPFragmentDefault = true
  46. if options.TLS == nil || !options.TLS.Enabled {
  47. return nil, C.ErrTLSRequired
  48. }
  49. abstractTLSConfig, err := tls.NewClient(router, options.Server, common.PtrValueOrDefault(options.TLS))
  50. if err != nil {
  51. return nil, err
  52. }
  53. tlsConfig, err := abstractTLSConfig.Config()
  54. if err != nil {
  55. return nil, err
  56. }
  57. tlsConfig.MinVersion = tls.VersionTLS13
  58. if len(tlsConfig.NextProtos) == 0 {
  59. tlsConfig.NextProtos = []string{hysteria.DefaultALPN}
  60. }
  61. quicConfig := &quic.Config{
  62. InitialStreamReceiveWindow: options.ReceiveWindowConn,
  63. MaxStreamReceiveWindow: options.ReceiveWindowConn,
  64. InitialConnectionReceiveWindow: options.ReceiveWindow,
  65. MaxConnectionReceiveWindow: options.ReceiveWindow,
  66. KeepAlivePeriod: hysteria.KeepAlivePeriod,
  67. DisablePathMTUDiscovery: options.DisableMTUDiscovery,
  68. EnableDatagrams: true,
  69. }
  70. if options.ReceiveWindowConn == 0 {
  71. quicConfig.InitialStreamReceiveWindow = hysteria.DefaultStreamReceiveWindow
  72. quicConfig.MaxStreamReceiveWindow = hysteria.DefaultStreamReceiveWindow
  73. }
  74. if options.ReceiveWindow == 0 {
  75. quicConfig.InitialConnectionReceiveWindow = hysteria.DefaultConnectionReceiveWindow
  76. quicConfig.MaxConnectionReceiveWindow = hysteria.DefaultConnectionReceiveWindow
  77. }
  78. if quicConfig.MaxIncomingStreams == 0 {
  79. quicConfig.MaxIncomingStreams = hysteria.DefaultMaxIncomingStreams
  80. }
  81. var auth []byte
  82. if len(options.Auth) > 0 {
  83. auth = options.Auth
  84. } else {
  85. auth = []byte(options.AuthString)
  86. }
  87. var xplus []byte
  88. if options.Obfs != "" {
  89. xplus = []byte(options.Obfs)
  90. }
  91. var up, down uint64
  92. if len(options.Up) > 0 {
  93. up = hysteria.StringToBps(options.Up)
  94. if up == 0 {
  95. return nil, E.New("invalid up speed format: ", options.Up)
  96. }
  97. } else {
  98. up = uint64(options.UpMbps) * hysteria.MbpsToBps
  99. }
  100. if len(options.Down) > 0 {
  101. down = hysteria.StringToBps(options.Down)
  102. if down == 0 {
  103. return nil, E.New("invalid down speed format: ", options.Down)
  104. }
  105. } else {
  106. down = uint64(options.DownMbps) * hysteria.MbpsToBps
  107. }
  108. if up < hysteria.MinSpeedBPS {
  109. return nil, E.New("invalid up speed")
  110. }
  111. if down < hysteria.MinSpeedBPS {
  112. return nil, E.New("invalid down speed")
  113. }
  114. return &Hysteria{
  115. myOutboundAdapter: myOutboundAdapter{
  116. protocol: C.TypeHysteria,
  117. network: options.Network.Build(),
  118. router: router,
  119. logger: logger,
  120. tag: tag,
  121. },
  122. ctx: ctx,
  123. dialer: dialer.New(router, options.DialerOptions),
  124. serverAddr: options.ServerOptions.Build(),
  125. tlsConfig: tlsConfig,
  126. quicConfig: quicConfig,
  127. authKey: auth,
  128. xplusKey: xplus,
  129. sendBPS: up,
  130. recvBPS: down,
  131. }, nil
  132. }
  133. func (h *Hysteria) offer(ctx context.Context) (quic.Connection, error) {
  134. conn := h.conn
  135. if conn != nil && !common.Done(conn.Context()) {
  136. return conn, nil
  137. }
  138. h.connAccess.Lock()
  139. defer h.connAccess.Unlock()
  140. h.udpAccess.Lock()
  141. defer h.udpAccess.Unlock()
  142. conn = h.conn
  143. if conn != nil && !common.Done(conn.Context()) {
  144. return conn, nil
  145. }
  146. conn, err := h.offerNew(ctx)
  147. if err != nil {
  148. return nil, err
  149. }
  150. if common.Contains(h.network, N.NetworkUDP) {
  151. for _, session := range h.udpSessions {
  152. close(session)
  153. }
  154. h.udpSessions = make(map[uint32]chan *hysteria.UDPMessage)
  155. h.udpDefragger = hysteria.Defragger{}
  156. go h.udpRecvLoop(conn)
  157. }
  158. return conn, nil
  159. }
  160. func (h *Hysteria) offerNew(ctx context.Context) (quic.Connection, error) {
  161. udpConn, err := h.dialer.DialContext(h.ctx, "udp", h.serverAddr)
  162. if err != nil {
  163. return nil, err
  164. }
  165. var packetConn net.PacketConn
  166. packetConn = bufio.NewUnbindPacketConn(udpConn)
  167. if h.xplusKey != nil {
  168. packetConn = hysteria.NewXPlusPacketConn(packetConn, h.xplusKey)
  169. }
  170. packetConn = &hysteria.PacketConnWrapper{PacketConn: packetConn}
  171. quicConn, err := quic.Dial(packetConn, udpConn.RemoteAddr(), h.serverAddr.AddrString(), h.tlsConfig, h.quicConfig)
  172. if err != nil {
  173. packetConn.Close()
  174. return nil, err
  175. }
  176. controlStream, err := quicConn.OpenStreamSync(ctx)
  177. if err != nil {
  178. packetConn.Close()
  179. return nil, err
  180. }
  181. err = hysteria.WriteClientHello(controlStream, hysteria.ClientHello{
  182. SendBPS: h.sendBPS,
  183. RecvBPS: h.recvBPS,
  184. Auth: h.authKey,
  185. })
  186. if err != nil {
  187. packetConn.Close()
  188. return nil, err
  189. }
  190. serverHello, err := hysteria.ReadServerHello(controlStream)
  191. if err != nil {
  192. packetConn.Close()
  193. return nil, err
  194. }
  195. if !serverHello.OK {
  196. packetConn.Close()
  197. return nil, E.New("remote error: ", serverHello.Message)
  198. }
  199. quicConn.SetCongestionControl(hysteria.NewBrutalSender(congestion.ByteCount(serverHello.RecvBPS)))
  200. h.conn = quicConn
  201. h.rawConn = udpConn
  202. return quicConn, nil
  203. }
  204. func (h *Hysteria) udpRecvLoop(conn quic.Connection) {
  205. for {
  206. packet, err := conn.ReceiveMessage()
  207. if err != nil {
  208. return
  209. }
  210. message, err := hysteria.ParseUDPMessage(packet)
  211. if err != nil {
  212. h.logger.Error("parse udp message: ", err)
  213. continue
  214. }
  215. dfMsg := h.udpDefragger.Feed(message)
  216. if dfMsg == nil {
  217. continue
  218. }
  219. h.udpAccess.RLock()
  220. ch, ok := h.udpSessions[dfMsg.SessionID]
  221. if ok {
  222. select {
  223. case ch <- dfMsg:
  224. // OK
  225. default:
  226. // Silently drop the message when the channel is full
  227. }
  228. }
  229. h.udpAccess.RUnlock()
  230. }
  231. }
  232. func (h *Hysteria) InterfaceUpdated() error {
  233. h.Close()
  234. return nil
  235. }
  236. func (h *Hysteria) Close() error {
  237. h.connAccess.Lock()
  238. defer h.connAccess.Unlock()
  239. h.udpAccess.Lock()
  240. defer h.udpAccess.Unlock()
  241. if h.conn != nil {
  242. h.conn.CloseWithError(0, "")
  243. h.rawConn.Close()
  244. }
  245. for _, session := range h.udpSessions {
  246. close(session)
  247. }
  248. h.udpSessions = make(map[uint32]chan *hysteria.UDPMessage)
  249. return nil
  250. }
  251. func (h *Hysteria) open(ctx context.Context) (quic.Connection, quic.Stream, error) {
  252. conn, err := h.offer(ctx)
  253. if err != nil {
  254. return nil, nil, err
  255. }
  256. stream, err := conn.OpenStream()
  257. if err != nil {
  258. return nil, nil, err
  259. }
  260. return conn, &hysteria.StreamWrapper{Stream: stream}, nil
  261. }
  262. func (h *Hysteria) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
  263. switch N.NetworkName(network) {
  264. case N.NetworkTCP:
  265. h.logger.InfoContext(ctx, "outbound connection to ", destination)
  266. _, stream, err := h.open(ctx)
  267. if err != nil {
  268. return nil, err
  269. }
  270. err = hysteria.WriteClientRequest(stream, hysteria.ClientRequest{
  271. Host: destination.AddrString(),
  272. Port: destination.Port,
  273. })
  274. if err != nil {
  275. stream.Close()
  276. return nil, err
  277. }
  278. return hysteria.NewConn(stream, destination, true), nil
  279. case N.NetworkUDP:
  280. conn, err := h.ListenPacket(ctx, destination)
  281. if err != nil {
  282. return nil, err
  283. }
  284. return conn.(*hysteria.PacketConn), nil
  285. default:
  286. return nil, E.New("unsupported network: ", network)
  287. }
  288. }
  289. func (h *Hysteria) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
  290. h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
  291. conn, stream, err := h.open(ctx)
  292. if err != nil {
  293. return nil, err
  294. }
  295. err = hysteria.WriteClientRequest(stream, hysteria.ClientRequest{
  296. UDP: true,
  297. Host: destination.AddrString(),
  298. Port: destination.Port,
  299. })
  300. if err != nil {
  301. stream.Close()
  302. return nil, err
  303. }
  304. var response *hysteria.ServerResponse
  305. response, err = hysteria.ReadServerResponse(stream)
  306. if err != nil {
  307. stream.Close()
  308. return nil, err
  309. }
  310. if !response.OK {
  311. stream.Close()
  312. return nil, E.New("remote error: ", response.Message)
  313. }
  314. h.udpAccess.Lock()
  315. nCh := make(chan *hysteria.UDPMessage, 1024)
  316. h.udpSessions[response.UDPSessionID] = nCh
  317. h.udpAccess.Unlock()
  318. packetConn := hysteria.NewPacketConn(conn, stream, response.UDPSessionID, destination, nCh, common.Closer(func() error {
  319. h.udpAccess.Lock()
  320. if ch, ok := h.udpSessions[response.UDPSessionID]; ok {
  321. close(ch)
  322. delete(h.udpSessions, response.UDPSessionID)
  323. }
  324. h.udpAccess.Unlock()
  325. return nil
  326. }))
  327. go packetConn.Hold()
  328. return packetConn, nil
  329. }
  330. func (h *Hysteria) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
  331. return NewConnection(ctx, h, conn, metadata)
  332. }
  333. func (h *Hysteria) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
  334. return NewPacketConnection(ctx, h, conn, metadata)
  335. }