Skip to main content

timestamped_socket/
networkaddress.rs

1use std::{
2    net::{IpAddr, 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: Copy + 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    #[doc(hidden)]
33    fn from_ip_and_port(addr: IpAddr, port: u16) -> Option<Self>;
34    #[doc(hidden)]
35    fn port(&self) -> u16;
36}
37
38pub trait MulticastJoinable: NetworkAddress + SealedMC {
39    #[doc(hidden)]
40    fn join_multicast(
41        &self,
42        socket: RawFd,
43        interface: InterfaceName,
44        _token: PrivateToken,
45    ) -> std::io::Result<()>;
46    #[doc(hidden)]
47    fn leave_multicast(
48        &self,
49        socket: RawFd,
50        interface: InterfaceName,
51        _token: PrivateToken,
52    ) -> std::io::Result<()>;
53}
54
55impl SealedNA for SocketAddrV4 {}
56
57impl NetworkAddress for SocketAddrV4 {
58    fn to_sockaddr(&self, _token: PrivateToken) -> libc::sockaddr_storage {
59        const _: () = assert!(
60            std::mem::size_of::<libc::sockaddr_storage>()
61                >= std::mem::size_of::<libc::sockaddr_in>()
62        );
63        const _: () = assert!(
64            std::mem::align_of::<libc::sockaddr_storage>()
65                >= std::mem::align_of::<libc::sockaddr_in>()
66        );
67
68        let mut result = zeroed_sockaddr_storage();
69        // Safety: the above assertions guarantee that alignment and size are correct.
70        // the resulting reference won't outlast the function, and result lives the entire
71        // duration of the function
72        let out = unsafe { &mut (*(&mut result as *mut _ as *mut libc::sockaddr_in)) };
73        out.sin_family = libc::AF_INET as _;
74        out.sin_port = u16::from_ne_bytes(self.port().to_be_bytes());
75        out.sin_addr = libc::in_addr {
76            s_addr: u32::from_ne_bytes(self.ip().octets()),
77        };
78
79        result
80    }
81
82    fn from_sockaddr(addr: libc::sockaddr_storage, _token: PrivateToken) -> Option<Self> {
83        const _: () = assert!(
84            std::mem::size_of::<libc::sockaddr_storage>()
85                >= std::mem::size_of::<libc::sockaddr_in>()
86        );
87        const _: () = assert!(
88            std::mem::align_of::<libc::sockaddr_storage>()
89                >= std::mem::align_of::<libc::sockaddr_in>()
90        );
91
92        if addr.ss_family != libc::AF_INET as _ {
93            return None;
94        }
95
96        // Safety: the above assertions guarantee that alignment and size are correct
97        // the resulting reference won't outlast the function, and addr lives the entire
98        // duration of the function
99        let input = unsafe { &(*(&addr as *const _ as *const libc::sockaddr_in)) };
100        Some(SocketAddrV4::new(
101            Ipv4Addr::from(input.sin_addr.s_addr.to_ne_bytes()),
102            u16::from_be_bytes(input.sin_port.to_ne_bytes()),
103        ))
104    }
105
106    fn from_ip_and_port(addr: IpAddr, port: u16) -> Option<Self> {
107        match addr {
108            IpAddr::V4(addr) => Some(SocketAddrV4::new(addr, port)),
109            IpAddr::V6(_) => None,
110        }
111    }
112
113    fn port(&self) -> u16 {
114        self.port()
115    }
116}
117
118impl SealedNA for SocketAddrV6 {}
119
120impl NetworkAddress for SocketAddrV6 {
121    fn to_sockaddr(&self, _token: PrivateToken) -> libc::sockaddr_storage {
122        const _: () = assert!(
123            std::mem::size_of::<libc::sockaddr_storage>()
124                >= std::mem::size_of::<libc::sockaddr_in6>()
125        );
126        const _: () = assert!(
127            std::mem::align_of::<libc::sockaddr_storage>()
128                >= std::mem::align_of::<libc::sockaddr_in6>()
129        );
130
131        let mut result = zeroed_sockaddr_storage();
132        // Safety: the above assertions guarantee that alignment and size are correct.
133        // the resulting reference won't outlast the function, and result lives the entire
134        // duration of the function
135        let out = unsafe { &mut (*(&mut result as *mut _ as *mut libc::sockaddr_in6)) };
136        out.sin6_family = libc::AF_INET6 as _;
137        out.sin6_port = u16::from_ne_bytes(self.port().to_be_bytes());
138        out.sin6_addr = libc::in6_addr {
139            s6_addr: self.ip().octets(),
140        };
141        out.sin6_flowinfo = self.flowinfo();
142        out.sin6_scope_id = self.scope_id();
143
144        result
145    }
146
147    fn from_sockaddr(addr: libc::sockaddr_storage, _token: PrivateToken) -> Option<Self> {
148        const _: () = assert!(
149            std::mem::size_of::<libc::sockaddr_storage>()
150                >= std::mem::size_of::<libc::sockaddr_in6>()
151        );
152        const _: () = assert!(
153            std::mem::align_of::<libc::sockaddr_storage>()
154                >= std::mem::align_of::<libc::sockaddr_in6>()
155        );
156
157        if addr.ss_family != libc::AF_INET6 as _ {
158            return None;
159        }
160
161        // Safety: the above assertions guarantee that alignment and size are correct
162        // the resulting reference won't outlast the function, and addr lives the entire
163        // duration of the function
164        let input = unsafe { &(*(&addr as *const _ as *const libc::sockaddr_in6)) };
165        Some(SocketAddrV6::new(
166            Ipv6Addr::from(input.sin6_addr.s6_addr),
167            u16::from_be_bytes(input.sin6_port.to_ne_bytes()),
168            input.sin6_flowinfo,
169            input.sin6_scope_id,
170        ))
171    }
172
173    fn from_ip_and_port(addr: IpAddr, port: u16) -> Option<Self> {
174        match addr {
175            IpAddr::V4(_) => None,
176            IpAddr::V6(addr) => Some(SocketAddrV6::new(addr, port, 0, 0)),
177        }
178    }
179
180    fn port(&self) -> u16 {
181        self.port()
182    }
183}
184
185impl SealedNA for SocketAddr {}
186
187impl NetworkAddress for SocketAddr {
188    fn to_sockaddr(&self, _token: PrivateToken) -> libc::sockaddr_storage {
189        match self {
190            SocketAddr::V4(addr) => addr.to_sockaddr(PrivateToken),
191            SocketAddr::V6(addr) => addr.to_sockaddr(PrivateToken),
192        }
193    }
194
195    fn from_sockaddr(addr: libc::sockaddr_storage, _token: PrivateToken) -> Option<Self> {
196        match addr.ss_family as _ {
197            libc::AF_INET => Some(SocketAddr::V4(SocketAddrV4::from_sockaddr(
198                addr,
199                PrivateToken,
200            )?)),
201            libc::AF_INET6 => Some(SocketAddr::V6(SocketAddrV6::from_sockaddr(
202                addr,
203                PrivateToken,
204            )?)),
205            _ => None,
206        }
207    }
208
209    fn from_ip_and_port(addr: IpAddr, port: u16) -> Option<Self> {
210        Some(SocketAddr::new(addr, port))
211    }
212
213    fn port(&self) -> u16 {
214        self.port()
215    }
216}