@@ -15,7 +15,6 @@ import (
15
15
"github.com/celzero/firestack/intra/core"
16
16
"github.com/celzero/firestack/intra/log"
17
17
"github.com/celzero/firestack/intra/settings"
18
- "gvisor.dev/gvisor/pkg/tcpip"
19
18
20
19
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
21
20
@@ -30,7 +29,7 @@ type GUDPConnHandler interface {
30
29
// Proxy proxies data between conn (src) and dst.
31
30
Proxy (conn * GUDPConn , src , dst netip.AddrPort ) bool
32
31
// ProxyMux proxies data between conn and multiple destinations.
33
- ProxyMux (conn * GUDPConn , src netip.AddrPort ) bool
32
+ ProxyMux (conn * GUDPConn , src , dst netip.AddrPort ) bool
34
33
// Error notes the error in connecting src to dst.
35
34
Error (conn * GUDPConn , src , dst netip.AddrPort , err error )
36
35
// CloseConns closes conns by ids, or all if ids is empty.
@@ -42,21 +41,26 @@ type GUDPConnHandler interface {
42
41
var _ core.UDPConn = (* GUDPConn )(nil )
43
42
44
43
type GUDPConn struct {
45
- c * core.Volatile [* gonet.UDPConn ] // conn exposes UDP semantics atop endpoint
46
- ep * core.Volatile [tcpip.Endpoint ] // ep is the endpoint for netstack io
47
- src netip.AddrPort // local addr (remote addr in netstack)
48
- dst netip.AddrPort // remote addr (local addr in netstack)
49
- req * udp.ForwarderRequest // egress request as UDP
44
+ 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
49
+
50
+ eim bool // endpoint is muxed
51
+ eif bool // endpoint is transparent
50
52
}
51
53
52
54
// ref: github.com/google/gvisor/blob/e89e736f1/pkg/tcpip/adapters/gonet/gonet_test.go#L373
53
- func makeGUDPConn (r * udp.ForwarderRequest , src , dst netip.AddrPort ) * GUDPConn {
55
+ func makeGUDPConn (s * stack. Stack , r * udp.ForwarderRequest , src , dst netip.AddrPort ) * GUDPConn {
54
56
return & GUDPConn {
55
- c : core .NewZeroVolatile [* gonet.UDPConn ](),
56
- ep : core .NewZeroVolatile [tcpip.Endpoint ](),
57
- src : src ,
58
- dst : dst ,
59
- req : r ,
57
+ stack : s ,
58
+ c : core .NewZeroVolatile [* gonet.UDPConn ](),
59
+ src : src ,
60
+ dst : dst ,
61
+ req : r ,
62
+ eim : settings .EndpointIndependentMapping .Load (),
63
+ eif : settings .EndpointIndependentFiltering .Load (),
60
64
}
61
65
}
62
66
@@ -90,11 +94,11 @@ func udpForwarder(s *stack.Stack, h GUDPConnHandler) *udp.Forwarder {
90
94
// multiple dst in the unconnected udp case.
91
95
dst := localAddrPort (id )
92
96
93
- gc := makeGUDPConn (req , src , dst )
97
+ gc := makeGUDPConn (s , req , src , dst )
94
98
// setup to recv right away, so that netstack's internal state is consistent
95
99
// in case there are multiple forwarders dispatching from the TUN device.
96
100
if ! settings .SingleThreaded .Load () {
97
- if err := gc .tryConnect (); err != nil {
101
+ if err := gc .Establish (); err != nil {
98
102
log .E ("ns: udp: forwarder: connect: %v; src(%v) dst(%v)" , err , src , dst )
99
103
go h .Error (gc , src , dst , err )
100
104
return
@@ -103,10 +107,10 @@ func udpForwarder(s *stack.Stack, h GUDPConnHandler) *udp.Forwarder {
103
107
104
108
// proxy in a separate gorountine; return immediately
105
109
// why? netstack/dispatcher.go:newReadvDispatcher
106
- if gc .connected () { // gc is connected udp; proxy it like a stream
107
- go h .Proxy (gc , src , dst )
110
+ if gc .eim {
111
+ go h .ProxyMux (gc , src , dst )
108
112
} else {
109
- go h .ProxyMux (gc , src )
113
+ go h .Proxy (gc , src , dst )
110
114
}
111
115
})
112
116
}
@@ -119,17 +123,16 @@ func (g *GUDPConn) conn() *gonet.UDPConn {
119
123
return g .c .Load ()
120
124
}
121
125
122
- func (g * GUDPConn ) endpoint () tcpip.Endpoint {
123
- return g .ep .Load ()
124
- }
125
-
126
126
func (g * GUDPConn ) StatefulTeardown () (fin bool ) {
127
127
_ = g .tryConnect () // establish circuit then teardown
128
128
_ = g .Close () // then shutdown
129
129
return true // always fin
130
130
}
131
131
132
- func (g * GUDPConn ) Connect () error {
132
+ func (g * GUDPConn ) Establish () error {
133
+ if g .eif {
134
+ return g .tryBind ()
135
+ }
133
136
return g .tryConnect ()
134
137
}
135
138
@@ -139,18 +142,33 @@ func (g *GUDPConn) tryConnect() error {
139
142
}
140
143
141
144
wq := new (waiter.Queue )
142
- // use gonet.DialUDP instead?
143
145
if endpoint , err := g .req .CreateEndpoint (wq ); err != nil {
144
146
// ex: CONNECT endpoint for [fd66:f83a:c650::1]:15753 => [fd66:f83a:c650::3]:53; err(no route to host)
145
147
log .E ("ns: udp: connect: endpoint for %v => %v; err(%v)" , g .src , g .dst , err )
146
148
return e (err )
147
149
} else {
148
- g .ep .Store (endpoint )
149
150
g .c .Store (gonet .NewUDPConn (wq , endpoint ))
150
151
}
151
152
return nil
152
153
}
153
154
155
+ func (g * GUDPConn ) tryBind () error {
156
+ if g .ok () { // already setup
157
+ return nil
158
+ }
159
+
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
165
+ } else {
166
+ // todo: handle the first pkt like in g.req.CreateEndpoint
167
+ g .c .Store (conn )
168
+ }
169
+ return nil
170
+ }
171
+
154
172
func (g * GUDPConn ) LocalAddr () (addr net.Addr ) {
155
173
if c := g .conn (); c != nil {
156
174
addr = c .RemoteAddr ()
@@ -227,15 +245,8 @@ func (g *GUDPConn) SetWriteDeadline(t time.Time) error {
227
245
228
246
// Close closes the connection.
229
247
func (g * GUDPConn ) Close () error {
230
- if ep := g .endpoint (); ep != nil {
231
- ep .Abort ()
232
- }
233
248
if c := g .conn (); c != nil {
234
249
_ = c .Close ()
235
250
}
236
251
return nil
237
252
}
238
-
239
- func (g * GUDPConn ) connected () bool {
240
- return ! g .dst .Addr ().IsUnspecified ()
241
- }
0 commit comments