BSNMPLIB(3)

πŸ“¦ version 15.1, in freebsd 14.5, freebsd 15.1

okay bestie, buckle up β€” this is BSNMPLIB(3) from the Library Functions Manual, and it's literally the SNMP decoding and encoding library and it is a lot ✨ there's so much here that it comes in three whole parts, so hydrate first 🫢


πŸŽ€ NAME πŸŽ€

all of these lil icons, together, are the SNMP decoding and encoding library:

  • snmp_value_free
  • snmp_value_parse
  • snmp_value_copy
  • snmp_pdu_free
  • snmp_pdu_decode
  • snmp_pdu_encode
  • snmp_pdu_decode_header
  • snmp_pdu_decode_scoped
  • snmp_pdu_decode_secmode
  • snmp_pdu_init_secparams
  • snmp_pdu_dump
  • snmp_passwd_to_keys
  • snmp_get_local_keys
  • snmp_calc_keychange
  • TRUTH_MK
  • TRUTH_GET
  • TRUTH_OK

like yes queen, that's the whole cast πŸ˜­πŸ’–


πŸ“š LIBRARY πŸ“š

it lives in the Begemot SNMP library, and you link it like this:

-lbsnmp

so when you're compiling, that's your girl 🧚 libbsnmp, one singular library, no cap.


🌈 SYNOPSIS 🌈

bestie, here's the whole lineup of what you get to #include and call β€” copying it exactly because we do not play with headers πŸ’…

#include <bsnmp/asn1.h>
#include <bsnmp/snmp.h>
void
snmp_value_free(struct snmp_value *value);

int
snmp_value_parse(const char *buf, enum snmp_syntax,
    union snmp_values *value);

int
snmp_value_copy(struct snmp_value *to, const struct snmp_value *from);

void
snmp_pdu_free(struct snmp_pdu *value);

enum snmp_code
snmp_pdu_decode(struct asn_buf *buf, struct snmp_pdu *pdu, int32_t *ip);

enum snmp_code
snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *buf);

enum snmp_code
snmp_pdu_decode_header(struct snmp_pdu *pdu, struct asn_buf *buf);

enum snmp_code
snmp_pdu_decode_scoped(struct asn_buf *buf, struct snmp_pdu *pdu,
    int32_t *ip);

enum snmp_code
snmp_pdu_decode_secmode(struct asn_buf *buf, struct snmp_pdu *pdu);

void
snmp_pdu_init_secparams(struct snmp_pdu *pdu);

void
snmp_pdu_dump(const struct snmp_pdu *pdu);

enum snmp_code
snmp_passwd_to_keys(struct snmp_user *user, char *passwd);

enum snmp_code
snmp_get_local_keys(struct snmp_user *user, uint8_t *eid,
    uint32_t elen);

enum snmp_code
snmp_calc_keychange(struct snmp_user *user, uint8_t *keychange);

int
TRUTH_MK(F);

int
TRUTH_GET(T);

int
TRUTH_OK(T);

look at all those enum snmp_code return types β€” it's giving consistent and we love that for them πŸ‘‘

okay but lowkey notice how the #include lines are at the top of the synopsis and the two headers are bsnmp/asn1.h and bsnmp/snmp.h β€” you genuinely need both, don't come for me πŸ’€

that's the whole vibe check for this section β€” but we're not done, bestie, the rest is coming and it's gonna be so good πŸŒΈπŸ¦‹

πŸ’– DESCRIPTION πŸ’–

okay bestie, so the SNMP library is literally the whole toolkit for handling SNMP version 1, 2 and 3 PDUs. There are several basic structures used throughout the library, and you're gonna see them everywhere, so let's get into it:

      struct snmp_value {
              struct asn_oid          var;
              enum snmp_syntax        syntax;
              union snmp_values {
                int32_t               integer;/* also integer32 */
                struct {
                  u_int               len;
                  u_char              *octets;
                }                     octetstring;
                struct asn_oid        oid;
                u_char                ipaddress[4];
                uint32_t              uint32; /* also gauge32, counter32,
                                                 unsigned32, timeticks */
                uint64_t              counter64;
              }                       v;
      };

