hysteria.go 9.1 KB

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