1
0

http.go 2.0 KB

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