towerops/lib/snmpkit/snmp_lib/pdu/constants.ex

295 lines
9 KiB
Elixir

defmodule SnmpKit.SnmpLib.PDU.Constants do
@moduledoc """
Constants and type definitions for SNMP PDU operations.
This module contains all ASN.1 tags, error codes, type definitions,
and utility functions used throughout the SNMP PDU system.
"""
import Bitwise
# Type definitions
@type snmp_type ::
:integer
| :octet_string
| :null
| :object_identifier
| :counter32
| :gauge32
| :timeticks
| :counter64
| :ip_address
| :opaque_type
| :no_such_object
| :no_such_instance
| :end_of_mib_view
# SNMP PDU Types
@get_request 0xA0
@getnext_request 0xA1
@get_response 0xA2
@set_request 0xA3
@getbulk_request 0xA5
# SNMP Data Types
@integer 0x02
@octet_string 0x04
@null 0x05
@object_identifier 0x06
@counter32 0x41
@gauge32 0x42
@timeticks 0x43
@counter64 0x46
@ip_address 0x40
@opaque_type 0x44
@no_such_object 0x80
@no_such_instance 0x81
@end_of_mib_view 0x82
# SNMP Error Status Codes
@no_error 0
@too_big 1
@no_such_name 2
@bad_value 3
@read_only 4
@gen_err 5
@type snmp_version :: :v1 | :v2c | :v2 | :v3 | 0 | 1 | 3
@type pdu_type ::
:get_request | :get_next_request | :get_response | :set_request | :get_bulk_request
@type error_status :: 0..18
@type oid :: [non_neg_integer()] | binary()
@type snmp_value :: any()
@type varbind :: {oid(), atom(), snmp_value()}
@type base_pdu :: %{
type: pdu_type(),
request_id: non_neg_integer(),
error_status: error_status(),
error_index: non_neg_integer(),
varbinds: [varbind()]
}
@type bulk_pdu :: %{
type: :get_bulk_request,
request_id: non_neg_integer(),
error_status: error_status(),
error_index: non_neg_integer(),
varbinds: [varbind()],
non_repeaters: non_neg_integer(),
max_repetitions: non_neg_integer()
}
@type pdu :: base_pdu() | bulk_pdu()
# SNMPv1/v2c message format
@type v1v2c_message :: %{
version: snmp_version() | non_neg_integer(),
community: binary(),
pdu: pdu()
}
# SNMPv3 message format
@type v3_message :: %{
version: 3,
msg_id: non_neg_integer(),
msg_max_size: non_neg_integer(),
msg_flags: binary(),
msg_security_model: non_neg_integer(),
msg_security_parameters: binary(),
msg_data: scoped_pdu()
}
@type message :: v1v2c_message() | v3_message()
# SNMPv3 specific types
@type scoped_pdu :: %{
context_engine_id: binary(),
context_name: binary(),
pdu: pdu()
}
@type msg_flags :: %{
auth: boolean(),
priv: boolean(),
reportable: boolean()
}
# Error status code accessors
def no_error, do: @no_error
def too_big, do: @too_big
def no_such_name, do: @no_such_name
def bad_value, do: @bad_value
def read_only, do: @read_only
def gen_err, do: @gen_err
# SNMPv3 constants
@usm_security_model 3
@default_max_message_size 65_507
def usm_security_model, do: @usm_security_model
def default_max_message_size, do: @default_max_message_size
# PDU type constants accessors
def get_request, do: @get_request
def getnext_request, do: @getnext_request
def get_response, do: @get_response
def set_request, do: @set_request
def getbulk_request, do: @getbulk_request
# Data type constants accessors
def integer, do: @integer
def octet_string, do: @octet_string
def null, do: @null
def object_identifier, do: @object_identifier
def counter32, do: @counter32
def gauge32, do: @gauge32
def timeticks, do: @timeticks
def counter64, do: @counter64
def ip_address, do: @ip_address
def opaque_type, do: @opaque_type
def no_such_object, do: @no_such_object
def no_such_instance, do: @no_such_instance
def end_of_mib_view, do: @end_of_mib_view
# Utility functions moved from main module
def normalize_version(:v1), do: 0
def normalize_version(:v2c), do: 1
def normalize_version(:v2), do: 1
def normalize_version(:v3), do: 3
def normalize_version(v) when is_integer(v), do: v
def normalize_version(_), do: 0
def normalize_oid(oid) when is_list(oid), do: oid
def normalize_oid(oid) when is_binary(oid) do
oid
|> String.split(".")
|> Enum.map(fn part ->
case Integer.parse(part) do
{num, ""} when num >= 0 -> num
_ -> throw(:invalid_oid)
end
end)
catch
# Safe default for invalid OID strings
:invalid_oid -> [1, 3, 6, 1]
end
# Safe default for invalid types
def normalize_oid(_), do: [1, 3, 6, 1]
# New utility functions for type conversion
def pdu_type_to_tag(:get_request), do: @get_request
def pdu_type_to_tag(:get_next_request), do: @getnext_request
def pdu_type_to_tag(:get_response), do: @get_response
def pdu_type_to_tag(:set_request), do: @set_request
def pdu_type_to_tag(:get_bulk_request), do: @getbulk_request
def tag_to_pdu_type(@get_request), do: :get_request
def tag_to_pdu_type(@getnext_request), do: :get_next_request
def tag_to_pdu_type(@get_response), do: :get_response
def tag_to_pdu_type(@set_request), do: :set_request
def tag_to_pdu_type(@getbulk_request), do: :get_bulk_request
def tag_to_pdu_type(_), do: nil
def data_type_to_tag(:integer), do: @integer
def data_type_to_tag(:octet_string), do: @octet_string
def data_type_to_tag(:null), do: @null
def data_type_to_tag(:object_identifier), do: @object_identifier
def data_type_to_tag(:counter32), do: @counter32
def data_type_to_tag(:gauge32), do: @gauge32
def data_type_to_tag(:timeticks), do: @timeticks
def data_type_to_tag(:counter64), do: @counter64
def data_type_to_tag(:ip_address), do: @ip_address
def data_type_to_tag(:opaque), do: @opaque_type
def data_type_to_tag(:no_such_object), do: @no_such_object
def data_type_to_tag(:no_such_instance), do: @no_such_instance
def data_type_to_tag(:end_of_mib_view), do: @end_of_mib_view
def tag_to_data_type(@integer), do: :integer
def tag_to_data_type(@octet_string), do: :octet_string
def tag_to_data_type(@null), do: :null
def tag_to_data_type(@object_identifier), do: :object_identifier
def tag_to_data_type(@counter32), do: :counter32
def tag_to_data_type(@gauge32), do: :gauge32
def tag_to_data_type(@timeticks), do: :timeticks
def tag_to_data_type(@counter64), do: :counter64
def tag_to_data_type(@ip_address), do: :ip_address
def tag_to_data_type(@opaque_type), do: :opaque
def tag_to_data_type(@no_such_object), do: :no_such_object
def tag_to_data_type(@no_such_instance), do: :no_such_instance
def tag_to_data_type(@end_of_mib_view), do: :end_of_mib_view
def tag_to_data_type(_), do: nil
@doc """
Normalizes an SNMP type atom.
"""
@spec normalize_type(atom()) :: snmp_type()
def normalize_type(:string), do: :octet_string
def normalize_type(type), do: type
@doc """
Converts an error status atom to its numeric code.
"""
@spec error_status_to_code(atom()) :: non_neg_integer()
def error_status_to_code(:no_error), do: @no_error
def error_status_to_code(:too_big), do: @too_big
def error_status_to_code(:no_such_name), do: @no_such_name
def error_status_to_code(:bad_value), do: @bad_value
def error_status_to_code(:read_only), do: @read_only
def error_status_to_code(:gen_err), do: @gen_err
def error_status_to_code(code) when is_integer(code), do: code
@doc """
Converts an error status code to its atom representation.
"""
@spec error_status_to_atom(non_neg_integer()) :: atom()
def error_status_to_atom(@no_error), do: :no_error
def error_status_to_atom(@too_big), do: :too_big
def error_status_to_atom(@no_such_name), do: :no_such_name
def error_status_to_atom(@bad_value), do: :bad_value
def error_status_to_atom(@read_only), do: :read_only
def error_status_to_atom(@gen_err), do: :gen_err
def error_status_to_atom(code), do: code
@doc """
Encodes SNMPv3 message flags to binary format.
"""
@spec encode_msg_flags(msg_flags()) :: binary()
def encode_msg_flags(%{auth: auth, priv: priv, reportable: reportable}) do
flags = 0
flags = if auth, do: flags ||| 0x01, else: flags
flags = if priv, do: flags ||| 0x02, else: flags
flags = if reportable, do: flags ||| 0x04, else: flags
<<flags>>
end
@doc """
Decodes SNMPv3 message flags from binary format.
"""
@spec decode_msg_flags(binary()) :: msg_flags()
def decode_msg_flags(<<flags::8>>) do
%{
auth: (flags &&& 0x01) != 0,
priv: (flags &&& 0x02) != 0,
reportable: (flags &&& 0x04) != 0
}
end
@doc """
Creates default SNMPv3 message flags for a security level.
"""
@spec default_msg_flags(atom()) :: msg_flags()
def default_msg_flags(:no_auth_no_priv) do
%{auth: false, priv: false, reportable: true}
end
def default_msg_flags(:auth_no_priv) do
%{auth: true, priv: false, reportable: true}
end
def default_msg_flags(:auth_priv) do
%{auth: true, priv: true, reportable: true}
end
end