netlink-proto 0.5.0

async netlink protocol
Documentation

netlink-proto is an asynchronous implementation of the Netlink protocol.

Example: listening for audit events

This example shows how to use netlink-proto with the tokio runtime to print audit events. It requires extra external dependencies:

  • futures = "^0.3"
  • tokio = "^0.2"
  • netlink-packet-audit = "^0.1"
use futures::stream::StreamExt;
use netlink_packet_audit::{
NLM_F_ACK, NLM_F_REQUEST, NetlinkMessage, NetlinkPayload,
AuditMessage, StatusMessage,
};
use std::process;

use netlink_proto::{
new_connection,
sys::{SocketAddr, protocols::NETLINK_AUDIT},
};

const AUDIT_STATUS_ENABLED: u32 = 1;
const AUDIT_STATUS_PID: u32 = 4;

#[tokio::main]
async fn main() -> Result<(), String> {
// Create a netlink socket. Here:
//
// - `conn` is a `Connection` that has the netlink socket. It's a
//   `Future` that keeps polling the socket and must be spawned an
//   the event loop.
//
// - `handle` is a `Handle` to the `Connection`. We use it to send
//   netlink messages and receive responses to these messages.
//
// - `messages` is a channel receiver through which we receive
//   messages that we have not solicited, ie that are not
//   response to a request we made. In this example, we'll receive
//   the audit event through that channel.
let (conn, mut handle, mut messages) = new_connection(NETLINK_AUDIT)
.map_err(|e| format!("Failed to create a new netlink connection: {}", e))?;

// Spawn the `Connection` so that it starts polling the netlink
// socket in the background.
tokio::spawn(conn);

// Use the `ConnectionHandle` to send a request to the kernel
// asking it to start multicasting audit event messages.
tokio::spawn(async move {
// Craft the packet to enable audit events
let mut status = StatusMessage::new();
status.enabled = 1;
status.pid = process::id();
status.mask = AUDIT_STATUS_ENABLED | AUDIT_STATUS_PID;
let payload = AuditMessage::SetStatus(status);
let mut nl_msg = NetlinkMessage::from(payload);
nl_msg.header.flags = NLM_F_REQUEST | NLM_F_ACK;

// We'll send unicast messages to the kernel.
let kernel_unicast: SocketAddr = SocketAddr::new(0, 0);
let mut response = match handle.request(nl_msg, kernel_unicast) {
Ok(response) => response,
Err(e) => {
eprintln!("{}", e);
return;
}
};

while let Some(message) = response.next().await {
if let NetlinkPayload::Error(err_message) = message.payload {
eprintln!("Received an error message: {:?}", err_message);
return;
}
}
});

// Finally, start receiving event through the `messages` channel.
println!("Starting to print audit events... press ^C to interrupt");
while let Some((message, _addr)) = messages.next().await {
if let NetlinkPayload::Error(err_message) = message.payload {
eprintln!("received an error message: {:?}", err_message);
} else {
println!("{:?}", message);
}
}

Ok(())
}

Example: dumping all the machine's links

This example shows how to use netlink-proto with the ROUTE protocol.

Here we do not use netlink_proto::new_connection(), and instead create the socket manually and use call send() and receive() directly. In the previous example, the NetlinkFramed was wrapped in a Connection which was polled automatically by the runtime.

use futures::StreamExt;

use netlink_packet_route::{
NLM_F_DUMP, NLM_F_REQUEST, NetlinkMessage, NetlinkHeader, LinkMessage, RtnlMessage
};

use netlink_proto::{
new_connection,
sys::{SocketAddr, protocols::NETLINK_ROUTE},
};

#[tokio::main]
async fn main() -> Result<(), String> {
// Create the netlink socket. Here, we won't use the channel that
// receives unsolicited messages.
let (conn, mut handle, _) = new_connection(NETLINK_ROUTE)
.map_err(|e| format!("Failed to create a new netlink connection: {}", e))?;

// Spawn the `Connection` in the background
tokio::spawn(conn);

// Create the netlink message that requests the links to be dumped
let msg = NetlinkMessage {
header: NetlinkHeader {
sequence_number: 1,
flags: NLM_F_DUMP | NLM_F_REQUEST,
..Default::default()
},
payload: RtnlMessage::GetLink(LinkMessage::default()).into(),
};

// Send the request
let mut response = handle
.request(msg, SocketAddr::new(0, 0))
.map_err(|e| format!("Failed to send request: {}", e))?;

// Print all the messages received in response
loop {
if let Some(packet) = response.next().await {
println!("<<< {:?}", packet);
} else {
break;
}
}

Ok(())
}