20 个版本 (10 个重大更新)
0.11.3 | 2024 年 1 月 29 日 |
---|---|
0.11.2 | 2023 年 7 月 9 日 |
0.11.1 | 2023 年 1 月 28 日 |
0.10.0 | 2022 年 6 月 24 日 |
0.1.1 | 2019 年 1 月 2 日 |
#473 在 网络编程 中
374,495 每月下载量
在 301 个包 (13 个直接使用)
44KB
843 行
Rust 异步 netlink 协议
netlink-proto
包是 netlink 协议的异步实现。它仅依赖于 netlink-packet-core
用于 NetlinkMessage
类型,以及 netlink-sys
用于套接字。
lib.rs
:
netlink-proto
是 Netlink 协议的异步实现。
示例:监听审计事件
此示例展示了如何使用 netlink-proto
和 tokio
运行时来打印审计事件。它需要额外的外部依赖
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(())
}
示例:导出所有机器的链路
此示例展示了如何使用 netlink-proto
和 ROUTE 协议。
在这里,我们不使用 netlink_proto::new_connection()
,而是手动创建套接字,并直接调用 send()
和 receive()
。在先前的示例中,NetlinkFramed
被包装在一个 Connection
中,该连接由运行时自动轮询。
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(())
}
依赖项
~3–14MB
~179K SLoC