5
5
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6
6
// option. This file may not be copied, modified, or distributed
7
7
// except according to those terms.
8
-
9
8
use std:: fmt;
10
9
use std:: io:: { self , Read , Write } ;
11
10
#[ cfg( not( target_os = "redox" ) ) ]
@@ -19,6 +18,10 @@ use std::os::unix::io::{FromRawFd, IntoRawFd};
19
18
#[ cfg( windows) ]
20
19
use std:: os:: windows:: io:: { FromRawSocket , IntoRawSocket } ;
21
20
use std:: time:: Duration ;
21
+ #[ cfg( all( windows, feature = "all" ) ) ]
22
+ use windows_sys:: Win32 :: Networking :: WinSock :: {
23
+ IP6T_SO_ORIGINAL_DST , SOCKET_ERROR , SOL_IP , SO_ORIGINAL_DST ,
24
+ } ;
22
25
23
26
use crate :: sys:: { self , c_int, getsockopt, setsockopt, Bool } ;
24
27
#[ cfg( all( unix, not( target_os = "redox" ) ) ) ]
@@ -27,6 +30,38 @@ use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
27
30
#[ cfg( not( target_os = "redox" ) ) ]
28
31
use crate :: { MaybeUninitSlice , MsgHdr , RecvFlags } ;
29
32
33
+ #[ cfg( all( windows, feature = "all" ) ) ]
34
+ #[ cfg_attr( docsrs, doc( cfg( all( windows, feature = "all" ) ) ) ) ]
35
+ /// Helper macro to execute a system call that returns an `io::Result`.
36
+ macro_rules! syscall {
37
+ ( $fn: ident ( $( $arg: expr) ,* $( , ) * ) , $err_test: path, $err_value: expr) => { {
38
+ #[ allow( unused_unsafe) ]
39
+ let res = unsafe { windows_sys:: Win32 :: Networking :: WinSock :: $fn( $( $arg, ) * ) } ;
40
+ if $err_test( & res, & $err_value) {
41
+ Err ( io:: Error :: last_os_error( ) )
42
+ } else {
43
+ Ok ( res)
44
+ }
45
+ } } ;
46
+ }
47
+
48
+ #[ cfg( all(
49
+ feature = "all" ,
50
+ any( target_os = "android" , target_os = "fuchsia" , target_os = "linux" , )
51
+ ) ) ]
52
+ /// Helper macro to execute a system call that returns an `io::Result`.
53
+ macro_rules! syscall {
54
+ ( $fn: ident ( $( $arg: expr) ,* $( , ) * ) ) => { {
55
+ #[ allow( unused_unsafe) ]
56
+ let res = unsafe { libc:: $fn( $( $arg, ) * ) } ;
57
+ if res == -1 {
58
+ Err ( std:: io:: Error :: last_os_error( ) )
59
+ } else {
60
+ Ok ( res)
61
+ }
62
+ } } ;
63
+ }
64
+
30
65
/// Owned wrapper around a system socket.
31
66
///
32
67
/// This type simply wraps an instance of a file descriptor (`c_int`) on Unix
@@ -2205,6 +2240,120 @@ impl Socket {
2205
2240
)
2206
2241
}
2207
2242
}
2243
+
2244
+ /// Get the value for the `SO_ORIGINAL_DST` option on this socket.
2245
+ ///
2246
+ /// This value contains the original destination IPv4 address of the connection
2247
+ /// redirected using `iptables` `REDIRECT` or `TPROXY`.
2248
+ #[ cfg( all(
2249
+ feature = "all" ,
2250
+ any( target_os = "android" , target_os = "fuchsia" , target_os = "linux" , )
2251
+ ) ) ]
2252
+ #[ cfg_attr(
2253
+ docsrs,
2254
+ doc( cfg( all(
2255
+ feature = "all" ,
2256
+ any( target_os = "android" , target_os = "fuchsia" , target_os = "linux" , )
2257
+ ) ) )
2258
+ ) ]
2259
+ pub fn original_dst ( & self ) -> io:: Result < SockAddr > {
2260
+ // Safety: `getsockopt` initialises the `SockAddr` for us.
2261
+ unsafe {
2262
+ SockAddr :: try_init ( |storage, len| {
2263
+ syscall ! ( getsockopt(
2264
+ self . as_raw( ) ,
2265
+ libc:: SOL_IP ,
2266
+ libc:: SO_ORIGINAL_DST ,
2267
+ storage. cast( ) ,
2268
+ len
2269
+ ) )
2270
+ } )
2271
+ }
2272
+ . map ( |( _, addr) | addr)
2273
+ }
2274
+
2275
+ /// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket.
2276
+ ///
2277
+ /// This value contains the original destination IPv6 address of the connection
2278
+ /// redirected using `ip6tables` `REDIRECT` or `TPROXY`.
2279
+ #[ cfg( all( feature = "all" , any( target_os = "android" , target_os = "linux" , ) ) ) ]
2280
+ #[ cfg_attr(
2281
+ docsrs,
2282
+ doc( cfg( all( feature = "all" , any( target_os = "android" , target_os = "linux" , ) ) ) )
2283
+ ) ]
2284
+ pub fn original_dst_ipv6 ( & self ) -> io:: Result < SockAddr > {
2285
+ // Safety: `getsockopt` initialises the `SockAddr` for us.
2286
+ unsafe {
2287
+ SockAddr :: try_init ( |storage, len| {
2288
+ syscall ! ( getsockopt(
2289
+ self . as_raw( ) ,
2290
+ libc:: SOL_IPV6 ,
2291
+ libc:: IP6T_SO_ORIGINAL_DST ,
2292
+ storage. cast( ) ,
2293
+ len
2294
+ ) )
2295
+ } )
2296
+ }
2297
+ . map ( |( _, addr) | addr)
2298
+ }
2299
+
2300
+ /// Get the value for the `SO_ORIGINAL_DST` option on this socket.
2301
+ /// Only valid for sockets in accepting mode.
2302
+ ///
2303
+ /// Note: if using this function in a proxy context, you must query the
2304
+ /// redirect records for this socket and set them on the outbound socket
2305
+ /// created by your proxy in order for any OS level firewall rules to be
2306
+ /// applied. Read more in the Windows bind and connect redirection
2307
+ /// [documentation](https://learn.microsoft.com/en-us/windows-hardware/drivers/network/using-bind-or-connect-redirection).
2308
+ #[ cfg( all( windows, feature = "all" ) ) ]
2309
+ #[ cfg_attr( docsrs, doc( cfg( all( windows, feature = "all" ) ) ) ) ]
2310
+ pub fn original_dst ( & self ) -> io:: Result < SockAddr > {
2311
+ unsafe {
2312
+ SockAddr :: try_init ( |storage, len| {
2313
+ syscall ! (
2314
+ getsockopt(
2315
+ self . as_raw( ) ,
2316
+ SOL_IP as i32 ,
2317
+ SO_ORIGINAL_DST as i32 ,
2318
+ storage. cast( ) ,
2319
+ len,
2320
+ ) ,
2321
+ PartialEq :: eq,
2322
+ SOCKET_ERROR
2323
+ )
2324
+ } )
2325
+ }
2326
+ . map ( |( _, addr) | addr)
2327
+ }
2328
+
2329
+ /// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket.
2330
+ /// Only valid for sockets in accepting mode.
2331
+ ///
2332
+ /// Note: if using this function in a proxy context, you must query the
2333
+ /// redirect records for this socket and set them on the outbound socket
2334
+ /// created by your proxy in order for any OS level firewall rules to be
2335
+ /// applied. Read more in the Windows bind and connect redirection
2336
+ /// [documentation](https://learn.microsoft.com/en-us/windows-hardware/drivers/network/using-bind-or-connect-redirection).
2337
+ #[ cfg( all( windows, feature = "all" ) ) ]
2338
+ #[ cfg_attr( docsrs, doc( cfg( all( windows, feature = "all" ) ) ) ) ]
2339
+ pub fn original_dst_ipv6 ( & self ) -> io:: Result < SockAddr > {
2340
+ unsafe {
2341
+ SockAddr :: try_init ( |storage, len| {
2342
+ syscall ! (
2343
+ getsockopt(
2344
+ self . as_raw( ) ,
2345
+ SOL_IP as i32 ,
2346
+ IP6T_SO_ORIGINAL_DST as i32 ,
2347
+ storage. cast( ) ,
2348
+ len,
2349
+ ) ,
2350
+ PartialEq :: eq,
2351
+ SOCKET_ERROR
2352
+ )
2353
+ } )
2354
+ }
2355
+ . map ( |( _, addr) | addr)
2356
+ }
2208
2357
}
2209
2358
2210
2359
impl Read for Socket {
0 commit comments