forked from sun8911879/shadowsocksR
-
Notifications
You must be signed in to change notification settings - Fork 0
/
client.go
148 lines (132 loc) · 3.12 KB
/
client.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package main
import (
"fmt"
"net"
"net/url"
"time"
"github.com/nareix/shadowsocksR"
"github.com/nareix/shadowsocksR/tools/leakybuf"
"github.com/nareix/shadowsocksR/tools/socks"
)
var (
readTimeout = 600 * time.Second
)
// SSInfo fields that shadowsocks/shadowsocksr used only
type SSInfo struct {
SSRInfo
EncryptMethod string
EncryptPassword string
}
// SSRInfo fields that shadowsocksr used only
type SSRInfo struct {
Obfs string
ObfsParam string
ObfsData interface{}
Protocol string
ProtocolParam string
ProtocolData interface{}
}
// BackendInfo all fields that a backend used
type BackendInfo struct {
SSInfo
Address string
Type string
}
func main() {
bi := &BackendInfo{
Address: "www.domain.com:445",
Type: "ssr",
SSInfo: SSInfo{
EncryptMethod: "aes-128-cfb",
EncryptPassword: "password",
SSRInfo: SSRInfo{
Protocol: "auth_aes128_sha1",
ProtocolParam: "",
Obfs: "tls1.2_ticket_auth",
ObfsParam: "",
},
},
}
bi.Listen()
}
func (bi *BackendInfo) Listen() {
listener, err := net.Listen("tcp", "0.0.0.0:2515")
if err != nil {
panic(err)
}
for {
localConn, err := listener.Accept()
if err != nil {
continue
}
go bi.Handle(localConn)
}
}
func (bi *BackendInfo) Handle(src net.Conn) {
//直接访问google
rawaddr := socks.ParseAddr("www.google.com.hk:443")
dst, err := bi.DialSSRConn(rawaddr)
if err != nil {
panic(err)
}
go bi.Pipe(src, dst)
bi.Pipe(dst, src)
src.Close()
dst.Close()
}
func (bi *BackendInfo) DialSSRConn(rawaddr socks.Addr) (net.Conn, error) {
u := &url.URL{
Scheme: bi.Type,
Host: bi.Address,
}
v := u.Query()
v.Set("encrypt-method", bi.EncryptMethod)
v.Set("encrypt-key", bi.EncryptPassword)
v.Set("obfs", bi.Obfs)
v.Set("obfs-param", bi.ObfsParam)
v.Set("protocol", bi.Protocol)
v.Set("protocol-param", bi.ProtocolParam)
u.RawQuery = v.Encode()
ssrconn, err := shadowsocksr.NewSSRClient(u)
if err != nil {
return nil, fmt.Errorf("connecting to SSR server failed :%v", err)
}
if bi.ObfsData == nil {
bi.ObfsData = ssrconn.IObfs.GetData()
}
ssrconn.IObfs.SetData(bi.ObfsData)
if bi.ProtocolData == nil {
bi.ProtocolData = ssrconn.IProtocol.GetData()
}
ssrconn.IProtocol.SetData(bi.ProtocolData)
if _, err := ssrconn.Write(rawaddr); err != nil {
ssrconn.Close()
return nil, err
}
return ssrconn, nil
}
// PipeThenClose copies data from src to dst, closes dst when done.
func (bi *BackendInfo) Pipe(src, dst net.Conn) error {
buf := leakybuf.GlobalLeakyBuf.Get()
for {
src.SetReadDeadline(time.Now().Add(readTimeout))
n, err := src.Read(buf)
// read may return EOF with n > 0
// should always process n > 0 bytes before handling error
if n > 0 {
// Note: avoid overwrite err returned by Read.
if _, err := dst.Write(buf[0:n]); err != nil {
break
}
}
if err != nil {
// Always "use of closed network connection", but no easy way to
// identify this specific error. So just leave the error along for now.
// More info here: https://code.google.com/p/go/issues/detail?id=4373
break
}
}
leakybuf.GlobalLeakyBuf.Put(buf)
dst.Close()
return nil
}