hysteria.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  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. dependencies: withDialerDependency(options.DialerOptions),
  122. },
  123. ctx: ctx,
  124. dialer: dialer.New(router, options.DialerOptions),
  125. serverAddr: options.ServerOptions.Build(),
  126. tlsConfig: tlsConfig,
  127. quicConfig: quicConfig,
  128. authKey: auth,
  129. xplusKey: xplus,
  130. sendBPS: up,
  131. recvBPS: down,
  132. }, nil
  133. }
  134. func (h *Hysteria) offer(ctx context.Context) (quic.Connection, error) {
  135. conn := h.conn
  136. if conn != nil && !common.Done(conn.Context()) {
  137. return conn, nil
  138. }
  139. h.connAccess.Lock()
  140. defer h.connAccess.Unlock()
  141. h.udpAccess.Lock()
  142. defer h.udpAccess.Unlock()
  143. conn = h.conn
  144. if conn != nil && !common.Done(conn.Context()) {
  145. return conn, nil
  146. }
  147. common.Close(h.rawConn)
  148. conn, err := h.offerNew(ctx)
  149. if err != nil {
  150. return nil, err
  151. }
  152. if common.Contains(h.network, N.NetworkUDP) {
  153. for _, session := range h.udpSessions {
  154. close(session)
  155. }
  156. h.udpSessions = make(map[uint32]chan *hysteria.UDPMessage)
  157. h.udpDefragger = hysteria.Defragger{}
  158. go h.udpRecvLoop(conn)
  159. }
  160. return conn, nil
  161. }
  162. func (h *Hysteria) offerNew(ctx context.Context) (quic.Connection, error) {
  163. udpConn, err := h.dialer.DialContext(h.ctx, "udp", h.serverAddr)
  164. if err != nil {
  165. return nil, err
  166. }
  167. var packetConn net.PacketConn
  168. packetConn = bufio.NewUnbindPacketConn(udpConn)
  169. if h.xplusKey != nil {
  170. packetConn = hysteria.NewXPlusPacketConn(packetConn, h.xplusKey)
  171. }
  172. packetConn = &hysteria.PacketConnWrapper{PacketConn: packetConn}
  173. quicConn, err := quic.Dial(h.ctx, packetConn, udpConn.RemoteAddr(), h.tlsConfig, h.quicConfig)
  174. if err != nil {
  175. packetConn.Close()
  176. return nil, err
  177. }
  178. controlStream, err := quicConn.OpenStreamSync(ctx)
  179. if err != nil {
  180. packetConn.Close()
  181. return nil, err
  182. }
  183. err = hysteria.WriteClientHello(controlStream, hysteria.ClientHello{
  184. SendBPS: h.sendBPS,
  185. RecvBPS: h.recvBPS,
  186. Auth: h.authKey,
  187. })
  188. if err != nil {
  189. packetConn.Close()
  190. return nil, err
  191. }
  192. serverHello, err := hysteria.ReadServerHello(controlStream)
  193. if err != nil {
  194. packetConn.Close()
  195. return nil, err
  196. }
  197. if !serverHello.OK {
  198. packetConn.Close()
  199. return nil, E.New("remote error: ", serverHello.Message)
  200. }
  201. quicConn.SetCongestionControl(hysteria.NewBrutalSender(congestion.ByteCount(serverHello.RecvBPS)))
  202. h.conn = quicConn
  203. h.rawConn = udpConn
  204. return quicConn, nil
  205. }
  206. func (h *Hysteria) udpRecvLoop(conn quic.Connection) {
  207. for {
  208. packet, err := conn.ReceiveMessage()
  209. if err != nil {
  210. return
  211. }
  212. message, err := hysteria.ParseUDPMessage(packet)
  213. if err != nil {
  214. h.logger.Error("parse udp message: ", err)
  215. continue
  216. }
  217. dfMsg := h.udpDefragger.Feed(message)
  218. if dfMsg == nil {
  219. continue
  220. }
  221. h.udpAccess.RLock()
  222. ch, ok := h.udpSessions[dfMsg.SessionID]
  223. if ok {
  224. select {
  225. case ch <- dfMsg:
  226. // OK
  227. default:
  228. // Silently drop the message when the channel is full
  229. }
  230. }
  231. h.udpAccess.RUnlock()
  232. }
  233. }
  234. func (h *Hysteria) InterfaceUpdated() {
  235. h.Close()
  236. return
  237. }
  238. func (h *Hysteria) Close() error {
  239. h.connAccess.Lock()
  240. defer h.connAccess.Unlock()
  241. h.udpAccess.Lock()
  242. defer h.udpAccess.Unlock()
  243. if h.conn != nil {
  244. h.conn.CloseWithError(0, "")
  245. h.rawConn.Close()
  246. }
  247. for _, session := range h.udpSessions {
  248. close(session)
  249. }
  250. h.udpSessions = make(map[uint32]chan *hysteria.UDPMessage)
  251. return nil
  252. }
  253. func (h *Hysteria) open(ctx context.Context, reconnect bool) (quic.Connection, quic.Stream, error) {
  254. conn, err := h.offer(ctx)
  255. if err != nil {
  256. if nErr, ok := err.(net.Error); ok && !nErr.Temporary() && reconnect {
  257. return h.open(ctx, false)
  258. }
  259. return nil, nil, err
  260. }
  261. stream, err := conn.OpenStream()
  262. if err != nil {
  263. if nErr, ok := err.(net.Error); ok && !nErr.Temporary() && reconnect {
  264. return h.open(ctx, false)
  265. }
  266. return nil, nil, err
  267. }
  268. return conn, &hysteria.StreamWrapper{Stream: stream}, nil
  269. }
  270. func (h *Hysteria) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
  271. switch N.NetworkName(network) {
  272. case N.NetworkTCP:
  273. h.logger.InfoContext(ctx, "outbound connection to ", destination)
  274. _, stream, err := h.open(ctx, true)
  275. if err != nil {
  276. return nil, err
  277. }
  278. err = hysteria.WriteClientRequest(stream, hysteria.ClientRequest{
  279. Host: destination.AddrString(),
  280. Port: destination.Port,
  281. })
  282. if err != nil {
  283. stream.Close()
  284. return nil, err
  285. }
  286. return hysteria.NewConn(stream, destination, true), nil
  287. case N.NetworkUDP:
  288. conn, err := h.ListenPacket(ctx, destination)
  289. if err != nil {
  290. return nil, err
  291. }
  292. return conn.(*hysteria.PacketConn), nil
  293. default:
  294. return nil, E.New("unsupported network: ", network)
  295. }
  296. }
  297. func (h *Hysteria) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
  298. h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
  299. conn, stream, err := h.open(ctx, true)
  300. if err != nil {
  301. return nil, err
  302. }
  303. err = hysteria.WriteClientRequest(stream, hysteria.ClientRequest{
  304. UDP: true,
  305. Host: destination.AddrString(),
  306. Port: destination.Port,
  307. })
  308. if err != nil {
  309. stream.Close()
  310. return nil, err
  311. }
  312. var response *hysteria.ServerResponse
  313. response, err = hysteria.ReadServerResponse(stream)
  314. if err != nil {
  315. stream.Close()
  316. return nil, err
  317. }
  318. if !response.OK {
  319. stream.Close()
  320. return nil, E.New("remote error: ", response.Message)
  321. }
  322. h.udpAccess.Lock()
  323. nCh := make(chan *hysteria.UDPMessage, 1024)
  324. h.udpSessions[response.UDPSessionID] = nCh
  325. h.udpAccess.Unlock()
  326. packetConn := hysteria.NewPacketConn(conn, stream, response.UDPSessionID, destination, nCh, common.Closer(func() error {
  327. h.udpAccess.Lock()
  328. if ch, ok := h.udpSessions[response.UDPSessionID]; ok {
  329. close(ch)
  330. delete(h.udpSessions, response.UDPSessionID)
  331. }
  332. h.udpAccess.Unlock()
  333. return nil
  334. }))
  335. go packetConn.Hold()
  336. return packetConn, nil
  337. }
  338. func (h *Hysteria) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
  339. return NewConnection(ctx, h, conn, metadata)
  340. }
  341. func (h *Hysteria) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
  342. return NewPacketConnection(ctx, h, conn, metadata)
  343. }