This structure represents one variable binding from an SNMP PDU. The field var is the ASN.1 of the variable that is bound. syntax contains either the syntax code of the value or an exception code for SNMPv2 and may be one of:

      enum snmp_syntax {
              SNMP_SYNTAX_NULL        = 0,
              SNMP_SYNTAX_INTEGER,    /* == INTEGER32 */
              SNMP_SYNTAX_OCTETSTRING,
              SNMP_SYNTAX_OID,
              SNMP_SYNTAX_IPADDRESS,
              SNMP_SYNTAX_COUNTER,
              SNMP_SYNTAX_GAUGE,      /* == UNSIGNED32 */
              SNMP_SYNTAX_TIMETICKS,

              /* v2 additions */
              SNMP_SYNTAX_COUNTER64,
              /* exceptions */
              SNMP_SYNTAX_NOSUCHOBJECT,
              SNMP_SYNTAX_NOSUCHINSTANCE,
              SNMP_SYNTAX_ENDOFMIBVIEW,
      };

The field v holds the actual value depending on syntax. Heads up: if syntax is SNMP_SYNTAX_OCTETSTRING and v.octetstring.len is not zero, v.octetstring.octets points to a string allocated by malloc(3). memory management is real, bestie πŸ’…


      #define SNMP_ENGINE_ID_SIZ              32

      struct snmp_engine {
              uint8_t                 engine_id[SNMP_ENGINE_ID_SIZ];
              uint32_t                engine_len;
              int32_t                 engine_boots;
              int32_t                 engine_time;
              int32_t                 max_msg_size;
      };

This structure represents an SNMP engine as specified by the SNMP Management Architecture described in RFC 3411.

      #define SNMP_ADM_STR32_SIZ              (32 + 1)
      #define SNMP_AUTH_KEY_SIZ               40
      #define SNMP_PRIV_KEY_SIZ               32

      enum snmp_usm_level {
              SNMP_noAuthNoPriv = 1,
              SNMP_authNoPriv = 2,
              SNMP_authPriv = 3
      };

      struct snmp_user {
              char                            sec_name[SNMP_ADM_STR32_SIZ];
              enum snmp_authentication        auth_proto;
              enum snmp_privacy               priv_proto;
              uint8_t                         auth_key[SNMP_AUTH_KEY_SIZ];
              uint8_t                         priv_key[SNMP_PRIV_KEY_SIZ];
      };

This structure represents an SNMPv3 user as specified by the User-based Security Model (USM) described in RFC 3414. The field sec_name is a human readable string containing the security user name. auth_proto contains the id of the authentication protocol in use by the user and may be one of:

      enum snmp_authentication {
              SNMP_AUTH_NOAUTH = 0,
              SNMP_AUTH_HMAC_MD5,
              SNMP_AUTH_HMAC_SHA
      };

priv_proto contains the id of the privacy protocol in use by the user and may be one of:

      enum snmp_privacy {
              SNMP_PRIV_NOPRIV = 0,
              SNMP_PRIV_DES = 1,
              SNMP_PRIV_AES
      };

