Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
snail007
GitHub Repository: snail007/goproxy
Path: blob/master/services/tunnel_server.go
686 views
1
package services
2
3
import (
4
"bufio"
5
"bytes"
6
"crypto/tls"
7
"encoding/binary"
8
"io"
9
"log"
10
"net"
11
"github.com/snail007/goproxy/utils"
12
"runtime/debug"
13
"strconv"
14
"strings"
15
"time"
16
)
17
18
type TunnelServer struct {
19
cfg TunnelServerArgs
20
udpChn chan UDPItem
21
sc utils.ServerChannel
22
}
23
24
func NewTunnelServer() Service {
25
return &TunnelServer{
26
cfg: TunnelServerArgs{},
27
udpChn: make(chan UDPItem, 50000),
28
}
29
}
30
31
type UDPItem struct {
32
packet *[]byte
33
localAddr *net.UDPAddr
34
srcAddr *net.UDPAddr
35
}
36
37
func (s *TunnelServer) InitService() {
38
s.UDPConnDeamon()
39
}
40
func (s *TunnelServer) Check() {
41
if *s.cfg.Parent != "" {
42
log.Printf("use tls parent %s", *s.cfg.Parent)
43
} else {
44
log.Fatalf("parent required")
45
}
46
if s.cfg.CertBytes == nil || s.cfg.KeyBytes == nil {
47
log.Fatalf("cert and key file required")
48
}
49
}
50
func (s *TunnelServer) StopService() {
51
}
52
func (s *TunnelServer) Start(args interface{}) (err error) {
53
s.cfg = args.(TunnelServerArgs)
54
s.Check()
55
s.InitService()
56
host, port, _ := net.SplitHostPort(*s.cfg.Local)
57
p, _ := strconv.Atoi(port)
58
s.sc = utils.NewServerChannel(host, p)
59
60
if *s.cfg.IsUDP {
61
err = s.sc.ListenUDP(func(packet []byte, localAddr, srcAddr *net.UDPAddr) {
62
s.udpChn <- UDPItem{
63
packet: &packet,
64
localAddr: localAddr,
65
srcAddr: srcAddr,
66
}
67
})
68
if err != nil {
69
return
70
}
71
log.Printf("proxy on udp tunnel server mode %s", (*s.sc.UDPListener).LocalAddr())
72
} else {
73
err = s.sc.ListenTCP(func(inConn net.Conn) {
74
defer func() {
75
if err := recover(); err != nil {
76
log.Printf("tserver conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
77
}
78
}()
79
var outConn net.Conn
80
for {
81
outConn, err = s.GetOutConn()
82
if err != nil {
83
utils.CloseConn(&outConn)
84
log.Printf("connect to %s fail, err: %s, retrying...", *s.cfg.Parent, err)
85
time.Sleep(time.Second * 3)
86
continue
87
} else {
88
break
89
}
90
}
91
92
utils.IoBind(inConn, outConn, func(isSrcErr bool, err error) {
93
utils.CloseConn(&outConn)
94
utils.CloseConn(&inConn)
95
log.Printf("%s conn %s - %s - %s - %s released", *s.cfg.Key, inConn.RemoteAddr(), inConn.LocalAddr(), outConn.LocalAddr(), outConn.RemoteAddr())
96
}, func(i int, b bool) {}, 0)
97
98
log.Printf("%s conn %s - %s - %s - %s created", *s.cfg.Key, inConn.RemoteAddr(), inConn.LocalAddr(), outConn.LocalAddr(), outConn.RemoteAddr())
99
})
100
if err != nil {
101
return
102
}
103
log.Printf("proxy on tunnel server mode %s", (*s.sc.Listener).Addr())
104
}
105
return
106
}
107
func (s *TunnelServer) Clean() {
108
s.StopService()
109
}
110
func (s *TunnelServer) GetOutConn() (outConn net.Conn, err error) {
111
outConn, err = s.GetConn()
112
if err != nil {
113
log.Printf("connection err: %s", err)
114
return
115
}
116
keyBytes := []byte(*s.cfg.Key)
117
keyLength := uint16(len(keyBytes))
118
pkg := new(bytes.Buffer)
119
binary.Write(pkg, binary.LittleEndian, CONN_SERVER)
120
binary.Write(pkg, binary.LittleEndian, keyLength)
121
binary.Write(pkg, binary.LittleEndian, keyBytes)
122
_, err = outConn.Write(pkg.Bytes())
123
if err != nil {
124
log.Printf("write connection data err: %s ,retrying...", err)
125
utils.CloseConn(&outConn)
126
return
127
}
128
return
129
}
130
func (s *TunnelServer) GetConn() (conn net.Conn, err error) {
131
var _conn tls.Conn
132
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
133
if err == nil {
134
conn = net.Conn(&_conn)
135
}
136
return
137
}
138
func (s *TunnelServer) UDPConnDeamon() {
139
go func() {
140
defer func() {
141
if err := recover(); err != nil {
142
log.Printf("udp conn deamon crashed with err : %s \nstack: %s", err, string(debug.Stack()))
143
}
144
}()
145
var outConn net.Conn
146
var cmdChn = make(chan bool, 1)
147
148
var err error
149
for {
150
item := <-s.udpChn
151
RETRY:
152
if outConn == nil {
153
for {
154
outConn, err = s.GetOutConn()
155
if err != nil {
156
cmdChn <- true
157
outConn = nil
158
utils.CloseConn(&outConn)
159
log.Printf("connect to %s fail, err: %s, retrying...", *s.cfg.Parent, err)
160
time.Sleep(time.Second * 3)
161
continue
162
} else {
163
go func(outConn net.Conn) {
164
go func() {
165
<-cmdChn
166
outConn.Close()
167
}()
168
for {
169
srcAddrFromConn, body, err := utils.ReadUDPPacket(&outConn)
170
if err == io.EOF || err == io.ErrUnexpectedEOF {
171
log.Printf("udp connection deamon exited, %s -> %s", outConn.LocalAddr(), outConn.RemoteAddr())
172
break
173
}
174
if err != nil {
175
log.Printf("parse revecived udp packet fail, err: %s", err)
176
continue
177
}
178
//log.Printf("udp packet revecived over parent , local:%s", srcAddrFromConn)
179
_srcAddr := strings.Split(srcAddrFromConn, ":")
180
if len(_srcAddr) != 2 {
181
log.Printf("parse revecived udp packet fail, addr error : %s", srcAddrFromConn)
182
continue
183
}
184
port, _ := strconv.Atoi(_srcAddr[1])
185
dstAddr := &net.UDPAddr{IP: net.ParseIP(_srcAddr[0]), Port: port}
186
_, err = s.sc.UDPListener.WriteToUDP(body, dstAddr)
187
if err != nil {
188
log.Printf("udp response to local %s fail,ERR:%s", srcAddrFromConn, err)
189
continue
190
}
191
//log.Printf("udp response to local %s success", srcAddrFromConn)
192
}
193
}(outConn)
194
break
195
}
196
}
197
}
198
writer := bufio.NewWriter(outConn)
199
writer.Write(utils.UDPPacket(item.srcAddr.String(), *item.packet))
200
err := writer.Flush()
201
if err != nil {
202
outConn = nil
203
log.Printf("write udp packet to %s fail ,flush err:%s", *s.cfg.Parent, err)
204
goto RETRY
205
}
206
//log.Printf("write packet %v", *item.packet)
207
}
208
}()
209
}
210
211