netlink_sys_mio_0_8/
addr.rs

1// SPDX-License-Identifier: MIT
2
3use std::{
4    fmt,
5    hash::{Hash, Hasher},
6    mem,
7};
8
9/// The address of a netlink socket
10///
11/// A netlink address is made of two parts: the unicast address of the socket, called _port number_ or _PID_, and the
12/// multicast address called _group ID_. In this library, we've chosen to stick to the "port number" terminology, since
13/// PID can be confused with process ID. However, the netlink man page mostly uses PID.
14///
15/// ## Port number
16///
17/// Sockets in kernel space have 0 as a port number. For sockets opened by a user-space process, the port number can
18/// either be assigned by the process itself, or by the kernel. The only constraint is that this port number must be
19/// unique: two netlink sockets created by a given process must have a different port number. However, netlinks sockets
20/// created by different processes can have the same port number.
21///
22/// ### Port number assigned by the kernel
23///
24/// One way to set the port number is to let the kernel assign it, by calling [`Socket::bind`][bind] with a port number set to
25/// 0. The kernel will usually use the process ID as port number for the first netlink socket created by the process,
26/// which is why the socket port number is also called PID. For example:
27///
28/// ```rust
29/// use std::process;
30/// use netlink_sys::{
31///     protocols::NETLINK_ROUTE,
32///     SocketAddr, Socket,
33/// };
34///
35/// let mut socket = Socket::new(NETLINK_ROUTE).unwrap();
36/// // The first parameter is the port number. By setting it to 0 we ask the kernel to pick a port for us
37/// let mut addr = SocketAddr::new(0, 0);
38/// socket.bind(&addr).unwrap();
39/// // Retrieve the socket address
40/// socket.get_address(&mut addr).unwrap();
41/// // the socket port number should be equal to the process ID, but there is no guarantee
42/// println!("socket port number = {}, process ID = {}", addr.port_number(), process::id());
43///
44/// let mut socket2 = Socket::new(NETLINK_ROUTE).unwrap();
45/// let mut addr2 = SocketAddr::new(0, 0);
46/// socket2.bind(&addr2).unwrap();
47/// socket2.get_address(&mut addr2).unwrap();
48/// // the unicast address picked by the kernel for the second socket should be different
49/// assert!(addr.port_number() != addr2.port_number());
50/// ```
51///
52/// Note that it's a little tedious to create a socket address, call `bind` and then retrive the address with
53/// [`Socket::get_address`][get_addr]. To avoid this boilerplate you can use [`Socket::bind_auto`][bind_auto]:
54///
55/// ```rust
56/// use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};
57/// use std::process;
58///
59/// let mut socket = Socket::new(NETLINK_ROUTE).unwrap();
60/// let addr = socket.bind_auto().unwrap();
61/// println!("socket port number = {}", addr.port_number());
62/// ```
63///
64/// ### Setting the port number manually
65///
66/// The application can also pick the port number by calling Socket::bind with an address with a non-zero port
67/// number. However, it must ensure that this number is unique for each socket created. For instance:
68///
69/// ```rust
70/// use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};
71/// use std::process;
72///
73/// let mut socket = Socket::new(NETLINK_ROUTE).unwrap();
74/// // set the socket port number to 2
75/// let mut addr = SocketAddr::new(2, 0);
76/// socket.bind(&addr).unwrap();
77/// // Retrieve the socket address
78/// socket.get_address(&mut addr).unwrap();
79/// assert_eq!(2, addr.port_number());
80///
81/// // Creating a second socket with the same port number fails
82/// let mut socket2 = Socket::new(NETLINK_ROUTE).unwrap();
83/// let mut addr2 = SocketAddr::new(2, 0);
84/// socket2.bind(&addr2).unwrap_err();
85/// ```
86///
87/// [bind]: crate::Socket::bind
88/// [bind_auto]: crate::Socket::bind_auto
89/// [get_addr]: crate::Socket::get_address
90#[derive(Copy, Clone)]
91pub struct SocketAddr(pub(crate) libc::sockaddr_nl);
92
93impl Hash for SocketAddr {
94    fn hash<H: Hasher>(&self, state: &mut H) {
95        self.0.nl_family.hash(state);
96        self.0.nl_pid.hash(state);
97        self.0.nl_groups.hash(state);
98    }
99}
100
101impl PartialEq for SocketAddr {
102    fn eq(&self, other: &SocketAddr) -> bool {
103        self.0.nl_family == other.0.nl_family
104            && self.0.nl_pid == other.0.nl_pid
105            && self.0.nl_groups == other.0.nl_groups
106    }
107}
108
109impl fmt::Debug for SocketAddr {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        write!(
112            f,
113            "SocketAddr(nl_family={}, nl_pid={}, nl_groups={})",
114            self.0.nl_family, self.0.nl_pid, self.0.nl_groups
115        )
116    }
117}
118
119impl Eq for SocketAddr {}
120
121impl fmt::Display for SocketAddr {
122    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123        write!(
124            f,
125            "address family: {}, pid: {}, multicast groups: {})",
126            self.0.nl_family, self.0.nl_pid, self.0.nl_groups
127        )
128    }
129}
130
131impl SocketAddr {
132    /// Create a new socket address for with th
133    pub fn new(port_number: u32, multicast_groups: u32) -> Self {
134        let mut addr: libc::sockaddr_nl = unsafe { mem::zeroed() };
135        addr.nl_family = libc::PF_NETLINK as libc::sa_family_t;
136        addr.nl_pid = port_number;
137        addr.nl_groups = multicast_groups;
138        SocketAddr(addr)
139    }
140
141    /// Get the unicast address of this socket
142    pub fn port_number(&self) -> u32 {
143        self.0.nl_pid
144    }
145
146    /// Get the multicast groups of this socket
147    pub fn multicast_groups(&self) -> u32 {
148        self.0.nl_groups
149    }
150
151    pub(crate) fn as_raw(&self) -> (*const libc::sockaddr, libc::socklen_t) {
152        let addr_ptr = &self.0 as *const libc::sockaddr_nl as *const libc::sockaddr;
153        //             \                                 / \                      /
154        //              +---------------+---------------+   +----------+---------+
155        //                               |                             |
156        //                               v                             |
157        //             create a raw pointer to the sockaddr_nl         |
158        //                                                             v
159        //                                                cast *sockaddr_nl -> *sockaddr
160        //
161        // This kind of things seems to be pretty usual when using C APIs from Rust. It could be
162        // written in a shorter way thank to type inference:
163        //
164        //      let addr_ptr: *const libc:sockaddr = &self.0 as *const _ as *const _;
165        //
166        // But since this is my first time dealing with this kind of things I chose the most
167        // explicit form.
168
169        let addr_len = mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t;
170        (addr_ptr, addr_len)
171    }
172
173    pub(crate) fn as_raw_mut(&mut self) -> (*mut libc::sockaddr, libc::socklen_t) {
174        let addr_ptr = &mut self.0 as *mut libc::sockaddr_nl as *mut libc::sockaddr;
175        let addr_len = mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t;
176        (addr_ptr, addr_len)
177    }
178}