auth_key and priv_key contain the authentication and privacy keys for the user.


      #define SNMP_COMMUNITY_MAXLEN           128
      #define SNMP_MAX_BINDINGS               100
      #define SNMP_CONTEXT_NAME_SIZ           (32 + 1)
      #define SNMP_TIME_WINDOW                150

      #define SNMP_USM_AUTH_SIZE              12
      #define SNMP_USM_PRIV_SIZE              8

      #define SNMP_MSG_AUTH_FLAG              0x1
      #define SNMP_MSG_PRIV_FLAG              0x2
      #define SNMP_MSG_REPORT_FLAG            0x4

      #define SNMP_MPM_SNMP_V1                0
      #define SNMP_MPM_SNMP_V2c               1
      #define SNMP_MPM_SNMP_V3                3

      struct snmp_pdu {
              char                    community[SNMP_COMMUNITY_MAXLEN + 1];
              enum snmp_version       version;
              u_int                   type;

              /* SNMPv3 PDU header fields */
              int32_t                 identifier;
              uint8_t                 flags;
              int32_t                 security_model;
              struct snmp_engine      engine;

              /* Associated USM user parameters */
              struct snmp_user        user;
              uint8_t                 msg_digest[SNMP_USM_AUTH_SIZE];
              uint8_t                 msg_salt[SNMP_USM_PRIV_SIZE];

              /*  View-based Access Model */
              uint32_t                context_engine_len;
              uint8_t                 context_engine[SNMP_ENGINE_ID_SIZ];
              char                    context_name[SNMP_CONTEXT_NAME_SIZ];

              /* trap only */
              struct asn_oid          enterprise;
              u_char                  agent_addr[4];
              int32_t                 generic_trap;
              int32_t                 specific_trap;
              uint32_t                time_stamp;

              /* others */
              int32_t                 request_id;
              int32_t                 error_status;
              int32_t                 error_index;

              /* fixes for encoding */
              size_t                  outer_len;
              size_t                  scoped_len;
              u_char                  *outer_ptr;
              u_char                  *digest_ptr;
              u_char                  *encrypted_ptr;
              u_char                  *scoped_ptr;
              u_char                  *pdu_ptr;
              u_char                  *vars_ptr;

              struct snmp_value       bindings[SNMP_MAX_BINDINGS];
              u_int                   nbindings;
      };

This structure contains a decoded SNMP PDU. version is one of:

      enum snmp_version {
              SNMP_Verr = 0,
              SNMP_V1 = 1,
              SNMP_V2c,
              SNMP_V3
      };

and type is the type of the PDU. security_model is the security model used for SNMPv3 PDUs. The only supported value currently is 3 (User-based Security Model). Additional values for any, unknown, SNMPv1 and SNMPv2c security models are also enumerated:

      enum snmp_secmodel {
              SNMP_SECMODEL_ANY = 0,
              SNMP_SECMODEL_SNMPv1 = 1,
              SNMP_SECMODEL_SNMPv2c = 2,
              SNMP_SECMODEL_USM = 3,
              SNMP_SECMODEL_UNKNOWN
      };

okay, now the function tea β˜• these are the little helpers that do the actual work:

  • snmp_value_free() β€” used to free all the dynamically allocated contents of an SNMP value. It does not free the structure pointed to by value itself.
  • snmp_value_parse() β€” parses the ASCII representation of an SNMP value into its binary form. This function is mainly used by the configuration file reader of bsnmpd(1).
  • snmp_value_copy() β€” makes a deep copy of the value pointed to by from to the structure pointed to by to. It assumes that to is uninitialized and will overwrite its previous contents. It does not itself allocate the structure pointed to by to.
  • snmp_pdu_free() β€” frees all the dynamically allocated components of the PDU. It does not itself free the structure pointed to by pdu.
  • snmp_pdu_decode() β€” decodes the PDU pointed to by buf and stores the result into pdu. If an error occurs in a variable binding, the (1 based) index of this binding is stored in the variable pointed to by ip.
  • snmp_pdu_encode() β€” encodes the PDU pdu into an octetstring in buffer, and if authentication and privacy are used, calculates a message digest and encrypts the PDU data in the buffer buf.
  • snmp_pdu_decode_header() β€” decodes the header of the PDU pointed to by buf. The uncoded PDU contents remain in the buffer.
  • snmp_pdu_decode_scoped() β€” decodes the scoped PDU pointed to by buf.
  • snmp_pdu_decode_secmode() β€” verifies the authentication parameter contained in the PDU (if present) and if the PDU is encrypted, decrypts the PDU contents pointed to by buf. If successful, a plain text scoped PDU is stored in the buffer.
  • snmp_pdu_init_secparams() β€” calculates the initialization vector for the privacy protocol in use before the PDU pointed to by pdu may be encrypted or decrypted.
  • snmp_pdu_dump() β€” dumps the PDU in a human readable form by calling snmp_printf().
  • snmp_passwd_to_keys() β€” calculates a binary private authentication key corresponding to a plain text human readable password string. The calculated key is placed in the auth_key field of the user.
  • snmp_get_local_keys() β€” calculates a localized authentication and privacy keys for a specified SNMPv3 engine. The calculated keys are placed in the auth_key and priv_key fields of the user.
  • snmp_calc_keychange() β€” calculates a binary key change octet string based on the contents of an old and a new binary localized key. The result is placed in the buffer pointed to by keychange and may be used by an SNMPv3 user who wishes to change his/her password or localized key.
  • TRUTH_MK() β€” takes a C truth value (zero or non-zero) and makes an SNMP truth value (2 or 1).
  • TRUTH_GET() β€” takes an SNMP truth value and makes a C truth value (0 or 1).
  • TRUTH_OK() β€” checks whether its argument is a legal SNMP truth value.

