@@ -8,9 +8,13 @@ import (
8
8
"fmt"
9
9
"io"
10
10
"io/ioutil"
11
+ "log"
11
12
"net"
12
13
"net/http"
13
14
"net/url"
15
+
16
+ "github.com/luyuhuang/subsocks/socks"
17
+ "github.com/luyuhuang/subsocks/utils"
14
18
)
15
19
16
20
func (c * Client ) wrapHTTPS (conn net.Conn ) net.Conn {
@@ -21,6 +25,130 @@ func (c *Client) wrapHTTP(conn net.Conn) net.Conn {
21
25
return newHTTPWrapper (conn , c )
22
26
}
23
27
28
+ func isValidHTTPProxyRequest (req * http.Request ) bool {
29
+ if req .URL .Host == "" {
30
+ return false
31
+ }
32
+ if req .Method != http .MethodConnect && req .URL .Scheme != "http" {
33
+ return false
34
+ }
35
+ return true
36
+ }
37
+
38
+ func httpReply (statusCode int , status string ) * http.Response {
39
+ return & http.Response {
40
+ ProtoMajor : 1 ,
41
+ ProtoMinor : 1 ,
42
+ StatusCode : statusCode ,
43
+ Status : status ,
44
+ }
45
+ }
46
+
47
+ func (c * Client ) httpHandler (conn net.Conn ) {
48
+ defer conn .Close ()
49
+
50
+ req , err := http .ReadRequest (bufio .NewReader (conn ))
51
+ if err != nil {
52
+ log .Printf ("[http] read HTTP request failed: %s" , err )
53
+ return
54
+ }
55
+ defer req .Body .Close ()
56
+
57
+ if ! isValidHTTPProxyRequest (req ) {
58
+ log .Printf ("[http] invalid http proxy request: %v" , req )
59
+ httpReply (http .StatusBadRequest , "" ).Write (conn )
60
+ return
61
+ }
62
+
63
+ host := req .URL .Hostname ()
64
+ addr := req .URL .Host
65
+ if req .URL .Port () == "" {
66
+ addr = net .JoinHostPort (addr , "80" )
67
+ }
68
+
69
+ var nextHop net.Conn
70
+ var isProxy bool
71
+ if rule := c .Rules .getRule (host ); rule == ruleProxy {
72
+ log .Printf (`[http] dial server to connect %s for %s` , addr , conn .RemoteAddr ())
73
+
74
+ isProxy = true
75
+ nextHop , err = c .dialServer ()
76
+ if err != nil {
77
+ log .Printf (`[http] dial server failed: %s` , err )
78
+ httpReply (http .StatusServiceUnavailable , "" ).Write (conn )
79
+ return
80
+ }
81
+
82
+ } else {
83
+ log .Printf (`[http] dial %s for %s` , addr , conn .RemoteAddr ())
84
+
85
+ nextHop , err = net .Dial ("tcp" , addr )
86
+ if err != nil {
87
+ if rule == ruleAuto {
88
+ log .Printf (`[http] dial %s failed, dial server for %s` , addr , conn .RemoteAddr ())
89
+
90
+ isProxy = true
91
+ nextHop , err = c .dialServer ()
92
+ if err != nil {
93
+ log .Printf (`[http] dial server failed: %s` , err )
94
+ httpReply (http .StatusServiceUnavailable , "" ).Write (conn )
95
+ return
96
+ }
97
+ c .Rules .setAsProxy (host )
98
+
99
+ } else {
100
+ log .Printf (`[http] dial remote failed: %s` , err )
101
+ httpReply (http .StatusServiceUnavailable , "" ).Write (conn )
102
+ return
103
+ }
104
+ }
105
+
106
+ }
107
+ defer nextHop .Close ()
108
+
109
+ var dash rune
110
+ if isProxy {
111
+ socksAddr , _ := socks .NewAddr (addr )
112
+ if err = socks .NewRequest (socks .CmdConnect , socksAddr ).Write (nextHop ); err != nil {
113
+ log .Printf (`[http] send request failed: %s` , err )
114
+ httpReply (http .StatusServiceUnavailable , "" ).Write (conn )
115
+ return
116
+ }
117
+ if r , e := socks .ReadReply (nextHop ); e != nil {
118
+ log .Printf (`[http] read reply failed: %s` , err )
119
+ httpReply (http .StatusServiceUnavailable , "" ).Write (conn )
120
+ return
121
+ } else if r .Rep != socks .Succeeded {
122
+ log .Printf (`[http] server connect failed: %q` , r )
123
+ httpReply (http .StatusServiceUnavailable , "" ).Write (conn )
124
+ return
125
+ }
126
+
127
+ dash = '-'
128
+ } else {
129
+ dash = '='
130
+ }
131
+
132
+ if req .Method == http .MethodConnect {
133
+ if err = httpReply (http .StatusOK , "200 Connection Established" ).Write (conn ); err != nil {
134
+ log .Printf (`[http] write reply failed: %s` , err )
135
+ return
136
+ }
137
+ } else {
138
+ req .Header .Del ("Proxy-Connection" )
139
+ if err = req .Write (nextHop ); err != nil {
140
+ log .Printf (`[http] relay request failed: %s` , err )
141
+ return
142
+ }
143
+ }
144
+
145
+ log .Printf (`[http] tunnel established %s <%c> %s` , conn .RemoteAddr (), dash , addr )
146
+ if err := utils .Transport (conn , nextHop ); err != nil {
147
+ log .Printf (`[http] transport failed: %s` , err )
148
+ }
149
+ log .Printf (`[http] tunnel disconnected %s >%c< %s` , conn .RemoteAddr (), dash , addr )
150
+ }
151
+
24
152
type httpWrapper struct {
25
153
net.Conn
26
154
client * Client
0 commit comments