hysteria.go 9.2 KB

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