feat: add SNMPv3 support to discovery and SNMP client
The discovery process was only passing SNMPv2c credentials (community string) to the SNMP client, causing SNMPv3 devices to fail discovery even when v3 credentials were configured. Changes: - Updated build_client_opts in discovery.ex to include SNMPv3 credentials (security_name, security_level, auth_protocol, auth_password, priv_protocol, priv_password) when version is "3" - Updated build_snmp_opts in client.ex to pass v3 credentials to SnmpKit - Added parse functions for security_level, auth_protocol, and priv_protocol - Updated connection_opts typespec to include v3 parameters - Fixed parameter names to match SnmpKit expectations (security_name vs sec_name) This enables full SNMPv3 discovery on devices like MikroTik routers that use v3 authentication, allowing them to discover the same sensors and data that SNMPv2c would show.
This commit is contained in:
parent
8e0fad599e
commit
ff89415ed3
2 changed files with 66 additions and 7 deletions
|
|
@ -10,11 +10,17 @@ defmodule Towerops.Snmp.Client do
|
|||
|
||||
@type connection_opts :: [
|
||||
ip: String.t(),
|
||||
community: String.t(),
|
||||
version: String.t(),
|
||||
port: non_neg_integer(),
|
||||
transport: String.t(),
|
||||
timeout: non_neg_integer()
|
||||
timeout: non_neg_integer(),
|
||||
community: String.t(),
|
||||
security_name: String.t(),
|
||||
security_level: String.t(),
|
||||
auth_protocol: String.t(),
|
||||
auth_password: String.t(),
|
||||
priv_protocol: String.t(),
|
||||
priv_password: String.t()
|
||||
]
|
||||
|
||||
@type oid :: String.t() | [non_neg_integer()]
|
||||
|
|
@ -417,25 +423,62 @@ defmodule Towerops.Snmp.Client do
|
|||
|
||||
defp build_snmp_opts(opts) do
|
||||
version = parse_version(Keyword.fetch!(opts, :version))
|
||||
community = Keyword.fetch!(opts, :community)
|
||||
port = Keyword.get(opts, :port, 161)
|
||||
timeout = Keyword.get(opts, :timeout, @default_timeout)
|
||||
|
||||
[
|
||||
community: community,
|
||||
base_opts = [
|
||||
version: version,
|
||||
port: port,
|
||||
timeout: timeout,
|
||||
retries: @default_retries
|
||||
]
|
||||
|
||||
# Add version-specific authentication options
|
||||
case version do
|
||||
:v3 ->
|
||||
base_opts ++
|
||||
[
|
||||
security_name: Keyword.fetch!(opts, :security_name),
|
||||
security_level: parse_security_level(Keyword.fetch!(opts, :security_level)),
|
||||
auth_protocol: parse_auth_proto(Keyword.get(opts, :auth_protocol)),
|
||||
auth_password: Keyword.get(opts, :auth_password),
|
||||
priv_protocol: parse_priv_proto(Keyword.get(opts, :priv_protocol)),
|
||||
priv_password: Keyword.get(opts, :priv_password)
|
||||
]
|
||||
|
||||
_ ->
|
||||
base_opts ++ [community: Keyword.fetch!(opts, :community)]
|
||||
end
|
||||
end
|
||||
|
||||
defp parse_version("1"), do: :v1
|
||||
defp parse_version("2c"), do: :v2c
|
||||
defp parse_version("3"), do: :v3
|
||||
defp parse_version(:v1), do: :v1
|
||||
defp parse_version(:v2c), do: :v2c
|
||||
defp parse_version(:v3), do: :v3
|
||||
defp parse_version(_other), do: :v2c
|
||||
|
||||
defp parse_security_level("noAuthNoPriv"), do: :no_auth_no_priv
|
||||
defp parse_security_level("authNoPriv"), do: :auth_no_priv
|
||||
defp parse_security_level("authPriv"), do: :auth_priv
|
||||
defp parse_security_level(_), do: :no_auth_no_priv
|
||||
|
||||
defp parse_auth_proto("MD5"), do: :md5
|
||||
defp parse_auth_proto("SHA"), do: :sha
|
||||
defp parse_auth_proto("SHA-224"), do: :sha224
|
||||
defp parse_auth_proto("SHA-256"), do: :sha256
|
||||
defp parse_auth_proto("SHA-384"), do: :sha384
|
||||
defp parse_auth_proto("SHA-512"), do: :sha512
|
||||
defp parse_auth_proto(_), do: :sha256
|
||||
|
||||
defp parse_priv_proto("DES"), do: :des
|
||||
defp parse_priv_proto("AES"), do: :aes
|
||||
defp parse_priv_proto("AES-192"), do: :aes192
|
||||
defp parse_priv_proto("AES-256"), do: :aes256
|
||||
defp parse_priv_proto("AES-256-C"), do: :aes256c
|
||||
defp parse_priv_proto(_), do: :aes
|
||||
|
||||
@doc """
|
||||
Resolve MIB name to numeric OID using SnmpKit.
|
||||
Handles MODULE-NAME::objectName format by stripping module prefix.
|
||||
|
|
|
|||
|
|
@ -382,12 +382,28 @@ defmodule Towerops.Snmp.Discovery do
|
|||
# Get SNMP config with hierarchical fallback (device -> site -> organization)
|
||||
snmp_config = Devices.get_snmp_config(device)
|
||||
|
||||
[
|
||||
base_opts = [
|
||||
ip: device.ip_address,
|
||||
community: snmp_config.community,
|
||||
version: snmp_config.version,
|
||||
port: device.snmp_port || 161
|
||||
]
|
||||
|
||||
# Add version-specific credentials
|
||||
if snmp_config.version == "3" do
|
||||
v3_config = Devices.get_snmpv3_config(device)
|
||||
|
||||
base_opts ++
|
||||
[
|
||||
security_name: v3_config.username,
|
||||
security_level: v3_config.security_level,
|
||||
auth_protocol: v3_config.auth_protocol,
|
||||
auth_password: v3_config.auth_password,
|
||||
priv_protocol: v3_config.priv_protocol,
|
||||
priv_password: v3_config.priv_password
|
||||
]
|
||||
else
|
||||
base_opts ++ [community: snmp_config.community]
|
||||
end
|
||||
end
|
||||
|
||||
@spec discover_system(Client.connection_opts()) :: {:ok, system_info()} | {:error, term()}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue