support snmp v1
This commit is contained in:
parent
0548ca313d
commit
dbf66af5c0
2 changed files with 76 additions and 20 deletions
|
|
@ -24,29 +24,23 @@ impl SnmpClient {
|
||||||
port: u16,
|
port: u16,
|
||||||
oid: &str,
|
oid: &str,
|
||||||
) -> SnmpResult<SnmpValue> {
|
) -> SnmpResult<SnmpValue> {
|
||||||
// Only SNMPv2c is supported by the snmp crate
|
|
||||||
if version != "2c" {
|
|
||||||
return Err(SnmpError::RequestFailed(format!(
|
|
||||||
"Unsupported SNMP version: {}. Only 2c is supported.",
|
|
||||||
version
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse OID string to Vec<u32>
|
// Parse OID string to Vec<u32>
|
||||||
let oid_parts = parse_oid(oid)?;
|
let oid_parts = parse_oid(oid)?;
|
||||||
|
|
||||||
// Clone data for the blocking task
|
// Clone data for the blocking task
|
||||||
let addr = format!("{}:{}", ip_address, port);
|
let addr = format!("{}:{}", ip_address, port);
|
||||||
let community = community.as_bytes().to_vec();
|
let community = community.as_bytes().to_vec();
|
||||||
|
let version_num = parse_snmp_version(version)?;
|
||||||
|
|
||||||
// Run SNMP operation in blocking thread pool
|
// Run SNMP operation in blocking thread pool
|
||||||
let result = tokio::task::spawn_blocking(move || {
|
let result = tokio::task::spawn_blocking(move || {
|
||||||
// Create session with configurable timeout
|
// Create session with configurable timeout
|
||||||
|
// The snmp crate supports both v1 (0) and v2c (1)
|
||||||
let mut session = SyncSession::new(
|
let mut session = SyncSession::new(
|
||||||
addr.as_str(),
|
addr.as_str(),
|
||||||
&community,
|
&community,
|
||||||
Some(Duration::from_secs(SNMP_TIMEOUT_SECS)),
|
Some(Duration::from_secs(SNMP_TIMEOUT_SECS)),
|
||||||
0,
|
version_num,
|
||||||
)
|
)
|
||||||
.map_err(|_| SnmpError::NetworkUnreachable)?;
|
.map_err(|_| SnmpError::NetworkUnreachable)?;
|
||||||
|
|
||||||
|
|
@ -84,29 +78,23 @@ impl SnmpClient {
|
||||||
port: u16,
|
port: u16,
|
||||||
base_oid: &str,
|
base_oid: &str,
|
||||||
) -> SnmpResult<Vec<(String, SnmpValue)>> {
|
) -> SnmpResult<Vec<(String, SnmpValue)>> {
|
||||||
// Only SNMPv2c is supported by the snmp crate
|
|
||||||
if version != "2c" {
|
|
||||||
return Err(SnmpError::RequestFailed(format!(
|
|
||||||
"Unsupported SNMP version: {}. Only 2c is supported.",
|
|
||||||
version
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse OID string to Vec<u32>
|
// Parse OID string to Vec<u32>
|
||||||
let base_oid_parts = parse_oid(base_oid)?;
|
let base_oid_parts = parse_oid(base_oid)?;
|
||||||
|
|
||||||
// Clone data for the blocking task
|
// Clone data for the blocking task
|
||||||
let addr = format!("{}:{}", ip_address, port);
|
let addr = format!("{}:{}", ip_address, port);
|
||||||
let community = community.as_bytes().to_vec();
|
let community = community.as_bytes().to_vec();
|
||||||
|
let version_num = parse_snmp_version(version)?;
|
||||||
|
|
||||||
// Run SNMP walk in blocking thread pool
|
// Run SNMP walk in blocking thread pool
|
||||||
let results = tokio::task::spawn_blocking(move || {
|
let results = tokio::task::spawn_blocking(move || {
|
||||||
// Create session with configurable timeout
|
// Create session with configurable timeout
|
||||||
|
// The snmp crate supports both v1 (0) and v2c (1)
|
||||||
let mut session = SyncSession::new(
|
let mut session = SyncSession::new(
|
||||||
addr.as_str(),
|
addr.as_str(),
|
||||||
&community,
|
&community,
|
||||||
Some(Duration::from_secs(SNMP_TIMEOUT_SECS)),
|
Some(Duration::from_secs(SNMP_TIMEOUT_SECS)),
|
||||||
0,
|
version_num,
|
||||||
)
|
)
|
||||||
.map_err(|_| SnmpError::NetworkUnreachable)?;
|
.map_err(|_| SnmpError::NetworkUnreachable)?;
|
||||||
|
|
||||||
|
|
@ -167,6 +155,21 @@ impl Default for SnmpClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse SNMP version string to integer for snmp crate
|
||||||
|
/// Returns: 0 for SNMPv1, 1 for SNMPv2c
|
||||||
|
fn parse_snmp_version(version: &str) -> SnmpResult<i32> {
|
||||||
|
let normalized = version.trim().to_lowercase();
|
||||||
|
|
||||||
|
match normalized.as_str() {
|
||||||
|
"1" | "v1" | "snmpv1" => Ok(0),
|
||||||
|
"2c" | "v2c" | "snmpv2c" | "2" | "v2" => Ok(1),
|
||||||
|
_ => Err(SnmpError::RequestFailed(format!(
|
||||||
|
"Unsupported SNMP version: '{}'. Supported versions: 1, v1, 2c, v2c",
|
||||||
|
version
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse OID string like "1.3.6.1.2.1.1.1.0" to Vec<u32>
|
/// Parse OID string like "1.3.6.1.2.1.1.1.0" to Vec<u32>
|
||||||
fn parse_oid(oid: &str) -> SnmpResult<Vec<u32>> {
|
fn parse_oid(oid: &str) -> SnmpResult<Vec<u32>> {
|
||||||
oid.split('.')
|
oid.split('.')
|
||||||
|
|
@ -246,6 +249,36 @@ mod tests {
|
||||||
assert!(format!("{:?}", client).contains("SnmpClient"));
|
assert!(format!("{:?}", client).contains("SnmpClient"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_snmp_version_v1() {
|
||||||
|
assert_eq!(parse_snmp_version("1").unwrap(), 0);
|
||||||
|
assert_eq!(parse_snmp_version("v1").unwrap(), 0);
|
||||||
|
assert_eq!(parse_snmp_version("V1").unwrap(), 0);
|
||||||
|
assert_eq!(parse_snmp_version("snmpv1").unwrap(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_snmp_version_v2c() {
|
||||||
|
assert_eq!(parse_snmp_version("2c").unwrap(), 1);
|
||||||
|
assert_eq!(parse_snmp_version("2C").unwrap(), 1);
|
||||||
|
assert_eq!(parse_snmp_version("v2c").unwrap(), 1);
|
||||||
|
assert_eq!(parse_snmp_version("V2C").unwrap(), 1);
|
||||||
|
assert_eq!(parse_snmp_version("2").unwrap(), 1);
|
||||||
|
assert_eq!(parse_snmp_version("v2").unwrap(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_snmp_version_invalid() {
|
||||||
|
let result = parse_snmp_version("3");
|
||||||
|
assert!(result.is_err());
|
||||||
|
match result {
|
||||||
|
Err(SnmpError::RequestFailed(msg)) => {
|
||||||
|
assert!(msg.contains("Unsupported SNMP version"));
|
||||||
|
}
|
||||||
|
_ => panic!("Expected RequestFailed error"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_oid_valid() {
|
fn test_parse_oid_valid() {
|
||||||
let result = parse_oid("1.3.6.1.2.1.1.1.0");
|
let result = parse_oid("1.3.6.1.2.1.1.1.0");
|
||||||
|
|
|
||||||
|
|
@ -357,6 +357,23 @@ impl AgentClient {
|
||||||
/// Execute an SNMP job and collect results.
|
/// Execute an SNMP job and collect results.
|
||||||
async fn execute_job(job: AgentJob, result_tx: mpsc::UnboundedSender<SnmpResult>) -> Result<()> {
|
async fn execute_job(job: AgentJob, result_tx: mpsc::UnboundedSender<SnmpResult>) -> Result<()> {
|
||||||
let snmp_device = job.snmp_device.ok_or("Job missing SNMP device info")?;
|
let snmp_device = job.snmp_device.ok_or("Job missing SNMP device info")?;
|
||||||
|
|
||||||
|
// Log SNMP connection parameters for debugging (mask community for security)
|
||||||
|
let community_masked = if snmp_device.community.len() > 4 {
|
||||||
|
format!("{}***", &snmp_device.community[..2])
|
||||||
|
} else {
|
||||||
|
"***".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
crate::log_info!(
|
||||||
|
"Executing SNMP job for device {} at {}:{} (community: {}, version: {})",
|
||||||
|
job.device_id,
|
||||||
|
snmp_device.ip,
|
||||||
|
snmp_device.port,
|
||||||
|
community_masked,
|
||||||
|
snmp_device.version
|
||||||
|
);
|
||||||
|
|
||||||
let mut oid_values: HashMap<String, String> = HashMap::new();
|
let mut oid_values: HashMap<String, String> = HashMap::new();
|
||||||
let snmp_client = SnmpClient::new();
|
let snmp_client = SnmpClient::new();
|
||||||
|
|
||||||
|
|
@ -382,9 +399,12 @@ async fn execute_job(job: AgentJob, result_tx: mpsc::UnboundedSender<SnmpResult>
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
crate::log_warn!(
|
crate::log_warn!(
|
||||||
"SNMP GET failed for device {} ({}), OID {}: {}",
|
"SNMP GET failed for device {} at {}:{} (version: {}, community: {}), OID {}: {}",
|
||||||
job.device_id,
|
job.device_id,
|
||||||
snmp_device.ip,
|
snmp_device.ip,
|
||||||
|
snmp_device.port,
|
||||||
|
snmp_device.version,
|
||||||
|
community_masked,
|
||||||
oid,
|
oid,
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
|
|
@ -412,9 +432,12 @@ async fn execute_job(job: AgentJob, result_tx: mpsc::UnboundedSender<SnmpResult>
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
crate::log_warn!(
|
crate::log_warn!(
|
||||||
"SNMP WALK failed for device {} ({}), OID {}: {}",
|
"SNMP WALK failed for device {} at {}:{} (version: {}, community: {}), OID {}: {}",
|
||||||
job.device_id,
|
job.device_id,
|
||||||
snmp_device.ip,
|
snmp_device.ip,
|
||||||
|
snmp_device.port,
|
||||||
|
snmp_device.version,
|
||||||
|
community_masked,
|
||||||
base_oid,
|
base_oid,
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue