netlink_sys/
socket.rs

1// SPDX-License-Identifier: MIT
2
3use std::{
4    io::{Error, Result},
5    mem,
6    os::unix::io::{AsRawFd, FromRawFd, RawFd},
7};
8
9use crate::SocketAddr;
10
11/// A netlink socket.
12///
13/// # Example
14///
15/// In this example we:
16///
17/// 1. open a new socket
18/// 2. send a message to the kernel
19/// 3. read the reponse
20///
21/// ```rust
22/// use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};
23/// use std::process;
24///
25/// // open a new socket for the NETLINK_ROUTE subsystem (see "man 7 rtnetlink")
26/// let mut socket = Socket::new(NETLINK_ROUTE).unwrap();
27/// // address of the remote peer we'll send a message to. This particular address is for the kernel
28/// let kernel_addr = SocketAddr::new(0, 0);
29/// // this is a valid message for listing the network links on the system
30/// let pkt = vec![
31///     0x14, 0x00, 0x00, 0x00, 0x12, 0x00, 0x01, 0x03, 0xfd, 0xfe, 0x38, 0x5c, 0x00, 0x00, 0x00,
32///     0x00, 0x00, 0x00, 0x00, 0x00,
33/// ];
34/// // send the message to the kernel
35/// let n_sent = socket.send_to(&pkt[..], &kernel_addr, 0).unwrap();
36/// assert_eq!(n_sent, pkt.len());
37/// // buffer for receiving the response
38/// let mut buf = vec![0; 4096];
39/// loop {
40///     // receive a datagram
41///     let (n_received, sender_addr) = socket.recv_from(&mut &mut buf[..], 0).unwrap();
42///     assert_eq!(sender_addr, kernel_addr);
43///     println!("received datagram {:?}", &buf[..n_received]);
44///     if buf[4] == 2 && buf[5] == 0 {
45///         println!("the kernel responded with an error");
46///         return;
47///     }
48///     if buf[4] == 3 && buf[5] == 0 {
49///         println!("end of dump");
50///         return;
51///     }
52/// }
53/// ```
54#[derive(Clone, Debug)]
55pub struct Socket(RawFd);
56
57impl AsRawFd for Socket {
58    fn as_raw_fd(&self) -> RawFd {
59        self.0
60    }
61}
62
63impl FromRawFd for Socket {
64    unsafe fn from_raw_fd(fd: RawFd) -> Self {
65        Socket(fd)
66    }
67}
68
69impl Drop for Socket {
70    fn drop(&mut self) {
71        unsafe { libc::close(self.0) };
72    }
73}
74
75impl Socket {
76    /// Open a new socket for the given netlink subsystem. `protocol` must be
77    /// one of the [`netlink_sys::protocols`][protos] constants.
78    ///
79    /// [protos]: crate::protocols
80    pub fn new(protocol: isize) -> Result<Self> {
81        let res = unsafe {
82            libc::socket(
83                libc::PF_NETLINK,
84                libc::SOCK_DGRAM | libc::SOCK_CLOEXEC,
85                protocol as libc::c_int,
86            )
87        };
88        if res < 0 {
89            return Err(Error::last_os_error());
90        }
91        Ok(Socket(res))
92    }
93
94    /// Bind the socket to the given address
95    pub fn bind(&mut self, addr: &SocketAddr) -> Result<()> {
96        let (addr_ptr, addr_len) = addr.as_raw();
97        let res = unsafe { libc::bind(self.0, addr_ptr, addr_len) };
98        if res < 0 {
99            return Err(Error::last_os_error());
100        }
101        Ok(())
102    }
103
104    /// Bind the socket to an address assigned by the kernel, and return that
105    /// address.
106    pub fn bind_auto(&mut self) -> Result<SocketAddr> {
107        let mut addr = SocketAddr::new(0, 0);
108        self.bind(&addr)?;
109        self.get_address(&mut addr)?;
110        Ok(addr)
111    }
112
113    /// Get the socket address
114    pub fn get_address(&self, addr: &mut SocketAddr) -> Result<()> {
115        let (addr_ptr, mut addr_len) = addr.as_raw_mut();
116        let addr_len_copy = addr_len;
117        let addr_len_ptr = &mut addr_len as *mut libc::socklen_t;
118        let res = unsafe { libc::getsockname(self.0, addr_ptr, addr_len_ptr) };
119        if res < 0 {
120            return Err(Error::last_os_error());
121        }
122        assert_eq!(addr_len, addr_len_copy);
123        Ok(())
124    }
125
126    // when building with --features smol we don't need this
127    #[allow(dead_code)]
128    /// Make this socket non-blocking
129    pub fn set_non_blocking(&self, non_blocking: bool) -> Result<()> {
130        let mut non_blocking = non_blocking as libc::c_int;
131        let res =
132            unsafe { libc::ioctl(self.0, libc::FIONBIO, &mut non_blocking) };
133        if res < 0 {
134            return Err(Error::last_os_error());
135        }
136        Ok(())
137    }
138
139    /// Connect the socket to the given address. Netlink is a connection-less
140    /// protocol, so a socket can communicate with multiple peers with the
141    /// [`Socket::send_to`] and [`Socket::recv_from`] methods. However, if the
142    /// socket only needs to communicate with one peer, it is convenient not
143    /// to have to bother with the peer address. This is what `connect` is
144    /// for. After calling `connect`, [`Socket::send`] and [`Socket::recv`]
145    /// respectively send and receive datagrams to and from `remote_addr`.
146    ///
147    /// # Examples
148    ///
149    /// In this example we:
150    ///
151    /// 1. open a socket
152    /// 2. connect it to the kernel with [`Socket::connect`]
153    /// 3. send a request to the kernel with [`Socket::send`]
154    /// 4. read the response (which can span over several messages)
155    /// [`Socket::recv`]
156    ///
157    /// ```rust
158    /// use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};
159    /// use std::process;
160    ///
161    /// let mut socket = Socket::new(NETLINK_ROUTE).unwrap();
162    /// let _ = socket.bind_auto().unwrap();
163    /// let kernel_addr = SocketAddr::new(0, 0);
164    /// socket.connect(&kernel_addr).unwrap();
165    /// // This is a valid message for listing the network links on the system
166    /// let msg = vec![
167    ///     0x14, 0x00, 0x00, 0x00, 0x12, 0x00, 0x01, 0x03, 0xfd, 0xfe, 0x38, 0x5c, 0x00, 0x00, 0x00,
168    ///     0x00, 0x00, 0x00, 0x00, 0x00,
169    /// ];
170    /// let n_sent = socket.send(&msg[..], 0).unwrap();
171    /// assert_eq!(n_sent, msg.len());
172    /// // buffer for receiving the response
173    /// let mut buf = vec![0; 4096];
174    /// loop {
175    ///     let mut n_received = socket.recv(&mut &mut buf[..], 0).unwrap();
176    ///     println!("received {:?}", &buf[..n_received]);
177    ///     if buf[4] == 2 && buf[5] == 0 {
178    ///         println!("the kernel responded with an error");
179    ///         return;
180    ///     }
181    ///     if buf[4] == 3 && buf[5] == 0 {
182    ///         println!("end of dump");
183    ///         return;
184    ///     }
185    /// }
186    /// ```
187    pub fn connect(&self, remote_addr: &SocketAddr) -> Result<()> {
188        // FIXME:
189        //
190        // Event though for SOCK_DGRAM sockets there's no IO, if our socket is
191        // non-blocking, connect() might return EINPROGRESS. In theory,
192        // the right way to treat EINPROGRESS would be to ignore the
193        // error, and let the user poll the socket to check when it becomes
194        // writable, indicating that the connection succeeded. The code already
195        // exists in mio for TcpStream:
196        //
197        // > pub fn connect(stream: net::TcpStream, addr: &SocketAddr) ->
198        // > io::Result<TcpStream> {
199        // > set_non_block(stream.as_raw_fd())?;
200        // > match stream.connect(addr) {
201        // > Ok(..) => {}
202        // > Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}
203        // > Err(e) => return Err(e),
204        // > }
205        // > Ok(TcpStream {  inner: stream })
206        // > }
207        //
208        // In practice, since the connection does not require any IO for
209        // SOCK_DGRAM sockets, it almost never returns EINPROGRESS and
210        // so for now, we just return whatever libc::connect returns. If
211        // it returns EINPROGRESS, the caller will have to handle the error
212        // themself
213        //
214        // Refs:
215        //
216        // - https://stackoverflow.com/a/14046386/1836144
217        // - https://lists.isc.org/pipermail/bind-users/2009-August/077527.html
218        let (addr, addr_len) = remote_addr.as_raw();
219        let res = unsafe { libc::connect(self.0, addr, addr_len) };
220        if res < 0 {
221            return Err(Error::last_os_error());
222        }
223        Ok(())
224    }
225
226    // Most of the comments in this method come from a discussion on rust users
227    // forum. [thread]: https://users.rust-lang.org/t/help-understanding-libc-call/17308/9
228    //
229    /// Read a datagram from the socket and return the number of bytes that have
230    /// been read and the address of the sender. The data being read is
231    /// copied into `buf`. If `buf` is too small, the datagram is truncated. The
232    /// supported flags are the `MSG_*` described in `man 2 recvmsg`
233    ///
234    /// # Warning
235    ///
236    /// In datagram oriented protocols, `recv` and `recvfrom` receive normally
237    /// only ONE datagram, but this seems not to be always true for netlink
238    /// sockets: with some protocols like `NETLINK_AUDIT`, multiple netlink
239    /// packets can be read with a single call.
240    pub fn recv_from<B>(
241        &self,
242        buf: &mut B,
243        flags: libc::c_int,
244    ) -> Result<(usize, SocketAddr)>
245    where
246        B: bytes::BufMut,
247    {
248        // Create an empty storage for the address. Note that Rust standard
249        // library create a sockaddr_storage so that it works for any
250        // address family, but here, we already know that we'll have a
251        // Netlink address, so we can create the appropriate storage.
252        let mut addr = unsafe { mem::zeroed::<libc::sockaddr_nl>() };
253
254        // recvfrom takes a *sockaddr as parameter so that it can accept any
255        // kind of address storage, so we need to create such a pointer
256        // for the sockaddr_nl we just initialized.
257        //
258        //                     Create a raw pointer to        Cast our raw
259        // pointer to a                     our storage. We cannot
260        // generic pointer to *sockaddr                     pass it to
261        // recvfrom yet.       that recvfrom can use
262        // ^                              ^
263        // |                              |
264        // +--------------+---------------+    +---------+--------+
265        //                 /                                \  /
266        // \
267        let addr_ptr =
268            &mut addr as *mut libc::sockaddr_nl as *mut libc::sockaddr;
269
270        // Why do we need to pass the address length? We're passing a generic
271        // *sockaddr to recvfrom. Somehow recvfrom needs to make sure
272        // that the address of the received packet would fit into the
273        // actual type that is behind *sockaddr: it could be a sockaddr_nl but
274        // also a sockaddr_in, a sockaddr_in6, or even the generic
275        // sockaddr_storage that can store any address.
276        let mut addrlen = mem::size_of_val(&addr);
277        // recvfrom does not take the address length by value (see [thread]), so
278        // we need to create a pointer to it.
279        let addrlen_ptr = &mut addrlen as *mut usize as *mut libc::socklen_t;
280
281        let chunk = buf.chunk_mut();
282        //                        Cast the *mut u8 into *mut void.
283        //                 This is equivalent to casting a *char into *void
284        //                                   See [thread]
285        //                                         ^
286        //             Create a *mut u8            |
287        //                    ^                    |
288        //                    |                    |
289        //             +------+-------+   +--------+-------+
290        //            /                \ /                  \
291        let buf_ptr = chunk.as_mut_ptr() as *mut libc::c_void;
292        let buf_len = chunk.len() as libc::size_t;
293
294        let res = unsafe {
295            libc::recvfrom(
296                self.0,
297                buf_ptr,
298                buf_len,
299                flags,
300                addr_ptr,
301                addrlen_ptr,
302            )
303        };
304        if res < 0 {
305            return Err(Error::last_os_error());
306        } else {
307            // with `MSG_TRUNC` `res` might exceed `buf_len`
308            let written = std::cmp::min(buf_len, res as usize);
309            unsafe {
310                buf.advance_mut(written);
311            }
312        }
313        Ok((res as usize, SocketAddr(addr)))
314    }
315
316    /// For a connected socket, `recv` reads a datagram from the socket. The
317    /// sender is the remote peer the socket is connected to (see
318    /// [`Socket::connect`]). See also [`Socket::recv_from`]
319    pub fn recv<B>(&self, buf: &mut B, flags: libc::c_int) -> Result<usize>
320    where
321        B: bytes::BufMut,
322    {
323        let chunk = buf.chunk_mut();
324        let buf_ptr = chunk.as_mut_ptr() as *mut libc::c_void;
325        let buf_len = chunk.len() as libc::size_t;
326
327        let res = unsafe { libc::recv(self.0, buf_ptr, buf_len, flags) };
328        if res < 0 {
329            return Err(Error::last_os_error());
330        } else {
331            // with `MSG_TRUNC` `res` might exceed `buf_len`
332            let written = std::cmp::min(buf_len, res as usize);
333            unsafe {
334                buf.advance_mut(written);
335            }
336        }
337        Ok(res as usize)
338    }
339
340    /// Receive a full message. Unlike [`Socket::recv_from`], which truncates
341    /// messages that exceed the length of the buffer passed as argument,
342    /// this method always reads a whole message, no matter its size.
343    pub fn recv_from_full(&self) -> Result<(Vec<u8>, SocketAddr)> {
344        // Peek
345        let mut buf: Vec<u8> = Vec::new();
346        let (peek_len, _) =
347            self.recv_from(&mut buf, libc::MSG_PEEK | libc::MSG_TRUNC)?;
348
349        // Receive
350        buf.clear();
351        buf.reserve(peek_len);
352        let (rlen, addr) = self.recv_from(&mut buf, 0)?;
353        assert_eq!(rlen, peek_len);
354        Ok((buf, addr))
355    }
356
357    /// Send the given buffer `buf` to the remote peer with address `addr`. The
358    /// supported flags are the `MSG_*` values documented in `man 2 send`.
359    pub fn send_to(
360        &self,
361        buf: &[u8],
362        addr: &SocketAddr,
363        flags: libc::c_int,
364    ) -> Result<usize> {
365        let (addr_ptr, addr_len) = addr.as_raw();
366        let buf_ptr = buf.as_ptr() as *const libc::c_void;
367        let buf_len = buf.len() as libc::size_t;
368
369        let res = unsafe {
370            libc::sendto(self.0, buf_ptr, buf_len, flags, addr_ptr, addr_len)
371        };
372        if res < 0 {
373            return Err(Error::last_os_error());
374        }
375        Ok(res as usize)
376    }
377
378    /// For a connected socket, `send` sends the given buffer `buf` to the
379    /// remote peer the socket is connected to. See also [`Socket::connect`]
380    /// and [`Socket::send_to`].
381    pub fn send(&self, buf: &[u8], flags: libc::c_int) -> Result<usize> {
382        let buf_ptr = buf.as_ptr() as *const libc::c_void;
383        let buf_len = buf.len() as libc::size_t;
384
385        let res = unsafe { libc::send(self.0, buf_ptr, buf_len, flags) };
386        if res < 0 {
387            return Err(Error::last_os_error());
388        }
389        Ok(res as usize)
390    }
391
392    pub fn set_pktinfo(&mut self, value: bool) -> Result<()> {
393        let value: libc::c_int = value.into();
394        setsockopt(self.0, libc::SOL_NETLINK, libc::NETLINK_PKTINFO, value)
395    }
396
397    pub fn get_pktinfo(&self) -> Result<bool> {
398        let res = getsockopt::<libc::c_int>(
399            self.0,
400            libc::SOL_NETLINK,
401            libc::NETLINK_PKTINFO,
402        )?;
403        Ok(res == 1)
404    }
405
406    pub fn add_membership(&mut self, group: u32) -> Result<()> {
407        setsockopt(
408            self.0,
409            libc::SOL_NETLINK,
410            libc::NETLINK_ADD_MEMBERSHIP,
411            group,
412        )
413    }
414
415    pub fn drop_membership(&mut self, group: u32) -> Result<()> {
416        setsockopt(
417            self.0,
418            libc::SOL_NETLINK,
419            libc::NETLINK_DROP_MEMBERSHIP,
420            group,
421        )
422    }
423
424    // pub fn list_membership(&self) -> Vec<u32> {
425    //     unimplemented!();
426    //     // getsockopt won't be enough here, because we may need to perform 2
427    // calls, and because the     // length of the list returned by
428    // libc::getsockopt is returned by mutating the length     // argument,
429    // which our implementation of getsockopt forbids. }
430
431    /// `NETLINK_BROADCAST_ERROR` (since Linux 2.6.30). When not set,
432    /// `netlink_broadcast()` only reports `ESRCH` errors and silently
433    /// ignore `NOBUFS` errors.
434    pub fn set_broadcast_error(&mut self, value: bool) -> Result<()> {
435        let value: libc::c_int = value.into();
436        setsockopt(
437            self.0,
438            libc::SOL_NETLINK,
439            libc::NETLINK_BROADCAST_ERROR,
440            value,
441        )
442    }
443
444    pub fn get_broadcast_error(&self) -> Result<bool> {
445        let res = getsockopt::<libc::c_int>(
446            self.0,
447            libc::SOL_NETLINK,
448            libc::NETLINK_BROADCAST_ERROR,
449        )?;
450        Ok(res == 1)
451    }
452
453    /// `NETLINK_NO_ENOBUFS` (since Linux 2.6.30). This flag can be used by
454    /// unicast and broadcast listeners to avoid receiving `ENOBUFS` errors.
455    pub fn set_no_enobufs(&mut self, value: bool) -> Result<()> {
456        let value: libc::c_int = value.into();
457        setsockopt(self.0, libc::SOL_NETLINK, libc::NETLINK_NO_ENOBUFS, value)
458    }
459
460    pub fn get_no_enobufs(&self) -> Result<bool> {
461        let res = getsockopt::<libc::c_int>(
462            self.0,
463            libc::SOL_NETLINK,
464            libc::NETLINK_NO_ENOBUFS,
465        )?;
466        Ok(res == 1)
467    }
468
469    /// `NETLINK_LISTEN_ALL_NSID` (since Linux 4.2). When set, this socket will
470    /// receive netlink notifications from  all  network  namespaces that
471    /// have an nsid assigned into the network namespace where the socket
472    /// has been opened. The nsid is sent to user space via an ancillary
473    /// data.
474    pub fn set_listen_all_namespaces(&mut self, value: bool) -> Result<()> {
475        let value: libc::c_int = value.into();
476        setsockopt(
477            self.0,
478            libc::SOL_NETLINK,
479            libc::NETLINK_LISTEN_ALL_NSID,
480            value,
481        )
482    }
483
484    pub fn get_listen_all_namespaces(&self) -> Result<bool> {
485        let res = getsockopt::<libc::c_int>(
486            self.0,
487            libc::SOL_NETLINK,
488            libc::NETLINK_LISTEN_ALL_NSID,
489        )?;
490        Ok(res == 1)
491    }
492
493    /// `NETLINK_CAP_ACK` (since Linux 4.2). The kernel may fail to allocate the
494    /// necessary room for the acknowledgment message back to user space.
495    /// This option trims off the payload of the original netlink message.
496    /// The netlink message header is still included, so the user can
497    /// guess from the sequence  number which message triggered the
498    /// acknowledgment.
499    pub fn set_cap_ack(&mut self, value: bool) -> Result<()> {
500        let value: libc::c_int = value.into();
501        setsockopt(self.0, libc::SOL_NETLINK, libc::NETLINK_CAP_ACK, value)
502    }
503
504    pub fn get_cap_ack(&self) -> Result<bool> {
505        let res = getsockopt::<libc::c_int>(
506            self.0,
507            libc::SOL_NETLINK,
508            libc::NETLINK_CAP_ACK,
509        )?;
510        Ok(res == 1)
511    }
512
513    /// `NETLINK_EXT_ACK`
514    /// Extended ACK controls reporting of additional error/warning TLVs in
515    /// NLMSG_ERROR and NLMSG_DONE messages.
516    pub fn set_ext_ack(&mut self, value: bool) -> Result<()> {
517        let value: libc::c_int = value.into();
518        setsockopt(self.0, libc::SOL_NETLINK, libc::NETLINK_EXT_ACK, value)
519    }
520
521    pub fn get_ext_ack(&self) -> Result<bool> {
522        let res = getsockopt::<libc::c_int>(
523            self.0,
524            libc::SOL_NETLINK,
525            libc::NETLINK_EXT_ACK,
526        )?;
527        Ok(res == 1)
528    }
529
530    /// Sets socket receive buffer in bytes.
531    /// The kernel doubles this value (to allow space for bookkeeping overhead),
532    /// and this doubled value is returned by [get_rx_buf_sz].(see socket(7)
533    /// The default value is set by the proc/sys/net/core/rmem_default file, and
534    /// the maximum allowed value is set by the /proc/sys/net/core/rmem_max
535    /// file. The minimum (doubled) value for this option is 256.
536    pub fn set_rx_buf_sz<T>(&self, size: T) -> Result<()> {
537        setsockopt(self.0, libc::SOL_SOCKET, libc::SO_RCVBUF, size)
538    }
539
540    /// Gets socket receive buffer in bytes
541    pub fn get_rx_buf_sz(&self) -> Result<usize> {
542        let res = getsockopt::<libc::c_int>(
543            self.0,
544            libc::SOL_SOCKET,
545            libc::SO_RCVBUF,
546        )?;
547        Ok(res as usize)
548    }
549
550    /// Set strict input checking(`NETLINK_GET_STRICT_CHK`) in netlink route
551    /// protocol. By default, `NETLINK_GET_STRICT_CHK` is not enabled.
552    pub fn set_netlink_get_strict_chk(&self, value: bool) -> Result<()> {
553        let value: u32 = value.into();
554        setsockopt(
555            self.0,
556            libc::SOL_NETLINK,
557            libc::NETLINK_GET_STRICT_CHK,
558            value,
559        )
560    }
561}
562
563/// Wrapper around `getsockopt`:
564///
565/// ```no_rust
566/// int getsockopt(int socket, int level, int option_name, void *restrict option_value, socklen_t *restrict option_len);
567/// ```
568pub(crate) fn getsockopt<T: Copy>(
569    fd: RawFd,
570    level: libc::c_int,
571    option: libc::c_int,
572) -> Result<T> {
573    // Create storage for the options we're fetching
574    let mut slot: T = unsafe { mem::zeroed() };
575
576    // Create a mutable raw pointer to the storage so that getsockopt can fill
577    // the value
578    let slot_ptr = &mut slot as *mut T as *mut libc::c_void;
579
580    // Let getsockopt know how big our storage is
581    let mut slot_len = mem::size_of::<T>() as libc::socklen_t;
582
583    // getsockopt takes a mutable pointer to the length, because for some
584    // options like NETLINK_LIST_MEMBERSHIP where the option value is a list
585    // with arbitrary length, getsockopt uses this parameter to signal how
586    // big the storage needs to be.
587    let slot_len_ptr = &mut slot_len as *mut libc::socklen_t;
588
589    let res =
590        unsafe { libc::getsockopt(fd, level, option, slot_ptr, slot_len_ptr) };
591    if res < 0 {
592        return Err(Error::last_os_error());
593    }
594
595    // Ignore the options that require the legnth to be set by getsockopt.
596    // We'll deal with them individually.
597    assert_eq!(slot_len as usize, mem::size_of::<T>());
598
599    Ok(slot)
600}
601
602// adapted from rust standard library
603fn setsockopt<T>(
604    fd: RawFd,
605    level: libc::c_int,
606    option: libc::c_int,
607    payload: T,
608) -> Result<()> {
609    let payload = &payload as *const T as *const libc::c_void;
610    let payload_len = mem::size_of::<T>() as libc::socklen_t;
611
612    let res =
613        unsafe { libc::setsockopt(fd, level, option, payload, payload_len) };
614    if res < 0 {
615        return Err(Error::last_os_error());
616    }
617    Ok(())
618}
619
620#[cfg(test)]
621mod test {
622    use super::*;
623    use crate::protocols::NETLINK_ROUTE;
624
625    #[test]
626    fn new() {
627        Socket::new(NETLINK_ROUTE).unwrap();
628    }
629
630    #[test]
631    fn connect() {
632        let sock = Socket::new(NETLINK_ROUTE).unwrap();
633        sock.connect(&SocketAddr::new(0, 0)).unwrap();
634    }
635
636    #[test]
637    fn bind() {
638        let mut sock = Socket::new(NETLINK_ROUTE).unwrap();
639        sock.bind(&SocketAddr::new(4321, 0)).unwrap();
640    }
641
642    #[test]
643    fn bind_auto() {
644        let mut sock = Socket::new(NETLINK_ROUTE).unwrap();
645        let addr = sock.bind_auto().unwrap();
646        // make sure that the address we got from the kernel is there
647        assert!(addr.port_number() != 0);
648    }
649
650    #[test]
651    fn set_non_blocking() {
652        let sock = Socket::new(NETLINK_ROUTE).unwrap();
653        sock.set_non_blocking(true).unwrap();
654        sock.set_non_blocking(false).unwrap();
655    }
656
657    #[test]
658    fn options() {
659        let mut sock = Socket::new(NETLINK_ROUTE).unwrap();
660
661        sock.set_cap_ack(true).unwrap();
662        assert!(sock.get_cap_ack().unwrap());
663        sock.set_cap_ack(false).unwrap();
664        assert!(!sock.get_cap_ack().unwrap());
665
666        sock.set_no_enobufs(true).unwrap();
667        assert!(sock.get_no_enobufs().unwrap());
668        sock.set_no_enobufs(false).unwrap();
669        assert!(!sock.get_no_enobufs().unwrap());
670
671        sock.set_broadcast_error(true).unwrap();
672        assert!(sock.get_broadcast_error().unwrap());
673        sock.set_broadcast_error(false).unwrap();
674        assert!(!sock.get_broadcast_error().unwrap());
675
676        // FIXME: these require root permissions
677        // sock.set_listen_all_namespaces(true).unwrap();
678        // assert!(sock.get_listen_all_namespaces().unwrap());
679        // sock.set_listen_all_namespaces(false).unwrap();
680        // assert!(!sock.get_listen_all_namespaces().unwrap());
681    }
682}