Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
snail007
GitHub Repository: snail007/goproxy
Path: blob/master/services/tunnel_client.go
686 views
1
package services
2
3
import (
4
"bytes"
5
"crypto/tls"
6
"encoding/binary"
7
"fmt"
8
"io"
9
"log"
10
"net"
11
"github.com/snail007/goproxy/utils"
12
"time"
13
)
14
15
type TunnelClient struct {
16
cfg TunnelClientArgs
17
}
18
19
func NewTunnelClient() Service {
20
return &TunnelClient{
21
cfg: TunnelClientArgs{},
22
}
23
}
24
25
func (s *TunnelClient) InitService() {
26
}
27
func (s *TunnelClient) Check() {
28
if *s.cfg.Parent != "" {
29
log.Printf("use tls parent %s", *s.cfg.Parent)
30
} else {
31
log.Fatalf("parent required")
32
}
33
if s.cfg.CertBytes == nil || s.cfg.KeyBytes == nil {
34
log.Fatalf("cert and key file required")
35
}
36
}
37
func (s *TunnelClient) StopService() {
38
}
39
func (s *TunnelClient) Start(args interface{}) (err error) {
40
s.cfg = args.(TunnelClientArgs)
41
s.Check()
42
s.InitService()
43
44
for {
45
ctrlConn, err := s.GetInConn(CONN_CONTROL)
46
if err != nil {
47
log.Printf("control connection err: %s", err)
48
time.Sleep(time.Second * 3)
49
utils.CloseConn(&ctrlConn)
50
continue
51
}
52
if *s.cfg.IsUDP {
53
log.Printf("proxy on udp tunnel client mode")
54
} else {
55
log.Printf("proxy on tcp tunnel client mode")
56
}
57
for {
58
signal := make([]byte, 1)
59
if signal[0] == 1 {
60
continue
61
}
62
_, err = ctrlConn.Read(signal)
63
if err != nil {
64
utils.CloseConn(&ctrlConn)
65
log.Printf("read connection signal err: %s", err)
66
break
67
}
68
log.Printf("signal revecived:%s", signal)
69
if *s.cfg.IsUDP {
70
go s.ServeUDP()
71
} else {
72
go s.ServeConn()
73
}
74
}
75
}
76
}
77
func (s *TunnelClient) Clean() {
78
s.StopService()
79
}
80
func (s *TunnelClient) GetInConn(typ uint8) (outConn net.Conn, err error) {
81
outConn, err = s.GetConn()
82
if err != nil {
83
err = fmt.Errorf("connection err: %s", err)
84
return
85
}
86
keyBytes := []byte(*s.cfg.Key)
87
keyLength := uint16(len(keyBytes))
88
pkg := new(bytes.Buffer)
89
binary.Write(pkg, binary.LittleEndian, typ)
90
binary.Write(pkg, binary.LittleEndian, keyLength)
91
binary.Write(pkg, binary.LittleEndian, keyBytes)
92
_, err = outConn.Write(pkg.Bytes())
93
if err != nil {
94
err = fmt.Errorf("write connection data err: %s ,retrying...", err)
95
utils.CloseConn(&outConn)
96
return
97
}
98
return
99
}
100
func (s *TunnelClient) GetConn() (conn net.Conn, err error) {
101
var _conn tls.Conn
102
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
103
if err == nil {
104
conn = net.Conn(&_conn)
105
}
106
return
107
}
108
func (s *TunnelClient) ServeUDP() {
109
var inConn net.Conn
110
var err error
111
for {
112
for {
113
inConn, err = s.GetInConn(CONN_CLIENT)
114
if err != nil {
115
utils.CloseConn(&inConn)
116
log.Printf("connection err: %s, retrying...", err)
117
time.Sleep(time.Second * 3)
118
continue
119
} else {
120
break
121
}
122
}
123
log.Printf("conn created , remote : %s ", inConn.RemoteAddr())
124
for {
125
srcAddr, body, err := utils.ReadUDPPacket(&inConn)
126
if err == io.EOF || err == io.ErrUnexpectedEOF {
127
log.Printf("connection %s released", srcAddr)
128
utils.CloseConn(&inConn)
129
break
130
}
131
//log.Printf("udp packet revecived:%s,%v", srcAddr, body)
132
go s.processUDPPacket(&inConn, srcAddr, body)
133
}
134
}
135
}
136
func (s *TunnelClient) processUDPPacket(inConn *net.Conn, srcAddr string, body []byte) {
137
dstAddr, err := net.ResolveUDPAddr("udp", *s.cfg.Local)
138
if err != nil {
139
log.Printf("can't resolve address: %s", err)
140
utils.CloseConn(inConn)
141
return
142
}
143
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
144
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
145
if err != nil {
146
log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
147
return
148
}
149
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
150
_, err = conn.Write(body)
151
if err != nil {
152
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
153
return
154
}
155
//log.Printf("send udp packet to %s success", dstAddr.String())
156
buf := make([]byte, 512)
157
len, _, err := conn.ReadFromUDP(buf)
158
if err != nil {
159
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
160
return
161
}
162
respBody := buf[0:len]
163
//log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
164
_, err = (*inConn).Write(utils.UDPPacket(srcAddr, respBody))
165
if err != nil {
166
log.Printf("send udp response fail ,ERR:%s", err)
167
utils.CloseConn(inConn)
168
return
169
}
170
//log.Printf("send udp response success ,from:%s", dstAddr.String())
171
}
172
func (s *TunnelClient) ServeConn() {
173
var inConn, outConn net.Conn
174
var err error
175
for {
176
inConn, err = s.GetInConn(CONN_CLIENT)
177
if err != nil {
178
utils.CloseConn(&inConn)
179
log.Printf("connection err: %s, retrying...", err)
180
time.Sleep(time.Second * 3)
181
continue
182
} else {
183
break
184
}
185
}
186
187
i := 0
188
for {
189
i++
190
outConn, err = utils.ConnectHost(*s.cfg.Local, *s.cfg.Timeout)
191
if err == nil || i == 3 {
192
break
193
} else {
194
if i == 3 {
195
log.Printf("connect to %s err: %s, retrying...", *s.cfg.Local, err)
196
time.Sleep(2 * time.Second)
197
continue
198
}
199
}
200
}
201
202
if err != nil {
203
utils.CloseConn(&inConn)
204
utils.CloseConn(&outConn)
205
log.Printf("build connection error, err: %s", err)
206
return
207
}
208
209
utils.IoBind(inConn, outConn, func(isSrcErr bool, err error) {
210
log.Printf("%s conn %s - %s - %s - %s released", *s.cfg.Key, inConn.RemoteAddr(), inConn.LocalAddr(), outConn.LocalAddr(), outConn.RemoteAddr())
211
utils.CloseConn(&inConn)
212
utils.CloseConn(&outConn)
213
}, func(i int, b bool) {}, 0)
214
log.Printf("%s conn %s - %s - %s - %s created", *s.cfg.Key, inConn.RemoteAddr(), inConn.LocalAddr(), outConn.LocalAddr(), outConn.RemoteAddr())
215
}
216
217