// SPDX-License-Identifier: MIT // This example shows how to use `netlink-proto` with the tokio runtime to print // audit events. // // This example shows how the netlink socket can be accessed // `netlink_proto::Connection`, and configured (in this case to // register to a multicast group). // // Compilation: // ------------ // // cargo build --example audit_netlink_events // // Usage: // ------ // // Find the example binary in the target directory, and run it *as // root*. If you compiled in debug mode with the command above, the // binary should be under: // `/target/debug/examples/audit_netlink_events`. This example runs // forever, you must hit ^C to kill it. use futures::stream::StreamExt; use netlink_packet_audit::{AuditMessage, StatusMessage}; use netlink_packet_core::{ NetlinkMessage, NetlinkPayload, NLM_F_ACK, NLM_F_REQUEST, }; 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 sollicated, ie that are not response to a request we made. // In this example, we'll receive the audit event through that channel. let (conn, 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(()) }