@@ -101,124 +101,133 @@ impl UdpInboundWrite for UdpRedirInboundWriter {
101
101
// then we should always use IPv6 sockets for sending IPv4 packets.
102
102
static SUPPORT_IPV6_TRANSPARENT : AtomicBool = AtomicBool :: new ( true ) ;
103
103
104
- #[ allow( unused_mut) ]
105
- let mut addr = match * remote_addr {
106
- Address :: SocketAddress ( sa) => {
107
- if SUPPORT_IPV6_TRANSPARENT . load ( Ordering :: Relaxed ) {
108
- match sa {
109
- // Converts IPv4 address to IPv4-mapped-IPv6
110
- // All sockets will be created in IPv6 (nearly all modern OS supports IPv6 sockets)
111
- SocketAddr :: V4 ( ref v4) => SocketAddr :: new ( v4. ip ( ) . to_ipv6_mapped ( ) . into ( ) , v4. port ( ) ) ,
112
- SocketAddr :: V6 ( ..) => sa,
113
- }
114
- } else {
115
- match sa {
116
- // Converts IPv4-mapped-IPv6 to IPv4
117
- SocketAddr :: V4 ( ..) => sa,
118
- SocketAddr :: V6 ( ref v6) => match v6. ip ( ) . to_ipv4_mapped ( ) {
119
- Some ( v4) => SocketAddr :: new ( v4. into ( ) , v6. port ( ) ) ,
120
- None => sa,
121
- } ,
104
+ loop {
105
+ let mut addr_mapped_ipv6 = false ;
106
+
107
+ let addr = match * remote_addr {
108
+ Address :: SocketAddress ( sa) => {
109
+ if SUPPORT_IPV6_TRANSPARENT . load ( Ordering :: Relaxed ) {
110
+ match sa {
111
+ // Converts IPv4 address to IPv4-mapped-IPv6
112
+ // All sockets will be created in IPv6 (nearly all modern OS supports IPv6 sockets)
113
+ SocketAddr :: V4 ( ref v4) => {
114
+ addr_mapped_ipv6 = true ;
115
+ SocketAddr :: new ( v4. ip ( ) . to_ipv6_mapped ( ) . into ( ) , v4. port ( ) )
116
+ }
117
+ SocketAddr :: V6 ( ..) => sa,
118
+ }
119
+ } else {
120
+ match sa {
121
+ // Converts IPv4-mapped-IPv6 to IPv4
122
+ SocketAddr :: V4 ( ..) => sa,
123
+ SocketAddr :: V6 ( ref v6) => match v6. ip ( ) . to_ipv4_mapped ( ) {
124
+ Some ( v4) => SocketAddr :: new ( v4. into ( ) , v6. port ( ) ) ,
125
+ None => sa,
126
+ } ,
127
+ }
122
128
}
123
129
}
124
- }
125
- Address :: DomainNameAddress ( ..) => {
126
- let err = io:: Error :: new (
127
- ErrorKind :: InvalidInput ,
128
- "redir destination must not be an domain name address" ,
129
- ) ;
130
- return Err ( err) ;
131
- }
132
- } ;
133
-
134
- let inbound = {
135
- let mut cache = self . inbound_cache . cache . lock ( ) . await ;
136
- if let Some ( socket) = cache. get ( & addr) {
137
- socket. clone ( )
138
- } else {
139
- // Create a socket binds to destination addr
140
- // This only works for systems that supports binding to non-local addresses
141
- //
142
- // This socket has to set SO_REUSEADDR and SO_REUSEPORT.
143
- // Outbound addresses could be connected from different source addresses.
144
- let inbound = match UdpRedirSocket :: bind_nonlocal ( self . redir_ty , addr, & self . socket_opts ) {
145
- Ok ( s) => s,
146
- #[ cfg( unix) ]
147
- Err ( err) => match err. raw_os_error ( ) {
148
- None => return Err ( err) ,
149
- // https://github.com/shadowsocks/shadowsocks-rust/issues/988
150
- // IPV6_TRANSPARENT was supported since 2.6.37.
151
- Some ( libc:: ENOPROTOOPT ) if addr. is_ipv6 ( ) => {
152
- SUPPORT_IPV6_TRANSPARENT . store ( false , Ordering :: Relaxed ) ;
130
+ Address :: DomainNameAddress ( ..) => {
131
+ let err = io:: Error :: new (
132
+ ErrorKind :: InvalidInput ,
133
+ "redir destination must not be an domain name address" ,
134
+ ) ;
135
+ return Err ( err) ;
136
+ }
137
+ } ;
153
138
154
- addr = match * remote_addr {
155
- Address :: SocketAddress ( sa) => {
156
- match sa {
157
- // Converts IPv4-mapped-IPv6 to IPv4
158
- SocketAddr :: V4 ( ..) => sa,
159
- SocketAddr :: V6 ( ref v6) => match v6. ip ( ) . to_ipv4_mapped ( ) {
160
- Some ( v4) => SocketAddr :: new ( v4. into ( ) , v6. port ( ) ) ,
161
- None => return Err ( err) ,
162
- } ,
163
- }
164
- }
165
- Address :: DomainNameAddress ( ..) => unreachable ! ( ) ,
166
- } ;
167
-
168
- UdpRedirSocket :: bind_nonlocal ( self . redir_ty , addr, & self . socket_opts ) ?
169
- }
170
- Some ( _) => return Err ( err) ,
171
- } ,
172
- #[ cfg( not( unix) ) ]
173
- Err ( err) => return Err ( err) ,
174
- } ;
139
+ let inbound = {
140
+ let mut cache = self . inbound_cache . cache . lock ( ) . await ;
141
+ if let Some ( socket) = cache. get ( & addr) {
142
+ socket. clone ( )
143
+ } else {
144
+ // Create a socket binds to destination addr
145
+ // This only works for systems that supports binding to non-local addresses
146
+ //
147
+ // This socket has to set SO_REUSEADDR and SO_REUSEPORT.
148
+ // Outbound addresses could be connected from different source addresses.
149
+ let inbound = match UdpRedirSocket :: bind_nonlocal ( self . redir_ty , addr, & self . socket_opts ) {
150
+ Ok ( s) => s,
151
+ #[ cfg( unix) ]
152
+ Err ( err) => match err. raw_os_error ( ) {
153
+ None => return Err ( err) ,
154
+ // https://github.com/shadowsocks/shadowsocks-rust/issues/988
155
+ // IPV6_TRANSPARENT was supported since 2.6.37.
156
+ Some ( libc:: ENOPROTOOPT ) if addr_mapped_ipv6 => {
157
+ SUPPORT_IPV6_TRANSPARENT . store ( false , Ordering :: Relaxed ) ;
158
+ debug ! ( "redir destination socket doesn't support IPv6, addr cannot be IPv4-mapped-IPv6: {}" , addr) ;
159
+ continue ;
160
+ }
161
+ Some ( _) => return Err ( err) ,
162
+ } ,
163
+ #[ cfg( not( unix) ) ]
164
+ Err ( err) => return Err ( err) ,
165
+ } ;
175
166
176
- // UDP socket could be shared between threads and is safe to be manipulated by multiple threads
177
- let inbound = Arc :: new ( inbound) ;
178
- cache. insert ( addr, inbound. clone ( ) ) ;
167
+ // UDP socket could be shared between threads and is safe to be manipulated by multiple threads
168
+ let inbound = Arc :: new ( inbound) ;
169
+ cache. insert ( addr, inbound. clone ( ) ) ;
179
170
180
- inbound
171
+ inbound
172
+ }
173
+ } ;
174
+
175
+ match ( addr, peer_addr) {
176
+ ( SocketAddr :: V4 ( ..) , SocketAddr :: V4 ( ..) ) | ( SocketAddr :: V6 ( ..) , SocketAddr :: V6 ( ..) ) => { }
177
+ ( SocketAddr :: V4 ( ..) , SocketAddr :: V6 ( v6_peer_addr) ) => {
178
+ if let Some ( v4_ip) = v6_peer_addr. ip ( ) . to_ipv4_mapped ( ) {
179
+ peer_addr = SocketAddr :: new ( v4_ip. into ( ) , v6_peer_addr. port ( ) ) ;
180
+ } else {
181
+ warn ! (
182
+ "udp redir send back {} bytes, remote: {}, peer: {}, protocol not match" ,
183
+ data. len( ) ,
184
+ addr,
185
+ peer_addr
186
+ ) ;
187
+ }
188
+ }
189
+ ( SocketAddr :: V6 ( ..) , SocketAddr :: V4 ( v4_peer_addr) ) => {
190
+ peer_addr = SocketAddr :: new ( v4_peer_addr. ip ( ) . to_ipv6_mapped ( ) . into ( ) , v4_peer_addr. port ( ) ) ;
191
+ }
181
192
}
182
- } ;
183
193
184
- match ( addr, peer_addr) {
185
- ( SocketAddr :: V4 ( ..) , SocketAddr :: V4 ( ..) ) | ( SocketAddr :: V6 ( ..) , SocketAddr :: V6 ( ..) ) => { }
186
- ( SocketAddr :: V4 ( ..) , SocketAddr :: V6 ( v6_peer_addr) ) => {
187
- if let Some ( v4_ip) = v6_peer_addr. ip ( ) . to_ipv4_mapped ( ) {
188
- peer_addr = SocketAddr :: new ( v4_ip. into ( ) , v6_peer_addr. port ( ) ) ;
189
- } else {
194
+ let send_result = inbound. send_to ( data, peer_addr) . await . map ( |n| {
195
+ if n < data. len ( ) {
190
196
warn ! (
191
- "udp redir send back {} bytes, remote: {}, peer: {}, protocol not match" ,
197
+ "udp redir send back data (actual: {} bytes, sent: {} bytes), remote: {}, peer: {}" ,
198
+ n,
192
199
data. len( ) ,
193
- addr ,
200
+ remote_addr ,
194
201
peer_addr
195
202
) ;
196
203
}
197
- }
198
- ( SocketAddr :: V6 ( ..) , SocketAddr :: V4 ( v4_peer_addr) ) => {
199
- peer_addr = SocketAddr :: new ( v4_peer_addr. ip ( ) . to_ipv6_mapped ( ) . into ( ) , v4_peer_addr. port ( ) ) ;
200
- }
201
- }
202
204
203
- inbound. send_to ( data, peer_addr) . await . map ( |n| {
204
- if n < data. len ( ) {
205
- warn ! (
206
- "udp redir send back data (actual: {} bytes, sent: {} bytes), remote: {}, peer: {}" ,
205
+ trace ! (
206
+ "udp redir send back data {} bytes, remote: {}, peer: {}, socket_opts: {:?}" ,
207
207
n,
208
- data. len( ) ,
209
208
remote_addr,
210
- peer_addr
209
+ peer_addr,
210
+ self . socket_opts
211
211
) ;
212
+ } ) ;
213
+
214
+ match send_result {
215
+ Ok ( ( ) ) => return Ok ( ( ) ) ,
216
+ Err ( err) => {
217
+ match err. kind ( ) {
218
+ // Invalid Argument
219
+ ErrorKind :: InvalidInput if addr_mapped_ipv6 => {
220
+ SUPPORT_IPV6_TRANSPARENT . store ( false , Ordering :: Relaxed ) ;
221
+ debug ! (
222
+ "redir destination socket doesn't support IPv6, addr cannot be IPv4-mapped-IPv6: {}" ,
223
+ addr
224
+ ) ;
225
+ }
226
+ _ => return Err ( err) ,
227
+ }
228
+ }
212
229
}
213
-
214
- trace ! (
215
- "udp redir send back data {} bytes, remote: {}, peer: {}, socket_opts: {:?}" ,
216
- n,
217
- remote_addr,
218
- peer_addr,
219
- self . socket_opts
220
- ) ;
221
- } )
230
+ }
222
231
}
223
232
}
224
233
0 commit comments