123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- package obfs
- import (
- "bytes"
- "crypto/rand"
- "encoding/base64"
- "fmt"
- "io"
- "net"
- "net/http"
- "github.com/metacubex/mihomo/common/pool"
- "github.com/metacubex/randv2"
- )
- // HTTPObfs is shadowsocks http simple-obfs implementation
- type HTTPObfs struct {
- net.Conn
- host string
- port string
- buf []byte
- offset int
- firstRequest bool
- firstResponse bool
- }
- func (ho *HTTPObfs) Read(b []byte) (int, error) {
- if ho.buf != nil {
- n := copy(b, ho.buf[ho.offset:])
- ho.offset += n
- if ho.offset == len(ho.buf) {
- pool.Put(ho.buf)
- ho.buf = nil
- }
- return n, nil
- }
- if ho.firstResponse {
- buf := pool.Get(pool.RelayBufferSize)
- n, err := ho.Conn.Read(buf)
- if err != nil {
- pool.Put(buf)
- return 0, err
- }
- idx := bytes.Index(buf[:n], []byte("\r\n\r\n"))
- if idx == -1 {
- pool.Put(buf)
- return 0, io.EOF
- }
- ho.firstResponse = false
- length := n - (idx + 4)
- n = copy(b, buf[idx+4:n])
- if length > n {
- ho.buf = buf[:idx+4+length]
- ho.offset = idx + 4 + n
- } else {
- pool.Put(buf)
- }
- return n, nil
- }
- return ho.Conn.Read(b)
- }
- func (ho *HTTPObfs) Write(b []byte) (int, error) {
- if ho.firstRequest {
- randBytes := make([]byte, 16)
- rand.Read(randBytes)
- req, err := http.NewRequest("GET", fmt.Sprintf("http://%s/", ho.host), bytes.NewBuffer(b[:]))
- if err != nil {
- return 0, err
- }
- req.Header.Set("User-Agent", fmt.Sprintf("curl/7.%d.%d", randv2.Int()%54, randv2.Int()%2))
- req.Header.Set("Upgrade", "websocket")
- req.Header.Set("Connection", "Upgrade")
- req.Host = ho.host
- if ho.port != "80" {
- req.Host = fmt.Sprintf("%s:%s", ho.host, ho.port)
- }
- req.Header.Set("Sec-WebSocket-Key", base64.URLEncoding.EncodeToString(randBytes))
- req.ContentLength = int64(len(b))
- err = req.Write(ho.Conn)
- ho.firstRequest = false
- return len(b), err
- }
- return ho.Conn.Write(b)
- }
- // NewHTTPObfs return a HTTPObfs
- func NewHTTPObfs(conn net.Conn, host string, port string) net.Conn {
- return &HTTPObfs{
- Conn: conn,
- firstRequest: true,
- firstResponse: true,
- host: host,
- port: port,
- }
- }
|