diff --git a/proto/agent.proto b/proto/agent.proto index 45149f1..8590b52 100644 --- a/proto/agent.proto +++ b/proto/agent.proto @@ -26,6 +26,7 @@ message SnmpConfig { string version = 2; string community = 3; uint32 port = 4; + string transport = 5; } message Sensor { @@ -148,6 +149,7 @@ message SnmpDevice { string v3_auth_password = 8; // Decrypted before sending string v3_priv_protocol = 9; // "DES" | "AES" | "AES-256" | etc. string v3_priv_password = 10; // Decrypted before sending + string transport = 11; // "udp" | "tcp" } message SnmpQuery { diff --git a/src/snmp/device_poller.rs b/src/snmp/device_poller.rs index 707f920..815d8ec 100644 --- a/src/snmp/device_poller.rs +++ b/src/snmp/device_poller.rs @@ -30,6 +30,7 @@ pub struct DeviceConfig { pub version: String, pub community: SecretString, pub v3_config: Option, + pub transport: String, } impl std::fmt::Debug for DeviceConfig { @@ -38,6 +39,7 @@ impl std::fmt::Debug for DeviceConfig { .field("ip", &self.ip) .field("port", &self.port) .field("version", &self.version) + .field("transport", &self.transport) .field("community", &"[REDACTED]") .field("v3_config", &self.v3_config) .finish() @@ -185,11 +187,25 @@ fn run_poller_thread( Ok(()) } -/// Create an SNMP session based on version +/// Create an SNMP session based on version and transport fn create_session(addr: &str, config: &DeviceConfig) -> Result { let timeout = Some(Duration::from_secs(SNMP_TIMEOUT_SECS)); let version_num = parse_snmp_version(&config.version)?; + let transport = config.transport.to_lowercase(); + // TCP transport warning - not yet implemented + // TODO: Implement SNMP-over-TCP (RFC 3430) - requires low-level PDU handling + // since snmp2 crate doesn't expose internal types needed for TCP framing + if transport == "tcp" { + tracing::warn!( + "TCP transport requested for {} but not yet implemented. \ + Falling back to UDP. TCP support requires custom PDU encoder/decoder \ + since snmp2 crate doesn't expose necessary internal types.", + addr + ); + } + + // UDP transport (default, also used as fallback for TCP) if config.version == "3" { let v3_config = config .v3_config diff --git a/src/websocket_client.rs b/src/websocket_client.rs index a910411..7ea5b65 100644 --- a/src/websocket_client.rs +++ b/src/websocket_client.rs @@ -576,6 +576,11 @@ async fn execute_snmp_job( version: snmp_device.version.clone(), community: SecretString::new(snmp_device.community.clone()), v3_config, + transport: if snmp_device.transport.is_empty() { + "udp".to_string() + } else { + snmp_device.transport.clone() + }, }; // Zeroize credentials in protobuf message after extraction