timestamped_socket/networkaddress/
linux.rs1use std::{
2 net::{Ipv4Addr, SocketAddrV4, SocketAddrV6},
3 os::fd::RawFd,
4};
5
6use crate::{
7 cerr, control_message::zeroed_sockaddr_storage, interface::InterfaceName,
8 networkaddress::NetworkAddress,
9};
10
11use super::{
12 sealed::{PrivateToken, SealedMC, SealedNA},
13 MulticastJoinable,
14};
15
16#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct MacAddress([u8; 6]);
18
19impl From<[u8; 6]> for MacAddress {
20 fn from(value: [u8; 6]) -> Self {
21 MacAddress(value)
22 }
23}
24
25impl AsRef<[u8]> for MacAddress {
26 fn as_ref(&self) -> &[u8] {
27 &self.0
28 }
29}
30
31impl MacAddress {
32 pub const fn new(address: [u8; 6]) -> Self {
33 MacAddress(address)
34 }
35}
36
37#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
38pub struct EthernetAddress {
39 protocol: u16,
40 mac_address: MacAddress,
41 if_index: libc::c_int,
42}
43
44impl EthernetAddress {
45 pub const fn new(protocol: u16, mac_address: MacAddress, if_index: libc::c_int) -> Self {
46 EthernetAddress {
47 protocol,
48 mac_address,
49 if_index,
50 }
51 }
52
53 pub const fn mac(&self) -> MacAddress {
54 self.mac_address
55 }
56
57 pub const fn protocol(&self) -> u16 {
58 self.protocol
59 }
60
61 pub const fn interface(&self) -> libc::c_int {
62 self.if_index
63 }
64}
65
66impl SealedNA for EthernetAddress {}
67
68impl NetworkAddress for EthernetAddress {
69 fn to_sockaddr(&self, _token: PrivateToken) -> libc::sockaddr_storage {
70 const _: () = assert!(
71 std::mem::size_of::<libc::sockaddr_storage>()
72 >= std::mem::size_of::<libc::sockaddr_ll>()
73 );
74 const _: () = assert!(
75 std::mem::align_of::<libc::sockaddr_storage>()
76 >= std::mem::align_of::<libc::sockaddr_ll>()
77 );
78
79 let mut result = zeroed_sockaddr_storage();
80 let out = unsafe { &mut (*(&mut result as *mut _ as *mut libc::sockaddr_ll)) };
84
85 out.sll_family = libc::AF_PACKET as _;
86 out.sll_addr[..6].copy_from_slice(&self.mac_address.0);
87 out.sll_halen = 6;
88 out.sll_protocol = u16::from_ne_bytes(self.protocol.to_be_bytes());
89 out.sll_ifindex = self.if_index;
90
91 result
92 }
93
94 fn from_sockaddr(addr: libc::sockaddr_storage, _token: PrivateToken) -> Option<Self> {
95 const _: () = assert!(
96 std::mem::size_of::<libc::sockaddr_storage>()
97 >= std::mem::size_of::<libc::sockaddr_ll>()
98 );
99 const _: () = assert!(
100 std::mem::align_of::<libc::sockaddr_storage>()
101 >= std::mem::align_of::<libc::sockaddr_ll>()
102 );
103
104 if addr.ss_family != libc::AF_PACKET as _ {
105 return None;
106 }
107
108 let input = unsafe { &(*(&addr as *const _ as *const libc::sockaddr_ll)) };
112
113 if input.sll_halen != 6 {
114 return None;
115 }
116
117 Some(EthernetAddress::new(
118 u16::from_be_bytes(input.sll_protocol.to_ne_bytes()),
119 MacAddress::new(input.sll_addr[..6].try_into().unwrap()),
120 input.sll_ifindex,
121 ))
122 }
123}
124
125impl SealedMC for EthernetAddress {}
126
127impl MulticastJoinable for EthernetAddress {
128 fn join_multicast(
129 &self,
130 socket: RawFd,
131 interface: InterfaceName,
132 _token: PrivateToken,
133 ) -> std::io::Result<()> {
134 let request = libc::packet_mreq {
135 mr_ifindex: interface
136 .get_index()
137 .ok_or(std::io::ErrorKind::InvalidInput)? as _,
138 mr_type: libc::PACKET_MR_MULTICAST as _,
139 mr_alen: 6,
140 mr_address: [
141 self.mac_address.0[0],
142 self.mac_address.0[1],
143 self.mac_address.0[2],
144 self.mac_address.0[3],
145 self.mac_address.0[4],
146 self.mac_address.0[5],
147 0,
148 0,
149 ],
150 };
151 cerr(unsafe {
154 libc::setsockopt(
155 socket,
156 libc::SOL_PACKET,
157 libc::PACKET_ADD_MEMBERSHIP,
158 &request as *const _ as *const _,
159 std::mem::size_of_val(&request) as _,
160 )
161 })?;
162 Ok(())
163 }
164
165 fn leave_multicast(
166 &self,
167 socket: RawFd,
168 interface: InterfaceName,
169 _token: PrivateToken,
170 ) -> std::io::Result<()> {
171 let request = libc::packet_mreq {
172 mr_ifindex: interface
173 .get_index()
174 .ok_or(std::io::ErrorKind::InvalidInput)? as _,
175 mr_type: libc::PACKET_MR_MULTICAST as _,
176 mr_alen: 6,
177 mr_address: [
178 self.mac_address.0[0],
179 self.mac_address.0[1],
180 self.mac_address.0[2],
181 self.mac_address.0[3],
182 self.mac_address.0[4],
183 self.mac_address.0[5],
184 0,
185 0,
186 ],
187 };
188 cerr(unsafe {
191 libc::setsockopt(
192 socket,
193 libc::SOL_PACKET,
194 libc::PACKET_DROP_MEMBERSHIP,
195 &request as *const _ as *const _,
196 std::mem::size_of_val(&request) as _,
197 )
198 })?;
199 Ok(())
200 }
201}
202
203impl SealedMC for SocketAddrV4 {}
204
205impl MulticastJoinable for SocketAddrV4 {
206 fn join_multicast(
207 &self,
208 socket: RawFd,
209 interface: InterfaceName,
210 _token: PrivateToken,
211 ) -> std::io::Result<()> {
212 let request = libc::ip_mreqn {
213 imr_multiaddr: libc::in_addr {
214 s_addr: u32::from_ne_bytes(self.ip().octets()),
215 },
216 imr_address: libc::in_addr {
217 s_addr: u32::from_ne_bytes(Ipv4Addr::UNSPECIFIED.octets()),
218 },
219 imr_ifindex: interface
220 .get_index()
221 .ok_or(std::io::ErrorKind::InvalidInput)? as _,
222 };
223 cerr(unsafe {
226 libc::setsockopt(
227 socket,
228 libc::IPPROTO_IP,
229 libc::IP_ADD_MEMBERSHIP,
230 &request as *const _ as *const _,
231 std::mem::size_of_val(&request) as _,
232 )
233 })?;
234 Ok(())
235 }
236
237 fn leave_multicast(
238 &self,
239 socket: RawFd,
240 interface: InterfaceName,
241 _token: PrivateToken,
242 ) -> std::io::Result<()> {
243 let request = libc::ip_mreqn {
244 imr_multiaddr: libc::in_addr {
245 s_addr: u32::from_ne_bytes(self.ip().octets()),
246 },
247 imr_address: libc::in_addr {
248 s_addr: u32::from_ne_bytes(Ipv4Addr::UNSPECIFIED.octets()),
249 },
250 imr_ifindex: interface
251 .get_index()
252 .ok_or(std::io::ErrorKind::InvalidInput)? as _,
253 };
254 cerr(unsafe {
257 libc::setsockopt(
258 socket,
259 libc::IPPROTO_IP,
260 libc::IP_DROP_MEMBERSHIP,
261 &request as *const _ as *const _,
262 std::mem::size_of_val(&request) as _,
263 )
264 })?;
265 Ok(())
266 }
267}
268
269impl SealedMC for SocketAddrV6 {}
270
271impl MulticastJoinable for SocketAddrV6 {
272 fn join_multicast(
273 &self,
274 socket: RawFd,
275 interface: InterfaceName,
276 _token: PrivateToken,
277 ) -> std::io::Result<()> {
278 let request = libc::ipv6_mreq {
279 ipv6mr_multiaddr: libc::in6_addr {
280 s6_addr: self.ip().octets(),
281 },
282 ipv6mr_interface: interface
283 .get_index()
284 .ok_or(std::io::ErrorKind::InvalidInput)? as _,
285 };
286 cerr(unsafe {
289 libc::setsockopt(
290 socket,
291 libc::IPPROTO_IPV6,
292 libc::IPV6_ADD_MEMBERSHIP,
293 &request as *const _ as *const _,
294 std::mem::size_of_val(&request) as _,
295 )
296 })?;
297 Ok(())
298 }
299
300 fn leave_multicast(
301 &self,
302 socket: RawFd,
303 interface: InterfaceName,
304 _token: PrivateToken,
305 ) -> std::io::Result<()> {
306 let request = libc::ipv6_mreq {
307 ipv6mr_multiaddr: libc::in6_addr {
308 s6_addr: self.ip().octets(),
309 },
310 ipv6mr_interface: interface
311 .get_index()
312 .ok_or(std::io::ErrorKind::InvalidInput)? as _,
313 };
314 cerr(unsafe {
317 libc::setsockopt(
318 socket,
319 libc::IPPROTO_IPV6,
320 libc::IPV6_DROP_MEMBERSHIP,
321 &request as *const _ as *const _,
322 std::mem::size_of_val(&request) as _,
323 )
324 })?;
325 Ok(())
326 }
327}