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}