Skip to content

Commit 4b85621

Browse files
committed
update udp transparent proxy
1 parent bd9fc76 commit 4b85621

File tree

3 files changed

+63
-95
lines changed

3 files changed

+63
-95
lines changed

forward.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ func (l *tcpRemoteForwardListener) Close() error {
610610
type udpRemoteForwardListener struct {
611611
addr net.Addr
612612
chain *Chain
613-
connMap udpConnMap
613+
connMap *udpConnMap
614614
connChan chan net.Conn
615615
ln *net.UDPConn
616616
errChan chan error
@@ -640,6 +640,7 @@ func UDPRemoteForwardListener(addr string, chain *Chain, cfg *UDPListenConfig) (
640640
ln := &udpRemoteForwardListener{
641641
addr: laddr,
642642
chain: chain,
643+
connMap: new(udpConnMap),
643644
connChan: make(chan net.Conn, backlog),
644645
errChan: make(chan error, 1),
645646
closed: make(chan struct{}),

redirect.go

Lines changed: 58 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import (
66
"errors"
77
"fmt"
88
"net"
9+
"sync"
910
"syscall"
11+
"time"
1012

1113
"github.com/LiamHaworth/go-tproxy"
1214
"github.com/go-log/log"
@@ -121,17 +123,15 @@ func (h *udpRedirectHandler) Init(options ...HandlerOption) {
121123
}
122124
}
123125

124-
func (h *udpRedirectHandler) Handle(c net.Conn) {
125-
defer c.Close()
126+
func (h *udpRedirectHandler) Handle(conn net.Conn) {
127+
defer conn.Close()
126128

127-
conn, ok := c.(*udpRedirectServerConn)
129+
raddr, ok := conn.LocalAddr().(*net.UDPAddr)
128130
if !ok {
129-
log.Log("wrong connection type")
131+
log.Log("[red-udp] wrong connection type")
130132
return
131133
}
132134

133-
raddr := conn.DstAddr()
134-
135135
var cc net.Conn
136136
var err error
137137
if h.options.Chain.IsEmpty() {
@@ -167,11 +167,8 @@ func (h *udpRedirectHandler) Handle(c net.Conn) {
167167
}
168168

169169
type udpRedirectListener struct {
170-
ln *net.UDPConn
171-
connChan chan net.Conn
172-
errChan chan error
173-
connMap udpConnMap
174-
config *UDPListenConfig
170+
*net.UDPConn
171+
config *UDPListenConfig
175172
}
176173

177174
// UDPRedirectListener creates a Listener for UDP transparent proxy server.
@@ -189,103 +186,72 @@ func UDPRedirectListener(addr string, cfg *UDPListenConfig) (Listener, error) {
189186
if cfg == nil {
190187
cfg = &UDPListenConfig{}
191188
}
189+
return &udpRedirectListener{
190+
UDPConn: ln,
191+
config: cfg,
192+
}, nil
193+
}
192194

193-
backlog := cfg.Backlog
194-
if backlog <= 0 {
195-
backlog = defaultBacklog
196-
}
195+
func (l *udpRedirectListener) Accept() (conn net.Conn, err error) {
196+
b := make([]byte, mediumBufferSize)
197197

198-
l := &udpRedirectListener{
199-
ln: ln,
200-
connChan: make(chan net.Conn, backlog),
201-
errChan: make(chan error, 1),
202-
config: cfg,
198+
n, raddr, dstAddr, err := tproxy.ReadFromUDP(l.UDPConn, b)
199+
if err != nil {
200+
log.Logf("[red-udp] %s : %s", l.Addr(), err)
201+
return
203202
}
204-
go l.listenLoop()
205-
return l, nil
206-
}
203+
log.Logf("[red-udp] %s: %s -> %s", l.Addr(), raddr, dstAddr)
207204

208-
func (l *udpRedirectListener) listenLoop() {
209-
for {
210-
b := make([]byte, mediumBufferSize)
211-
n, raddr, dstAddr, err := tproxy.ReadFromUDP(l.ln, b)
212-
if err != nil {
213-
log.Logf("[red-udp] peer -> %s : %s", l.Addr(), err)
214-
l.Close()
215-
l.errChan <- err
216-
close(l.errChan)
217-
return
218-
}
219-
220-
conn, ok := l.connMap.Get(raddr.String())
221-
if !ok {
222-
conn = newUDPServerConn(l.ln, raddr, &udpServerConnConfig{
223-
ttl: l.config.TTL,
224-
qsize: l.config.QueueSize,
225-
onClose: func() {
226-
l.connMap.Delete(raddr.String())
227-
log.Logf("[red-udp] %s closed (%d)", raddr, l.connMap.Size())
228-
},
229-
})
230-
231-
cc := udpRedirectServerConn{
232-
udpServerConn: conn,
233-
dstAddr: dstAddr,
234-
}
235-
select {
236-
case l.connChan <- cc:
237-
l.connMap.Set(raddr.String(), conn)
238-
log.Logf("[red-udp] %s -> %s (%d)", raddr, l.Addr(), l.connMap.Size())
239-
default:
240-
conn.Close()
241-
log.Logf("[red-udp] %s - %s: connection queue is full (%d)",
242-
raddr, l.Addr(), cap(l.connChan))
243-
}
244-
}
205+
c, err := tproxy.DialUDP("udp", dstAddr, raddr)
206+
if err != nil {
207+
log.Logf("[red-udp] %s -> %s : %s", raddr, dstAddr, err)
208+
return
209+
}
245210

246-
select {
247-
case conn.rChan <- b[:n]:
248-
if Debug {
249-
log.Logf("[red-udp] %s >>> %s : length %d", raddr, l.Addr(), n)
250-
}
251-
default:
252-
log.Logf("[red-udp] %s -> %s : recv queue is full (%d)",
253-
raddr, l.Addr(), cap(conn.rChan))
254-
}
211+
ttl := l.config.TTL
212+
if ttl <= 0 {
213+
ttl = defaultTTL
255214
}
256-
}
257215

258-
func (l *udpRedirectListener) Accept() (conn net.Conn, err error) {
259-
var ok bool
260-
select {
261-
case conn = <-l.connChan:
262-
case err, ok = <-l.errChan:
263-
if !ok {
264-
err = errors.New("accpet on closed listener")
265-
}
216+
conn = &udpRedirectServerConn{
217+
Conn: c,
218+
buf: b[:n],
219+
ttl: ttl,
266220
}
267221
return
268222
}
269223

270224
func (l *udpRedirectListener) Addr() net.Addr {
271-
return l.ln.LocalAddr()
225+
return l.UDPConn.LocalAddr()
272226
}
273227

274-
func (l *udpRedirectListener) Close() error {
275-
err := l.ln.Close()
276-
l.connMap.Range(func(k interface{}, v *udpServerConn) bool {
277-
v.Close()
278-
return true
279-
})
280-
281-
return err
228+
type udpRedirectServerConn struct {
229+
net.Conn
230+
buf []byte
231+
ttl time.Duration
232+
once sync.Once
282233
}
283234

284-
type udpRedirectServerConn struct {
285-
*udpServerConn
286-
dstAddr *net.UDPAddr
235+
func (c *udpRedirectServerConn) Read(b []byte) (n int, err error) {
236+
if c.ttl > 0 {
237+
c.SetReadDeadline(time.Now().Add(c.ttl))
238+
defer c.SetReadDeadline(time.Time{})
239+
}
240+
c.once.Do(func() {
241+
n = copy(b, c.buf)
242+
c.buf = nil
243+
})
244+
245+
if n == 0 {
246+
n, err = c.Conn.Read(b)
247+
}
248+
return
287249
}
288250

289-
func (c *udpRedirectServerConn) DstAddr() *net.UDPAddr {
290-
return c.dstAddr
251+
func (c *udpRedirectServerConn) Write(b []byte) (n int, err error) {
252+
if c.ttl > 0 {
253+
c.SetWriteDeadline(time.Now().Add(c.ttl))
254+
defer c.SetWriteDeadline(time.Time{})
255+
}
256+
return c.Conn.Write(b)
291257
}

udp.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ type udpListener struct {
5454
ln net.PacketConn
5555
connChan chan net.Conn
5656
errChan chan error
57-
connMap udpConnMap
57+
connMap *udpConnMap
5858
config *UDPListenConfig
5959
}
6060

@@ -82,6 +82,7 @@ func UDPListener(addr string, cfg *UDPListenConfig) (Listener, error) {
8282
ln: ln,
8383
connChan: make(chan net.Conn, backlog),
8484
errChan: make(chan error, 1),
85+
connMap: new(udpConnMap),
8586
config: cfg,
8687
}
8788
go l.listenLoop()
@@ -159,8 +160,8 @@ func (l *udpListener) Close() error {
159160
}
160161

161162
type udpConnMap struct {
162-
m sync.Map
163163
size int64
164+
m sync.Map
164165
}
165166

166167
func (m *udpConnMap) Get(key interface{}) (conn *udpServerConn, ok bool) {

0 commit comments

Comments
 (0)