Skip to content

Commit 2afad8e

Browse files
committed
support HTTP proxy
1 parent 6699ed4 commit 2afad8e

File tree

1 file changed

+106
-62
lines changed

1 file changed

+106
-62
lines changed

client/main.go

Lines changed: 106 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"net/url"
1212
"os"
1313
"strconv"
14+
"strings"
1415

1516
"github.com/gorilla/websocket"
1617
uuid "github.com/satori/go.uuid"
@@ -46,91 +47,125 @@ func main() {
4647
go handleConnection(conn)
4748
}
4849
}
50+
func convertToMap(input string) map[string]string {
51+
result := make(map[string]string)
52+
53+
lines := strings.Split(input, "\n")
54+
for _, line := range lines {
55+
parts := strings.SplitN(line, ": ", 2)
56+
if len(parts) == 2 {
57+
result[strings.ToLower(strings.TrimSpace(parts[0]))] = strings.TrimSpace(parts[1])
58+
}
59+
}
60+
61+
return result
62+
}
4963

5064
func handleConnection(clientConn net.Conn) {
5165
defer clientConn.Close()
5266

5367
// Step 1: Version identification and authentication
5468
// Read and verify the SOCKS5 initial handshake message
5569
buf := make([]byte, 257)
56-
_, err := io.ReadAtLeast(clientConn, buf, 2)
70+
nbytes, err := io.ReadAtLeast(clientConn, buf, 2)
5771
if err != nil {
5872
log.Printf("Failed to read client handshake: %v", err)
5973
return
6074
}
75+
_ = nbytes
6176

77+
var destAddr string
78+
var destPort string
79+
isSocks5 := false
80+
isHttps := false
6281
// Check SOCKS version and authentication methods
63-
if buf[0] != 0x05 {
64-
log.Printf("Unsupported SOCKS version: %v", buf[0])
65-
return
66-
}
82+
if buf[0] == 0x05 {
83+
isSocks5 = true
84+
// Number of authentication methods supported
85+
numMethods := int(buf[1])
86+
authMethods := buf[2 : 2+numMethods]
6787

68-
// Number of authentication methods supported
69-
numMethods := int(buf[1])
70-
authMethods := buf[2 : 2+numMethods]
88+
// Check if "no authentication" method (0x00) is supported
89+
noAuth := false
90+
for _, m := range authMethods {
91+
if m == 0x00 {
92+
noAuth = true
93+
break
94+
}
95+
}
7196

72-
// Check if "no authentication" method (0x00) is supported
73-
noAuth := false
74-
for _, m := range authMethods {
75-
if m == 0x00 {
76-
noAuth = true
77-
break
97+
if !noAuth {
98+
log.Printf("No supported authentication methods")
99+
// Send handshake failure response to client
100+
clientConn.Write([]byte{0x05, 0xFF})
101+
return
78102
}
79-
}
80103

81-
if !noAuth {
82-
log.Printf("No supported authentication methods")
83-
// Send handshake failure response to client
84-
clientConn.Write([]byte{0x05, 0xFF})
85-
return
86-
}
104+
// Send handshake response to client indicating "no authentication" method
105+
clientConn.Write([]byte{0x05, 0x00})
87106

88-
// Send handshake response to client indicating "no authentication" method
89-
clientConn.Write([]byte{0x05, 0x00})
107+
// Step 2: Request processing
108+
// Read and verify the SOCKS5 request
109+
_, err = io.ReadAtLeast(clientConn, buf, 4)
110+
if err != nil {
111+
log.Printf("Failed to read client request: %v", err)
112+
return
113+
}
90114

91-
// Step 2: Request processing
92-
// Read and verify the SOCKS5 request
93-
_, err = io.ReadAtLeast(clientConn, buf, 4)
94-
if err != nil {
95-
log.Printf("Failed to read client request: %v", err)
96-
return
97-
}
115+
if buf[0] != 0x05 {
116+
log.Printf("Unsupported SOCKS version: %v", buf[0])
117+
return
118+
}
98119

99-
if buf[0] != 0x05 {
100-
log.Printf("Unsupported SOCKS version: %v", buf[0])
101-
return
102-
}
120+
if buf[1] != 0x01 {
121+
log.Printf("Unsupported command: %v", buf[1])
122+
return
123+
}
103124

104-
if buf[1] != 0x01 {
105-
log.Printf("Unsupported command: %v", buf[1])
106-
return
107-
}
125+
// Check the address type
126+
switch buf[3] {
127+
case 0x01: // IPv4 address
128+
ip := net.IP(buf[4 : 4+net.IPv4len])
129+
destAddr = ip.String()
130+
destPort = fmt.Sprintf("%d", int(buf[8])<<8+int(buf[9]))
131+
case 0x03: // Domain name
132+
domainLen := int(buf[4])
133+
domain := string(buf[5 : 5+domainLen])
134+
destAddr = domain
135+
destPort = strconv.Itoa(int(buf[5+domainLen])<<8 + int(buf[5+domainLen+1]))
136+
case 0x04: // IPv6 address
137+
ip := net.IP(buf[4 : 4+net.IPv6len])
138+
destAddr = ip.String()
139+
destPort = strconv.Itoa(int(buf[20])<<8 + int(buf[21]))
140+
default:
141+
log.Printf("Unsupported address type: %v", buf[3])
142+
return
143+
}
108144

109-
// Check the address type
110-
var destAddr string
111-
var destPort string
112-
switch buf[3] {
113-
case 0x01: // IPv4 address
114-
ip := net.IP(buf[4 : 4+net.IPv4len])
115-
destAddr = ip.String()
116-
destPort = fmt.Sprintf("%d", int(buf[8])<<8+int(buf[9]))
117-
case 0x03: // Domain name
118-
domainLen := int(buf[4])
119-
domain := string(buf[5 : 5+domainLen])
120-
destAddr = domain
121-
destPort = strconv.Itoa(int(buf[5+domainLen])<<8 + int(buf[5+domainLen+1]))
122-
case 0x04: // IPv6 address
123-
ip := net.IP(buf[4 : 4+net.IPv6len])
124-
destAddr = ip.String()
125-
destPort = strconv.Itoa(int(buf[20])<<8 + int(buf[21]))
126-
default:
127-
log.Printf("Unsupported address type: %v", buf[3])
128-
return
145+
// Send request response to client indicating success
146+
clientConn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
147+
} else if (buf[0] == 'G' && buf[1] == 'E') || (buf[0] == 'P' && buf[1] == 'O') || (buf[0] == 'O' && buf[1] == 'P') || (buf[0] == 'P' && buf[1] == 'U') || (buf[0] == 'D' && buf[1] == 'E') || (buf[0] == 'H' && buf[1] == 'E') || (buf[0] == 'T' && buf[1] == 'R') {
148+
r := convertToMap(string(buf[:nbytes]))
149+
hosts := r["host"]
150+
if strings.Index(hosts, ":") == -1 {
151+
destAddr = hosts
152+
destPort = "80"
153+
} else {
154+
destAddr = strings.Split(hosts, ":")[0]
155+
destPort = strings.Split(hosts, ":")[1]
156+
}
157+
} else if buf[0] == 'C' && buf[1] == 'O' {
158+
isHttps = true
159+
r := convertToMap(string(buf[:nbytes]))
160+
hosts := r["host"]
161+
if strings.Index(hosts, ":") == -1 {
162+
destAddr = hosts
163+
destPort = "443"
164+
} else {
165+
destAddr = strings.Split(hosts, ":")[0]
166+
destPort = strings.Split(hosts, ":")[1]
167+
}
129168
}
130-
131-
// Send request response to client indicating success
132-
clientConn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
133-
134169
u := url.URL{
135170
Scheme: "ws",
136171
Host: *wsServer,
@@ -175,6 +210,15 @@ func handleConnection(clientConn net.Conn) {
175210
clientConn.Close()
176211
return
177212
}
213+
if isHttps {
214+
clientConn.Write([]byte("HTTP/1.1 200 Connection Established\r\n\r\n"))
215+
}
216+
if false == isSocks5 && false == isHttps {
217+
err = ws.Conn.WriteJSON(common.Proto{MsgType: common.ReqData, Data: buf[:nbytes]})
218+
if err != nil {
219+
log.Printf("[%s]Failed to send http data to WebSocket server: %v", msgId, err)
220+
}
221+
}
178222
go func() {
179223
resp := common.Proto{}
180224
for {

0 commit comments

Comments
 (0)