20 releases (10 breaking)
0.11.3 | Jan 29, 2024 |
---|---|
0.11.2 | Jul 9, 2023 |
0.11.1 | Jan 28, 2023 |
0.10.0 | Jun 24, 2022 |
0.1.1 | Jan 2, 2019 |
#490 in Network programming
397,262 downloads per month
Used in 340 crates
(13 directly)
44KB
843 lines
Rust async netlink protocol
The netlink-proto
crate is an asynchronous implementation of the netlink
protocol. It only depends on netlink-packet-core
for the
NetlinkMessage
type and netlink-sys
for the socket.
lib.rs
:
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 = "^1.0"
netlink-packet-audit = "^0.1"
use futures::stream::StreamExt;
use netlink_packet_core::{NetlinkMessage, NetlinkPayload, NLM_F_ACK,
NLM_F_REQUEST};
use netlink_packet_audit::{
AuditMessage,
StatusMessage,
};
use std::process;
use netlink_proto::{
new_connection,
sys::{protocols::NETLINK_AUDIT, SocketAddr},
};
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::{link::LinkMessage, RouteNetlinkMessage};
use netlink_packet_core::{
NetlinkHeader,
NetlinkMessage,
NLM_F_REQUEST, NLM_F_DUMP
};
use netlink_proto::{
new_connection,
sys::{protocols::NETLINK_ROUTE, SocketAddr},
};
#[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 mut nl_hdr = NetlinkHeader::default();
nl_hdr.flags = NLM_F_DUMP | NLM_F_REQUEST;
let msg = NetlinkMessage::new(
nl_hdr,
RouteNetlinkMessage::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(())
}
Dependencies
~3–18MB
~186K SLoC