gun.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. // Modified from: https://github.com/Qv2ray/gun-lite
  2. // License: MIT
  3. package gun
  4. import (
  5. "bufio"
  6. "context"
  7. "crypto/tls"
  8. "encoding/binary"
  9. "errors"
  10. "fmt"
  11. "io"
  12. "net"
  13. "net/http"
  14. "net/url"
  15. "sync"
  16. "time"
  17. "github.com/metacubex/mihomo/common/atomic"
  18. "github.com/metacubex/mihomo/common/buf"
  19. "github.com/metacubex/mihomo/common/pool"
  20. tlsC "github.com/metacubex/mihomo/component/tls"
  21. "golang.org/x/net/http2"
  22. )
  23. var (
  24. ErrInvalidLength = errors.New("invalid length")
  25. ErrSmallBuffer = errors.New("buffer too small")
  26. )
  27. var defaultHeader = http.Header{
  28. "content-type": []string{"application/grpc"},
  29. "user-agent": []string{"grpc-go/1.36.0"},
  30. }
  31. type DialFn = func(network, addr string) (net.Conn, error)
  32. type Conn struct {
  33. response *http.Response
  34. request *http.Request
  35. transport *TransportWrap
  36. writer *io.PipeWriter
  37. once sync.Once
  38. close atomic.Bool
  39. err error
  40. remain int
  41. br *bufio.Reader
  42. // deadlines
  43. deadline *time.Timer
  44. }
  45. type Config struct {
  46. ServiceName string
  47. Host string
  48. ClientFingerprint string
  49. }
  50. func (g *Conn) initRequest() {
  51. response, err := g.transport.RoundTrip(g.request)
  52. if err != nil {
  53. g.err = err
  54. g.writer.Close()
  55. return
  56. }
  57. if !g.close.Load() {
  58. g.response = response
  59. g.br = bufio.NewReader(response.Body)
  60. } else {
  61. response.Body.Close()
  62. }
  63. }
  64. func (g *Conn) Read(b []byte) (n int, err error) {
  65. g.once.Do(g.initRequest)
  66. if g.err != nil {
  67. return 0, g.err
  68. }
  69. if g.remain > 0 {
  70. size := g.remain
  71. if len(b) < size {
  72. size = len(b)
  73. }
  74. n, err = io.ReadFull(g.br, b[:size])
  75. g.remain -= n
  76. return
  77. } else if g.response == nil {
  78. return 0, net.ErrClosed
  79. }
  80. // 0x00 grpclength(uint32) 0x0A uleb128 payload
  81. _, err = g.br.Discard(6)
  82. if err != nil {
  83. return 0, err
  84. }
  85. protobufPayloadLen, err := binary.ReadUvarint(g.br)
  86. if err != nil {
  87. return 0, ErrInvalidLength
  88. }
  89. size := int(protobufPayloadLen)
  90. if len(b) < size {
  91. size = len(b)
  92. }
  93. n, err = io.ReadFull(g.br, b[:size])
  94. if err != nil {
  95. return
  96. }
  97. remain := int(protobufPayloadLen) - n
  98. if remain > 0 {
  99. g.remain = remain
  100. }
  101. return n, nil
  102. }
  103. func (g *Conn) Write(b []byte) (n int, err error) {
  104. protobufHeader := [binary.MaxVarintLen64 + 1]byte{0x0A}
  105. varuintSize := binary.PutUvarint(protobufHeader[1:], uint64(len(b)))
  106. var grpcHeader [5]byte
  107. grpcPayloadLen := uint32(varuintSize + 1 + len(b))
  108. binary.BigEndian.PutUint32(grpcHeader[1:5], grpcPayloadLen)
  109. buf := pool.GetBuffer()
  110. defer pool.PutBuffer(buf)
  111. buf.Write(grpcHeader[:])
  112. buf.Write(protobufHeader[:varuintSize+1])
  113. buf.Write(b)
  114. _, err = g.writer.Write(buf.Bytes())
  115. if err == io.ErrClosedPipe && g.err != nil {
  116. err = g.err
  117. }
  118. return len(b), err
  119. }
  120. func (g *Conn) WriteBuffer(buffer *buf.Buffer) error {
  121. defer buffer.Release()
  122. dataLen := buffer.Len()
  123. varLen := UVarintLen(uint64(dataLen))
  124. header := buffer.ExtendHeader(6 + varLen)
  125. _ = header[6] // bounds check hint to compiler
  126. header[0] = 0x00
  127. binary.BigEndian.PutUint32(header[1:5], uint32(1+varLen+dataLen))
  128. header[5] = 0x0A
  129. binary.PutUvarint(header[6:], uint64(dataLen))
  130. _, err := g.writer.Write(buffer.Bytes())
  131. if err == io.ErrClosedPipe && g.err != nil {
  132. err = g.err
  133. }
  134. return err
  135. }
  136. func (g *Conn) FrontHeadroom() int {
  137. return 6 + binary.MaxVarintLen64
  138. }
  139. func (g *Conn) Close() error {
  140. g.close.Store(true)
  141. if r := g.response; r != nil {
  142. r.Body.Close()
  143. }
  144. return g.writer.Close()
  145. }
  146. func (g *Conn) LocalAddr() net.Addr { return g.transport.LocalAddr() }
  147. func (g *Conn) RemoteAddr() net.Addr { return g.transport.RemoteAddr() }
  148. func (g *Conn) SetReadDeadline(t time.Time) error { return g.SetDeadline(t) }
  149. func (g *Conn) SetWriteDeadline(t time.Time) error { return g.SetDeadline(t) }
  150. func (g *Conn) SetDeadline(t time.Time) error {
  151. d := time.Until(t)
  152. if g.deadline != nil {
  153. g.deadline.Reset(d)
  154. return nil
  155. }
  156. g.deadline = time.AfterFunc(d, func() {
  157. g.Close()
  158. })
  159. return nil
  160. }
  161. func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, realityConfig *tlsC.RealityConfig) *TransportWrap {
  162. wrap := TransportWrap{}
  163. dialFunc := func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
  164. pconn, err := dialFn(network, addr)
  165. if err != nil {
  166. return nil, err
  167. }
  168. wrap.remoteAddr = pconn.RemoteAddr()
  169. if tlsConfig == nil {
  170. return pconn, nil
  171. }
  172. if len(Fingerprint) != 0 {
  173. if realityConfig == nil {
  174. if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists {
  175. utlsConn := tlsC.UClient(pconn, cfg, fingerprint)
  176. if err := utlsConn.HandshakeContext(ctx); err != nil {
  177. pconn.Close()
  178. return nil, err
  179. }
  180. state := utlsConn.ConnectionState()
  181. if p := state.NegotiatedProtocol; p != http2.NextProtoTLS {
  182. utlsConn.Close()
  183. return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS)
  184. }
  185. return utlsConn, nil
  186. }
  187. } else {
  188. realityConn, err := tlsC.GetRealityConn(ctx, pconn, Fingerprint, cfg, realityConfig)
  189. if err != nil {
  190. pconn.Close()
  191. return nil, err
  192. }
  193. //state := realityConn.(*utls.UConn).ConnectionState()
  194. //if p := state.NegotiatedProtocol; p != http2.NextProtoTLS {
  195. // realityConn.Close()
  196. // return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS)
  197. //}
  198. return realityConn, nil
  199. }
  200. }
  201. if realityConfig != nil {
  202. return nil, errors.New("REALITY is based on uTLS, please set a client-fingerprint")
  203. }
  204. conn := tls.Client(pconn, cfg)
  205. if err := conn.HandshakeContext(ctx); err != nil {
  206. pconn.Close()
  207. return nil, err
  208. }
  209. state := conn.ConnectionState()
  210. if p := state.NegotiatedProtocol; p != http2.NextProtoTLS {
  211. conn.Close()
  212. return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS)
  213. }
  214. return conn, nil
  215. }
  216. wrap.Transport = &http2.Transport{
  217. DialTLSContext: dialFunc,
  218. TLSClientConfig: tlsConfig,
  219. AllowHTTP: false,
  220. DisableCompression: true,
  221. PingTimeout: 0,
  222. }
  223. return &wrap
  224. }
  225. func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, error) {
  226. serviceName := "GunService"
  227. if cfg.ServiceName != "" {
  228. serviceName = cfg.ServiceName
  229. }
  230. reader, writer := io.Pipe()
  231. request := &http.Request{
  232. Method: http.MethodPost,
  233. Body: reader,
  234. URL: &url.URL{
  235. Scheme: "https",
  236. Host: cfg.Host,
  237. Path: fmt.Sprintf("/%s/Tun", serviceName),
  238. // for unescape path
  239. Opaque: fmt.Sprintf("//%s/%s/Tun", cfg.Host, serviceName),
  240. },
  241. Proto: "HTTP/2",
  242. ProtoMajor: 2,
  243. ProtoMinor: 0,
  244. Header: defaultHeader,
  245. }
  246. conn := &Conn{
  247. request: request,
  248. transport: transport,
  249. writer: writer,
  250. close: atomic.NewBool(false),
  251. }
  252. go conn.once.Do(conn.initRequest)
  253. return conn, nil
  254. }
  255. func StreamGunWithConn(conn net.Conn, tlsConfig *tls.Config, cfg *Config, realityConfig *tlsC.RealityConfig) (net.Conn, error) {
  256. dialFn := func(network, addr string) (net.Conn, error) {
  257. return conn, nil
  258. }
  259. transport := NewHTTP2Client(dialFn, tlsConfig, cfg.ClientFingerprint, realityConfig)
  260. return StreamGunWithTransport(transport, cfg)
  261. }