pub struct AgentBuilder { /* private fields */ }Expand description
Builder for Agent.
Use this builder to configure and construct an SNMP agent. The builder
pattern allows you to chain configuration methods before calling
build() to create the agent.
§Access Control
By default, the agent operates in permissive mode: any authenticated request (valid community string for v1/v2c, valid USM credentials for v3) has full read and write access to all registered handlers.
For production deployments, use the vacm() method
to configure View-based Access Control (RFC 3415), which allows fine-grained
control over which security names can access which OID subtrees.
§Minimal Example
use async_snmp::agent::Agent;
use async_snmp::handler::{MibHandler, RequestContext, GetResult, GetNextResult, BoxFuture};
use async_snmp::{Oid, Value, VarBind, oid};
use std::sync::Arc;
struct MyHandler;
impl MibHandler for MyHandler {
fn get<'a>(&'a self, _: &'a RequestContext, _: &'a Oid) -> BoxFuture<'a, GetResult> {
Box::pin(async { GetResult::NoSuchObject })
}
fn get_next<'a>(&'a self, _: &'a RequestContext, _: &'a Oid) -> BoxFuture<'a, GetNextResult> {
Box::pin(async { GetNextResult::EndOfMibView })
}
}
let agent = Agent::builder()
.bind("0.0.0.0:1161") // Use non-privileged port
.community(b"public")
.handler(oid!(1, 3, 6, 1, 4, 1, 99999), Arc::new(MyHandler))
.build()
.await?;Implementations§
Source§impl AgentBuilder
impl AgentBuilder
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new builder with default settings.
Defaults:
- Bind address:
0.0.0.0:161(UDP) - Max message size: 1472 bytes (Ethernet MTU - IP/UDP headers)
- Max concurrent requests: 1000
- Receive buffer size: 4MB (requested from kernel)
- No communities or USM users (all requests rejected)
- No handlers registered
Sourcepub fn bind(self, addr: impl Into<String>) -> Self
pub fn bind(self, addr: impl Into<String>) -> Self
Set the UDP bind address.
Default is 0.0.0.0:161 (standard SNMP agent port). Note that binding
to UDP port 161 typically requires root/administrator privileges.
§IPv4 Examples
use async_snmp::agent::Agent;
// Bind to all IPv4 interfaces on standard port (requires privileges)
let agent = Agent::builder().bind("0.0.0.0:161").community(b"public").build().await?;
// Bind to localhost only on non-privileged port
let agent = Agent::builder().bind("127.0.0.1:1161").community(b"public").build().await?;
// Bind to specific interface
let agent = Agent::builder().bind("192.168.1.100:161").community(b"public").build().await?;§IPv6 / Dual-Stack Examples
use async_snmp::agent::Agent;
// Bind to all interfaces via dual-stack (handles both IPv4 and IPv6)
let agent = Agent::builder().bind("[::]:161").community(b"public").build().await?;
// Bind to IPv6 localhost only
let agent = Agent::builder().bind("[::1]:1161").community(b"public").build().await?;Sourcepub fn community(self, community: &[u8]) -> Self
pub fn community(self, community: &[u8]) -> Self
Add an accepted community string for v1/v2c requests.
Multiple communities can be added. If none are added, all v1/v2c requests are rejected.
§Example
use async_snmp::agent::Agent;
let agent = Agent::builder()
.bind("0.0.0.0:1161")
.community(b"public") // Read-only access
.community(b"private") // Read-write access (with VACM)
.build()
.await?;Sourcepub fn communities<I, C>(self, communities: I) -> Self
pub fn communities<I, C>(self, communities: I) -> Self
Add multiple community strings.
§Example
use async_snmp::agent::Agent;
let communities = ["public", "private", "monitor"];
let agent = Agent::builder()
.bind("0.0.0.0:1161")
.communities(communities)
.build()
.await?;Sourcepub fn usm_user<F>(self, username: impl Into<Bytes>, configure: F) -> Self
pub fn usm_user<F>(self, username: impl Into<Bytes>, configure: F) -> Self
Add a USM user for SNMPv3 authentication.
Configure authentication and privacy settings using the closure. Multiple users can be added with different security levels.
§Security Levels
- noAuthNoPriv: No authentication or encryption
- authNoPriv: Authentication only (HMAC verification)
- authPriv: Authentication and encryption
§Example
use async_snmp::agent::Agent;
use async_snmp::{AuthProtocol, PrivProtocol};
let agent = Agent::builder()
.bind("0.0.0.0:1161")
// Read-only user with authentication only
.usm_user("monitor", |u| {
u.auth(AuthProtocol::Sha256, b"monitorpass123")
})
// Admin user with full encryption
.usm_user("admin", |u| {
u.auth(AuthProtocol::Sha256, b"adminauth123")
.privacy(PrivProtocol::Aes128, b"adminpriv123")
})
.build()
.await?;Sourcepub fn engine_id(self, engine_id: impl Into<Vec<u8>>) -> Self
pub fn engine_id(self, engine_id: impl Into<Vec<u8>>) -> Self
Set the engine ID for SNMPv3.
If not set, a default engine ID will be generated based on the RFC 3411 format using enterprise number and timestamp.
§Example
use async_snmp::agent::Agent;
let agent = Agent::builder()
.bind("0.0.0.0:1161")
.engine_id(b"\x80\x00\x00\x00\x01MyEngine".to_vec())
.community(b"public")
.build()
.await?;Sourcepub fn max_message_size(self, size: usize) -> Self
pub fn max_message_size(self, size: usize) -> Self
Set the maximum message size for responses.
Default is 1472 octets (fits Ethernet MTU minus IP/UDP headers). GETBULK responses will be truncated to fit within this limit.
For SNMPv3 requests, the agent uses the minimum of this value and the msgMaxSize from the request.
Sourcepub fn max_concurrent_requests(self, limit: Option<usize>) -> Self
pub fn max_concurrent_requests(self, limit: Option<usize>) -> Self
Set the maximum number of concurrent requests the agent will process.
Default is 1000. Requests beyond this limit will queue until a slot
becomes available. Set to None for unbounded concurrency.
This controls memory usage under high load while still allowing parallel request processing.
Sourcepub fn recv_buffer_size(self, size: Option<usize>) -> Self
pub fn recv_buffer_size(self, size: Option<usize>) -> Self
Set the UDP socket receive buffer size.
Default is 4MB. The kernel may cap this at net.core.rmem_max.
A larger buffer prevents packet loss during request bursts.
Set to None to use the kernel default.
Sourcepub fn handler(self, prefix: Oid, handler: Arc<dyn MibHandler>) -> Self
pub fn handler(self, prefix: Oid, handler: Arc<dyn MibHandler>) -> Self
Register a MIB handler for an OID subtree.
Handlers are matched by longest prefix. When a request comes in, the handler with the longest matching prefix is used.
§Example
use async_snmp::agent::Agent;
use async_snmp::handler::{MibHandler, RequestContext, GetResult, GetNextResult, BoxFuture};
use async_snmp::{Oid, Value, VarBind, oid};
use std::sync::Arc;
struct SystemHandler;
impl MibHandler for SystemHandler {
fn get<'a>(&'a self, _: &'a RequestContext, oid: &'a Oid) -> BoxFuture<'a, GetResult> {
Box::pin(async move {
if oid == &oid!(1, 3, 6, 1, 2, 1, 1, 1, 0) {
GetResult::Value(Value::OctetString("My Agent".into()))
} else {
GetResult::NoSuchObject
}
})
}
fn get_next<'a>(&'a self, _: &'a RequestContext, _: &'a Oid) -> BoxFuture<'a, GetNextResult> {
Box::pin(async { GetNextResult::EndOfMibView })
}
}
let agent = Agent::builder()
.bind("0.0.0.0:1161")
.community(b"public")
// Register handler for system MIB subtree
.handler(oid!(1, 3, 6, 1, 2, 1, 1), Arc::new(SystemHandler))
.build()
.await?;Sourcepub fn vacm<F>(self, configure: F) -> Self
pub fn vacm<F>(self, configure: F) -> Self
Configure VACM (View-based Access Control Model) using a builder function.
When VACM is configured, all requests are checked against the configured
access control rules. Requests that don’t have proper access are rejected
with noAccess error (v2c/v3) or noSuchName (v1).
Without VACM configuration, the agent operates in permissive mode: any authenticated request has full read/write access to all handlers.
§Example
use async_snmp::agent::{Agent, SecurityModel, VacmBuilder};
use async_snmp::message::SecurityLevel;
use async_snmp::oid;
let agent = Agent::builder()
.bind("0.0.0.0:161")
.community(b"public")
.community(b"private")
.vacm(|v| v
.group("public", SecurityModel::V2c, "readonly_group")
.group("private", SecurityModel::V2c, "readwrite_group")
.access("readonly_group", |a| a
.read_view("full_view"))
.access("readwrite_group", |a| a
.read_view("full_view")
.write_view("write_view"))
.view("full_view", |v| v
.include(oid!(1, 3, 6, 1)))
.view("write_view", |v| v
.include(oid!(1, 3, 6, 1, 2, 1, 1))))
.build()
.await?;Sourcepub fn cancel(self, token: CancellationToken) -> Self
pub fn cancel(self, token: CancellationToken) -> Self
Set a cancellation token for graceful shutdown.
If not set, the agent creates its own token accessible via Agent::cancel().