Skip to content

Commit 4c3020c

Browse files
authored
TUN inbound: Fix UDP FullCone NAT (#5888)
Fixes #5845
1 parent ba88aa1 commit 4c3020c

2 files changed

Lines changed: 102 additions & 44 deletions

File tree

proxy/tun/stack_gvisor.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,23 @@ func (t *stackGVisor) Start() error {
105105
// Use custom UDP packet handler, instead of strict gVisor forwarder, for FullCone NAT support
106106
udpForwarder := newUdpConnectionHandler(t.handler.HandleConnection, t.writeRawUDPPacket)
107107
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, func(id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool {
108-
data := pkt.Data().AsRange().ToSlice()
109-
if len(data) == 0 {
110-
return false
111-
}
108+
data := pkt.Clone().Data().AsRange().ToSlice()
109+
// if len(data) == 0 {
110+
// return false
111+
// }
112112
// source/destination of the packet we process as incoming, on gVisor side are Remote/Local
113113
// in other terms, src is the side behind tun, dst is the side behind gVisor
114114
// this function handle packets passing from the tun to the gVisor, therefore the src/dst assignement
115-
src := net.UDPDestination(net.IPAddress(id.RemoteAddress.AsSlice()), net.Port(id.RemotePort))
116-
dst := net.UDPDestination(net.IPAddress(id.LocalAddress.AsSlice()), net.Port(id.LocalPort))
117-
118-
return udpForwarder.HandlePacket(src, dst, data)
115+
srcIP := net.IPAddress(id.RemoteAddress.AsSlice())
116+
dstIP := net.IPAddress(id.LocalAddress.AsSlice())
117+
if srcIP == nil || dstIP == nil {
118+
errors.LogDebug(context.Background(), "drop udp with size ", len(data), " > invalid ip address ", id.RemoteAddress.AsSlice(), " ", id.LocalAddress.AsSlice())
119+
return true
120+
}
121+
src := net.UDPDestination(srcIP, net.Port(id.RemotePort))
122+
dst := net.UDPDestination(dstIP, net.Port(id.LocalPort))
123+
udpForwarder.HandlePacket(src, dst, data)
124+
return true
119125
})
120126

121127
t.stack = ipStack

proxy/tun/udp_fullcone.go

Lines changed: 88 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
package tun
22

33
import (
4+
"context"
45
"io"
56
"sync"
7+
"time"
68

79
"github.com/xtls/xray-core/common/buf"
10+
"github.com/xtls/xray-core/common/errors"
811
"github.com/xtls/xray-core/common/net"
912
)
1013

14+
type packet struct {
15+
data []byte
16+
dest *net.Destination
17+
}
18+
1119
// sub-handler specifically for udp connections under main handler
1220
type udpConnectionHandler struct {
13-
sync.Mutex
21+
sync.RWMutex
1422

1523
udpConns map[net.Destination]*udpConn
1624

@@ -30,25 +38,44 @@ func newUdpConnectionHandler(handleConnection func(conn net.Conn, dest net.Desti
3038

3139
// HandlePacket handles UDP packets coming from tun, to forward to the dispatcher
3240
// this custom handler support FullCone NAT of returning packets, binding connection only by the source addr:port
33-
func (u *udpConnectionHandler) HandlePacket(src net.Destination, dst net.Destination, data []byte) bool {
34-
u.Lock()
41+
func (u *udpConnectionHandler) HandlePacket(src net.Destination, dst net.Destination, data []byte) {
42+
u.RLock()
3543
conn, found := u.udpConns[src]
44+
if found {
45+
select {
46+
case conn.egress <- &packet{
47+
data: data,
48+
dest: &dst,
49+
}:
50+
default:
51+
errors.LogDebug(context.Background(), "drop udp with size ", len(data), " to ", dst.NetAddr(), " original ", conn.dst.NetAddr(), " > queue full")
52+
}
53+
u.RUnlock()
54+
return
55+
}
56+
u.RUnlock()
57+
58+
u.Lock()
59+
defer u.Unlock()
60+
61+
conn, found = u.udpConns[src]
3662
if !found {
37-
egress := make(chan []byte, 16)
63+
egress := make(chan *packet, 1024)
3864
conn = &udpConn{handler: u, egress: egress, src: src, dst: dst}
3965
u.udpConns[src] = conn
4066

4167
go u.handleConnection(conn, dst)
4268
}
43-
u.Unlock()
4469

4570
// send packet data to the egress channel, if it has buffer, or discard
4671
select {
47-
case conn.egress <- data:
72+
case conn.egress <- &packet{
73+
data: data,
74+
dest: &dst,
75+
}:
4876
default:
77+
errors.LogDebug(context.Background(), "drop udp with size ", len(data), " to ", dst.NetAddr(), " original ", conn.dst.NetAddr(), " > queue full")
4978
}
50-
51-
return true
5279
}
5380

5481
func (u *udpConnectionHandler) connectionFinished(src net.Destination) {
@@ -63,27 +90,64 @@ func (u *udpConnectionHandler) connectionFinished(src net.Destination) {
6390

6491
// udp connection abstraction
6592
type udpConn struct {
66-
net.Conn
67-
buf.Writer
68-
6993
handler *udpConnectionHandler
7094

71-
egress chan []byte
95+
egress chan *packet
7296
src net.Destination
7397
dst net.Destination
7498
}
7599

100+
func (c *udpConn) ReadMultiBuffer() (buf.MultiBuffer, error) {
101+
for {
102+
e, ok := <-c.egress
103+
if !ok {
104+
return nil, io.EOF
105+
}
106+
107+
b := buf.New()
108+
109+
_, err := b.Write(e.data)
110+
if err != nil {
111+
errors.LogDebugInner(context.Background(), err, "drop udp with size ", len(e.data), " to ", e.dest.NetAddr(), " original ", c.dst.NetAddr())
112+
b.Release()
113+
continue
114+
}
115+
116+
b.UDP = e.dest
117+
118+
return buf.MultiBuffer{b}, nil
119+
}
120+
}
121+
76122
// Read packets from the connection
77123
func (c *udpConn) Read(p []byte) (int, error) {
78-
data, ok := <-c.egress
124+
e, ok := <-c.egress
79125
if !ok {
80126
return 0, io.EOF
81127
}
82-
83-
n := copy(p, data)
128+
n := copy(p, e.data)
129+
if n != len(e.data) {
130+
return 0, io.ErrShortBuffer
131+
}
84132
return n, nil
85133
}
86134

135+
func (c *udpConn) WriteMultiBuffer(mb buf.MultiBuffer) error {
136+
for i, b := range mb {
137+
dst := c.dst
138+
if b.UDP != nil {
139+
dst = *b.UDP
140+
}
141+
err := c.handler.writePacket(b.Bytes(), dst, c.src)
142+
if err != nil {
143+
buf.ReleaseMulti(mb[i:])
144+
return err
145+
}
146+
b.Release()
147+
}
148+
return nil
149+
}
150+
87151
// Write returning packets back
88152
func (c *udpConn) Write(p []byte) (int, error) {
89153
// sending packets back mean sending payload with source/destination reversed
@@ -102,33 +166,21 @@ func (c *udpConn) Close() error {
102166
}
103167

104168
func (c *udpConn) LocalAddr() net.Addr {
105-
return &net.UDPAddr{IP: c.dst.Address.IP(), Port: int(c.dst.Port.Value())}
169+
return c.dst.RawNetAddr()
106170
}
107171

108172
func (c *udpConn) RemoteAddr() net.Addr {
109-
return &net.UDPAddr{IP: c.src.Address.IP(), Port: int(c.src.Port.Value())}
173+
return c.src.RawNetAddr()
110174
}
111175

112-
// Write returning packets back
113-
func (c *udpConn) WriteMultiBuffer(mb buf.MultiBuffer) error {
114-
for _, b := range mb {
115-
dst := c.dst
116-
if b.UDP != nil {
117-
dst = *b.UDP
118-
}
119-
120-
// validate address family matches between buffer packet and the connection
121-
if dst.Address.Family() != c.dst.Address.Family() {
122-
continue
123-
}
176+
func (c *udpConn) SetDeadline(t time.Time) error {
177+
return nil
178+
}
124179

125-
// sending packets back mean sending payload with source/destination reversed
126-
err := c.handler.writePacket(b.Bytes(), dst, c.src)
127-
if err != nil {
128-
// udp doesn't guarantee delivery, so in any failure we just continue to the next packet
129-
continue
130-
}
131-
}
180+
func (c *udpConn) SetReadDeadline(t time.Time) error {
181+
return nil
182+
}
132183

184+
func (c *udpConn) SetWriteDeadline(t time.Time) error {
133185
return nil
134186
}

0 commit comments

Comments
 (0)