Skip to content

Commit 533039a

Browse files
Add support for FreeBSD
Constant and structure extract from <sys/socket.h>, <netlink/netlink.h> and <netlink/netlink_route.h> Signed-off-by: molyuu <bigsaltyfishes@gmail.com>
1 parent 498df8b commit 533039a

File tree

6 files changed

+135
-57
lines changed

6 files changed

+135
-57
lines changed

src/addr.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use std::{
66
mem,
77
};
88

9+
use crate::{constants::PF_NETLINK, sys::sockaddr_nl};
10+
911
/// The address of a netlink socket
1012
///
1113
/// A netlink address is made of two parts: the unicast address of the socket,
@@ -96,7 +98,7 @@ use std::{
9698
/// [bind_auto]: crate::Socket::bind_auto
9799
/// [get_addr]: crate::Socket::get_address
98100
#[derive(Copy, Clone)]
99-
pub struct SocketAddr(pub(crate) libc::sockaddr_nl);
101+
pub struct SocketAddr(pub(crate) sockaddr_nl);
100102

101103
impl Hash for SocketAddr {
102104
fn hash<H: Hasher>(&self, state: &mut H) {
@@ -139,8 +141,8 @@ impl fmt::Display for SocketAddr {
139141
impl SocketAddr {
140142
/// Create a new socket address for with th
141143
pub fn new(port_number: u32, multicast_groups: u32) -> Self {
142-
let mut addr: libc::sockaddr_nl = unsafe { mem::zeroed() };
143-
addr.nl_family = libc::PF_NETLINK as libc::sa_family_t;
144+
let mut addr: sockaddr_nl = unsafe { mem::zeroed() };
145+
addr.nl_family = PF_NETLINK as libc::sa_family_t;
144146
addr.nl_pid = port_number;
145147
addr.nl_groups = multicast_groups;
146148
SocketAddr(addr)
@@ -157,8 +159,7 @@ impl SocketAddr {
157159
}
158160

159161
pub(crate) fn as_raw(&self) -> (*const libc::sockaddr, libc::socklen_t) {
160-
let addr_ptr =
161-
&self.0 as *const libc::sockaddr_nl as *const libc::sockaddr;
162+
let addr_ptr = &self.0 as *const sockaddr_nl as *const libc::sockaddr;
162163
// \ / \
163164
// / +---------------+---------------+
164165
// +----------+---------+ |
@@ -178,16 +179,15 @@ impl SocketAddr {
178179
// But since this is my first time dealing with this kind of things I
179180
// chose the most explicit form.
180181

181-
let addr_len = mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t;
182+
let addr_len = mem::size_of::<sockaddr_nl>() as libc::socklen_t;
182183
(addr_ptr, addr_len)
183184
}
184185

185186
pub(crate) fn as_raw_mut(
186187
&mut self,
187188
) -> (*mut libc::sockaddr, libc::socklen_t) {
188-
let addr_ptr =
189-
&mut self.0 as *mut libc::sockaddr_nl as *mut libc::sockaddr;
190-
let addr_len = mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t;
189+
let addr_ptr = &mut self.0 as *mut sockaddr_nl as *mut libc::sockaddr;
190+
let addr_len = mem::size_of::<sockaddr_nl>() as libc::socklen_t;
191191
(addr_ptr, addr_len)
192192
}
193193
}

src/constants.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,12 @@ pub const NETLINK_CAP_ACK: int = 10;
141141
pub const NETLINK_EXT_ACK: int = 11;
142142
pub const NL_MMAP_MSG_ALIGNMENT: int = 4;
143143
pub const NET_MAJOR: int = 36;
144+
145+
pub const NETLINK_GET_STRICT_CHK: int = 12;
146+
147+
#[cfg(target_os = "freebsd")]
148+
pub const AF_NETLINK: int = 38;
149+
#[cfg(not(target_os = "freebsd"))]
150+
pub const AF_NETLINK: int = 16;
151+
pub const PF_NETLINK: int = AF_NETLINK;
152+
pub const SOL_NETLINK: int = 270;

src/ffi/freebsd.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
/* automatically generated by rust-bindgen 0.72.1 */
4+
5+
pub type __uint8_t = ::core::ffi::c_uchar;
6+
pub type __sa_family_t = __uint8_t;
7+
pub type sa_family_t = __sa_family_t;
8+
#[repr(C)]
9+
#[derive(Debug, Copy, Clone)]
10+
pub struct sockaddr_nl {
11+
pub nl_len: u8,
12+
pub nl_family: sa_family_t,
13+
pub nl_pad: u16,
14+
pub nl_pid: u32,
15+
pub nl_groups: u32,
16+
}
17+
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
18+
const _: () = {
19+
["Size of sockaddr_nl"][::core::mem::size_of::<sockaddr_nl>() - 12usize];
20+
["Alignment of sockaddr_nl"]
21+
[::core::mem::align_of::<sockaddr_nl>() - 4usize];
22+
["Offset of field: sockaddr_nl::nl_len"]
23+
[::core::mem::offset_of!(sockaddr_nl, nl_len) - 0usize];
24+
["Offset of field: sockaddr_nl::nl_family"]
25+
[::core::mem::offset_of!(sockaddr_nl, nl_family) - 1usize];
26+
["Offset of field: sockaddr_nl::nl_pad"]
27+
[::core::mem::offset_of!(sockaddr_nl, nl_pad) - 2usize];
28+
["Offset of field: sockaddr_nl::nl_pid"]
29+
[::core::mem::offset_of!(sockaddr_nl, nl_pid) - 4usize];
30+
["Offset of field: sockaddr_nl::nl_groups"]
31+
[::core::mem::offset_of!(sockaddr_nl, nl_groups) - 8usize];
32+
};

src/lib.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
// SPDX-License-Identifier: MIT
22

3+
pub mod sys;
4+
35
pub mod constants;
46
pub mod protocols {
57
pub use super::constants::{
6-
NETLINK_AUDIT, NETLINK_CONNECTOR, NETLINK_CRYPTO, NETLINK_DNRTMSG,
7-
NETLINK_ECRYPTFS, NETLINK_FIB_LOOKUP, NETLINK_FIREWALL,
8-
NETLINK_GENERIC, NETLINK_IP6_FW, NETLINK_ISCSI, NETLINK_KOBJECT_UEVENT,
8+
AF_NETLINK, NETLINK_AUDIT, NETLINK_CONNECTOR, NETLINK_CRYPTO,
9+
NETLINK_DNRTMSG, NETLINK_ECRYPTFS, NETLINK_FIB_LOOKUP,
10+
NETLINK_FIREWALL, NETLINK_GENERIC, NETLINK_GET_STRICT_CHK,
11+
NETLINK_IP6_FW, NETLINK_ISCSI, NETLINK_KOBJECT_UEVENT,
912
NETLINK_NETFILTER, NETLINK_NFLOG, NETLINK_RDMA, NETLINK_ROUTE,
1013
NETLINK_SCSITRANSPORT, NETLINK_SELINUX, NETLINK_SOCK_DIAG,
11-
NETLINK_UNUSED, NETLINK_USERSOCK, NETLINK_XFRM,
14+
NETLINK_UNUSED, NETLINK_USERSOCK, NETLINK_XFRM, PF_NETLINK,
15+
SOL_NETLINK,
1216
};
1317
}
1418

src/socket.rs

Lines changed: 59 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,16 @@ use std::{
99
},
1010
};
1111

12-
use crate::SocketAddr;
12+
use crate::{
13+
constants::{
14+
NETLINK_ADD_MEMBERSHIP, NETLINK_BROADCAST_ERROR, NETLINK_CAP_ACK,
15+
NETLINK_DROP_MEMBERSHIP, NETLINK_EXT_ACK, NETLINK_GET_STRICT_CHK,
16+
NETLINK_LISTEN_ALL_NSID, NETLINK_NO_ENOBUFS, NETLINK_PKTINFO,
17+
PF_NETLINK, SOL_NETLINK,
18+
},
19+
sys::sockaddr_nl,
20+
SocketAddr,
21+
};
1322

1423
/// A netlink socket.
1524
///
@@ -89,7 +98,7 @@ impl Socket {
8998
pub fn new(protocol: isize) -> Result<Self> {
9099
let res = unsafe {
91100
libc::socket(
92-
libc::PF_NETLINK,
101+
PF_NETLINK as _,
93102
libc::SOCK_DGRAM | libc::SOCK_CLOEXEC,
94103
protocol as libc::c_int,
95104
)
@@ -196,6 +205,7 @@ impl Socket {
196205
/// }
197206
/// }
198207
/// ```
208+
#[cfg(not(target_os = "freebsd"))]
199209
pub fn connect(&self, remote_addr: &SocketAddr) -> Result<()> {
200210
// FIXME:
201211
//
@@ -261,7 +271,7 @@ impl Socket {
261271
// library create a sockaddr_storage so that it works for any
262272
// address family, but here, we already know that we'll have a
263273
// Netlink address, so we can create the appropriate storage.
264-
let mut addr = unsafe { mem::zeroed::<libc::sockaddr_nl>() };
274+
let mut addr = unsafe { mem::zeroed::<sockaddr_nl>() };
265275

266276
// recvfrom takes a *sockaddr as parameter so that it can accept any
267277
// kind of address storage, so we need to create such a pointer
@@ -276,8 +286,7 @@ impl Socket {
276286
// +--------------+---------------+ +---------+--------+
277287
// / \ /
278288
// \
279-
let addr_ptr =
280-
&mut addr as *mut libc::sockaddr_nl as *mut libc::sockaddr;
289+
let addr_ptr = &mut addr as *mut sockaddr_nl as *mut libc::sockaddr;
281290

282291
// Why do we need to pass the address length? We're passing a generic
283292
// *sockaddr to recvfrom. Somehow recvfrom needs to make sure
@@ -414,35 +423,35 @@ impl Socket {
414423
let value: libc::c_int = value.into();
415424
setsockopt(
416425
self.as_raw_fd(),
417-
libc::SOL_NETLINK,
418-
libc::NETLINK_PKTINFO,
426+
SOL_NETLINK as _,
427+
NETLINK_PKTINFO as _,
419428
value,
420429
)
421430
}
422431

423432
pub fn get_pktinfo(&self) -> Result<bool> {
424433
let res = getsockopt::<libc::c_int>(
425434
self.as_raw_fd(),
426-
libc::SOL_NETLINK,
427-
libc::NETLINK_PKTINFO,
435+
SOL_NETLINK as _,
436+
NETLINK_PKTINFO as _,
428437
)?;
429438
Ok(res == 1)
430439
}
431440

432441
pub fn add_membership(&mut self, group: u32) -> Result<()> {
433442
setsockopt(
434443
self.as_raw_fd(),
435-
libc::SOL_NETLINK,
436-
libc::NETLINK_ADD_MEMBERSHIP,
444+
SOL_NETLINK as _,
445+
NETLINK_ADD_MEMBERSHIP as _,
437446
group,
438447
)
439448
}
440449

441450
pub fn drop_membership(&mut self, group: u32) -> Result<()> {
442451
setsockopt(
443452
self.as_raw_fd(),
444-
libc::SOL_NETLINK,
445-
libc::NETLINK_DROP_MEMBERSHIP,
453+
SOL_NETLINK as _,
454+
NETLINK_DROP_MEMBERSHIP as _,
446455
group,
447456
)
448457
}
@@ -457,42 +466,44 @@ impl Socket {
457466
/// `NETLINK_BROADCAST_ERROR` (since Linux 2.6.30). When not set,
458467
/// `netlink_broadcast()` only reports `ESRCH` errors and silently
459468
/// ignore `NOBUFS` errors.
469+
#[cfg(not(target_os = "freebsd"))]
460470
pub fn set_broadcast_error(&mut self, value: bool) -> Result<()> {
461471
let value: libc::c_int = value.into();
462472
setsockopt(
463473
self.as_raw_fd(),
464-
libc::SOL_NETLINK,
465-
libc::NETLINK_BROADCAST_ERROR,
474+
SOL_NETLINK as _,
475+
NETLINK_BROADCAST_ERROR as _,
466476
value,
467477
)
468478
}
469479

470480
pub fn get_broadcast_error(&self) -> Result<bool> {
471481
let res = getsockopt::<libc::c_int>(
472482
self.as_raw_fd(),
473-
libc::SOL_NETLINK,
474-
libc::NETLINK_BROADCAST_ERROR,
483+
SOL_NETLINK as _,
484+
NETLINK_BROADCAST_ERROR as _,
475485
)?;
476486
Ok(res == 1)
477487
}
478488

479489
/// `NETLINK_NO_ENOBUFS` (since Linux 2.6.30). This flag can be used by
480490
/// unicast and broadcast listeners to avoid receiving `ENOBUFS` errors.
491+
#[cfg(not(target_os = "freebsd"))]
481492
pub fn set_no_enobufs(&mut self, value: bool) -> Result<()> {
482493
let value: libc::c_int = value.into();
483494
setsockopt(
484495
self.as_raw_fd(),
485-
libc::SOL_NETLINK,
486-
libc::NETLINK_NO_ENOBUFS,
496+
SOL_NETLINK as _,
497+
NETLINK_NO_ENOBUFS as _,
487498
value,
488499
)
489500
}
490501

491502
pub fn get_no_enobufs(&self) -> Result<bool> {
492503
let res = getsockopt::<libc::c_int>(
493504
self.as_raw_fd(),
494-
libc::SOL_NETLINK,
495-
libc::NETLINK_NO_ENOBUFS,
505+
SOL_NETLINK as _,
506+
NETLINK_NO_ENOBUFS as _,
496507
)?;
497508
Ok(res == 1)
498509
}
@@ -506,17 +517,17 @@ impl Socket {
506517
let value: libc::c_int = value.into();
507518
setsockopt(
508519
self.as_raw_fd(),
509-
libc::SOL_NETLINK,
510-
libc::NETLINK_LISTEN_ALL_NSID,
520+
SOL_NETLINK as _,
521+
NETLINK_LISTEN_ALL_NSID as _,
511522
value,
512523
)
513524
}
514525

515526
pub fn get_listen_all_namespaces(&self) -> Result<bool> {
516527
let res = getsockopt::<libc::c_int>(
517528
self.as_raw_fd(),
518-
libc::SOL_NETLINK,
519-
libc::NETLINK_LISTEN_ALL_NSID,
529+
SOL_NETLINK as _,
530+
NETLINK_LISTEN_ALL_NSID as _,
520531
)?;
521532
Ok(res == 1)
522533
}
@@ -531,17 +542,17 @@ impl Socket {
531542
let value: libc::c_int = value.into();
532543
setsockopt(
533544
self.as_raw_fd(),
534-
libc::SOL_NETLINK,
535-
libc::NETLINK_CAP_ACK,
545+
SOL_NETLINK as _,
546+
NETLINK_CAP_ACK as _,
536547
value,
537548
)
538549
}
539550

540551
pub fn get_cap_ack(&self) -> Result<bool> {
541552
let res = getsockopt::<libc::c_int>(
542553
self.as_raw_fd(),
543-
libc::SOL_NETLINK,
544-
libc::NETLINK_CAP_ACK,
554+
SOL_NETLINK as _,
555+
NETLINK_CAP_ACK as _,
545556
)?;
546557
Ok(res == 1)
547558
}
@@ -553,17 +564,17 @@ impl Socket {
553564
let value: libc::c_int = value.into();
554565
setsockopt(
555566
self.as_raw_fd(),
556-
libc::SOL_NETLINK,
557-
libc::NETLINK_EXT_ACK,
567+
SOL_NETLINK as _,
568+
NETLINK_EXT_ACK as _,
558569
value,
559570
)
560571
}
561572

562573
pub fn get_ext_ack(&self) -> Result<bool> {
563574
let res = getsockopt::<libc::c_int>(
564575
self.as_raw_fd(),
565-
libc::SOL_NETLINK,
566-
libc::NETLINK_EXT_ACK,
576+
SOL_NETLINK as _,
577+
NETLINK_EXT_ACK as _,
567578
)?;
568579
Ok(res == 1)
569580
}
@@ -594,8 +605,8 @@ impl Socket {
594605
let value: u32 = value.into();
595606
setsockopt(
596607
self.as_raw_fd(),
597-
libc::SOL_NETLINK,
598-
libc::NETLINK_GET_STRICT_CHK,
608+
SOL_NETLINK as _,
609+
NETLINK_GET_STRICT_CHK as _,
599610
value,
600611
)
601612
}
@@ -668,6 +679,7 @@ mod test {
668679
Socket::new(NETLINK_ROUTE).unwrap();
669680
}
670681

682+
#[cfg(not(target_os = "freebsd"))]
671683
#[test]
672684
fn connect() {
673685
let sock = Socket::new(NETLINK_ROUTE).unwrap();
@@ -704,15 +716,18 @@ mod test {
704716
sock.set_cap_ack(false).unwrap();
705717
assert!(!sock.get_cap_ack().unwrap());
706718

707-
sock.set_no_enobufs(true).unwrap();
708-
assert!(sock.get_no_enobufs().unwrap());
709-
sock.set_no_enobufs(false).unwrap();
710-
assert!(!sock.get_no_enobufs().unwrap());
711-
712-
sock.set_broadcast_error(true).unwrap();
713-
assert!(sock.get_broadcast_error().unwrap());
714-
sock.set_broadcast_error(false).unwrap();
715-
assert!(!sock.get_broadcast_error().unwrap());
719+
#[cfg(not(target_os = "freebsd"))]
720+
{
721+
sock.set_no_enobufs(true).unwrap();
722+
assert!(sock.get_no_enobufs().unwrap());
723+
sock.set_no_enobufs(false).unwrap();
724+
assert!(!sock.get_no_enobufs().unwrap());
725+
726+
sock.set_broadcast_error(true).unwrap();
727+
assert!(sock.get_broadcast_error().unwrap());
728+
sock.set_broadcast_error(false).unwrap();
729+
assert!(!sock.get_broadcast_error().unwrap());
730+
}
716731

717732
// FIXME: these require root permissions
718733
// sock.set_listen_all_namespaces(true).unwrap();

0 commit comments

Comments
 (0)