Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
snail007
GitHub Repository: snail007/goproxy
Path: blob/master/services/tunnel_bridge.go
686 views
1
package services
2
3
import (
4
"bufio"
5
"encoding/binary"
6
"fmt"
7
"log"
8
"net"
9
"github.com/snail007/goproxy/utils"
10
"strconv"
11
"sync"
12
"time"
13
)
14
15
type BridgeItem struct {
16
ServerChn chan *net.Conn
17
ClientChn chan *net.Conn
18
ClientControl *net.Conn
19
Once *sync.Once
20
Key string
21
}
22
type TunnelBridge struct {
23
cfg TunnelBridgeArgs
24
br utils.ConcurrentMap
25
}
26
27
func NewTunnelBridge() Service {
28
return &TunnelBridge{
29
cfg: TunnelBridgeArgs{},
30
br: utils.NewConcurrentMap(),
31
}
32
}
33
34
func (s *TunnelBridge) InitService() {
35
36
}
37
func (s *TunnelBridge) Check() {
38
if s.cfg.CertBytes == nil || s.cfg.KeyBytes == nil {
39
log.Fatalf("cert and key file required")
40
}
41
42
}
43
func (s *TunnelBridge) StopService() {
44
45
}
46
func (s *TunnelBridge) Start(args interface{}) (err error) {
47
s.cfg = args.(TunnelBridgeArgs)
48
s.Check()
49
s.InitService()
50
host, port, _ := net.SplitHostPort(*s.cfg.Local)
51
p, _ := strconv.Atoi(port)
52
sc := utils.NewServerChannel(host, p)
53
54
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, func(inConn net.Conn) {
55
reader := bufio.NewReader(inConn)
56
var connType uint8
57
err = binary.Read(reader, binary.LittleEndian, &connType)
58
if err != nil {
59
utils.CloseConn(&inConn)
60
return
61
}
62
var key string
63
var connTypeStrMap = map[uint8]string{CONN_SERVER: "server", CONN_CLIENT: "client", CONN_CONTROL: "client"}
64
if connType == CONN_SERVER || connType == CONN_CLIENT || connType == CONN_CONTROL {
65
var keyLength uint16
66
err = binary.Read(reader, binary.LittleEndian, &keyLength)
67
if err != nil {
68
return
69
}
70
_key := make([]byte, keyLength)
71
n, err := reader.Read(_key)
72
if err != nil {
73
return
74
}
75
if n != int(keyLength) {
76
return
77
}
78
key = string(_key)
79
log.Printf("connection from %s , key: %s", connTypeStrMap[connType], key)
80
}
81
switch connType {
82
case CONN_SERVER:
83
s.ServerConn(&inConn, key)
84
case CONN_CLIENT:
85
s.ClientConn(&inConn, key)
86
case CONN_CONTROL:
87
s.ClientControlConn(&inConn, key)
88
default:
89
log.Printf("unkown conn type %d", connType)
90
utils.CloseConn(&inConn)
91
}
92
})
93
if err != nil {
94
return
95
}
96
log.Printf("proxy on tunnel bridge mode %s", (*sc.Listener).Addr())
97
return
98
}
99
func (s *TunnelBridge) Clean() {
100
s.StopService()
101
}
102
func (s *TunnelBridge) ClientConn(inConn *net.Conn, key string) {
103
chn, _ := s.ConnChn(key, CONN_CLIENT)
104
chn <- inConn
105
}
106
func (s *TunnelBridge) ServerConn(inConn *net.Conn, key string) {
107
chn, _ := s.ConnChn(key, CONN_SERVER)
108
chn <- inConn
109
}
110
func (s *TunnelBridge) ClientControlConn(inConn *net.Conn, key string) {
111
_, item := s.ConnChn(key, CONN_CLIENT)
112
utils.CloseConn(item.ClientControl)
113
if item.ClientControl != nil {
114
*item.ClientControl = *inConn
115
} else {
116
item.ClientControl = inConn
117
}
118
log.Printf("set client control conn,remote: %s", (*inConn).RemoteAddr())
119
}
120
func (s *TunnelBridge) ConnChn(key string, typ uint8) (chn chan *net.Conn, item *BridgeItem) {
121
s.br.SetIfAbsent(key, &BridgeItem{
122
ServerChn: make(chan *net.Conn, 10000),
123
ClientChn: make(chan *net.Conn, 10000),
124
Once: &sync.Once{},
125
Key: key,
126
})
127
_item, _ := s.br.Get(key)
128
item = _item.(*BridgeItem)
129
item.Once.Do(func() {
130
s.ChnDeamon(item)
131
})
132
if typ == CONN_CLIENT {
133
chn = item.ClientChn
134
} else {
135
chn = item.ServerChn
136
}
137
return
138
}
139
func (s *TunnelBridge) ChnDeamon(item *BridgeItem) {
140
go func() {
141
log.Printf("%s conn chan deamon started", item.Key)
142
for {
143
var clientConn *net.Conn
144
var serverConn *net.Conn
145
serverConn = <-item.ServerChn
146
log.Printf("%s server conn picked up", item.Key)
147
OUT:
148
for {
149
_item, _ := s.br.Get(item.Key)
150
Item := _item.(*BridgeItem)
151
var err error
152
if Item.ClientControl != nil && *Item.ClientControl != nil {
153
_, err = (*Item.ClientControl).Write([]byte{'0'})
154
} else {
155
err = fmt.Errorf("client control conn not exists")
156
}
157
if err != nil {
158
log.Printf("%s client control conn write signal fail, err: %s, retrying...", item.Key, err)
159
utils.CloseConn(Item.ClientControl)
160
*Item.ClientControl = nil
161
Item.ClientControl = nil
162
time.Sleep(time.Second * 3)
163
continue
164
} else {
165
select {
166
case clientConn = <-item.ClientChn:
167
log.Printf("%s client conn picked up", item.Key)
168
break OUT
169
case <-time.After(time.Second * time.Duration(*s.cfg.Timeout*5)):
170
log.Printf("%s client conn picked timeout, retrying...", item.Key)
171
}
172
}
173
}
174
175
utils.IoBind(*serverConn, *clientConn, func(isSrcErr bool, err error) {
176
utils.CloseConn(serverConn)
177
utils.CloseConn(clientConn)
178
log.Printf("%s conn %s - %s - %s - %s released", item.Key, (*serverConn).RemoteAddr(), (*serverConn).LocalAddr(), (*clientConn).LocalAddr(), (*clientConn).RemoteAddr())
179
}, func(i int, b bool) {}, 0)
180
log.Printf("%s conn %s - %s - %s - %s created", item.Key, (*serverConn).RemoteAddr(), (*serverConn).LocalAddr(), (*clientConn).LocalAddr(), (*clientConn).RemoteAddr())
181
}
182
}()
183
}
184
185