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 fn from_ip_and_port(_addr: std::net::IpAddr, _port: u16) -> Option<Self> {
125 None
126 }
127
128 fn port(&self) -> u16 {
129 0
131 }
132}
133
134impl SealedMC for EthernetAddress {}
135
136impl MulticastJoinable for EthernetAddress {
137 fn join_multicast(
138 &self,
139 socket: RawFd,
140 interface: InterfaceName,
141 _token: PrivateToken,
142 ) -> std::io::Result<()> {
143 let request = libc::packet_mreq {
144 mr_ifindex: interface
145 .get_index()
146 .ok_or(std::io::ErrorKind::InvalidInput)? as _,
147 mr_type: libc::PACKET_MR_MULTICAST as _,
148 mr_alen: 6,
149 mr_address: [
150 self.mac_address.0[0],
151 self.mac_address.0[1],
152 self.mac_address.0[2],
153 self.mac_address.0[3],
154 self.mac_address.0[4],
155 self.mac_address.0[5],
156 0,
157 0,
158 ],
159 };
160 cerr(unsafe {
163 libc::setsockopt(
164 socket,
165 libc::SOL_PACKET,
166 libc::PACKET_ADD_MEMBERSHIP,
167 &request as *const _ as *const _,
168 std::mem::size_of_val(&request) as _,
169 )
170 })?;
171 Ok(())
172 }
173
174 fn leave_multicast(
175 &self,
176 socket: RawFd,
177 interface: InterfaceName,
178 _token: PrivateToken,
179 ) -> std::io::Result<()> {
180 let request = libc::packet_mreq {
181 mr_ifindex: interface
182 .get_index()
183 .ok_or(std::io::ErrorKind::InvalidInput)? as _,
184 mr_type: libc::PACKET_MR_MULTICAST as _,
185 mr_alen: 6,
186 mr_address: [
187 self.mac_address.0[0],
188 self.mac_address.0[1],
189 self.mac_address.0[2],
190 self.mac_address.0[3],
191 self.mac_address.0[4],
192 self.mac_address.0[5],
193 0,
194 0,
195 ],
196 };
197 cerr(unsafe {
200 libc::setsockopt(
201 socket,
202 libc::SOL_PACKET,
203 libc::PACKET_DROP_MEMBERSHIP,
204 &request as *const _ as *const _,
205 std::mem::size_of_val(&request) as _,
206 )
207 })?;
208 Ok(())
209 }
210}
211
212impl SealedMC for SocketAddrV4 {}
213
214impl MulticastJoinable for SocketAddrV4 {
215 fn join_multicast(
216 &self,
217 socket: RawFd,
218 interface: InterfaceName,
219 _token: PrivateToken,
220 ) -> std::io::Result<()> {
221 let request = libc::ip_mreqn {
222 imr_multiaddr: libc::in_addr {
223 s_addr: u32::from_ne_bytes(self.ip().octets()),
224 },
225 imr_address: libc::in_addr {
226 s_addr: u32::from_ne_bytes(Ipv4Addr::UNSPECIFIED.octets()),
227 },
228 imr_ifindex: interface
229 .get_index()
230 .ok_or(std::io::ErrorKind::InvalidInput)? as _,
231 };
232 cerr(unsafe {
235 libc::setsockopt(
236 socket,
237 libc::IPPROTO_IP,
238 libc::IP_ADD_MEMBERSHIP,
239 &request as *const _ as *const _,
240 std::mem::size_of_val(&request) as _,
241 )
242 })?;
243 Ok(())
244 }
245
246 fn leave_multicast(
247 &self,
248 socket: RawFd,
249 interface: InterfaceName,
250 _token: PrivateToken,
251 ) -> std::io::Result<()> {
252 let request = libc::ip_mreqn {
253 imr_multiaddr: libc::in_addr {
254 s_addr: u32::from_ne_bytes(self.ip().octets()),
255 },
256 imr_address: libc::in_addr {
257 s_addr: u32::from_ne_bytes(Ipv4Addr::UNSPECIFIED.octets()),
258 },
259 imr_ifindex: interface
260 .get_index()
261 .ok_or(std::io::ErrorKind::InvalidInput)? as _,
262 };
263 cerr(unsafe {
266 libc::setsockopt(
267 socket,
268 libc::IPPROTO_IP,
269 libc::IP_DROP_MEMBERSHIP,
270 &request as *const _ as *const _,
271 std::mem::size_of_val(&request) as _,
272 )
273 })?;
274 Ok(())
275 }
276}
277
278impl SealedMC for SocketAddrV6 {}
279
280impl MulticastJoinable for SocketAddrV6 {
281 fn join_multicast(
282 &self,
283 socket: RawFd,
284 interface: InterfaceName,
285 _token: PrivateToken,
286 ) -> std::io::Result<()> {
287 let request = libc::ipv6_mreq {
288 ipv6mr_multiaddr: libc::in6_addr {
289 s6_addr: self.ip().octets(),
290 },
291 ipv6mr_interface: interface
292 .get_index()
293 .ok_or(std::io::ErrorKind::InvalidInput)? as _,
294 };
295 cerr(unsafe {
298 libc::setsockopt(
299 socket,
300 libc::IPPROTO_IPV6,
301 libc::IPV6_ADD_MEMBERSHIP,
302 &request as *const _ as *const _,
303 std::mem::size_of_val(&request) as _,
304 )
305 })?;
306 Ok(())
307 }
308
309 fn leave_multicast(
310 &self,
311 socket: RawFd,
312 interface: InterfaceName,
313 _token: PrivateToken,
314 ) -> std::io::Result<()> {
315 let request = libc::ipv6_mreq {
316 ipv6mr_multiaddr: libc::in6_addr {
317 s6_addr: self.ip().octets(),
318 },
319 ipv6mr_interface: interface
320 .get_index()
321 .ok_or(std::io::ErrorKind::InvalidInput)? as _,
322 };
323 cerr(unsafe {
326 libc::setsockopt(
327 socket,
328 libc::IPPROTO_IPV6,
329 libc::IPV6_DROP_MEMBERSHIP,
330 &request as *const _ as *const _,
331 std::mem::size_of_val(&request) as _,
332 )
333 })?;
334 Ok(())
335 }
336}