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