- Notifications
You must be signed in to change notification settings - Fork 26
Expand file tree
/
Copy pathtcpproxy.go
More file actions
Latest commit
156 lines (134 loc) · 3.53 KB
/
Copy pathtcpproxy.go
File metadata and controls
156 lines (134 loc) · 3.53 KB
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
149
150
151
152
153
154
155
156
package tcpproxy
import (
"crypto/tls"
"fmt"
"net"
"os"
"sync/atomic"
"time"
)
// Proxy is a TCP server that takes an incoming request and sends it to another
// server, proxying the response back to the client.
typeProxystruct {
// Target address
Target*net.TCPAddr
// Local address
Addr*net.TCPAddr
// Director must be a function which modifies the request into a new request
// to be sent. Its response is then copied back to the client unmodified.
Directorfunc(b*[]byte)
// If config is not nil, the proxy connects to the target address and then
// initiates a TLS handshake.
Config*tls.Config
// Timeout is the duration the proxy is staying alive without activity from
// both client and target. Also, if a pipe is closed, the proxy waits 'timeout'
// seconds before closing the other one. By default timeout is 60 seconds.
Timeout time.Duration
}
// NewProxy created a new proxy which sends all packet to target. The function dir
// intercept and can change the packet before sending it to the target.
funcNewProxy(target*net.TCPAddr, dirfunc(*[]byte), config*tls.Config) *Proxy {
p:=&Proxy{
Target: target,
Director: dir,
Timeout: time.Minute,
Config: config,
}
returnp
}
// ListenAndServe listens on the TCP network address laddr and then handle packets
// on incoming connections.
func (p*Proxy) ListenAndServe(laddr*net.TCPAddr) {
p.Addr=laddr
varlistener net.Listener
listener, err:=net.ListenTCP("tcp", laddr)
iferr!=nil {
fmt.Println(err)
os.Exit(1)
}
p.serve(listener)
}
// ListenAndServeTLS acts identically to ListenAndServe, except that it uses TLS
// protocol. Additionally, files containing a certificate and matching private key
// for the server must be provided.
func (p*Proxy) ListenAndServeTLS(laddr*net.TCPAddr, certFile, keyFilestring) {
p.Addr=laddr
varlistener net.Listener
cer, err:=tls.LoadX509KeyPair(certFile, keyFile)
iferr!=nil {
fmt.Println(err)
return
}
config:=&tls.Config{Certificates: []tls.Certificate{cer}}
listener, err=tls.Listen("tcp", laddr.String(), config)
iferr!=nil {
fmt.Println(err)
return
}
p.serve(listener)
}
func (p*Proxy) serve(ln net.Listener) {
for {
conn, err:=ln.Accept()
iferr!=nil {
fmt.Println(err)
continue
}
gop.handleConn(conn)
}
}
// handleConn handles connection.
func (p*Proxy) handleConn(conn net.Conn) {
// connects to target server
varrconn net.Conn
varerrerror
ifp.Config==nil {
rconn, err=net.Dial("tcp", p.Target.String())
} else {
rconn, err=tls.Dial("tcp", p.Target.String(), p.Config)
}
iferr!=nil {
fmt.Println(err)
return
}
// pipeDone counts closed pipe
varpipeDoneint32
vartimer*time.Timer
// write to dst what it reads from src
varpipe=func(src, dst net.Conn, filterfunc(b*[]byte)) {
deferfunc() {
// if it is the first pipe to end...
ifv:=atomic.AddInt32(&pipeDone, 1); v==1 {
// ...wait 'timeout' seconds before closing connections
timer=time.AfterFunc(p.Timeout, func() {
// test if the other pipe is still alive before closing conn
ifatomic.AddInt32(&pipeDone, 1) ==2 {
conn.Close()
rconn.Close()
}
})
} elseifv==2 {
conn.Close()
rconn.Close()
timer.Stop()
}
}()
buff:=make([]byte, 65535)
for {
n, err:=src.Read(buff)
iferr!=nil {
return
}
b:=buff[:n]
iffilter!=nil {
filter(&b)
}
n, err=dst.Write(b)
iferr!=nil {
return
}
}
}
gopipe(conn, rconn, p.Director)
gopipe(rconn, conn, nil)
}