Skip to content

Commit 11c3d8f

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 11c3d8f

File tree

6 files changed

+137
-57
lines changed

6 files changed

+137
-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: 61 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,46 @@ 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

480+
#[cfg(not(target_os = "freebsd"))]
470481
pub fn get_broadcast_error(&self) -> Result<bool> {
471482
let res = getsockopt::<libc::c_int>(
472483
self.as_raw_fd(),
473-
libc::SOL_NETLINK,
474-
libc::NETLINK_BROADCAST_ERROR,
484+
SOL_NETLINK as _,
485+
NETLINK_BROADCAST_ERROR as _,
475486
)?;
476487
Ok(res == 1)
477488
}
478489

479490
/// `NETLINK_NO_ENOBUFS` (since Linux 2.6.30). This flag can be used by
480491
/// unicast and broadcast listeners to avoid receiving `ENOBUFS` errors.
492+
#[cfg(not(target_os = "freebsd"))]
481493
pub fn set_no_enobufs(&mut self, value: bool) -> Result<()> {
482494
let value: libc::c_int = value.into();
483495
setsockopt(
484496
self.as_raw_fd(),
485-
libc::SOL_NETLINK,
486-
libc::NETLINK_NO_ENOBUFS,
497+
SOL_NETLINK as _,
498+
NETLINK_NO_ENOBUFS as _,
487499
value,
488500
)
489501
}
490502

503+
#[cfg(not(target_os = "freebsd"))]
491504
pub fn get_no_enobufs(&self) -> Result<bool> {
492505
let res = getsockopt::<libc::c_int>(
493506
self.as_raw_fd(),
494-
libc::SOL_NETLINK,
495-
libc::NETLINK_NO_ENOBUFS,
507+
SOL_NETLINK as _,
508+
NETLINK_NO_ENOBUFS as _,
496509
)?;
497510
Ok(res == 1)
498511
}
@@ -506,17 +519,17 @@ impl Socket {
506519
let value: libc::c_int = value.into();
507520
setsockopt(
508521
self.as_raw_fd(),
509-
libc::SOL_NETLINK,
510-
libc::NETLINK_LISTEN_ALL_NSID,
522+
SOL_NETLINK as _,
523+
NETLINK_LISTEN_ALL_NSID as _,
511524
value,
512525
)
513526
}
514527

515528
pub fn get_listen_all_namespaces(&self) -> Result<bool> {
516529
let res = getsockopt::<libc::c_int>(
517530
self.as_raw_fd(),
518-
libc::SOL_NETLINK,
519-
libc::NETLINK_LISTEN_ALL_NSID,
531+
SOL_NETLINK as _,
532+
NETLINK_LISTEN_ALL_NSID as _,
520533
)?;
521534
Ok(res == 1)
522535
}
@@ -531,17 +544,17 @@ impl Socket {
531544
let value: libc::c_int = value.into();
532545
setsockopt(
533546
self.as_raw_fd(),
534-
libc::SOL_NETLINK,
535-
libc::NETLINK_CAP_ACK,
547+
SOL_NETLINK as _,
548+
NETLINK_CAP_ACK as _,
536549
value,
537550
)
538551
}
539552

540553
pub fn get_cap_ack(&self) -> Result<bool> {
541554
let res = getsockopt::<libc::c_int>(
542555
self.as_raw_fd(),
543-
libc::SOL_NETLINK,
544-
libc::NETLINK_CAP_ACK,
556+
SOL_NETLINK as _,
557+
NETLINK_CAP_ACK as _,
545558
)?;
546559
Ok(res == 1)
547560
}
@@ -553,17 +566,17 @@ impl Socket {
553566
let value: libc::c_int = value.into();
554567
setsockopt(
555568
self.as_raw_fd(),
556-
libc::SOL_NETLINK,
557-
libc::NETLINK_EXT_ACK,
569+
SOL_NETLINK as _,
570+
NETLINK_EXT_ACK as _,
558571
value,
559572
)
560573
}
561574

562575
pub fn get_ext_ack(&self) -> Result<bool> {
563576
let res = getsockopt::<libc::c_int>(
564577
self.as_raw_fd(),
565-
libc::SOL_NETLINK,
566-
libc::NETLINK_EXT_ACK,
578+
SOL_NETLINK as _,
579+
NETLINK_EXT_ACK as _,
567580
)?;
568581
Ok(res == 1)
569582
}
@@ -594,8 +607,8 @@ impl Socket {
594607
let value: u32 = value.into();
595608
setsockopt(
596609
self.as_raw_fd(),
597-
libc::SOL_NETLINK,
598-
libc::NETLINK_GET_STRICT_CHK,
610+
SOL_NETLINK as _,
611+
NETLINK_GET_STRICT_CHK as _,
599612
value,
600613
)
601614
}
@@ -668,6 +681,7 @@ mod test {
668681
Socket::new(NETLINK_ROUTE).unwrap();
669682
}
670683

684+
#[cfg(not(target_os = "freebsd"))]
671685
#[test]
672686
fn connect() {
673687
let sock = Socket::new(NETLINK_ROUTE).unwrap();
@@ -704,15 +718,18 @@ mod test {
704718
sock.set_cap_ack(false).unwrap();
705719
assert!(!sock.get_cap_ack().unwrap());
706720

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());
721+
#[cfg(not(target_os = "freebsd"))]
722+
{
723+
sock.set_no_enobufs(true).unwrap();
724+
assert!(sock.get_no_enobufs().unwrap());
725+
sock.set_no_enobufs(false).unwrap();
726+
assert!(!sock.get_no_enobufs().unwrap());
727+
728+
sock.set_broadcast_error(true).unwrap();
729+
assert!(sock.get_broadcast_error().unwrap());
730+
sock.set_broadcast_error(false).unwrap();
731+
assert!(!sock.get_broadcast_error().unwrap());
732+
}
716733

717734
// FIXME: these require root permissions
718735
// sock.set_listen_all_namespaces(true).unwrap();

0 commit comments

Comments
 (0)