github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/net/proxy/shadowsocks/obfs_http.go (about) 1 package shadowsocks 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/base64" 7 "fmt" 8 "io" 9 "math/rand/v2" 10 "net" 11 "net/http" 12 "time" 13 14 "github.com/Asutorufa/yuhaiin/pkg/net/netapi" 15 "github.com/Asutorufa/yuhaiin/pkg/protos/node/point" 16 "github.com/Asutorufa/yuhaiin/pkg/protos/node/protocol" 17 "github.com/Asutorufa/yuhaiin/pkg/utils/pool" 18 ) 19 20 /* 21 from https://github.com/Dreamacro/clash/blob/master/component/simple-obfs/http.go 22 */ 23 // HTTPObfs is shadowsocks http simple-obfs implementation 24 type HTTPObfs struct { 25 net.Conn 26 host string 27 port string 28 buf []byte 29 offset int 30 firstRequest bool 31 firstResponse bool 32 } 33 34 func (ho *HTTPObfs) Read(b []byte) (int, error) { 35 if ho.buf != nil { 36 n := copy(b, ho.buf[ho.offset:]) 37 ho.offset += n 38 if ho.offset == len(ho.buf) { 39 ho.buf = nil 40 } 41 return n, nil 42 } 43 44 if ho.firstResponse { 45 buf := pool.GetBytes(pool.DefaultSize) 46 defer pool.PutBytes(buf) 47 n, err := ho.Conn.Read(buf) 48 if err != nil { 49 // utils.BuffPool(pool.DefaultSize).Put(&(buf)) 50 return 0, err 51 } 52 idx := bytes.Index(buf[:n], []byte("\r\n\r\n")) 53 if idx == -1 { 54 // utils.BuffPool(pool.DefaultSize).Put(&(buf)) 55 return 0, io.EOF 56 } 57 ho.firstResponse = false 58 length := n - (idx + 4) 59 n = copy(b, buf[idx+4:n]) 60 if length > n { 61 ho.buf = buf[:idx+4+length] 62 ho.offset = idx + 4 + n 63 } else { 64 // utils.BuffPool(pool.DefaultSize).Put(&(buf)) 65 } 66 return n, nil 67 } 68 return ho.Conn.Read(b) 69 } 70 71 func (ho *HTTPObfs) Write(b []byte) (int, error) { 72 if ho.firstRequest { 73 req, _ := http.NewRequest("GET", fmt.Sprintf("http://%s/", ho.host), bytes.NewBuffer(b[:])) 74 req.Header.Set("User-Agent", fmt.Sprintf("curl/7.%d.%d", rand.Int()%54, rand.Int()%2)) 75 req.Header.Set("Upgrade", "websocket") 76 req.Header.Set("Connection", "Upgrade") 77 req.Host = fmt.Sprintf("%s:%s", ho.host, ho.port) 78 req.Header.Set("Sec-WebSocket-Key", base64.URLEncoding.EncodeToString([]byte(time.Now().String()[:16]))) 79 req.ContentLength = int64(len(b)) 80 err := req.Write(ho.Conn) 81 ho.firstRequest = false 82 return len(b), err 83 } 84 85 return ho.Conn.Write(b) 86 } 87 88 // newHTTPObfs return a HTTPObfs 89 func newHTTPObfs(conn net.Conn, host string, port string) net.Conn { 90 return &HTTPObfs{ 91 Conn: conn, 92 firstRequest: true, 93 firstResponse: true, 94 host: host, 95 port: port, 96 } 97 } 98 99 var _ netapi.Proxy = (*httpOBFS)(nil) 100 101 type httpOBFS struct { 102 host string 103 port string 104 105 netapi.Proxy 106 } 107 108 func init() { 109 point.RegisterProtocol(NewHTTPOBFS) 110 } 111 112 func NewHTTPOBFS(config *protocol.Protocol_ObfsHttp) point.WrapProxy { 113 return func(p netapi.Proxy) (netapi.Proxy, error) { 114 return &httpOBFS{ 115 host: config.ObfsHttp.Host, 116 port: config.ObfsHttp.Port, 117 Proxy: p, 118 }, nil 119 } 120 } 121 122 func (h *httpOBFS) Conn(ctx context.Context, s netapi.Address) (net.Conn, error) { 123 conn, err := h.Proxy.Conn(ctx, s) 124 if err != nil { 125 return nil, err 126 } 127 return newHTTPObfs(conn, h.host, h.port), nil 128 }