🚨 DIAGNOSTICS 🚨

When an error occurs in any of the functions, the function pointed to by the global pointer

      extern void (*snmp_error)(const char *, ...);

with a printf(3) style format string. There is a default error handler in the library that prints a message starting with SNMP: followed by the error message to standard error.

The function pointed to by

      extern void (*snmp_printf)(const char *, ...);

is called by the snmp_pdu_dump() function. The default handler is printf(3).

πŸ’€ ERRORS πŸ’€

okay bestie, so when things go wrong (and they will), here's the tea on what the functions hand back to you πŸ«–

snmp_pdu_decode() will return one of these return codes, no cap:

  • [SNMP_CODE_OK] β€” Success. slay, we ate πŸ’…
  • [SNMP_CODE_FAILED] β€” The ASN.1 coding was wrong. literally the encoding said no πŸ™ˆ
  • [SNMP_CODE_BADLEN] β€” A variable binding value had a wrong length field. the length was giving lies 😭
  • [SNMP_CODE_OORANGE] β€” A variable binding value was out of the allowed range. bestie it was not in its lane 🚫
  • [SNMP_CODE_BADVERS] β€” The PDU is of an unsupported version. wrong version energy, not the main character we needed πŸ’€
  • [SNMP_CODE_BADENQ] β€” There was an ASN.1 value with an unsupported tag. that tag was not invited to the party πŸŽ€
  • [SNMP_CODE_BADSECLEVEL] β€” The requested securityLevel contained in the PDU is not supported. it asked for a vibe we don't do πŸ”’
  • [SNMP_CODE_BADDIGEST] β€” The PDU authentication parameter received in the PDU did not match the calculated message digest. ngl that's fake ID energy, the digest didn't match and we noticed πŸ”₯
  • [SNMP_CODE_EDECRYPT] β€” Error occurred while trying to decrypt the PDU. the decrypt said nope, not today 🫢

and then snmp_pdu_encode() keeps it short and sweet:

  • [SNMP_CODE_OK] β€” Success. iconic ✨
  • [SNMP_CODE_FAILED] β€” Encoding failed. it tried and it did not slay πŸ’€

πŸ‘€ SEE ALSO πŸ‘€

go read them, iykyk πŸ¦‹


⚠️ CAVEAT ⚠️

okay so this is the important bit, don't skip it πŸ™

The SNMPv3 message digests, encryption and decryption, and key routines use the cryptographic functions from crypto(3). The library may optionally be built without references to the crypto(3) library. In such case only plain text SNMPv3 PDUs without message digests may be proccessed correctly.

and if you skipped the caveat when you built it? bestie you get plain text only, no digests, no encryption, no privacy. that's the whole deal, fr fr 🌸

🌈 STANDARDS 🌈

This implementation conforms to the applicable IETF RFCs and ITU-T recommendations. periodt πŸ‘‘


🫢 AUTHORS 🫢

The Begemot SNMP library was originally written by Hartmut Brandt <harti@FreeBSD.org>

Shteryana Shopova <syrinx@FreeBSD.org> added support for the SNMPv3 message proccessing and User-Based Security model message authentication and privacy.

absolute icons, both of them πŸ‘‘πŸ’–

and that's the whole page bestie, you made it to the end πŸŽ‰πŸ’–βœ¨

this little beauty came from Debian, dated December 31, 2016 β€” BSNMPLIB(3), go forth and snmp responsibly, mwah πŸ’‹

πŸ“¦ where this page comes from
  • freebsd 14.5: base 14.5
  • freebsd 15.1: base 15.1
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms