http.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package obfs
  2. import (
  3. "bytes"
  4. "crypto/rand"
  5. "encoding/base64"
  6. "fmt"
  7. "io"
  8. "net"
  9. "net/http"
  10. "github.com/metacubex/mihomo/common/pool"
  11. "github.com/metacubex/randv2"
  12. )
  13. // HTTPObfs is shadowsocks http simple-obfs implementation
  14. type HTTPObfs struct {
  15. net.Conn
  16. host string
  17. port string
  18. buf []byte
  19. offset int
  20. firstRequest bool
  21. firstResponse bool
  22. }
  23. func (ho *HTTPObfs) Read(b []byte) (int, error) {
  24. if ho.buf != nil {
  25. n := copy(b, ho.buf[ho.offset:])
  26. ho.offset += n
  27. if ho.offset == len(ho.buf) {
  28. pool.Put(ho.buf)
  29. ho.buf = nil
  30. }
  31. return n, nil
  32. }
  33. if ho.firstResponse {
  34. buf := pool.Get(pool.RelayBufferSize)
  35. n, err := ho.Conn.Read(buf)
  36. if err != nil {
  37. pool.Put(buf)
  38. return 0, err
  39. }
  40. idx := bytes.Index(buf[:n], []byte("\r\n\r\n"))
  41. if idx == -1 {
  42. pool.Put(buf)
  43. return 0, io.EOF
  44. }
  45. ho.firstResponse = false
  46. length := n - (idx + 4)
  47. n = copy(b, buf[idx+4:n])
  48. if length > n {
  49. ho.buf = buf[:idx+4+length]
  50. ho.offset = idx + 4 + n
  51. } else {
  52. pool.Put(buf)
  53. }
  54. return n, nil
  55. }
  56. return ho.Conn.Read(b)
  57. }
  58. func (ho *HTTPObfs) Write(b []byte) (int, error) {
  59. if ho.firstRequest {
  60. randBytes := make([]byte, 16)
  61. rand.Read(randBytes)
  62. req, err := http.NewRequest("GET", fmt.Sprintf("http://%s/", ho.host), bytes.NewBuffer(b[:]))
  63. if err != nil {
  64. return 0, err
  65. }
  66. req.Header.Set("User-Agent", fmt.Sprintf("curl/7.%d.%d", randv2.Int()%54, randv2.Int()%2))
  67. req.Header.Set("Upgrade", "websocket")
  68. req.Header.Set("Connection", "Upgrade")
  69. req.Host = ho.host
  70. if ho.port != "80" {
  71. req.Host = fmt.Sprintf("%s:%s", ho.host, ho.port)
  72. }
  73. req.Header.Set("Sec-WebSocket-Key", base64.URLEncoding.EncodeToString(randBytes))
  74. req.ContentLength = int64(len(b))
  75. err = req.Write(ho.Conn)
  76. ho.firstRequest = false
  77. return len(b), err
  78. }
  79. return ho.Conn.Write(b)
  80. }
  81. // NewHTTPObfs return a HTTPObfs
  82. func NewHTTPObfs(conn net.Conn, host string, port string) net.Conn {
  83. return &HTTPObfs{
  84. Conn: conn,
  85. firstRequest: true,
  86. firstResponse: true,
  87. host: host,
  88. port: port,
  89. }
  90. }