Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
snail007
GitHub Repository: snail007/goproxy
Path: blob/master/services/tcp.go
686 views
1
package services
2
3
import (
4
"fmt"
5
"io"
6
"log"
7
"net"
8
"github.com/snail007/goproxy/utils"
9
"runtime/debug"
10
"time"
11
12
"strconv"
13
)
14
15
type TCP struct {
16
outPool utils.OutPool
17
cfg TCPArgs
18
}
19
20
func NewTCP() Service {
21
return &TCP{
22
outPool: utils.OutPool{},
23
cfg: TCPArgs{},
24
}
25
}
26
func (s *TCP) InitService() {
27
s.InitOutConnPool()
28
}
29
func (s *TCP) StopService() {
30
if s.outPool.Pool != nil {
31
s.outPool.Pool.ReleaseAll()
32
}
33
}
34
func (s *TCP) Start(args interface{}) (err error) {
35
s.cfg = args.(TCPArgs)
36
if *s.cfg.Parent != "" {
37
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
38
} else {
39
log.Fatalf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local)
40
}
41
42
s.InitService()
43
44
host, port, _ := net.SplitHostPort(*s.cfg.Local)
45
p, _ := strconv.Atoi(port)
46
sc := utils.NewServerChannel(host, p)
47
if !*s.cfg.IsTLS {
48
err = sc.ListenTCP(s.callback)
49
} else {
50
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback)
51
}
52
if err != nil {
53
return
54
}
55
log.Printf("%s proxy on %s", s.cfg.Protocol(), (*sc.Listener).Addr())
56
return
57
}
58
59
func (s *TCP) Clean() {
60
s.StopService()
61
}
62
func (s *TCP) callback(inConn net.Conn) {
63
defer func() {
64
if err := recover(); err != nil {
65
log.Printf("%s conn handler crashed with err : %s \nstack: %s", s.cfg.Protocol(), err, string(debug.Stack()))
66
}
67
}()
68
var err error
69
switch *s.cfg.ParentType {
70
case TYPE_TCP:
71
fallthrough
72
case TYPE_TLS:
73
err = s.OutToTCP(&inConn)
74
case TYPE_UDP:
75
err = s.OutToUDP(&inConn)
76
default:
77
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
78
}
79
if err != nil {
80
log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
81
utils.CloseConn(&inConn)
82
}
83
}
84
func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
85
var outConn net.Conn
86
var _outConn interface{}
87
_outConn, err = s.outPool.Pool.Get()
88
if err == nil {
89
outConn = _outConn.(net.Conn)
90
}
91
if err != nil {
92
log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
93
utils.CloseConn(inConn)
94
return
95
}
96
inAddr := (*inConn).RemoteAddr().String()
97
inLocalAddr := (*inConn).LocalAddr().String()
98
outAddr := outConn.RemoteAddr().String()
99
outLocalAddr := outConn.LocalAddr().String()
100
utils.IoBind((*inConn), outConn, func(isSrcErr bool, err error) {
101
log.Printf("conn %s - %s - %s -%s released", inAddr, inLocalAddr, outLocalAddr, outAddr)
102
utils.CloseConn(inConn)
103
utils.CloseConn(&outConn)
104
}, func(n int, d bool) {}, 0)
105
log.Printf("conn %s - %s - %s -%s connected", inAddr, inLocalAddr, outLocalAddr, outAddr)
106
return
107
}
108
func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
109
log.Printf("conn created , remote : %s ", (*inConn).RemoteAddr())
110
for {
111
srcAddr, body, err := utils.ReadUDPPacket(inConn)
112
if err == io.EOF || err == io.ErrUnexpectedEOF {
113
//log.Printf("connection %s released", srcAddr)
114
utils.CloseConn(inConn)
115
break
116
}
117
//log.Debugf("udp packet revecived:%s,%v", srcAddr, body)
118
dstAddr, err := net.ResolveUDPAddr("udp", *s.cfg.Parent)
119
if err != nil {
120
log.Printf("can't resolve address: %s", err)
121
utils.CloseConn(inConn)
122
break
123
}
124
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
125
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
126
if err != nil {
127
log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
128
continue
129
}
130
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
131
_, err = conn.Write(body)
132
if err != nil {
133
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
134
continue
135
}
136
//log.Debugf("send udp packet to %s success", dstAddr.String())
137
buf := make([]byte, 512)
138
len, _, err := conn.ReadFromUDP(buf)
139
if err != nil {
140
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
141
continue
142
}
143
respBody := buf[0:len]
144
//log.Debugf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
145
_, err = (*inConn).Write(utils.UDPPacket(srcAddr, respBody))
146
if err != nil {
147
log.Printf("send udp response fail ,ERR:%s", err)
148
utils.CloseConn(inConn)
149
break
150
}
151
//log.Printf("send udp response success ,from:%s", dstAddr.String())
152
}
153
return
154
155
}
156
func (s *TCP) InitOutConnPool() {
157
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP {
158
//dur int, isTLS bool, certBytes, keyBytes []byte,
159
//parent string, timeout int, InitialCap int, MaxCap int
160
s.outPool = utils.NewOutPool(
161
*s.cfg.CheckParentInterval,
162
*s.cfg.ParentType == TYPE_TLS,
163
s.cfg.CertBytes, s.cfg.KeyBytes,
164
*s.cfg.Parent,
165
*s.cfg.Timeout,
166
*s.cfg.PoolSize,
167
*s.cfg.PoolSize*2,
168
)
169
}
170
}
171
172