Skip to content

Commit cdefa08

Browse files
wuxingzhangnephen
wuxingzhang
authored andcommitted
init
1 parent f844425 commit cdefa08

File tree

3 files changed

+189
-0
lines changed

3 files changed

+189
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@
1919

2020
# Go workspace file
2121
go.work
22+
go-socks-proxy
23+
.env

go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module go-socks-proxy
2+
3+
go 1.18

main.go

+184
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"context"
6+
"encoding/binary"
7+
"errors"
8+
"fmt"
9+
"io"
10+
"log"
11+
"net"
12+
)
13+
14+
const socks5Ver = 0x05
15+
const cmdBind = 0x01
16+
const atypIPV4 = 0x01
17+
const atypeHOST = 0x03
18+
const atypeIPV6 = 0x04
19+
20+
func main() {
21+
server, err := net.Listen("tcp", "0.0.0.0:1080")
22+
if err != nil {
23+
panic(err)
24+
}
25+
for {
26+
client, err := server.Accept()
27+
if err != nil {
28+
log.Printf("Accept failed %v", err)
29+
continue
30+
}
31+
go process(client)
32+
}
33+
}
34+
35+
func process(conn net.Conn) {
36+
defer conn.Close()
37+
reader := bufio.NewReader(conn)
38+
err := auth(reader, conn)
39+
if err != nil {
40+
log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)
41+
return
42+
}
43+
err = connect(reader, conn)
44+
if err != nil {
45+
log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)
46+
return
47+
}
48+
}
49+
50+
func auth(reader *bufio.Reader, conn net.Conn) (err error) {
51+
// +----+----------+----------+
52+
// |VER | NMETHODS | METHODS |
53+
// +----+----------+----------+
54+
// | 1 | 1 | 1 to 255 |
55+
// +----+----------+----------+
56+
// VER: 协议版本,socks5为0x05
57+
// NMETHODS: 支持认证的方法数量
58+
// METHODS: 对应NMETHODS,NMETHODS的值为多少,METHODS就有多少个字节。RFC预定义了一些值的含义,内容如下:
59+
// X’00’ NO AUTHENTICATION REQUIRED
60+
// X’02’ USERNAME/PASSWORD
61+
62+
ver, err := reader.ReadByte()
63+
if err != nil {
64+
return fmt.Errorf("read ver failed:%w", err)
65+
}
66+
if ver != socks5Ver {
67+
return fmt.Errorf("not supported ver:%v", ver)
68+
}
69+
methodSize, err := reader.ReadByte()
70+
if err != nil {
71+
return fmt.Errorf("read methodSize failed:%w", err)
72+
}
73+
method := make([]byte, methodSize)
74+
_, err = io.ReadFull(reader, method)
75+
if err != nil {
76+
return fmt.Errorf("read method failed:%w", err)
77+
}
78+
79+
// +----+--------+
80+
// |VER | METHOD |
81+
// +----+--------+
82+
// | 1 | 1 |
83+
// +----+--------+
84+
_, err = conn.Write([]byte{socks5Ver, 0x00})
85+
if err != nil {
86+
return fmt.Errorf("write failed:%w", err)
87+
}
88+
return nil
89+
}
90+
91+
func connect(reader *bufio.Reader, conn net.Conn) (err error) {
92+
// +----+-----+-------+------+----------+----------+
93+
// |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
94+
// +----+-----+-------+------+----------+----------+
95+
// | 1 | 1 | X'00' | 1 | Variable | 2 |
96+
// +----+-----+-------+------+----------+----------+
97+
// VER 版本号,socks5的值为0x05
98+
// CMD 0x01表示CONNECT请求
99+
// RSV 保留字段,值为0x00
100+
// ATYP 目标地址类型,DST.ADDR的数据对应这个字段的类型。
101+
// 0x01表示IPv4地址,DST.ADDR为4个字节
102+
// 0x03表示域名,DST.ADDR是一个可变长度的域名
103+
// DST.ADDR 一个可变长度的值
104+
// DST.PORT 目标端口,固定2个字节
105+
106+
buf := make([]byte, 4)
107+
_, err = io.ReadFull(reader, buf)
108+
if err != nil {
109+
return fmt.Errorf("read header failed:%w", err)
110+
}
111+
ver, cmd, atyp := buf[0], buf[1], buf[3]
112+
if ver != socks5Ver {
113+
return fmt.Errorf("not supported ver:%v", ver)
114+
}
115+
if cmd != cmdBind {
116+
return fmt.Errorf("not supported cmd:%v", ver)
117+
}
118+
addr := ""
119+
switch atyp {
120+
case atypIPV4:
121+
_, err = io.ReadFull(reader, buf)
122+
if err != nil {
123+
return fmt.Errorf("read atyp failed:%w", err)
124+
}
125+
addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3])
126+
case atypeHOST:
127+
hostSize, err := reader.ReadByte()
128+
if err != nil {
129+
return fmt.Errorf("read hostSize failed:%w", err)
130+
}
131+
host := make([]byte, hostSize)
132+
_, err = io.ReadFull(reader, host)
133+
if err != nil {
134+
return fmt.Errorf("read host failed:%w", err)
135+
}
136+
addr = string(host)
137+
case atypeIPV6:
138+
return errors.New("IPv6: no supported yet")
139+
default:
140+
return errors.New("invalid atyp")
141+
}
142+
_, err = io.ReadFull(reader, buf[:2])
143+
if err != nil {
144+
return fmt.Errorf("read port failed:%w", err)
145+
}
146+
port := binary.BigEndian.Uint16(buf[:2])
147+
148+
dest, err := net.Dial("tcp", fmt.Sprintf("%v:%v", addr, port))
149+
if err != nil {
150+
return fmt.Errorf("dial dst failed:%w", err)
151+
}
152+
defer dest.Close()
153+
log.Println("dial", addr, port)
154+
155+
// +----+-----+-------+------+----------+----------+
156+
// |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
157+
// +----+-----+-------+------+----------+----------+
158+
// | 1 | 1 | X'00' | 1 | Variable | 2 |
159+
// +----+-----+-------+------+----------+----------+
160+
// VER socks版本,这里为0x05
161+
// REP Relay field,内容取值如下 X’00’ succeeded
162+
// RSV 保留字段
163+
// ATYPE 地址类型
164+
// BND.ADDR 服务绑定的地址
165+
// BND.PORT 服务绑定的端口DST.PORT
166+
_, err = conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0})
167+
if err != nil {
168+
return fmt.Errorf("write failed: %w", err)
169+
}
170+
ctx, cancel := context.WithCancel(context.Background())
171+
defer cancel()
172+
173+
go func() {
174+
_, _ = io.Copy(dest, reader)
175+
cancel()
176+
}()
177+
go func() {
178+
_, _ = io.Copy(conn, dest)
179+
cancel()
180+
}()
181+
182+
<-ctx.Done()
183+
return nil
184+
}

0 commit comments

Comments
 (0)