@@ -23,13 +23,20 @@ import (
23
23
"gvisor.dev/gvisor/pkg/waiter"
24
24
)
25
25
26
- var errMissingEp = errors .New ("not connected to any endpoint" )
26
+ var (
27
+ errMissingEp = errors .New ("not connected to any endpoint" )
28
+ errMissingReq = errors .New ("missing forwarder request" )
29
+ errFilteredOut = errors .New ("no eif; filtered out" )
30
+ )
31
+
32
+ type DemuxerFn func (dst netip.AddrPort ) error
27
33
28
34
type GUDPConnHandler interface {
29
35
// Proxy proxies data between conn (src) and dst.
30
36
Proxy (conn * GUDPConn , src , dst netip.AddrPort ) bool
31
- // ProxyMux proxies data between conn and multiple destinations.
32
- ProxyMux (conn * GUDPConn , src , dst netip.AddrPort ) bool
37
+ // ProxyMux proxies data between conn and multiple destinations
38
+ // (endpoint-independent mapping).
39
+ ProxyMux (conn * GUDPConn , src , dst netip.AddrPort , dmx DemuxerFn ) bool
33
40
// Error notes the error in connecting src to dst.
34
41
Error (conn * GUDPConn , src , dst netip.AddrPort , err error )
35
42
// CloseConns closes conns by ids, or all if ids is empty.
@@ -42,10 +49,17 @@ var _ core.UDPConn = (*GUDPConn)(nil)
42
49
43
50
type GUDPConn struct {
44
51
stack * stack.Stack
45
- c * core.Volatile [* gonet.UDPConn ] // conn exposes UDP semantics atop endpoint
46
- src netip.AddrPort // local addr (remote addr in netstack)
47
- dst netip.AddrPort // remote addr (local addr in netstack)
48
- req * udp.ForwarderRequest // egress request as UDP
52
+
53
+ // conn exposes UDP semantics atop endpoint
54
+ c * core.Volatile [* gonet.UDPConn ]
55
+ // local addr (remote addr in netstack)
56
+ // ex: 10.111.222.1:20716; same as endpoint.GetRemoteAddress
57
+ src netip.AddrPort
58
+ // remote addr (local addr in netstack)
59
+ // ex: 10.111.222.3:53; same as endpoint.GetLocalAddress
60
+ dst netip.AddrPort
61
+
62
+ req * udp.ForwarderRequest // egress request as UDP
49
63
50
64
eim bool // endpoint is muxed
51
65
eif bool // endpoint is transparent
@@ -85,6 +99,21 @@ func udpForwarder(s *stack.Stack, h GUDPConnHandler) *udp.Forwarder {
85
99
log .E ("ns: udp: forwarder: nil request" )
86
100
return
87
101
}
102
+
103
+ // owner app tun ns h
104
+ // repr socket packet endpoint socket
105
+ // type udp fd gudpconn core.minconn
106
+ //
107
+ // (src, dst) :1111, :53 :1111, :53 :53, :1111 :9999, :53
108
+ //
109
+ // write :1111 => :53 :1111, :53 :53 => :1111 :9999 => :53
110
+ // \ /
111
+ // \ /
112
+ // (pipe) \ /
113
+ // / \
114
+ // / \
115
+ // / \
116
+ // read :1111 <= :53 :1111, :53 :53 <= :1111 :9999 <= :53
88
117
id := req .ID ()
89
118
// src 10.111.222.1:20716; same as endpoint.GetRemoteAddress
90
119
src := remoteAddrPort (id )
@@ -105,10 +134,30 @@ func udpForwarder(s *stack.Stack, h GUDPConnHandler) *udp.Forwarder {
105
134
}
106
135
}
107
136
137
+ demux := func (newdst netip.AddrPort ) error {
138
+ if newdst == dst {
139
+ log .D ("ns: udp: demuxer: no-op; src(%v) same as dst(%v)" , src , newdst )
140
+ return nil
141
+ }
142
+ if ! gc .eif {
143
+ return errFilteredOut
144
+ }
145
+ newgc := makeGUDPConn (s , nil /*not a forwarder req*/ , src , newdst )
146
+ if ! settings .SingleThreaded .Load () {
147
+ if err := newgc .Establish (); err != nil {
148
+ log .E ("ns: udp: demuxer: dial: %v; src(%v) dst(%v)" , err , src , newdst )
149
+ go h .Error (newgc , src , newdst , err )
150
+ return err
151
+ }
152
+ }
153
+ go h .Proxy (newgc , src , newdst )
154
+ return nil
155
+ }
156
+
108
157
// proxy in a separate gorountine; return immediately
109
158
// why? netstack/dispatcher.go:newReadvDispatcher
110
159
if gc .eim {
111
- go h .ProxyMux (gc , src , dst )
160
+ go h .ProxyMux (gc , src , dst , demux )
112
161
} else {
113
162
go h .Proxy (gc , src , dst )
114
163
}
@@ -124,47 +173,35 @@ func (g *GUDPConn) conn() *gonet.UDPConn {
124
173
}
125
174
126
175
func (g * GUDPConn ) StatefulTeardown () (fin bool ) {
127
- _ = g .tryConnect () // establish circuit then teardown
128
- _ = g .Close () // then shutdown
129
- return true // always fin
176
+ _ = g .Establish () // establish circuit then teardown
177
+ _ = g .Close () // then shutdown
178
+ return true // always fin
130
179
}
131
180
132
181
func (g * GUDPConn ) Establish () error {
133
- if g .eif {
134
- return g .tryBind ()
135
- }
136
- return g .tryConnect ()
137
- }
138
-
139
- func (g * GUDPConn ) tryConnect () error {
140
- if g .ok () { // already setup
141
- return nil
142
- }
143
-
144
- wq := new (waiter.Queue )
145
- if endpoint , err := g .req .CreateEndpoint (wq ); err != nil {
146
- // ex: CONNECT endpoint for [fd66:f83a:c650::1]:15753 => [fd66:f83a:c650::3]:53; err(no route to host)
147
- log .E ("ns: udp: connect: endpoint for %v => %v; err(%v)" , g .src , g .dst , err )
148
- return e (err )
149
- } else {
150
- g .c .Store (gonet .NewUDPConn (wq , endpoint ))
151
- }
152
- return nil
153
- }
154
-
155
- func (g * GUDPConn ) tryBind () error {
156
182
if g .ok () { // already setup
157
183
return nil
158
184
}
159
185
160
- src , proto := addrport2nsaddr (g .src )
161
- // unconnected socket w/ gonet.DialUDP
162
- if conn , err := gonet .DialUDP (g .stack , & src , nil , proto ); err != nil {
163
- log .E ("ns: udp: bind: endpoint for %v [=> %v]; err(%v)" , g .src , g .dst , err )
164
- return err
186
+ if g .req == nil {
187
+ src , proto := addrport2nsaddr (g .dst ) // remote addr is local addr in netstack
188
+ dst , _ := addrport2nsaddr (g .src ) // local addr is remote addr in netstack
189
+ // ingress socket w/ gonet.DialUDP
190
+ if conn , err := gonet .DialUDP (g .stack , & src , & dst , proto ); err != nil {
191
+ log .E ("ns: udp: dial: endpoint for %v => %v; err(%v)" , g .src , g .dst , err )
192
+ return err
193
+ } else {
194
+ g .c .Store (conn )
195
+ }
165
196
} else {
166
- // todo: handle the first pkt like in g.req.CreateEndpoint
167
- g .c .Store (conn )
197
+ wq := new (waiter.Queue )
198
+ if endpoint , err := g .req .CreateEndpoint (wq ); err != nil {
199
+ // ex: CONNECT endpoint for [fd66:f83a:c650::1]:15753 => [fd66:f83a:c650::3]:53; err(no route to host)
200
+ log .E ("ns: udp: connect: endpoint for %v => %v; err(%v)" , g .src , g .dst , err )
201
+ return e (err )
202
+ } else {
203
+ g .c .Store (gonet .NewUDPConn (wq , endpoint ))
204
+ }
168
205
}
169
206
return nil
170
207
}
@@ -196,7 +233,14 @@ func (g *GUDPConn) Write(data []byte) (int, error) {
196
233
// ep(state 3 / info &{2048 17 {53 10.111.222.3 17711 10.111.222.1} 1 10.111.222.3 1} / stats &{{{1}} {{0}} {{{0}} {{0}} {{0}} {{0}}} {{{0}} {{0}} {{0}}} {{{0}} {{0}}} {{{0}} {{0}} {{0}}}})
197
234
// 3: status:datagram-connected / {2048=>proto, 17=>transport, {53=>local-port localip 17711=>remote-port remoteip}=>endpoint-id, 1=>bind-nic-id, ip=>bind-addr, 1=>registered-nic-id}
198
235
// g.ep may be nil: log.V("ns: writeFrom: from(%v) / ep(state %v / info %v / stats %v)", addr, g.ep.State(), g.ep.Info(), g.ep.Stats())
199
- return c .Write (data )
236
+ if g .eif {
237
+ // unexpected except in cases of DNS override;
238
+ // forward the packet to the dst as got from the first pkt
239
+ log .W ("ns: udp: Write(To): unexpected; %s <= %s; sz: %d" , g .src , g .dst , len (data ))
240
+ return c .WriteTo (data , net .UDPAddrFromAddrPort (g .dst ))
241
+ } else {
242
+ return c .Write (data )
243
+ }
200
244
}
201
245
return 0 , netError (g , "udp" , "write" , io .ErrClosedPipe )
202
246
}
0 commit comments