timestamped_socket/
networkaddress.rs

1use std::{
2    net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
3    os::fd::RawFd,
4};
5
6use crate::{control_message::zeroed_sockaddr_storage, interface::InterfaceName};
7
8use self::sealed::{PrivateToken, SealedMC, SealedNA};
9
10#[cfg(target_os = "linux")]
11pub use self::linux::*;
12
13#[cfg(target_os = "linux")]
14mod linux;
15
16pub(crate) mod sealed {
17    // Seal to ensure NetworkAddress can't be implemented outside our crate
18    pub trait SealedNA {}
19
20    // Seal to ensure MulticastJoinable can't be implemented outside our crate
21    pub trait SealedMC {}
22
23    // Token to ensure trait functions cannot be called outside our crate
24    pub struct PrivateToken;
25}
26
27pub trait NetworkAddress: Sized + SealedNA {
28    #[doc(hidden)]
29    fn to_sockaddr(&self, _token: PrivateToken) -> libc::sockaddr_storage;
30    #[doc(hidden)]
31    fn from_sockaddr(addr: libc::sockaddr_storage, _token: PrivateToken) -> Option<Self>;
32}
33
34pub trait MulticastJoinable: NetworkAddress + SealedMC {
35    #[doc(hidden)]
36    fn join_multicast(
37        &self,
38        socket: RawFd,
39        interface: InterfaceName,
40        _token: PrivateToken,
41    ) -> std::io::Result<()>;
42    #[doc(hidden)]
43    fn leave_multicast(
44        &self,
45        socket: RawFd,
46        interface: InterfaceName,
47        _token: PrivateToken,
48    ) -> std::io::Result<()>;
49}
50
51impl SealedNA for SocketAddrV4 {}
52
53impl NetworkAddress for SocketAddrV4 {
54    fn to_sockaddr(&self, _token: PrivateToken) -> libc::sockaddr_storage {
55        const _: () = assert!(
56            std::mem::size_of::<libc::sockaddr_storage>()
57                >= std::mem::size_of::<libc::sockaddr_in>()
58        );
59        const _: () = assert!(
60            std::mem::align_of::<libc::sockaddr_storage>()
61                >= std::mem::align_of::<libc::sockaddr_in>()
62        );
63
64        let mut result = zeroed_sockaddr_storage();
65        // Safety: the above assertions guarantee that alignment and size are correct.
66        // the resulting reference won't outlast the function, and result lives the entire
67        // duration of the function
68        let out = unsafe { &mut (*(&mut result as *mut _ as *mut libc::sockaddr_in)) };
69        out.sin_family = libc::AF_INET as _;
70        out.sin_port = u16::from_ne_bytes(self.port().to_be_bytes());
71        out.sin_addr = libc::in_addr {
72            s_addr: u32::from_ne_bytes(self.ip().octets()),
73        };
74
75        result
76    }
77
78    fn from_sockaddr(addr: libc::sockaddr_storage, _token: PrivateToken) -> Option<Self> {
79        const _: () = assert!(
80            std::mem::size_of::<libc::sockaddr_storage>()
81                >= std::mem::size_of::<libc::sockaddr_in>()
82        );
83        const _: () = assert!(
84            std::mem::align_of::<libc::sockaddr_storage>()
85                >= std::mem::align_of::<libc::sockaddr_in>()
86        );
87
88        if addr.ss_family != libc::AF_INET as _ {
89            return None;
90        }
91
92        // Safety: the above assertions guarantee that alignment and size are correct
93        // the resulting reference won't outlast the function, and addr lives the entire
94        // duration of the function
95        let input = unsafe { &(*(&addr as *const _ as *const libc::sockaddr_in)) };
96        Some(SocketAddrV4::new(
97            Ipv4Addr::from(input.sin_addr.s_addr.to_ne_bytes()),
98            u16::from_be_bytes(input.sin_port.to_ne_bytes()),
99        ))
100    }
101}
102
103impl SealedNA for SocketAddrV6 {}
104
105impl NetworkAddress for SocketAddrV6 {
106    fn to_sockaddr(&self, _token: PrivateToken) -> libc::sockaddr_storage {
107        const _: () = assert!(
108            std::mem::size_of::<libc::sockaddr_storage>()
109                >= std::mem::size_of::<libc::sockaddr_in6>()
110        );
111        const _: () = assert!(
112            std::mem::align_of::<libc::sockaddr_storage>()
113                >= std::mem::align_of::<libc::sockaddr_in6>()
114        );
115
116        let mut result = zeroed_sockaddr_storage();
117        // Safety: the above assertions guarantee that alignment and size are correct.
118        // the resulting reference won't outlast the function, and result lives the entire
119        // duration of the function
120        let out = unsafe { &mut (*(&mut result as *mut _ as *mut libc::sockaddr_in6)) };
121        out.sin6_family = libc::AF_INET6 as _;
122        out.sin6_port = u16::from_ne_bytes(self.port().to_be_bytes());
123        out.sin6_addr = libc::in6_addr {
124            s6_addr: self.ip().octets(),
125        };
126        out.sin6_flowinfo = self.flowinfo();
127        out.sin6_scope_id = self.scope_id();
128
129        result
130    }
131
132    fn from_sockaddr(addr: libc::sockaddr_storage, _token: PrivateToken) -> Option<Self> {
133        const _: () = assert!(
134            std::mem::size_of::<libc::sockaddr_storage>()
135                >= std::mem::size_of::<libc::sockaddr_in6>()
136        );
137        const _: () = assert!(
138            std::mem::align_of::<libc::sockaddr_storage>()
139                >= std::mem::align_of::<libc::sockaddr_in6>()
140        );
141
142        if addr.ss_family != libc::AF_INET6 as _ {
143            return None;
144        }
145
146        // Safety: the above assertions guarantee that alignment and size are correct
147        // the resulting reference won't outlast the function, and addr lives the entire
148        // duration of the function
149        let input = unsafe { &(*(&addr as *const _ as *const libc::sockaddr_in6)) };
150        Some(SocketAddrV6::new(
151            Ipv6Addr::from(input.sin6_addr.s6_addr),
152            u16::from_be_bytes(input.sin6_port.to_ne_bytes()),
153            input.sin6_flowinfo,
154            input.sin6_scope_id,
155        ))
156    }
157}
158
159impl SealedNA for SocketAddr {}
160
161impl NetworkAddress for SocketAddr {
162    fn to_sockaddr(&self, _token: PrivateToken) -> libc::sockaddr_storage {
163        match self {
164            SocketAddr::V4(addr) => addr.to_sockaddr(PrivateToken),
165            SocketAddr::V6(addr) => addr.to_sockaddr(PrivateToken),
166        }
167    }
168
169    fn from_sockaddr(addr: libc::sockaddr_storage, _token: PrivateToken) -> Option<Self> {
170        match addr.ss_family as _ {
171            libc::AF_INET => Some(SocketAddr::V4(SocketAddrV4::from_sockaddr(
172                addr,
173                PrivateToken,
174            )?)),
175            libc::AF_INET6 => Some(SocketAddr::V6(SocketAddrV6::from_sockaddr(
176                addr,
177                PrivateToken,
178            )?)),
179            _ => None,
180        }
181    }
182}