PowerSNMPv3

package module
v1.4.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 5, 2026 License: MIT Imports: 23 Imported by: 0

README

PowerSNMPv3

Go Go Report Card PowerSNMPv3 CI LibHunt GitHub stars DEV.to Article Examples

📖 Quick Links:


Pure Go SNMP v2c/v3 Library

Author: Volkov Oleg Contact: [email protected] License: MIT Commercial support and custom development available.


Features

  • SNMPv2c and SNMPv3 support
  • Authentication: MD5, SHA, SHA-224, SHA-256, SHA-384, SHA-512
  • Encryption: DES, AES-128, AES-192, AES-256 (including AGENT++ variants)
  • SNMP operations: Get, GetMulti, Set, SetMulti, Walk, BulkWalk
  • Streaming operations via channels: Walk_WChan, BulkWalk_WChan
  • TRAP/INFORM reception with automatic ACK
  • Minimal dependencies: only github.com/OlegPowerC/asn1modsnmp
  • Partial error handling support

Installation

go get github.com/OlegPowerC/powersnmpv3

Quick Start

SNMPv3 Get
package main

import (
    "fmt"
    "log"

    snmp "github.com/OlegPowerC/powersnmpv3"
)

func main() {
    device := snmp.NetworkDevice{
        IPaddress: "192.168.1.1",
        Port:      161,
        SNMPparameters: snmp.SNMPUserParameters{
            SNMPversion:      3,
            Username:         "snmpuser",
            AuthProtocol:     "sha",
            AuthKey:          "authpass123",
            PrivProtocol:     "aes",
            PrivKey:          "privpass123",
            RetryCount:       3,
            TimeoutBtwRepeat: 500,
        },
    }

    sess, err := snmp.SNMP_Init(device)
    if err != nil {
        log.Fatal(err)
    }
    defer sess.Close()

    // sysDescr.0
    oid, _ := snmp.ParseOID("1.3.6.1.2.1.1.1.0")
    result, err := sess.SNMP_Get(oid)
    if err != nil {
        log.Fatal(err)
    }

    for _, vb := range result {
        fmt.Printf("%s = %s\n",
            snmp.Convert_OID_IntArrayToString_RAW(vb.RSnmpOID),
            snmp.Convert_Variable_To_String(vb.RSnmpVar))
    }
}
SNMPv2c Get
device := snmp.NetworkDevice{
    IPaddress: "192.168.1.1",
    Port:      161,
    SNMPparameters: snmp.SNMPUserParameters{
        SNMPversion:      2,
        Community:        "public",
        RetryCount:       3,
        TimeoutBtwRepeat: 500,
    },
}

sess, err := snmp.SNMP_Init(device)
// ...
Smart Session Parameters
Parameter Default Feature
TimeoutBtwRepeat 300ms base × (attempt+1): 300→600→900ms backoff
MaxMsgSize 1360 bytes Like TCP MSS — prevents IP fragmentation
MaxRepetitions 25 BulkWalk without packet loss

Data Types

NetworkDevice

Device configuration for session initialization.

type NetworkDevice struct {
    IPaddress      string             // Device IP address
    Port           int                // UDP port (usually 161)
    SNMPparameters SNMPUserParameters // SNMP parameters
    DebugLevel     uint8              // Debug level (0-3)
}
SNMPUserParameters

SNMP session parameters.

type SNMPUserParameters struct {
    SNMPversion      int    // 2 for v2c, 3 for v3
    Username         string // Username (v3)
    AuthKey          string // Authentication password (v3)
    AuthProtocol     string // "md5", "sha", "sha224", "sha256", "sha384", "sha512"
    PrivKey          string // Privacy password (v3)
    PrivProtocol     string // "des", "aes", "aes192", "aes256", "aes192a", "aes256a"
    ContextName      string // SNMPv3 context (optional)
    RetryCount       int    // Retry count (1-10, default 3)
    TimeoutBtwRepeat int    // Timeout between retries in ms (default 300)
    MaxRepetitions   uint16 // Max repetitions for BulkWalk (default 25)
    MaxMsgSize       uint16 // Max SNMP v3 message size
    Community        string // Community string (v2c)
}
Parameter Type description
SNMPversion int SNMP version, 2 for v2c, 3 for v3
Username string USM User for SNMP v3
AuthKey string Authentication password for v3
AuthProtocol string "md5", "sha", "sha224", "sha256", "sha384", "sha512"
PrivKey string Privacy password for v3
PrivProtocol string "des", "aes", "aes192", "aes256", "aes192a", "aes256a"
ContextName string Optional SNMP v3 context name. For example, to retrieve a MAC address table for VLAN 10 on a Cisco switch, specify the vlan-10 context
RetryCount int Retry count (1-10, default 3)
TimeoutBtwRepeat int Timeout between retries in ms (default 300). Uses linear backoff: timeout = base × (attempt + 1)
MaxRepetitions uint16 Max repetitions for BulkWalk (default 25)
MaxMsgSize Uint16 limits the maximum size of SNMP messages sent to and received from the device. It functions similarly to the MSS (Maximum Segment Size) parameter in TCP, defining the upper limit for the payload to avoid IP fragmentation and improve delivery reliability.
SNMPv3Session

Active SNMP session. Created via SNMP_Init().

type SNMPv3Session struct {
    IPaddress  string
    Port       int
    Debuglevel uint8
    SNMPparams SNMPParameters
    // ... internal fields
}
SNMP_Packet_V2_Decoded_VarBind

SNMP request result - OID and value pair.

type SNMP_Packet_V2_Decoded_VarBind struct {
    RSnmpOID []int   // OID as int array
    RSnmpVar SNMPVar // Variable value
}
SNMPVar

SNMP variable with type and value.

type SNMPVar struct {
    ValueType  int    // Value type (ASN.1 tag)
    ValueClass int    // Class (Universal, Application, Context, Private)
    IsCompound bool   // Compound type (SEQUENCE, etc.)
    Value      []byte // Raw value
}
ChanDataWErr

Result for streaming operations via channels.

type ChanDataWErr struct {
    Data  SNMP_Packet_V2_Decoded_VarBind // Data
    Error error                          // Error (nil if OK)
    ValidData bool                       // Data is valid
}
SNMPTrapParameters

Parameters for TRAP/INFORM reception.

type SNMPTrapParameters struct {
    SNMPversion  int    // 2 or 3
    Username     string // Username (v3)
    AuthKey      string // Authentication password
    AuthProtocol string // Authentication protocol
    PrivKey      string // Privacy password
    PrivProtocol string // Privacy protocol
    Community    string // Community (v2c)
}

Public Functions

Session Initialization and Closing
SNMP_Init

Creates and initializes SNMP session. Performs Engine Discovery for SNMPv3.

func SNMP_Init(Ndev NetworkDevice) (*SNMPv3Session, error)

Parameters:

  • Ndev - device configuration

Returns:

  • *SNMPv3Session - pointer to session
  • error - initialization error or nil

Example:

sess, err := snmp.SNMP_Init(device)
if err != nil {
    log.Fatal("Init failed:", err)
}
defer sess.Close()
Close

Closes UDP connection and releases resources.

func (s *SNMPv3Session) Close() error

Read Operations
SNMP_Get

Performs SNMP GET request for a single OID.

func (s *SNMPv3Session) SNMP_Get(Oid []int) ([]SNMP_Packet_V2_Decoded_VarBind, error)

Parameters:

  • Oid - OID as int array (use ParseOID)

Returns:

  • []SNMP_Packet_V2_Decoded_VarBind - array with single result
  • error - fatal error or nil

Example:

oid, _ := snmp.ParseOID("1.3.6.1.2.1.1.1.0")
result, err := sess.SNMP_Get(oid)
SNMP_GetMulti

Performs SNMP GET request for multiple OIDs in a single PDU.

func (s *SNMPv3Session) SNMP_GetMulti(OidVar []SNMP_Packet_V2_Decoded_VarBind) ([]SNMP_Packet_V2_Decoded_VarBind, error)

Parameters:

  • OidVar - VarBind array with filled OIDs (RSnmpOID field)

Returns:

  • []SNMP_Packet_V2_Decoded_VarBind - results
  • error - can be partial error (SNMPne_Errors) or fatal

Example:

oids := []snmp.SNMP_Packet_V2_Decoded_VarBind{
    {RSnmpOID: oid1},
    {RSnmpOID: oid2},
    {RSnmpOID: oid3},
}
results, err := sess.SNMP_GetMulti(oids)
SNMP_Walk

Performs complete SNMP Walk of subtree using GETNEXT.

func (s *SNMPv3Session) SNMP_Walk(oid []int) ([]SNMP_Packet_V2_Decoded_VarBind, error)

Parameters:

  • oid - root OID of subtree

Returns:

  • []SNMP_Packet_V2_Decoded_VarBind - all values in subtree
  • error - error or nil

Example:

// Walk ifDescr (1.3.6.1.2.1.2.2.1.2)
oid, _ := snmp.ParseOID("1.3.6.1.2.1.2.2.1.2")
interfaces, err := sess.SNMP_Walk(oid)
for _, iface := range interfaces {
    fmt.Println(snmp.Convert_Variable_To_String(iface.RSnmpVar))
}
SNMP_BulkWalk

Performs high-performance SNMP Walk using GETBULK.

func (s *SNMPv3Session) SNMP_BulkWalk(oid []int) ([]SNMP_Packet_V2_Decoded_VarBind, error)

Parameters and returns are similar to SNMP_Walk.

Uses MaxRepetitions to get multiple values per request.

SNMP_Walk_WChan

Streaming Walk via channel. Results are sent as received.

func (s *SNMPv3Session) SNMP_Walk_WChan(ctx context.Context,oid []int, CData chan<- ChanDataWErr)

Parameters:

  • ctx - context with timeout
  • oid - root OID
  • CData - channel for results (closed on completion)

Recommended: buffered channel prevents blocking, context adds timeout

Example:

ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second)
defer cancel()
ch := make(chan snmp.ChanDataWErr,30000)
go sess.SNMP_Walk_WChan(ctx,oid, ch)

for result := range ch {
    if result.Error != nil {
        log.Println("Error:", result.Error)
        continue
    }
    fmt.Printf("%s = %s\n",
        snmp.Convert_OID_IntArrayToString_RAW(result.Data.RSnmpOID),
        snmp.Convert_Variable_To_String(result.Data.RSnmpVar))
}
SNMP_BulkWalk_WChan

Streaming BulkWalk via channel.

func (s *SNMPv3Session) SNMP_BulkWalk_WChan(ctx context.Context,oid []int, CData chan<- ChanDataWErr)

Similar to SNMP_Walk_WChan, but uses GETBULK.


Write Operations
SNMP_Set

Performs SNMP SET for a single OID.

func (s *SNMPv3Session) SNMP_Set(Oid []int, VBvalue SNMPVar) ([]SNMP_Packet_V2_Decoded_VarBind, error)

Parameters:

  • Oid - OID to write
  • VBvalue - value (create using SetSNMPVar_* functions)

Returns:

  • []SNMP_Packet_V2_Decoded_VarBind - SET result
  • error - error or nil

Example:

oid, _ := snmp.ParseOID("1.3.6.1.2.1.1.6.0") // sysLocation
value := snmp.SetSNMPVar_OctetString("Server Room A1")
result, err := sess.SNMP_Set(oid, value)
SNMP_SetMulti

Performs SNMP SET for multiple OIDs in a single PDU.

func (s *SNMPv3Session) SNMP_SetMulti(OidVar []SNMP_Packet_V2_Decoded_VarBind) ([]SNMP_Packet_V2_Decoded_VarBind, error)

Value Creation Functions for SET
SetSNMPVar_OctetString

Creates SNMP OctetString.

func SetSNMPVar_OctetString(str string) SNMPVar
SetSNMPVar_Int

Creates SNMP Integer.

func SetSNMPVar_Int(ival int32) SNMPVar
SetSNMPVar_IpAddr

Creates SNMP IpAddress.

func SetSNMPVar_IpAddr(ipval net.IP) (SNMPVar, error)

Conversion Functions
Convert_OID_StringToIntArray

Converts OID string to BER-encoded int array.

func Convert_OID_StringToIntArray(OIDStr string) ([]int, error)

Example:

oid, err := snmp.Convert_OID_StringToIntArray("1.3.6.1.2.1.1.1.0")
// oid = []int{43, 6, 1, 2, 1, 1, 1, 0} (BER encoded)
ParseOID

Converts OID string to "raw" int array (without BER encoding). Use for convert string OID to []int for us in the Get/Set/Walk function

func ParseOID(OIDStr string) ([]int, error)

Example:

oid, err := snmp.ParseOID("1.3.6.1.2.1.1.1.0")
// oid = []int{1, 3, 6, 1, 2, 1, 1, 1, 0}
Convert_OID_IntArrayToString_RAW

Converts int array back to OID string.

func Convert_OID_IntArrayToString_RAW(OIDIntArray []int) string

Example:

str := snmp.Convert_OID_IntArrayToString_RAW([]int{1, 3, 6, 1, 2, 1, 1, 1, 0})
// str = "1.3.6.1.2.1.1.1.0"
Convert_Variable_To_String

Converts SNMPVar to human-readable string.

func Convert_Variable_To_String(Var SNMPVar) string

Automatically detects type and formats:

  • OctetString → string
  • Integer → number
  • Counter32/64, Gauge32 → number
  • TimeTicks → number
  • IpAddress → "x.x.x.x"
  • OID → "1.3.6.1..."
Convert_ClassTag_to_String

Returns ASN.1/SNMP type name.

func Convert_ClassTag_to_String(Var SNMPVar) string

Example:

typeStr := snmp.Convert_ClassTag_to_String(varbind.RSnmpVar)
// "Universal OCTET STRING", "Application COUNTER32", etc.

Type Checking Functions

Functions for identifying SNMP variable types. Return true if the variable matches the specified ASN.1 type.

IsBoolean

Checks if SNMPVar is Universal Class BOOLEAN (Tag 1).

func IsBoolean(Val SNMPVar) bool

Matches: Class=0, Constructed=0, Tag=1 (0x01)

Example:

if snmp.IsBoolean(varbind.RSnmpVar) {
    fmt.Println("Boolean value:", varbind.RSnmpVar.Value[0] != 0)
}
IsInteger

Checks if SNMPVar is Universal Class INTEGER (Tag 2).

func IsInteger(Val SNMPVar) bool

Matches: Class=0, Constructed=0, Tag=2 (0x02)

Example:

if snmp.IsInteger(varbind.RSnmpVar) {
    value := snmp.Convert_snmpint_to_int32(varbind.RSnmpVar.Value)
    fmt.Println("Integer:", value)
}
IsBitstring

Checks if SNMPVar is Universal Class BIT STRING (Tag 3).

func IsBitstring(Val SNMPVar) bool

Matches: Class=0, Constructed=0, Tag=3 (0x03)

IsOctetString

Checks if SNMPVar is Universal Class OCTET STRING (Tag 4).

func IsOctetString(Val SNMPVar) bool

Matches: Class=0, Constructed=0, Tag=4 (0x04)
Used in: sysName, sysLocation

Example:

if snmp.IsOctetString(varbind.RSnmpVar) {
    str := string(varbind.RSnmpVar.Value)
    fmt.Println("String:", str)
}
IsNull

Checks if SNMPVar is Universal Class NULL (Tag 5).

func IsNull(Val SNMPVar) bool

Matches: Class=0, Constructed=0, Tag=5 (0x05)

Example:

if snmp.IsNull(varbind.RSnmpVar) {
    fmt.Println("NULL value")
}
IsOid

Checks if SNMPVar is Universal Class OID (Tag 6).

func IsOid(Val SNMPVar) bool

Matches: Class=0, Constructed=0, Tag=6 (0x06)
Used in: OID value processing

Example:

if snmp.IsOid(varbind.RSnmpVar) {
    oidArray := snmp.Convert_bytearray_to_intarray(varbind.RSnmpVar.Value)
    oidStr := snmp.Convert_OID_IntArrayToString_DER(oidArray)
    fmt.Println("OID:", oidStr)
}
IsIpaddr

Checks if SNMPVar is Application Class IPADDRESS (Tag 0).

func IsIpaddr(Val SNMPVar) bool

Matches: Class=1, Constructed=0, Tag=0 (0x40)
Used in: ipAdEntAddr, IP address fields

IsCounter32

Checks if SNMPVar is Application Class Counter32 (Tag 1).

func IsCounter32(Val SNMPVar) bool

Matches: Class=1, Constructed=0, Tag=1 (0x41)

Example:

if snmp.IsCounter32(varbind.RSnmpVar) {
    counter := snmp.Convert_snmpint_to_int32(varbind.RSnmpVar.Value)
    fmt.Printf("Counter32: %d\n", counter)
}
IsGauge32

Checks if SNMPVar is Application Class Gauge32 (Tag 2).

func IsGauge32(Val SNMPVar) bool

Matches: Class=1, Constructed=0, Tag=2 (0x42)

Example:

if snmp.IsGauge32(varbind.RSnmpVar) {
    gauge := snmp.Convert_snmpint_to_int32(varbind.RSnmpVar.Value)
    fmt.Printf("Gauge32: %d\n", gauge)
}
IsTimetick

Checks if SNMPVar is Application Class Timeticks (Tag 3).

func IsTimetick(Val SNMPVar) bool

Matches: Class=1, Constructed=0, Tag=3 (0x43)
Used in: sysUpTime.0, time measurements

Example:

if snmp.IsTimetick(varbind.RSnmpVar) {
    ticks := snmp.Convert_bytearray_to_int(varbind.RSnmpVar.Value)
    duration := time.Duration(ticks * 10 * time.Millisecond)
    fmt.Println("Uptime:", duration.String())
}
IsOpaque

Checks if SNMPVar is Application Class Opaque (Tag 4).

func IsOpaque(Val SNMPVar) bool

Matches: Class=1, Constructed=0, Tag=4 (0x44)
Used in: Binary data, vendor-specific encodings

Example:

if snmp.IsOpaque(varbind.RSnmpVar) {
    hexStr := hex.EncodeToString(varbind.RSnmpVar.Value)
    fmt.Println("Opaque (hex):", hexStr)
}
IsCounter64

Checks if SNMPVar is Application Class Counter64 (Tag 6).

func IsCounter64(Val SNMPVar) bool

Matches: Class=1, Constructed=0, Tag=6 (0x46)
Used in: high-capacity counters

Example:

if snmp.IsCounter64(varbind.RSnmpVar) {
    counter := snmp.Convert_bytearray_to_uint(varbind.RSnmpVar.Value)
    fmt.Printf("Counter64: %d\n", counter)
}

TRAP/INFORM Handling

Supports simultaneous reception of SNMP v2c and SNMP v3 TRAPs/INFORMs

ParseTrapUsername

Quick extraction of username or community from TRAP packet.

func ParseTrapUsername(packet []byte) (version int, username string, v3secdata SNMPv3_SecSeq, err error)

Returns:

  • version - SNMP version (1 for v2c, 3 for v3)
  • username - username (v3) or community (v2c)
  • v3secdata - v3 security data (EngineID, Boots, Time)
  • err - parsing error
ParseTrapWithCredentials

Full TRAP/INFORM parsing with authentication verification and decryption.

func ParseTrapWithCredentials(
    SenderIp string,
    SenderPort int,
    packet []byte,
    UserData SNMPTrapParameters,
    debuglevel uint8,
) (decodedversion int, messagetype int, decryptedData SNMP_Packet_V2_decoded_PDU, err error)

Parameters:

  • SenderIp, SenderPort - sender address
  • packet - raw UDP packet
  • UserData - credentials for decryption
  • debuglevel - debug level

Returns:

  • decodedversion - SNMP version
  • messagetype - type (1=REPORT, 2=TRAP, 3=INFORM)
  • decryptedData - decrypted PDU data
  • err - error

Message type constants:

const (
    REPORT_MESSAGE = 1
    TRAP_MESSAGE   = 2
    INFORM_MESSAGE = 3
)

Workflow:
After initial packet parsing extracts Username from SNMPv3 header, matching credentials can be looked up in a map by Username for decryption/authentication.


Helper Functions
InSubTreeCheck

Checks if OID is within subtree.

func InSubTreeCheck(OidMain []int, OidCurrent []int) bool

Example:

main := []int{1, 3, 6, 1, 2, 1}
current := []int{1, 3, 6, 1, 2, 1, 1, 1}
inTree := snmp.InSubTreeCheck(main, current) // true
SNMPErrorIntToText

Converts SNMP error code to text.

func SNMPErrorIntToText(code int) string
SNMPPDUErrorIntToText

Converts PDU error code to text.

func SNMPPDUErrorIntToText(code int) string

Error Handling

The library distinguishes between fatal and partial errors.

Error Types
SNMPfe_Errors - Fatal Errors

Operation completely failed. Results are unavailable.

type SNMPfe_Errors struct {
    ErrorStatusRaw int32  // SNMP error code
    ErrorIndexRaw  int32  // Failed OID index
    FailedOID      []int  // OID that caused error
    RequestType    uint32 // Request type
}

Examples: network timeout, authentication error, notWritable.

SNMPne_Errors - Partial Errors

Part of request completed successfully. Results are available!

type SNMPne_Errors struct {
    AllOIDsFail bool
    Failedoids []PowerSNMPv3_Errors_FailedOids_Error
}

type PowerSNMPv3_Errors_FailedOids_Error struct {
    Failedoid []int // Failed OID
    Error_id  int   // Error code (noSuchInstance, etc.)
}

Examples: noSuchInstance, noSuchObject for some OIDs in GetMulti.

ParseError - Unified Error Analysis

The ParseError function helps determine error type:

func ParseError(err error) (SNMPerr SNMPud_Errors, CommonError error)

Returns:

type SNMPud_Errors struct {
    IsFatal bool             // true = fatal, false = partial
    Oids    []SNMPud_OidError // List of failed OIDs
}

type SNMPud_OidError struct {
    Failedoid        []int  // Failed OID
    Error_id         int32  // Error code
    ErrorDescription string // Error description
}

Usage example:

results, err := sess.SNMP_GetMulti(oids)
if err != nil {
    snmpErr, commonErr := snmp.ParseError(err)

    if commonErr != nil {
        // Network error, cryptography, etc.
        log.Fatal("Network/system error:", commonErr)
    }

    if snmpErr.IsFatal {
        // Fatal SNMP error
        log.Fatal("Fatal SNMP error:", snmpErr.Oids[0].ErrorDescription)
    }

    // Partial error - results are available!
    log.Printf("Partial error, %d OIDs failed:", len(snmpErr.Oids))
    for _, oidErr := range snmpErr.Oids {
        log.Printf("  - %s: %s",
            snmp.Convert_OID_IntArrayToString_RAW(oidErr.Failedoid),
            oidErr.ErrorDescription)
    }
}

// Process successful results
for _, vb := range results {
    // ...
}
gosnmp and PowerSNMPv3 difference
Gosnmp:

Sample code:

    fmt.Println("=== MULTI GET ===")
    oids := []string{
    "1.3.6.1.2.1.1.5.0",   // sysName
    "1.3.6.1.2.1.1.6.0",   // sysLocation
    "1.3.6.1.2.1.1.99.0",  // invalid oid (will be noSuchObject)
    "1.3.6.1.2.1.1.100.0", // invalid oid (will be noSuchObject)
    }

	result, err := params.Get(oids)
	fmt.Println("--- Check errors ---")
	if err != nil {
		fmt.Printf("MultiGet ERROR: %v\n", err)
	} else {
		fmt.Println("- NO Errors -")
		fmt.Println("--- Print result ---")
		for i, pdu := range result.Variables {
			fmt.Printf("OID[%d]: %s = ", i, pdu.Name)
			switch pdu.Type {
			case gosnmp.OctetString:
				fmt.Printf("%s\n", string(pdu.Value.([]byte)))
			case gosnmp.NoSuchObject:
				fmt.Printf("NoSuchObject\n")
			default:
				fmt.Printf("%v (%s)\n", pdu.Value, pdu.Type)
			}
		}
	}

	fmt.Println("=== MULTI SET ===")
	vars := []gosnmp.SnmpPDU{
		{
			Name:  "1.3.6.1.2.1.1.6.0", // sysLocation
			Type:  gosnmp.OctetString,
			Value: []byte("Test from gosnmp"),
		},
		{
			Name:  "1.3.6.1.2.1.1.99.0", // Wrong OID
			Type:  gosnmp.OctetString,
			Value: []byte("Should fail"),
		},
	}

	resultSet, err := params.Set(vars)
	fmt.Println("--- Check errors ---")
	if err != nil {
		fmt.Printf("MultiSet ERROR: %v\n", err)
	} else {
		fmt.Println("- NO Errors -")
		fmt.Println("--- Print result ---")
		for i, pdu := range resultSet.Variables {
			fmt.Printf("OID[%d]: %s = ", i, pdu.Name)
			switch pdu.Type {
			case gosnmp.OctetString:
				fmt.Printf("%s\n", string(pdu.Value.([]byte)))
			case gosnmp.NoSuchObject:
				fmt.Printf("NoSuchObject\n")
			default:
				fmt.Printf("%v (%s)\n", pdu.Value, pdu.Type)
			}
		}
	}

	fmt.Println("explicit check errors (resultSet.Error,resultSet.ErrorIndex)", resultSet.Error, resultSet.ErrorIndex)

	fmt.Println("=== Get 1.3.6.1.2.1.1.6.0 ===")
	oids = []string{
		"1.3.6.1.2.1.1.6.0", // sysLocation
	}

	result, err = params.Get(oids)
	if err != nil {
		fmt.Printf("Get ERROR: %v\n", err)
	} else {
		for i, pdu := range result.Variables {
			fmt.Println("- NO Errors -")
			fmt.Println("--- Print result ---")
			fmt.Printf("OID[%d]: %s = ", i, pdu.Name)
			switch pdu.Type {
			case gosnmp.OctetString:
				fmt.Printf("%s\n", string(pdu.Value.([]byte)))
			case gosnmp.NoSuchObject:
				fmt.Printf("NoSuchObject\n")
			default:
				fmt.Printf("%v (%s)\n", pdu.Value, pdu.Type)
			}
		}
	}

Result:

=== MULTI GET ===
--- Check errors ---
- NO Errors -
  --- Print result ---
  OID[0]: .1.3.6.1.2.1.1.5.0 = powercsw01.powerc
  OID[1]: .1.3.6.1.2.1.1.6.0 = Test 6.0
  OID[2]: .1.3.6.1.2.1.1.99.0 = NoSuchObject
  OID[3]: .1.3.6.1.2.1.1.100.0 = NoSuchObject
  === MULTI SET ===
  --- Check errors ---
- NO Errors -
  --- Print result ---
  OID[0]: .1.3.6.1.2.1.1.6.0 = Test from gosnmp
  OID[1]: .1.3.6.1.2.1.1.99.0 = Should fail
  explicit check errors (resultSet.Error,resultSet.ErrorIndex) NoCreation 2
  === Get 1.3.6.1.2.1.1.6.0 ===
- NO Errors -
  --- Print result ---
  OID[0]: .1.3.6.1.2.1.1.6.0 = Test 6.0
PowerSNMPv3:

Sample code:

fmt.Println("=== MULTI GET ===")
OidsStrings := []string{"1.3.6.1.2.1.1.6.0", "1.3.6.1.2.1.1.99.0", "1.3.6.1.2.1.1.5.0", "1.3.6.1.2.1.1.100.0"}
OidsConverted := []PowerSNMP.SNMP_Packet_V2_Decoded_VarBind{}

	for _, OidSting := range OidsStrings {
		Ioid, IoidErr := PowerSNMP.Convert_OID_StringToIntArray_RAW(OidSting)
		if IoidErr != nil {
			fmt.Println(IoidErr)
			return
		}
		OidsConverted = append(OidsConverted, PowerSNMP.SNMP_Packet_V2_Decoded_VarBind{Ioid, PowerSNMP.SNMPvbNullValue})
	}
	GetRes2, verr2 := Ssess.SNMP_GetMulti(OidsConverted)

	fmt.Println("--- Check errors ---")
	if verr2 != nil {
		snmpErr, commonErr := PowerSNMP.ParseError(verr2)
		if commonErr != nil {
			// Network error, cryptography, etc.
			fmt.Println("Network/system error:", commonErr)
		}

		if snmpErr.IsFatal {
			// Fatal SNMP error
			fmt.Println("Fatal SNMP error, results are not available")
			for _, descr := range snmpErr.Oids {
				fmt.Println("Error description:", descr.ErrorDescription, descr)
			}
		}

		// Partial error - results are available!
		fmt.Printf("Partial error, %d OIDs failed:", len(snmpErr.Oids))
		for _, oidErr := range snmpErr.Oids {
			fmt.Printf("  | %s", oidErr.ErrorDescription)
		}
		fmt.Println("")
	} else {
		fmt.Println("- NO Errors -")
	}

	fmt.Println("--- Print result ---")
	for _, wl := range GetRes2 {
		fmt.Println(PowerSNMP.Convert_OID_IntArrayToString_RAW(wl.RSnmpOID), "=", PowerSNMP.Convert_Variable_To_String(wl.RSnmpVar), ":", PowerSNMP.Convert_ClassTag_to_String(wl.RSnmpVar))
	}

	fmt.Println("=== MULTI SET ===")
	VarData := []PowerSNMP.SNMPVar{PowerSNMP.SetSNMPVar_OctetString("Test 6.0"), PowerSNMP.SetSNMPVar_OctetString("Test 99.0"), PowerSNMP.SetSNMPVar_OctetString("Test 5.0")}
	SetStringOids := []string{"1.3.6.1.2.1.1.6.0", "1.3.6.1.2.1.1.99.0", "1.3.6.1.2.1.1.5.0"}
	SetDataVB := []PowerSNMP.SNMP_Packet_V2_Decoded_VarBind{}
	if len(VarData) == len(SetStringOids) {
		for VdataInd, StoidS := range SetStringOids {
			IoidS, IoidErrS := PowerSNMP.Convert_OID_StringToIntArray_RAW(StoidS)
			if IoidErrS != nil {
				fmt.Println(IoidErrS)
				return
			}
			SetDataVB = append(SetDataVB, PowerSNMP.SNMP_Packet_V2_Decoded_VarBind{IoidS, VarData[VdataInd]})
		}
	} else {
		fmt.Println("Mismatch oids and data")
		return
	}

	sdata, verres3 := Ssess.SNMP_SetMulti(SetDataVB)
	fmt.Println("--- Check errors ---")
	if verres3 != nil {
		snmpErr, commonErr := PowerSNMP.ParseError(verres3)
		if commonErr != nil {
			// Network error, cryptography, etc.
			fmt.Println("Network/system error:", commonErr)
		}
		if snmpErr.IsFatal {
			// Fatal SNMP error
			fmt.Println("Fatal SNMP error, results are not available")
			for _, descr := range snmpErr.Oids {
				fmt.Println("Error description:", descr.ErrorDescription)
			}
		} else {
			// Partial error - results are available!
			fmt.Printf("Partial error, %d OIDs failed:", len(snmpErr.Oids))
			for _, oidErr := range snmpErr.Oids {
				fmt.Printf("  | %s", oidErr.ErrorDescription)
			}
		}

		fmt.Println("")
	} else {
		fmt.Println("- NO Errors -")
	}

	fmt.Println("--- Print result ---")
	for _, wl := range sdata {
		fmt.Println(PowerSNMP.Convert_OID_IntArrayToString_RAW(wl.RSnmpOID), "=", PowerSNMP.Convert_Variable_To_String(wl.RSnmpVar), ":", PowerSNMP.Convert_ClassTag_to_String(wl.RSnmpVar))
	}

Result:

=== MULTI GET ===
--- Check errors ---
Partial error, 2 OIDs failed:  | 1.3.6.1.2.1.1.99.0 (status=128): NoSuchObject  | 1.3.6.1.2.1.1.100.0 (status=128): NoSuchObject
--- Print result ---
1.3.6.1.2.1.1.6.0 = Test 6.0 : Universal OCTET STRING
1.3.6.1.2.1.1.5.0 = powercsw01.powerc : Universal OCTET STRING
=== MULTI SET ===
--- Check errors ---
Fatal SNMP error, results are not available
Error description: 1.3.6.1.2.1.1.99.0 (status=11): CannotCreateVariable

--- Print result ---
Key difference:

In Get operation:

  • gosnmp returns all VarBinds in result and the user must check for noSuchObject manually

  • PowerSNMPv3 returns a partial error which contains information about which OIDs are noSuchObject and returns result without failed OIDs

In Set operation:

  • gosnmp returns result with VarBinds which it tried to set and no error Result may be incorrectly interpreted by user. User must explicitly check resultSet.Error,resultSet.ErrorIndex to detect error

  • PowerSNMPv3 returns a fatal error which contains the first failed OID and type of error and no result. It is really a fatal error, because the SET operation is atomic


Examples

SNMP Walk CLI (examples/SNMPWalk.go)

Command-line utility for SNMP Walk.

# SNMPv3 Walk
go run cmd/SNMPWalk.go -h 192.168.1.1 -v 3 \
    -u snmpuser -a sha -A authpass -x aes -X privpass \
    -o 1.3.6.1.2.1.2.2.1.2

# SNMPv3 BulkWalk
go run cmd/SNMPWalk.go -h 192.168.1.1 -v 3 \
    -u snmpuser -a sha -A authpass -x aes -X privpass \
    -o 1.3.6.1.2.1.2.2.1.2 -bulk

# SNMPv2c Walk
go run cmd/SNMPWalk.go -h 192.168.1.1 -v 2 -c public \
    -o 1.3.6.1.2.1.2.2.1.2
TRAP/INFORM Receiver (examples/TrapInformReceiver.go)

TRAP and INFORM message receiver with SNMPv3 support.

// Configure credentials
Userv3Map := make(map[string]*snmp.SNMPTrapParameters)
Userv3Map["snmpuser"] = &snmp.SNMPTrapParameters{
    Username:     "snmpuser",
    AuthProtocol: "sha",
    AuthKey:      "authpass123",
    PrivProtocol: "aes",
    PrivKey:      "privpass123",
}

// Receive packet
conn, _ := net.ListenPacket("udp", ":162")
n, addr, _ := conn.ReadFrom(buff)

// Parse
version, msgtype, data, err := snmp.ParseTrapWithCredentials(
    addr.IP.String(), addr.Port, buff[:n], credentials, 0)

Testing with net-snmp:

# SNMPv3 INFORM
snmpinform -v 3 -u snmpuser -a sha -A authpass123 \
    -l authPriv -x aes -X privpass123 \
    -e 0x80001f8880f7996d5a41965d69 192.168.1.100 42 coldStart.0

# SNMPv2c INFORM
snmpinform -v 2c -c public 192.168.1.100 42 coldStart.0
Get Cisco sysName sysDescription Location
	
	const (
        DESCRIPTION_OID                = "1.3.6.1.2.1.1.1.0"
        LOCATION_OID                   = "1.3.6.1.2.1.1.6.0"
        NAME_OID                       = "1.3.6.1.2.1.1.5.0"
    )

    func GetSwData(SNMPsession *PowerSNMPv3.SNMPv3Session) (SwDescription string, SwName string, SwLocation string, err error) {
    SwNm := ""
    SwDsc := ""
    SwLoc := ""
    
        if !SNMPsession.SNMPparams.DiscoveredEngineId.Load() && SNMPsession.SNMPparams.SNMPversion == 3 {
            return SwDsc, SwNm, SwLoc, errors.New(DISCOVERY_ERR)
        }
    
        seqoid := [3]string{NAME_OID, DESCRIPTION_OID, LOCATION_OID}
        seoidi := []PowerSNMPv3.SNMP_Packet_V2_Decoded_VarBind{}
        for _, so := range seqoid {
            ioc, oierr := PowerSNMPv3.ParseOID(so)
            if oierr != nil {
                return SwDsc, SwNm, SwLoc, oierr
            }
            seoidi = append(seoidi, PowerSNMPv3.SNMP_Packet_V2_Decoded_VarBind{ioc, PowerSNMPv3.SNMPvbNullValue})
        }
        SwdataGm, SwdataGerr := SNMPsession.SNMP_GetMulti(seoidi)
        if SwdataGerr != nil {
            pe, ce := PowerSNMPv3.ParseError(SwdataGerr)
            if ce != nil {
                return SwDsc, SwNm, SwLoc, ce
            }
            if pe.IsFatal {
                return SwDsc, SwNm, SwLoc, SwdataGerr
            }
        }
    
        for _, rdata := range SwdataGm {
            if PowerSNMPv3.IsOctetString(rdata.RSnmpVar) && len(seoidi) == 3 {
                if slices.Equal(rdata.RSnmpOID, seoidi[0].RSnmpOID) {
                    SwNm = string(rdata.RSnmpVar.Value)
                }
                if slices.Equal(rdata.RSnmpOID, seoidi[1].RSnmpOID) {
                    SwDsc = string(rdata.RSnmpVar.Value)
                }
                if slices.Equal(rdata.RSnmpOID, seoidi[2].RSnmpOID) {
                    SwLoc = string(rdata.RSnmpVar.Value)
                }
            }
        }
    
        return SwDsc, SwNm, SwLoc, nil
    }
Complete examples are located in the cmd folder

Testing

Requirements

Full testing requires a real SNMP device (switch, router).

Running Tests
go test -v -args \
    -h <DEVICE_IP> \
    -u <SNMP_USER> \
    -a <AUTH_PROTO> \
    -A <AUTH_PASS> \
    -x <PRIV_PROTO> \
    -X <PRIV_PASS> \
    -c <COMMUNITY>

Example:

go test -v -args -h 192.168.1.252 -u SNMPv3-U -a sha -A test123 -x aes -X test321 -c private123
What is Tested
  1. Unit tests (no device required):

    • TestConvert_Variable_To_String - value conversion
    • TestConvert_ClassTag_to_String - type detection
    • TestConvert_bytearray_to_int - number conversion
    • TestConvert_bytearray_to_uint - unsigned conversion
    • TestCovert_OID_IntArrayToString - OID conversion
    • TestCovert_OID_IntArrayToString_RAW - RAW OID conversion
    • TestConvert_bytearray_to_intarray_with_multibyte_data - multibyte OID
    • TestConvert_snmpint_to_int32 - SNMP int32
    • TestConvert_snmpint_to_uint32 - SNMP uint32
    • TestConvert_Covert_OID_StringToIntArray - string to OID
    • Test_PKCS5Padding - PKCS5 padding/unpadding
  2. Integration tests (device required):

    • TestSNMPv3Session_SNMP_Get_Set_Walk:
      • SNMPv2c GET (read sysLocation)
      • SNMPv2c SET (write sysLocation)
      • SNMPv3 initialization with Engine Discovery
      • SNMPv3 GET (read sysLocation)
      • SNMPv3 SET (write sysLocation)
      • V2→V3 verification (check that v2 SET is visible from v3)
      • SNMPv3 Walk (ifDescr)
      • SNMPv3 BulkWalk (ifDescr)
Expected Output
=== RUN   TestConvert_Variable_To_String
--- PASS: TestConvert_Variable_To_String (0.00s)
...
=== RUN   TestSNMPv3Session_SNMP_Get_Set_Walk
1.3.6.1.2.1.1.6.0 = Test location : Universal OCTET STRING
    snmpfunc_test.go:55: 59 <nil>
1.3.6.1.2.1.1.6.0 = Test location from V2 : Universal OCTET STRING
    snmpfunc_test.go:88: 67 <nil>
    snmpfunc_test.go:93: V2→V3 VERIFICATION PASS! 'Test location from V2'
1.3.6.1.2.1.2.2.1.2.1 = Vlan1 : Universal OCTET STRING
...
--- PASS: TestSNMPv3Session_SNMP_Get_Set_Walk (0.75s)
PASS
ok      github.com/OlegPowerC/powersnmpv3       2.273s

Constants

Authentication Protocols
Constant Value String
AUTH_PROTOCOL_NONE 0 -
AUTH_PROTOCOL_MD5 1 "md5"
AUTH_PROTOCOL_SHA 2 "sha"
AUTH_PROTOCOL_SHA224 3 "sha224"
AUTH_PROTOCOL_SHA256 4 "sha256"
AUTH_PROTOCOL_SHA384 5 "sha384"
AUTH_PROTOCOL_SHA512 6 "sha512"
Privacy Protocols
Constant Value String
PRIV_PROTOCOL_NONE 0 -
PRIV_PROTOCOL_DES 2 "des"
PRIV_PROTOCOL_AES128 1 "aes"
PRIV_PROTOCOL_AES192 3 "aes192"
PRIV_PROTOCOL_AES256 4 "aes256"
PRIV_PROTOCOL_AES192A 5 "aes192a" (AGENT++)
PRIV_PROTOCOL_AES256A 6 "aes256a" (AGENT++)
Limits
Constant Value Description
SNMP_MAXIMUMWALK 1000000 Max Walk entries
SNMP_BUFFERSIZE 2048 UDP buffer size
SNMP_MAXTIMEOUT_MS 1000 Max timeout
SNMP_DEFAULTTIMEOUT_MS 300 Default timeout
SNMP_MAXIMUM_RETRY 10 Max retries
SNMP_DEFAULTRETRY 3 Default retries
SNMP_MAXREPETITION 80 Max repetitions
SNMP_DEFAULTREPETITION 25 Default repetitions

Dependencies

  • github.com/OlegPowerC/asn1modsnmp - fork of standard encoding/asn1 with SNMP optimizations:
    • ShortLengthAllow - support for short-length encoding (some switches, e.g., Moxa) and indefinite length (include nested)
    • FindSNMPv3AuthParamsOffset() - find AuthParams position for USM verification
    • ExtractDataWOTagAndLen() - extract data without TLV wrapper for cryptography

Performance

Benchmarked on 15,381 OIDs (SNMPv3 AES128+SHA, 1Gbps network, Cisco S8000v target):

Implementation Time Throughput Memory
PowerSNMPv3 (Channel) 4.02s 3,827 OID/s 12.4 MB
PowerSNMPv3 (Callback) 4.46s 3,449 OID/s 8.8 MB
gosnmp 4.43s 3,472 OID/s 10.0 MB
net-snmp (C) 6.43s 2,393 OID/s 8.8 MB
snmp4j (Java) 8.27s 1,860 OID/s 145.6 MB

PowerSNMP is 37% faster than net-snmp and uses 12x less memory than snmp4j.

When to use each mode:
  • Channel (SNMP_BulkWalk_WChan): Maximum speed for large tables (5000+ OIDs)
  • Callback (SNMP_BulkWalk_WCallback): Memory-efficient for scripts (100-5000 OIDs)
  • Sync (SNMP_Walk): Debugging and small queries (<100 OIDs)

License

MIT License

Commercial version with extended support available.

Contact: [email protected]

v1.2.6 – Improved Buffer Management and MaxMsgSize Discovery
What’s new
SNMPv2 buffers:
The RX buffer size is now fixed at 65535 bytes, while the TX buffer defaults to 1500 bytes (can be modified via a constant).

SNMPv3 buffers:
The RX buffer size now dynamically matches the MaxMsgSize value negotiated with the agent.

Dynamic discovery:
During the initial exchange, the library automatically discovers the agent’s MaxMsgSize and adjusts the session configuration. Subsequent messages are validated to ensure they do not exceed this limit.
Why this matters

These changes make message exchange more robust across different devices and agents, especially those with non‑standard or limited buffer sizes. They also reduce the risk of transmission errors and improve performance when communicating with high‑capacity agents. Impact

Better interoperability with diverse SNMP implementations.
Automatic buffer sizing for SNMPv3.
Configurable TX buffer for SNMPv2 to match specific deployment needs.
v.2.9 January 27, 2026

Key Improvement

  • Discovery Agent EngineID: Now performed in main get/set functions when proper REPORT is received
  • Automatic EngineID update without additional calls
Security Level Mismatch Handling

PowerSNMPv3 provides RFC 3414-compliant handling of security level mismatches with optimal network efficiency and zero unnecessary retries.

Testing Methodology

The behavior comparison was conducted using simple SNMP Walk operations against the same SNMP agent with identical misconfigurations. Test scenario: client configured with authentication (authNoPriv or authPriv), agent has the same username configured with noAuthNoPriv (no authentication). This represents a common misconfiguration in production environments.

All three libraries (PowerSNMPv3, SNMP4J, gosnmp) were tested with identical parameters, and network traffic was captured via PCAP for analysis.

The Problem

Security level mismatches occur when the client is configured with authentication/encryption (authNoPriv or authPriv) but the agent has the same username configured with a different security level (e.g., noAuthNoPriv). According to RFC 3414 §3.2, the agent responds with a REPORT PDU containing usmStatsUnsupportedSecLevels (OID 1.3.6.1.6.3.15.1.1.1.0). Critically, the REPORT is sent without authentication or encryption, even if the request was authenticated/encrypted.

How PowerSNMPv3 Handles It
Discovery Phase
Client → Agent: GetRequest (EngineID discovery, noAuthNoPriv)
Agent → Client: Report (usmStatsUnknownEngineIDs)
  Returns: EngineID, Boots, Time
Request Phase (Security Level Mismatch)
Client → Agent: GetRequest/GetBulk
  Flags: 0x05 (Auth, Reportable) or 0x07 (Auth, Priv, Reportable)
  Auth Params: HMAC digest present
  Priv Params: AES/DES IV (if authPriv)

Agent → Client: Report
  Flags: 0x00 (None) ← NO authentication!
  Report OID: 1.3.6.1.6.3.15.1.1.1.0 (usmStatsUnsupportedSecLevels)
  Counter: Increments on each mismatch

PowerSNMPv3 Response:
  ✓ Accepts REPORT (checks packet flags, not client config)
  ✓ Parses report OID
  ✓ Returns error: "unsupported security levels"
  ✓ NO RETRY - immediate error return
RFC 3414 Compliance

PowerSNMPv3 correctly implements RFC 3414 requirements:

  • Accepts REPORT PDUs without authentication - Even when client expects authenticated responses, REPORT PDUs with msgFlags=0x00 are accepted as valid error indications
  • No retry on configuration errors - UnsupportedSecLevels is a non-recoverable configuration error; retrying with the same credentials won't help
  • Checks packet flags, not client config - Authentication verification is based on actual packet flags, not expected client configuration
Intelligent Error Classification

PowerSNMPv3 distinguishes between recoverable and non-recoverable errors:

Recoverable (auto-retry with recovery):

  • usmStatsNotInTimeWindows - Syncs time, then retries
  • usmStatsUnknownEngineIDs - Performs discovery with key re-localization, then retries

Non-recoverable (immediate error return):

  • usmStatsUnsupportedSecLevels - Configuration mismatch
  • usmStatsUnknownUserNames - Unknown user
  • usmStatsWrongDigests - Wrong password
  • usmStatsDecryptionErrors - Wrong encryption key
Comparison with Other Libraries
Library Total Packets Retry Count RFC 3414 Compliant Automatic REPORT Handling
PowerSNMPv3 4 0 ✅ Yes
SNMP4J 6 1 ❌ Manual
gosnmp 10 3 ⚠️ Partial

Network efficiency: PowerSNMPv3 typically uses 60% fewer packets than gosnmp and 33% fewer than SNMP4J when handling misconfigurations.

User Experience

PowerSNMPv3:

Error: unsupported security levels

✅ Clear, actionable error message
✅ Immediate feedback
✅ Obvious what to fix (check security level configuration)

gosnmp:

Walk Error: incoming packet is not authentic, discarding

❌ Confusing error message - suggests authentication problem, not configuration mismatch
❌ Multiple retries before error
❌ Unclear root cause - could be wrong password, wrong protocol, or security level mismatch

SNMP4J (without manual PDU type check):

1.3.6.1.6.3.15.1.1.1.0 = 17
1.3.6.1.6.3.15.1.1.1.0 = 18

❌ Returns REPORT OID and counter as data
❌ Requires manual PDU type checking: if (response.getType() == PDU.REPORT)
❌ User must interpret OID meaning and handle appropriately

Documentation

Overview

PowerSNMPv3 - SNMP library for Go Автор: Волков Олег Author: Volkov Oleg License: MIT Лицензия: MIT Commercial support and custom development available.

PowerSNMPv3 - SNMP library for Go Автор: Волков Олег Author: Volkov Oleg License: MIT Лицензия: MIT Commercial support and custom development available.

PowerSNMPv3 - SNMP library for Go Автор: Волков Олег Author: Volkov Oleg License: MIT Лицензия: MIT Commercial support and custom development available.

PowerSNMPv3 - SNMP library for Go Автор: Волков Олег Author: Volkov Oleg License: MIT Лицензия: MIT Commercial support and custom development available.

PowerSNMPv3 - SNMP library for Go Автор: Волков Олег Author: Volkov Oleg License: MIT Лицензия: MIT Commercial support and custom development available.

PowerSNMPv3 - SNMP library for Go Автор: Волков Олег Author: Volkov Oleg License: MIT Лицензия: MIT Commercial support and custom development available.

PowerSNMPv3 - SNMP library for Go Автор: Волков Олег Author: Volkov Oleg License: MIT Лицензия: MIT Commercial support and custom development available.

PowerSNMPv3 - SNMP library for Go Автор: Волков Олег Author: Volkov Oleg License: MIT Лицензия: MIT Commercial support and custom development available.

PowerSNMPv3 - SNMP library for Go Автор: Волков Олег Author: Volkov Oleg License: MIT Лицензия: MIT Commercial support and custom development available.

Index

Constants

View Source
const (
	SNMP_type_BOOLEAN     = ASNber.TagBoolean
	SNMP_type_INTEGER     = ASNber.TagInteger
	SNMP_type_BITSTRING   = ASNber.TagBitString
	SNMP_type_OCTETSTRING = ASNber.TagOctetString
	SNMP_type_NULL        = ASNber.TagNull
	SNMP_type_OID         = ASNber.TagOID
)

Reexport ASN.1 Tags Class=0x00 (Universal)

View Source
const (
	// SNMP Application Types (Class=1)
	SNMP_type_IPADDR    = 0
	SNMP_type_COUNTER32 = 1
	SNMP_type_GAUGE32   = 2
	SNMP_type_TIMETICKS = 3
	SNMP_type_OPAQUE    = 4
	SNMP_type_COUNTER64 = 6

	// Limits & Defaults
	SNMP_MAXIMUMWALK                     = 1000000
	SNMP_BUFFERSIZE                      = 65535
	SNMP_MAXTIMEOUT_MS                   = 1000
	SNMP_DEFAULTTIMEOUT_MS               = 300
	SNMP_MAXIMUM_RETRY                   = 10
	SNMP_DEFAULTRETRY                    = 3
	SNMP_MAXREPETITION            uint16 = 80
	SNMP_DEFAULTREPETITION        uint16 = 25
	SNMP_MAXMSGSIZE               uint16 = 65535
	SNMP_DEFAULTMSGSITE           uint16 = 1360
	SNMP_MINMSGSITE               uint16 = 500
	SNMP_START_TX_MAXMSGSIZE             = 1360
	MIN_ALLOWED_TX_MAXMESSAGESIZE        = 500
)

ASN.1/BER tag encoding constants. Bits 7-6: Class (Universal=00, Application=01, Context=10, Private=11) Bit 5: Constructed flag (0=primitive, 1=constructed/compound like SEQUENCE) Bits 4-0: Tag Number

Example: Class=0x01 (Application), Tag=0x03 → 0x43 (APPLICATION 3 = SNMP TIMETICKS) ASN.1 tags represent the type of the following object.

View Source
const (
	// SNMPv2 PDU Types (RFC3416)
	SNMPv2_REQUEST_GET      = 0
	SNMPv2_REQUEST_GETNEXT  = 1
	SNMPv2_REQUEST_RESPONSE = 2
	SNMPv2_REQUEST_SET      = 3
	SNMPv2_REQUEST_GETBULK  = 5
)
View Source
const (
	// SNMPv3 USM Authentication Protocols
	AUTH_PROTOCOL_NONE   = 0
	AUTH_PROTOCOL_MD5    = 1
	AUTH_PROTOCOL_SHA    = 2
	AUTH_PROTOCOL_SHA224 = 3
	AUTH_PROTOCOL_SHA256 = 4
	AUTH_PROTOCOL_SHA384 = 5
	AUTH_PROTOCOL_SHA512 = 6
)
View Source
const (
	// SNMPv3 USM Privacy Protocols
	PRIV_PROTOCOL_NONE    = 0
	PRIV_PROTOCOL_AES128  = 1
	PRIV_PROTOCOL_DES     = 2
	PRIV_PROTOCOL_AES192  = 3
	PRIV_PROTOCOL_AES256  = 4
	PRIV_PROTOCOL_AES192A = 5
	PRIV_PROTOCOL_AES256A = 6
)
View Source
const (
	// SNMPv3 Security Levels (RFC3411)
	SECLEVEL_NOAUTH_NOPRIV = 0
	SECLEVEL_AUTHNOPRIV    = 1
	SECLEVEL_AUTHPRIV      = 2
)
View Source
const (
	// SNMP Notification Types
	REPORT_MESSAGE = 1
	TRAP_MESSAGE   = 2
	INFORM_MESSAGE = 3
)
View Source
const (
	// Internal Parser Errors
	PARCE_ERR_WRONGMSGID = 0xf1
	PARCE_ERR_WRONGREQID = 0xf2
)

Variables

View Source
var OID_DecryptionError = []int{1, 3, 6, 1, 6, 3, 15, 1, 1, 6, 0}
View Source
var OID_NoInTime = []int{1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0}
View Source
var OID_UnknownContext = []int{1, 3, 6, 1, 6, 3, 12, 1, 5, 0}
View Source
var OID_UnknownEngineId = []int{1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0}
View Source
var OID_UnsupportedSecLevels = []int{1, 3, 6, 1, 6, 3, 15, 1, 1, 1, 0}
View Source
var OID_WrongDigest = []int{1, 3, 6, 1, 6, 3, 15, 1, 1, 5, 0}
View Source
var OID_WrongUsername = []int{1, 3, 6, 1, 6, 3, 15, 1, 1, 3, 0}
View Source
var SNMPErrorNames = map[int]string{
	// contains filtered or unexported fields
}
View Source
var SNMPvbNullValue = SNMPVar{ValueType: ASNber.NullRawValue.Tag}

Functions

func CheckUserParams

func CheckUserParams(ndev NetworkDevice) error

func Convert_ClassTag_to_String

func Convert_ClassTag_to_String(Var SNMPVar) string

Convert_ClassTag_to_String converts SNMPVar to human-readable ASN.1/SNMP type string.

Parameters:

Var - SNMP variable with Class, Type, IsCompound, Value bytes

Algorithm:

**Universal Class**: BOOLEAN/INTEGER/BITSTRING/OCTET_STRING/NULL/OID/SEQUENCE/SET
**OCTET_STRING**: isAscii() → "OCTET STRING" vs "HEX STRING"
**Application Class**: IPADDR/COUNTER32/GAUGE32/TIMETICKS/COUNTER64/OPAQUE

Returns:

StringType - Descriptive type name ("Universal OID", "COUNTER32", "IP ADDRESS")

func Convert_OID_IntArrayToString_DER added in v1.1.7

func Convert_OID_IntArrayToString_DER(OIDIntArray []int) (OIDStr string)

Convert_OID_IntArrayToString - INTERNAL. BER-encoded OID array → human-readable string.

**NOT for API calls!** Decodes subidentifiers (>127) back to decimal. SNMP Walk/BulkWalk/Get accept []int ONLY.

Args:

OIDIntArray - BER encoded [1,3,6,1,4,1,0x81,1,1]  (129→[0x81,1])

Returns:

"1.3.6.1.4.1.129.1.1"

BER decoding (RFC2578 §7.2):

  • 0x81,1 → 129
  • 0-127 → single decimal
  • 0x2b (first) → "1.3" (ITU T.1 encoding)

vs Convert_OID_IntArrayToString_RAW():

| BER Input     | This       | RAW         |
|---------------|------------|-------------|
| [1,3,0x81,1] | "1.3.129" | "1.3.129.1" |
| [1,3,6,1]    | "1.3.6.1" | "1.3.6.1"   |

func Convert_OID_IntArrayToString_RAW

func Convert_OID_IntArrayToString_RAW(OIDIntArray []int) (OIDStr string)

Convert_OID_IntArrayToString_RAW - INTERNAL utility. Raw OID array → dotted string.

**NOT for API calls!** Use ONLY for logging, JSON export, fmt.Printf(), debugging. SNMP Walk/BulkWalk/Get accept []int ONLY - this is visualization helper.

Args:

OIDIntArray - [1,3,6,1,2,1,2,2,1,2,1]

Returns:

"1.3.6.1.2.1.2.2.1.2.1"

func Convert_OID_StringToIntArray_DER added in v1.1.7

func Convert_OID_StringToIntArray_DER(OIDStr string) (OIDIntArray []int, err error)

Convert_OID_StringToIntArray converts OID string to BER-encoded int array.

Handles both decimal OID strings and subidentifier encoding (>127 → 2x uint8). Used by SNMPv3 BER encoders for packet construction.

Arguments:

OIDStr - "1.3.6.1.2.1.1.1" or "1.3.6.1.4.1.9.9.91.1.1.1.1"

Returns:

[]int  - BER subidentifiers (128→[0x81,0], 150→[0x82,22])
error  - strconv.Atoi failures

BER encoding (RFC2578 §7.2):

  • 0-127 → single uint8
  • 128-16383 → 0x81-N + mod128

Examples:

"1.3.6.1.2.1" → [1,3,6,1,2,1]
"1.3.6.1.4.1.9.9.129.1" → [1,3,6,1,4,1,9,9,129→[0x81,1],1]

func Convert_OID_StringToIntArray_RAW

func Convert_OID_StringToIntArray_RAW(OIDStr string) (OIDIntArray []int, err error)

Convert_OID_StringToIntArray_RAW converts OID string to raw decimal int array.

Direct decimal parsing WITHOUT BER subidentifier encoding (>127 stays single int). Used for SNMP API calls, InSubTreeCheck(), lexicographic comparisons.

Arguments:

OIDStr - "1.3.6.1.2.1.1.1" or "1.3.6.1.4.1.9.9.129.1"

Returns:

[]int  - Raw decimals [1,3,6,1,4,1,9,9,129,1]
error  - strconv.Atoi failures

vs Convert_OID_StringToIntArray():

| Input      | RAW           | BER Encoded       |
|------------|---------------|-------------------|
| "1.3.6.129"| [1,3,6,129]  | [1,3,6,0x81,1]   |
| "1.3.6.1"  | [1,3,6,1]    | [1,3,6,1]        |

SNMP Walk/BulkWalk API usage:

ifTableOID, _ := Convert_OID_StringToIntArray_RAW("1.3.6.1.2.1.2.2.1")
results, _ := sess.SNMP_BulkWalk(ifTableOID)

func Convert_Variable_To_String

func Convert_Variable_To_String(Var SNMPVar) string

Convert_Variable_To_String formats SNMPVar value as human-readable string.

Parameters:

Var - SNMP variable with decoded Class/Type/Value

Algorithm: **Universal Types**: INTEGER→decimal, OCTET_STRING→ASCII/HEX, OID→dotted notation **Application Types**:

  • IPADDR→"x.x.x.x"
  • TIMETICKS→"Xh Ym Zs" (×10ms → time.Duration)
  • COUNTER32/GAUGE32→decimal
  • COUNTER64→decimal (int64)
  • OPAQUE→hex

**Compound** (SEQUENCE/SET)→hex dump

Returns:

Formatted string for logging/display ("123", "1.3.6.1...", "192.168.1.1")

func Convert_bytearray_OID_with_multibyte_data_to_int_array added in v1.4.2

func Convert_bytearray_OID_with_multibyte_data_to_int_array(bytearray []byte) ([]int, error)

Convert_bytearray_OID_with_multibyte_data_to_int_array decodes DER-encoded ASN.1 OID from byte array to integer array.

Decodes: - First byte as two components: 40*X + Y where X∈{0,1,2}, Y∈{0-39} - Subsequent components using ASN.1 base-128 encoding (7 bits/byte)

Returns error for incomplete multibyte sequences at end.

Examples:

[]byte{0x2B, 0x06, 0x01} → []int{1, 3, 6, 1}, nil  // 1.3.6.1
[]byte{0x81}             → [], err "incomplete multibyte"

Conforms to ITU-T X.690 §8.19.

func Convert_bytearray_to_int

func Convert_bytearray_to_int(bytearray []byte) (intdata int64)

Convert_bytearray_to_int - INTERNAL. SNMP signed INTEGER → int64 (1-8 bytes).

**NO BER decoding** - ASN.1 parser stripped TLV. Full BigEndian + sign extension. Handles all SNMP INTEGER sizes: sysUpTime, ifHCInOctets, Timeticks.

Usage: ifHCInOctets → [0x00,0x00,0x00,0x01,0xFF,0xFF,0xFF,0xFF] → 4294967295

func Convert_bytearray_to_intarray

func Convert_bytearray_to_intarray(bytearray []byte) (intarray []int)

Convert_bytearray_to_intarray - INTERNAL. []byte → []int zero-copy cast.

Simple uint8→int conversion. NO BER decoding. Used before full BER processing.

func Convert_bytearray_to_intarray_with_multibyte_data

func Convert_bytearray_to_intarray_with_multibyte_data(bytearray []byte) (intarray []int)

Convert_bytearray_to_intarray_with_multibyte_data - INTERNAL. BER byte stream → decoded OID.

**REAL BER DECODING!** Converts raw BER bytes with multi-byte subidentifiers (>127) to decimal. Used by SNMPv3 packet decoders for complete OID reconstruction.

Args:

bytearray - Raw BER [0x01,0x03,0x81,0x01,0x02]

Returns:

[]int     - [1,3,129,2] (0x81,0x01 → 129 decoded)

BER decoding (RFC2578 §7.2):

  • 0x81,0x01 → (0x81-0x80)*128 + 0x01 = 129
  • 0x00-0x7F → single byte value

Pipeline:

packet[oidOffset:] → []byte → THIS → []int → Walk/BulkWalk validation

vs simple cast:

| BER Input    | Simple Cast     | This (Decoded) |
|--------------|-----------------|----------------|
| [0x81,0x01] | [129,1]        | [129]         |
| [0x01,0x03] | [1,3]          | [1,3]         |

func Convert_bytearray_to_uint

func Convert_bytearray_to_uint(bytearray []byte) (intdata uint64)

Convert_bytearray_to_uint - INTERNAL. SNMP unsigned INTEGER → uint64 (1-8 bytes).

**NO BER decoding** - ASN.1 parser stripped TLV. Full BigEndian unsigned conversion. Handles Counter64, ifHCInOctets, Gauge64, Timeticks.

Usage: ifHCInOctets → [0x00,0x00,0x00,0x01,0xFF,0xFF,0xFF,0xFF] → 1099511627775

func Convert_setvar_toasn1raw

func Convert_setvar_toasn1raw(invar SNMPVar) ASNber.RawValue

Convert_setvar_toasn1raw converts SNMPVar to ASN.1 RawValue for SET requests.

Parameters:

invar - Source SNMPVar (parsed from previous GET or user input)

Algorithm:

Direct field mapping: ValueType→Tag, ValueClass→Class, Value→Bytes
Preserves original BER encoding from SNMPVar.Value

Returns:

Retvar - ASN.1 RawValue ready for SNMP SET packet marshaling

func Convert_snmpint_to_int32

func Convert_snmpint_to_int32(bytearray []byte) (intdata int32)

Convert_snmpint_to_int32 - INTERNAL. SNMP INTEGER value bytes → int32.

**NO BER decoding** - ASN.1 parser already stripped TLV. Pure BigEndian conversion of raw INTEGER content octets (1-4 bytes).

Usage: sysUpTime.0 → [0x00,0x01,0x2C] → 300

func Convert_snmpint_to_uint32

func Convert_snmpint_to_uint32(bytearray []byte) (intdata uint32)

Convert_snmpint_to_uint32 - INTERNAL. SNMP unsigned INTEGER → uint32.

**NO BER decoding** - ASN.1 parser already stripped TLV. Pure BigEndian conversion of raw Counter32/Gauge32 content (1-4 bytes).

Usage: ifInOctets → [0x00,0xFF,0xFF,0xFF] → 16777215

func InSubTreeCheck

func InSubTreeCheck(OidMain []int, OidCurrent []int) bool

InSubTreeCheck determines if OidCurrent is within the OidMain MIB subtree.

Returns true if OidCurrent starts with OidMain prefix (e.g. 1.3.6.1.2.1 → 1.3.6.1.2.1.1). Used in SNMP Walk to detect when leaving the target subtree.

Example:

InSubTreeCheck([1,3,6,1,2,1], [1,3,6,1,2,1,1,1])  // true (system.1.1)
InSubTreeCheck([1,3,6,1,2,1], [1,3,6,1,2,2,1])    // false (interfaces.1)

func IsBitstring added in v1.3.3

func IsBitstring(Val SNMPVar) bool

IsBitstring returns true if SNMPVar is Universal Class BIT STRING (Tag 3).

Matches: Class=0, Constructed=0, Tag=3 (0x03) Used in: Rare bitfield processing

Example:

if IsBitstring(v) { return fmt.Sprintf("%d", Convert_bytearray_to_int(v.Value)) }

func IsBoolean added in v1.3.3

func IsBoolean(Val SNMPVar) bool

IsBoolean returns true if SNMPVar is Universal Class BOOLEAN (Tag 1).

Matches: Class=0, Constructed=0, Tag=1 (0x01) Used in: Convert_Variable_To_String() boolean processing

Example:

if IsBoolean(varbind.RSnmpVar) { fmt.Println("true/false") }

func IsCounter32 added in v1.3.3

func IsCounter32(Val SNMPVar) bool

IsCounter32 returns true if SNMPVar is Application Class Counter32 (Tag 1).

Matches: Class=1, Constructed=0, Tag=1 (0x41) Used in: ifInOctets → Convert_snmpint_to_int32()

Example:

if IsCounter32(v) { return fmt.Sprintf("%d", Convert_snmpint_to_int32(v.Value)) }

func IsCounter64 added in v1.3.3

func IsCounter64(Val SNMPVar) bool

IsCounter64 returns true if SNMPVar is Application Class Counter64 (Tag 6).

Matches: Class=1, Constructed=0, Tag=6 (0x46) Used in: ifHCInOctets → Convert_bytearray_to_uint()

Example:

if IsCounter64(v) { return fmt.Sprintf("%d", Convert_bytearray_to_uint(v.Value)) }

func IsGauge32 added in v1.3.3

func IsGauge32(Val SNMPVar) bool

IsGauge32 returns true if SNMPVar is Application Class Gauge32 (Tag 2).

Matches: Class=1, Constructed=0, Tag=2 (0x42) Used in: ifSpeed → Convert_snmpint_to_int32()

Example:

if IsGauge32(v) { return fmt.Sprintf("%d", Convert_snmpint_to_int32(v.Value)) }

func IsInteger added in v1.3.3

func IsInteger(Val SNMPVar) bool

IsInteger returns true if SNMPVar is Universal Class INTEGER (Tag 2).

Matches: Class=0, Constructed=0, Tag=2 (0x02) Used in: Convert_snmpint_to_int32(), sysUpTime processing

Example:

if IsInteger(v) { return Convert_snmpint_to_int32(v.Value) }

func IsIpaddr added in v1.3.3

func IsIpaddr(Val SNMPVar) bool

IsIpaddr returns true if SNMPVar is Application Class IPADDRESS (Tag 0).

Matches: Class=1, Constructed=0, Tag=0 (0x40) Used in: ipAdEntAddr → formatIPAddress()

Example:

if IsIpaddr(v) { return formatIPAddress(v.Value) }

func IsNull added in v1.3.3

func IsNull(Val SNMPVar) bool

IsNull returns true if SNMPVar is Universal Class NULL (Tag 5).

Matches: Class=0, Constructed=0, Tag=5 (0x05) Used in: SNMPv2 noSuchObject/noSuchInstance

Example:

if IsNull(v) { return "NULL" }

func IsOctetString added in v1.3.3

func IsOctetString(Val SNMPVar) bool

IsOctetString returns true if SNMPVar is Universal Class OCTET STRING (Tag 4).

Matches: Class=0, Constructed=0, Tag=4 (0x04) Used in: sysName.0, ifAlias → formatOctetString()

Example:

if IsOctetString(v) { return formatOctetString(v.Value) }

func IsOid added in v1.3.3

func IsOid(Val SNMPVar) bool

IsOid returns true if SNMPVar is Universal Class OID (Tag 6).

Matches: Class=0, Constructed=0, Tag=6 (0x06) Used in: Convert_OID_IntArrayToString_DER()

Example:

if IsOid(v) { return Convert_OID_IntArrayToString_DER(Convert_bytearray_to_intarray(v.Value)) }

func IsOpaque added in v1.3.3

func IsOpaque(Val SNMPVar) bool

IsOpaque returns true if SNMPVar is Application Class Opaque (Tag 4).

Matches: Class=1, Constructed=0, Tag=4 (0x44) Used in: Binary data → hex.EncodeToString()

Example:

if IsOpaque(v) { return hex.EncodeToString(v.Value) }

func IsTimetick added in v1.3.3

func IsTimetick(Val SNMPVar) bool

IsTimetick returns true if SNMPVar is Application Class Timeticks (Tag 3).

Matches: Class=1, Constructed=0, Tag=3 (0x43) Used in: sysUpTime.0 → time.Duration formatting

Example:

if IsTimetick(v) { return time.Duration(Convert_bytearray_to_int(v.Value)*10).String() }

func ParseOID added in v1.1.7

func ParseOID(OIDStr string) (OIDIntArray []int, err error)

ParseOID converts OID string (e.g., "1.3.6.1.2.1.1.1.0") to integer array []int. Performs basic validation and splitting by dots. Invalid formats return error.

Example:

oid, err := ParseOID("1.3.6.1.2.1.1.1.0")  // []int{1,3,6,1,2,1,1,1,0}, nil

func SNMPErrorIntToText

func SNMPErrorIntToText(code int) string

SNMPErrorIntToText converts SNMP error-status codes to human-readable strings.

Standardizes SNMP error reporting per RFC3416 §4.1.2.1 (PDU errorStatus field). Provides symbolic names for all standard SNMPv2c/v3 error codes.

Arguments:

code - Raw error-status integer (0-31, RFC 3416)

Returns:

string - Symbolic name or "error-status: N" fallback

Standard SNMP error codes mapping: | Code | Symbolic Name | Meaning | |------|--------------------|----------------------------------| | 0 | noError | Success | | 1 | tooBig | Response exceeds MsgSize | | 2 | noSuchName | Requested OID doesn't exist | | 3 | badValue | SET operation invalid value | | 5 | readOnly | Attempt to SET read-only OID | | 6 | genErr | General processing failure | | 10 | authError | Authentication failure (v3) | | 12 | notWritable | OID exists but not writable | | 17 | authNoPriv | Unknown userName (v3 USM) | | 18 | unknownSecModel | Unknown security model (v3) | | 19 | notInTimeWindow | Time window validation failed | | 20 | unsupportedSecLevel | SecurityLevel mismatch |

Usage cmd:

// ParseError() integration
snmpErr, _ := ParseError(err)
if snmpErr != nil {
    fmt.Printf("VarBind %s: %s\n",
        Convert_OID_IntArrayToString(snmpErr.Oids[0]),
        SNMPErrorIntToText(snmpErr.ErrorStatus))
}
// Output: "VarBind 1.3.6.1.2.1.1.99.0: noSuchName"

// Wireshark correlation
// Response PDU errorStatus=2 → "noSuchName"
// Response PDU errorStatus=17 → "authNoPriv" (wrong userName)

Production error reporting:

```go
results, err := sess.SNMP_BulkWalk([]int{1,3,6,1,2,1,1,99,0})
if err != nil {
    snmpErr, commonErr := ParseError(err)
    if snmpErr != nil {
        for i, oid := range snmpErr.Oids {
            fmt.Printf("OID %s: %s\n",
                Convert_OID_IntArrayToString(oid),
                SNMPErrorIntToText(snmpErr.ErrorStatus))
        }
    } else if commonErr != nil {
        log.Fatal("Network error:", commonErr)
    }
}
```

SNMPv3 USM-specific errors (RFC3414 §A.7):

  • authNoPriv (17) → Wrong userName/password
  • authError (10) → HMAC failure (wrong authKey)
  • decryptErr (11) → AES decryption failure (wrong privKey)
  • notInTimeWindow (19) → EngineID/boottime mismatch

Integrates with ParseError(), SNMPne_Errors, SNMPfe_Errors structs.

func SNMPPDUErrorIntToText

func SNMPPDUErrorIntToText(code int) string

SNMPPDUErrorIntToText converts ScopedPDU error-status codes to human-readable strings.

Converts SNMPv3 ScopedPDU-level errorStatus (RFC3412 §4, RFC3826) to symbolic names. Used by snmpv3 engines for USM/EngineID validation BEFORE reaching VarBind processing.

Arguments:

code - ScopedPDU error-status integer (0-31, RFC 3412)

Returns:

string - Symbolic name or "pdu error-status: N" fallback

ScopedPDU vs VarBind error levels (critical distinction): | Level | Function Called | Error Examples | |----------------|--------------------------|------------------------------------| | **ScopedPDU** | SNMPPDUErrorIntToText() | authNoPriv(17), decryptErr(11) | | **VarBind** | SNMPErrorIntToText() | noSuchName(2), badValue(3) |

SNMPv3 ScopedPDU error flow (Wireshark → godoc):

  1. USM processing → authNoPriv(17) / decryptErr(11)
  2. EngineID mismatch → reportInconsistentValue(21)
  3. ScopedPDU valid → VarBind errors (noSuchName, etc.)

Common ScopedPDU errors (RFC3826 §3.1.2): | Code | Name | Cause | |------|--------------------------|------------------------------------| | 10 | authError | HMAC-SHA/AES authKey failure | | 11 | decryptErr | AES-128/192/256 privKey failure | | 17 | authNoPriv | unknown userName | | 18 | unknownSecModel | non-USM securityModel | | 19 | notInTimeWindow | EngineBoots/EngineTime mismatch | | 20 | unsupportedSecLevel | authPriv vs noAuth mismatch | | 21 | reportInconsistentValue | EngineID length/type invalid |

Production ParseError() integration:

```go
snmpErr, _ := ParseError(err)
if snmpErr.PDUErrorStatus != 0 {
    fmt.Printf("ScopedPDU: %s\n",
        SNMPPDUErrorIntToText(snmpErr.PDUErrorStatus))
    // "ScopedPDU: authNoPriv" → wrong userName!
} else if snmpErr.ErrorStatus != 0 {
    fmt.Printf("VarBind %s: %s\n",
        Convert_OID_IntArrayToString(snmpErr.Oids),
        SNMPErrorIntToText(snmpErr.ErrorStatus))
    // "VarBind 1.3.6.1.2.1.1.99.0: noSuchName"
}
```

Wireshark debugging correlation:

  • SNMPv3 Response: errorStatus=17 → SNMPPDUErrorIntToText(17) = "authNoPriv"
  • SNMPv3 Response: errorStatus=2, errorIndex=1 → SNMPErrorIntToText(2) = "noSuchName"
  • reportInconsistentValue(21) → EngineID format problem

Debug checklist (PDU vs VarBind):

  • PDU errorStatus=17 → **userName** wrong
  • PDU errorStatus=10 → **authKey** wrong
  • PDU errorStatus=11 → **privKey** wrong
  • PDU errorStatus=0 + VarBind errorStatus=2 → OID doesn't exist

Integrates with ParseError() → SNMPpdu_Errors / SNMPfe_Errors structs.

Types

type ChanDataWErr

type ChanDataWErr struct {
	Data      SNMP_Packet_V2_Decoded_VarBind
	ValidData bool
	Error     error
}

ChanDataWErr - streaming SNMP result: valid object OR VarBind exception. Enables continuous walk through noSuchInstance/badValue errors.

Fields:

Data  - SNMP object (nil on exception)
Error - nil (valid) OR SNMP error (stream continues)

Usage:

for result := range ch {
    if result.Error != nil {
        log.Printf("Skipped: %v", result.Error)  // Continues!
    } else {
        fmt.Printf("%s=%s\n", result.Data.OID(), result.Data.Value())
    }
}

type NetworkDevice

type NetworkDevice struct {
	IPaddress      string
	Port           int
	SSHusername    string
	SSHPassword    string
	SNMPparameters SNMPUserParameters
	DebugLevel     uint8
}

type PowerSNMPv3_Errors_FailedOids_Error

type PowerSNMPv3_Errors_FailedOids_Error struct {
	Failedoid []int
	Error_id  int
}

type SNMPParameters

type SNMPParameters struct {
	//Атомарные переменные
	PrivParameter    uint64
	PrivParameterDes uint32
	MessageId        int32
	MessageIDv2      int32
	RBoots           int32
	RTime            int32
	DataFlag         uint32
	SNMPversion      int
	// Authoritative Engine ID (RFC 3414) - получается через Discovery
	// Используется для генерации локализованных ключей (security)
	EngineID            []byte
	DiscoveredEngineId  atomic.Bool
	DiscoveredTimeBoots atomic.Bool

	Username         string
	AuthKey          string
	AuthProtocol     int
	PrivKey          string
	PrivProtocol     int
	SecurityLevel    int
	LocalizedKeyAuth []byte
	LocalizedKeyPriv []byte
	ContextName      string
	// Context Engine ID (RFC 3412) - для Scoped PDU
	// Обычно совпадает с EngineID, может отличаться при proxy
	ContextEngineId  []byte
	RetryCount       int
	TimeoutBtwRepeat int
	MaxRepetitions   int32
	MaxMsgSize       uint16

	Community string
	// contains filtered or unexported fields
}

Данные SNMP о текущей сессии SNMP

type SNMPTrapParameters

type SNMPTrapParameters struct {
	SNMPversion  int
	Username     string
	AuthKey      string
	AuthProtocol string
	PrivKey      string
	PrivProtocol string
	Community    string
}

Пользовательские данные

type SNMPUserParameters

type SNMPUserParameters struct {
	SNMPversion      int
	Username         string
	AuthKey          string
	AuthProtocol     string
	PrivKey          string
	PrivProtocol     string
	ContextName      string
	RetryCount       int
	TimeoutBtwRepeat int
	MaxRepetitions   uint16
	MaxMsgSize       uint16
	Community        string
}

Пользовательские данные

type SNMPVar

type SNMPVar struct {
	ValueType  int
	ValueClass int
	IsCompound bool
	Value      []byte
}

SNMPVar represents ASN.1/BER decoded SNMP variable (VarBind value).

**Exact mapping** from ASN.1 Tag byte: [Class:биты7-6][Constructed:бит5][Tag#:биты4-0] Contains raw Value bytes (NO auto-decoding) + metadata for type-safe processing.

Fields:

ValueType  - Tag Number (0-31): INTEGER=2, OCTET STRING=4, OID=6, COUNTER32=1
ValueClass - Class (0-3):
             • 0=Universal (INTEGER/OCTET/OID/NULL)
             • 1=Application (COUNTER32/IPADDR/TIMETICKS)
             • 2=ContextSpecific (noSuchObject=0, endOfMibView=2)
IsCompound - Constructed flag: true=SEQUENCE/SET, false=primitive
Value      - **Raw BER content octets** (NO TLV wrapper, NO decoding):
             • INTEGER:     [0x00,0x01,0x2C] → sysUpTime=300
             • OCTET:       []byte("Cisco")
             • IPADDR:      [192,168,1,1]
             • OID:         [0x2B,0x06,0x01,0x02,0x01,0x01] → "1.3.6.1.2.1.1"

**Production usage:**

```go // 1. Type-safe value extraction

for _, vb := range pdu.VarBinds {
    switch vb.RSnmpVar {
    case ValueClass==1 && ValueType==1:  // COUNTER32
        counter := binary.BigEndian.Uint32(vb.RSnmpVar.Value)
    case ValueClass==0 && ValueType==4:  // OCTET STRING
        str := string(vb.RSnmpVar.Value)
    case ValueClass==1 && ValueType==0:  // IPADDR
        ip := net.IP(vb.RSnmpVar.Value).String()
    }
}

// 2. Human-readable (library helpers) fmt.Printf("%s=%s (%s)\n",

Convert_OID_IntArrayToString_RAW(vb.RSnmpOID),
Convert_Variable_To_String(vb.RSnmpVar),
Convert_ClassTag_to_String(vb.RSnmpVar))

// 3. Exception detection (ContextSpecific) if vb.RSnmpVar.ValueClass == 2 { // ContextSpecific

    switch vb.RSnmpVar.ValueType {
    case 0: log.Println("noSuchObject")     // Continue walk!
    case 1: log.Println("noSuchInstance")   // Continue walk!
    case 2: log.Println("endOfMibView")     // Walk complete!
    }
}

```

**Raw Value philosophy:** • **NO auto-conversion** → 100% type safety • **Raw bytes** → user controls decoding (int32/uint64/IP/string) • **Wireshark exact** → Value=content octets после TLV stripping

**ASN.1 Tag decoding example:** ``` BER: 41 04 C0 A8 01 01 → Class=1(App), Constructed=0, Tag=0(IPADDR)

→ SNMPVar{ValueType:0, ValueClass:1, IsCompound:false, Value:}[2]

```

func SetSNMPVar_Int

func SetSNMPVar_Int(ival int32) SNMPVar

SetSNMPVar_Int creates SNMP INTEGER VarBind for SET operations.

**NO BER encoding** - returns raw ASN.1-ready BigEndian bytes (4 bytes fixed). Tag=0x02. Used in SNMP SET for ifAdminStatus.1, sysContact.0.

Usage:

ifUp := SetSNMPVar_Int(1)  // ifAdminStatus up
vb := SNMP_Packet_V2_Decoded_VarBind{...}
sess.SNMP_SET([]vb)

func SetSNMPVar_IpAddr

func SetSNMPVar_IpAddr(ipval net.IP) (SNMPVar, error)

SetSNMPVar_IpAddr creates SNMP IpAddress VarBind for SET operations.

**NO BER encoding** - returns raw ASN.1-ready IPv4 bytes (4 bytes fixed). Application Tag=1 (RFC2578). Used in SNMP SET for ipAdEntAddr.

Usage:

ipVar := SetSNMPVar_IpAddr(net.ParseIP("192.168.1.1"))
vb := SNMP_Packet_V2_Decoded_VarBind{...}
sess.SNMP_SET([]vb)

func SetSNMPVar_OctetString

func SetSNMPVar_OctetString(str string) SNMPVar

SetSNMPVar_OctetString creates SNMP OctetString VarBind for SET operations.

**NO BER encoding** - returns raw ASN.1-ready bytes for packet builder. Tag=0x04, string → []byte. Used in SNMP SET for sysName.0, ifAlias.

Usage:

sysName := SetSNMPVar_OctetString("my-router")
vb := SNMP_Packet_V2_Decoded_VarBind{RSnmpOID: sysNameOID, RSnmpVar: sysName}
sess.SNMP_SET([]vb)

type SNMP_Packet_V2

type SNMP_Packet_V2 struct {
	Version            int
	V2CcommunityString []byte
	V2VarBind          ASNber.RawValue
}

type SNMP_Packet_V2_Decoded_VarBind

type SNMP_Packet_V2_Decoded_VarBind struct {
	RSnmpOID ASNber.ObjectIdentifier
	RSnmpVar SNMPVar
}

SNMP_Packet_V2_Decoded_VarBind represents single SNMP VarBind (OID + Value pair).

**RFC3416 §4.1.2.2** compliant structure: ObjectName + ObjectSyntax. Exact 1:1 mapping from BER-decoded VarBind SEQUENCE { ObjectName, ObjectSyntax }.

Fields:

RSnmpOID - **Raw OID** as ASNber.ObjectIdentifier ([]int):
           • Input:  []int{1,3,6,1,2,1,1,1,0} → sysDescr.0
           • TRAP:   Unique event OID (linkDown=1.3.6.1.6.3.1.1.5.3)
           • WALK:   Lexicographic progression (ifInOctets.1 → .2 → .3)
RSnmpVar - Value metadata + raw bytes (see SNMPVar docs)

**Core usage patterns:**

```go // 1. Value extraction helpers (public API) oidStr := Convert_OID_IntArrayToString_RAW(vb.RSnmpOID) // "1.3.6.1.2.1.1.1.0" value := Convert_Variable_To_String(vb.RSnmpVar) // "Cisco IOS v15.1" typ := Convert_ClassTag_to_String(vb.RSnmpVar) // "OCTET STRING"

// 2. Type-specific decoding if vb.RSnmpVar.ValueClass == 1 && vb.RSnmpVar.ValueType == 1 { // COUNTER32

    counter := binary.BigEndian.Uint32(vb.RSnmpVar.Value)
}

// 3. Exception handling (walk continuation) if vb.RSnmpVar.ValueClass == 2 { // ContextSpecific

    switch vb.RSnmpVar.ValueType {
    case TAGERR_noSuchObject:    // Continue walk
    case TAGERR_noSuchInstance:  // Continue walk
    case TAGERR_EndOfMibView:    // Walk END
    }
}

// 4. TRAP processing if oidStr == "1.3.6.1.6.3.1.1.5.3" { // linkDown

    ifName := Convert_Variable_To_String(vb.RSnmpVar)  // "GigabitEthernet0/1"
}

```

**Wireshark field mapping:** ``` snmp.name → RSnmpOID snmp.value → RSnmpVar (Tag+Class+Bytes) snmp.value.type → RSnmpVar.ValueType snmp.value.string → Convert_Variable_To_String(RSnmpVar) ```

**Memory layout (zero-allocation):** • RSnmpOID: []int (pointer to BER-decoded subidentifiers) • RSnmpVar: Raw bytes slice (NO copy, direct from packet) • **Total: ~32 bytes** per VarBind (scalable to 100k+ objects)

**Production guarantees:** • **Order preserved** (input → output 1:1) • **Exceptions marked** (noSuchObject в ValueClass=2) • **TRAP first VarBind** = snmpTrapOID (mandatory RFC1907)

type SNMP_Packet_V2_PDU

type SNMP_Packet_V2_PDU struct {
	RequestID      int32
	ErrorStatusRaw int32
	ErrorIndexRaw  int32
	VarBinds       []SNMP_Packet_V2_VarBind
}

type SNMP_Packet_V2_VarBind

type SNMP_Packet_V2_VarBind struct {
	RSnmpOID ASNber.ObjectIdentifier
	RSnmpVar ASNber.RawValue
}

type SNMP_Packet_V2_decoded_PDU

type SNMP_Packet_V2_decoded_PDU struct {
	RequestID      int32
	ErrorStatusRaw int32
	ErrorIndexRaw  int32
	VarBinds       []SNMP_Packet_V2_Decoded_VarBind
}

SNMP_Packet_V2_decoded_PDU represents decoded SNMPv2 PDU (RFC3416 §4.1 compliant).

**Unified structure** for ALL SNMPv2 operations: GET/SET/GETBULK/WALK + TRAP/INFORM/REPORT. Exact field mapping from BER-decoded PDU: request-id, error-status, error-index, varbind-list.

Fields:

RequestID      - **UNIQUE identifier** [1..2147483647]
                 • GET/SET/INFORM: matches original request
                 • TRAP: **unique per trap**
                 • RESPONSE: matches request
ErrorStatusRaw - Raw SNMP errorStatus (0=noError, 2=noSuchName, 17=notWritable)
                 • TRAP/INFORM: **always 0** (ignored)
ErrorIndexRaw  - 1-based index of first failed VarBind (0=no errors)
                 • TRAP/INFORM: **always 0** (ignored)
VarBinds       - Response data (same length/order как input)

**Production usage patterns:**

```go // 1. GET response validation resp, err := sess.SNMP_Get(sysDescrOID)

if resp.ErrorStatusRaw != 0 {
    panic(fmt.Sprintf("PDU error %d at index %d",
        resp.ErrorStatusRaw, resp.ErrorIndexRaw))
}

value := resp.VarBinds // Guaranteed valid!

// 2. TRAP receiver (RequestID ≠ 0!) version, msgType, pdu, _ := ParseTrapWithCredentials(pkt, creds) fmt.Printf("TRAP RequestID=%d: %d events\n", pdu.RequestID, len(pdu.VarBinds))

// 3. BulkWalk partial response resp, err := sess.SNMP_BulkWalk(ifTableOID)

if resp.ErrorStatusRaw == 0 {
    // All VarBinds valid, process all
} else if len(resp.VarBinds) > 0 {

    // Partial success: process valid + log failed at ErrorIndexRaw
}

```

**Wireshark field mapping (100% точное соответствие):** ``` snmp.request-id → RequestID snmp.error-status → ErrorStatusRaw snmp.error-index → ErrorIndexRaw snmp.varbind-list → VarBinds ```

**Error conditions:** • ErrorStatusRaw != 0 → **PDU-level failure**, check ErrorIndexRaw • TRAP/INFORM: RequestID=unique, ErrorStatusRaw=0, ErrorIndexRaw=0 • VarBind exceptions (noSuchObject/endOfMibView) → individual VarBind.Tag

func ParseTrapWithCredentials

func ParseTrapWithCredentials(SenderIp string, SenderPort int, packet []byte, UserData SNMPTrapParameters, debuglevel uint8) (decodedversion int, messagetype int, decryptedData SNMP_Packet_V2_decoded_PDU, err error)

ParseTrapWithCredentials decodes SNMP TRAP/INFORM packets with credential validation.

Handles SNMPv2c/v3 TRAPs and SNMPv3 INFORMs (with ACK response). Supports authPriv decryption. Auto-detects version and sends INFORM ACK per RFC3411 §5 and RFC3826.

Arguments:

SenderIp    - Source IP (for ACK response)
SenderPort  - Source UDP port (for ACK response)
packet      - Raw SNMP packet bytes (TRAP/INFORM)
UserData    - Credentials (userName/authKey/privKey)
debuglevel  - Debug verbosity (0-255)

Returns:

version     - 1(SNMPv2c), 3(SNMPv3)
messagetype - TRAP_MESSAGE(7), INFORM_MESSAGE(8)
pdu         - Decoded SNMPv2 PDU (varbinds only)
err         - Parse/decrypt/ACK errors

INFORM ACK flow (RFC3411):

  1. Decode INFORM → RequestID extraction
  2. Send Response PDU (same RequestID, noError)
  3. Original INFORM varbinds returned

Production trap receiver:

```go
pkt, _ := readUDPSocket()  // 162 UDP
version, msgType, pdu, err := ParseTrapWithCredentials(
    senderIP, senderPort, pkt, creds, 1)
if err != nil { return }

if msgType == INFORM_MESSAGE {
    log.Printf("INFORM ACK sent for RequestID=%d", pdu.RequestID)
}

for _, vb := range pdu.VarBinds {
    fmt.Printf("Trap %s=%s\n", vb.RSnmpOID, vb.RSnmpVar)
}
```

Error hierarchy:

  • ASN.1 decode → ASNber.Unmarshal
  • Auth/Priv → authNoPriv(17), decryptErr(11)
  • ACK send → Network/timeout errors

Supports: Cisco/Huawei/Eltex TRAPs (tested).

type SNMP_UnknownVersionPacket

type SNMP_UnknownVersionPacket struct {
	Version int
	PtData  ASNber.RawValue
}

type SNMPfe_Errors

type SNMPfe_Errors struct {
	ErrorStatusRaw int32
	ErrorIndexRaw  int32
	FailedOID      []int
	RequestType    uint32
}

func (SNMPfe_Errors) Error

func (e SNMPfe_Errors) Error() string

type SNMPne_Errors

type SNMPne_Errors struct {
	AllOIDsFail bool
	Failedoids  []PowerSNMPv3_Errors_FailedOids_Error
}

func (SNMPne_Errors) Error

func (e SNMPne_Errors) Error() string

Print partial error for man

type SNMPud_Errors

type SNMPud_Errors struct {
	IsFatal bool
	Oids    []SNMPud_OidError
}

func ParseError

func ParseError(err error) (SNMPerr SNMPud_Errors, CommonError error)

ParseError analyzes SNMP errors and returns a unified result for user-friendly handling.

Supported error types:

  • SNMPne_Errors: partial response errors (non-fatal), IsFatal=false
  • SNMPfe_Errors: fatal SNMP errors (notWritable, etc), IsFatal=true
  • All others: network/crypto errors (CommonError != nil)

Behavior:

GetMulti with 1 bad OID → SNMPud_Errors{IsFatal:false, Oids:[1 failed OID]}
SetRequest on RO OID → SNMPud_Errors{IsFatal:true, Oids:[1 failed OID]}
Network timeout → SNMPud_Errors{}, CommonError!=nil

Usage:

snmpErr, commonErr := ParseError(err)
if commonErr != nil { log.Fatal("Network failure") }
if snmpErr.IsFatal { log.Fatal("SNMP fatal error") }
for _, oidErr := range snmpErr.Oids { retry(oidErr.Failedoid) }

type SNMPud_OidError

type SNMPud_OidError struct {
	Failedoid        []int
	Error_id         int32
	ErrorDescription string
}

type SNMPv2_DecodePacket

type SNMPv2_DecodePacket struct {
	Version     int
	Community   []byte
	V2PDU       SNMP_Packet_V2_decoded_PDU
	MessageType int
}

type SNMPv3Session

type SNMPv3Session struct {
	IPaddress  string
	Port       int
	Debuglevel uint8
	SNMPparams SNMPParameters
	// contains filtered or unexported fields
}

func SNMP_Init

func SNMP_Init(Ndev NetworkDevice) (*SNMPv3Session, error)

SNMP_Init creates and initializes SNMPv2c/v3 session from NetworkDevice configuration.

High-level factory function performing discovery + network connection setup. Supports automatic version detection and validation.

Arguments:

Ndev - NetworkDevice with complete SNMP configuration:
       * IPaddress, Port (default 161)
       * SNMPversion (2=v2c, 3=v3)
       * V2c: Community string (e.g. "public", "private")
       * V3:  Username, AuthProtocol/AuthKey, PrivProtocol/PrivKey, ContextName
       * TimeoutBtwRepeat, RetryCount, DebugLevel

Returns:

*SNMPv3Session - Ready-to-use session with established UDP connection
error - Configuration, discovery, or network connectivity failure

Process:

  1. Version-specific discovery (SNMPv3: sysDescr+engineID, SNMPv2c: sysDescr)
  2. UDP connection to device:161 (configurable port, 10s timeout)
  3. Session validation + parameter normalization
  4. Returns connected session (call Close() when done)

Example:

dev := NetworkDevice{
    IPaddress: "192.168.1.1",
    Port:      161,
    SNMPparameters: SNMPParameters{
        SNMPversion:   3,
        Username:      "admin",
        AuthProtocol:  "SHA",
        AuthKey:       "shapass",
        PrivProtocol:  "AES",
        PrivKey:       "aespass",
        ContextName:   "",
        TimeoutBtwRepeat: 3 * time.Second,
        RetryCount:   3,
    },
}

sess, err := SNMP_Init(dev)
if err != nil {
    log.Fatalf("SNMP init failed for %s: %v", dev.IPaddress, err)
}
defer sess.Close()

Error scenarios:

  • "unsupported SNMP version" - version != 2,3
  • SNMPv3 discovery failures:
  • usmStatsUnknownEngineIDs - EngineID changed (config change/reboot/cached mismatch)
  • usmStatsWrongDigests - authentication failure (wrong AuthKey/AuthProtocol)
  • usmStatsDecryptionErrors - privacy failure (wrong PrivKey/PrivProtocol)
  • usmStatsTimeWindow - engineBoots/engineTime sync lost
  • usmStatsUnsupportedSecModels - device doesn't support USM
  • SNMPv2c: "No Such Object" or "No Such Name" on sysDescr.0
  • Network unreachable - "dial udp 192.168.1.1:161: i/o timeout"
  • Invalid parameters - empty username/community, malformed keys

Production usage:

sess, err := SNMP_Init(dev)
if err != nil {
    return nil, fmt.Errorf("SNMP init failed for %s: %w", dev.IPaddress, err)
}
defer sess.Close()
return sess, nil

func SNMPv2_Init

func SNMPv2_Init(Ndev NetworkDevice) (SNMPsession *SNMPv3Session, err error)

SNMPv2_Init creates SNMPv2c session from NetworkDevice config.

Validates and normalizes parameters (retries, timeouts, max-repetitions). Copies community string, IP/port, debug level for v2c operations.

Prepares session for snmpv2_GetSet, snmpv2_Walk operations.

func SNMPv3_Discovery

func SNMPv3_Discovery(Ndev NetworkDevice) (SNMPsession *SNMPv3Session, err error)

SNMPv3_Discovery initializes SNMPv3 session with automatic EngineID discovery.

Sends discovery GET request to `1.3.6.1.2.1.1.1.0` expecting "unknownEngineID" error. Extracts EngineID, Boots, Time from REPORT response and localizes Auth/Priv keys.

Example:

device := PowerSNMP.NetworkDevice{
    IPaddress: "192.168.5.252",
    SNMPparameters: PowerSNMP.SNMPparameters{Username: "SNMPv3User", AuthProtocol: "SHA", ...},
}
session, err := PowerSNMP.SNMPv3_Discovery(device)

Automatically handles:

  • EngineID discovery from REPORT (1.3.6.1.6.3.15.1.1.4.0)
  • Key localization (makeLocalizedKey/expandPrivKey)
  • AES128/192/256C protocols
  • Parameter validation (defaults: Retry=3, Timeout=300ms, MaxRep=25)

func (*SNMPv3Session) Close

func (SNMPparameters *SNMPv3Session) Close() error

Close safely closes SNMPv3Session UDP connection and releases resources.

Thread-safe cleanup function using mutex protection. Ensures connection is closed exactly once (idempotent).

Behavior:

  • If conn != nil: closes underlying net.UDPConn, sets conn=nil
  • If conn == nil: returns nil (already closed)
  • Mutex protected: safe for concurrent use

Usage:

sess, err := SNMP_Init(device)
defer sess.Close()  // Standard Go idiom

// Or explicit:
if err := sess.Close(); err != nil {
    log.Printf("Session close warning: %v", err)
}

Returns:

error - Underlying connection close error (typically nil)

Production patterns:

func probeDevice(device NetworkDevice) error {
    sess, err := SNMP_Init(device)
    if err != nil { return err }
    defer sess.Close()  // Guaranteed cleanup

    vb, err := sess.SNMP_Get(sysDescrOID)
    return err
}

Note:

  • Always call Close() to release UDP file descriptors
  • Safe to call multiple times (idempotent)
  • Panic-safe: mutex prevents data races
  • conn=nil after close prevents double-close

Typical errors (rare):

  • "use of closed network connection" - if used after close
  • "invalid argument" - OS-level socket cleanup issues

func (*SNMPv3Session) SNMP_BulkWalk

func (SNMPparameters *SNMPv3Session) SNMP_BulkWalk(oid []int) (ReturnValue []SNMP_Packet_V2_Decoded_VarBind, err error)

SNMP_BulkWalk performs complete SNMP BULK WALK starting from base OID using GETBULK.

High-performance lexicographic traversal using SNMPv2_GETBULK PDUs (RFC3416 §4.2.3). Returns 10-50x more objects per PDU vs SNMP_Walk (GETNEXT). Ideal for large tables.

Arguments:

oid - Base OID for bulk walk (e.g.: []int{1,3,6,1,2,1,2,2,1} = ifTable)

Returns:

[]SNMP_Packet_V2_Decoded_VarBind - ALL discovered objects (lexicographic order)
error - Network/PDU failures or ParseError() compatible SNMPne_Errors

Bulk vs Walk performance:

  • ifTable (1000 interfaces): 20-100 PDUs vs 1000+ PDUs (GETNEXT)
  • Nonexistent OID: 1 GETBULK PDU vs N GETNEXT PDUs
  • Same InSubTreeCheck() logic → identical termination conditions

Examples:

// High-performance interface table
ifTableOID := []int{1,3,6,1,2,1,2,2,1}
results, err := sess.SNMP_BulkWalk(ifTableOID)
if err != nil {
    snmpErr, commonErr := ParseError(err)
    if commonErr != nil {
        log.Fatal("Network failure:", commonErr)
    }
    fmt.Printf("BulkWalk: %d objects + %d exceptions\n",
        len(results), len(snmpErr.Oids))
}
// len(results) = 5000+ (ifTable/ifStack complete)

// Nonexistent base OID (1 PDU efficiency!)
badOID := []int{1,3,6,1,2,1,1,99,0}
results, err = sess.SNMP_BulkWalk(badOID)
// len(results) == 0 && err == nil (same as SNMP_Walk)

Real-world bulk responses (Wireshark confirmed):

GETBULK(1.3.6.1.2.1.1.99.0, maxRepetitions=10):
→ noError(0) + 10x ifTable OIDs (ifNumber, ifDescr.1-N, ifType.1-N)
→ InSubTreeCheck() = false → [] + nil (1 PDU termination)

Algorithm (identical to SNMP_Walk logic):

  1. GETBULK(current_oid, maxRepetitions=10) → N objects
  2. Filter InSubTreeCheck(): keep only baseOID subtree objects
  3. Update current_oid = last valid OID, repeat
  4. Lexicographic boundary → normal termination

Production recommendations:

  • SNMP_BulkWalk: ifTable, ipAddrTable, tcpConnTable (>100 objects)
  • SNMP_Walk: sysObjectID, small config OIDs (<50 objects)
  • SNMP_BulkWalk_WChan: real-time dashboards, streaming pipelines

Error handling (identical SNMP_Walk):

  • PDU failures → ParseError() compatible (SNMPne_Errors/SNMPfe_Errors)
  • VarBind exceptions → walk continues (handled by snmpv3_Walk)
  • Nonexistent OID → [] + nil (1 PDU, SNMP4J compatible)

vs SNMP_Walk performance:

| Table | SNMP_Walk PDUs | SNMP_BulkWalk PDUs | Speedup |
|-------|----------------|-------------------|---------|
| ifTable (1000) | 5000+ | 100-200 | 25-50x |
| ipAddrTable | 10000+ | 500 | 20x |
| sysDescr.0 | 1 | 1 | 1x |

func (*SNMPv3Session) SNMP_BulkWalk_WCallback added in v1.1.1

func (SNMPparameters *SNMPv3Session) SNMP_BulkWalk_WCallback(oid []int, callback func(ChanDataWErr))

func (*SNMPv3Session) SNMP_BulkWalk_WChan

func (SNMPparameters *SNMPv3Session) SNMP_BulkWalk_WChan(ctx context.Context, oid []int, CData chan<- ChanDataWErr)

SNMP_BulkWalk_WChan performs high-performance SNMP BULK WALK with streaming via channel.

Concurrent lexicographic traversal using SNMPv2_GETBULK PDUs (RFC3416 §4.2.3). Streams results as they arrive - ideal for large tables (ifTable 1000+ interfaces).

Do not use context.Background() without timeout - may cause deadlock if receiver stops reading from the channel.

Arguments:

ctx    - Context with timeout/deadline (REQUIRED for graceful cancellation):
         * WithTimeout: automatic termination after duration
         * WithDeadline: termination at specific time
         * WithCancel: manual cancellation support
         WARNING: context.Background() alone may cause goroutine leak!
oid    - Base OID for bulk walk (e.g.: []int{1,3,6,1,2,1,2,2,1} = ifTable)
CData  - Output channel receiving ChanDataWErr structs:
         * Data:      SNMP_Packet_V2_Decoded_VarBind (valid objects)
         * Error:     nil, individual VarBind exceptions, or ctx.Err()
         * ValidData: true for valid data, false for errors

Context cancellation:

  • Terminates walk immediately on ctx.Done()
  • Sends context.Canceled or context.DeadlineExceeded via Error field
  • Closes channel gracefully (safe for range loops)
  • Does NOT block indefinitely waiting for receiver

Channel semantics:

  • Non-blocking producer: sends results as fast as device responds
  • Closes channel on completion/error/cancellation (range loop safe)
  • Goroutine-safe: multiple consumers possible
  • Buffering recommended (100-1000) for optimal performance

Basic example with timeout:

// Walk with automatic 30-second timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

ifTableOID := []int{1,3,6,1,2,1,2,2,1}
ch := make(chan ChanDataWErr, 100)  // Buffered for performance

go sess.SNMP_BulkWalk_WChan(ctx, ifTableOID, ch)

for result := range ch {
    if !result.ValidData {
        if result.Error == context.DeadlineExceeded {
            log.Println("Walk timeout - partial results received")
            break
        }
        log.Printf("Error: %v", result.Error)
        continue
    }
    fmt.Printf("%s = %s\n",
        Convert_OID_IntArrayToString_RAW(result.Data.RSnmpOID),
        Convert_Variable_To_String(result.Data.RSnmpVar))
}

Manual cancellation example:

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

ch := make(chan ChanDataWErr, 100)
go sess.SNMP_BulkWalk_WChan(ctx, ifTableOID, ch)

found := false
for result := range ch {
    if !result.ValidData {
        continue
    }
    if isWhatWeNeed(result.Data) {
        found = true
        cancel()  // Stop walk immediately - found what we need!
        break
    }
}

Production streaming with timeout:

// Concurrent processing with deadline
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()

var wg sync.WaitGroup
ch := make(chan ChanDataWErr, 1000)
go sess.SNMP_BulkWalk_WChan(ctx, ifTableOID, ch)

for result := range ch {
    if !result.ValidData {
        if result.Error == context.DeadlineExceeded {
            log.Println("Walk timeout reached")
        }
        continue
    }
    wg.Add(1)
    go func(r ChanDataWErr) {
        defer wg.Done()
        processInterface(r.Data)  // Parallel processing!
    }(result)
}
wg.Wait()

Performance advantages (vs SNMP_Walk):

  • GETBULK(N) per PDU → N objects per request (vs 1 per GETNEXT)
  • Non-blocking streaming → immediate processing
  • Channel buffering → backpressure handling
  • Goroutine parallelization → CPU-bound processing
  • Context-based cancellation → resource efficiency

Error handling:

  • Individual VarBind errors → streamed via Error field (walk continues)
  • PDU/network failures → channel closed immediately
  • Context cancellation → context.Canceled or context.DeadlineExceeded
  • Unsupported version → immediate error + channel close

Channel lifecycle:

  1. Objects streamed as ChanDataWErr{Data: varbind, Error: nil, ValidData: true}
  2. Individual exceptions: ChanDataWErr{Data: empty, Error: snmpError, ValidData: false}
  3. Context cancelled: ChanDataWErr{Error: ctx.Err(), ValidData: false}
  4. Completion/PDU failure: close(CData)
  5. Safe for range loop: for result := range ch {}

Common pitfalls:

WRONG - May deadlock if receiver stops reading:
  ctx := context.Background()
  go sess.SNMP_BulkWalk_WChan(ctx, oid, ch)

CORRECT - Always use timeout:
  ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
  defer cancel()
  go sess.SNMP_BulkWalk_WChan(ctx, oid, ch)

WRONG - Forgot to read from channel:
  go sess.SNMP_BulkWalk_WChan(ctx, oid, ch)
  // No for range ch - goroutine leak!

CORRECT - Always consume the channel:
  go sess.SNMP_BulkWalk_WChan(ctx, oid, ch)
  for result := range ch { /* process */ }

Optimal for:

  • Large MIB tables (ifTable, ipAddrTable, tcpConnTable)
  • Real-time monitoring dashboards
  • Concurrent data processing pipelines
  • Memory-constrained environments (streaming vs buffering)
  • Interactive applications requiring cancellation

func (*SNMPv3Session) SNMP_Get

func (SNMPparameters *SNMPv3Session) SNMP_Get(Oid []int) (SNMPretPacket []SNMP_Packet_V2_Decoded_VarBind, err error)

SNMP_Get performs SNMP GET request for a single OID.

Wrapper over SNMP_GetMulti that converts partial errors to fatal for single OID. Ensures semantic consistency: single OID request either succeeds completely or fails atomically with structured error details.

Arguments:

Oid - SNMP OID as []int (e.g.: []int{1,3,6,1,2,1,1,1,0} = sysDescr)

Returns:

[]SNMP_Packet_V2_Decoded_VarBind - result (exactly 1 VarBind on success)
error - SNMPfe_Errors (IsFatal=true) for SNMP failures, CommonError for network

Error conversion logic:

  • SNMP_GetMulti returns SNMPne_Errors (partial) → converted to SNMPfe_Errors
  • Network/auth/timeout errors passed through unchanged
  • Successful response returned as-is

Example:

// Get sysDescr (exists)
vb, err := sess.SNMP_Get([]int{1,3,6,1,2,1,1,1,0})
if err == nil {
    fmt.Printf("sysDescr = %s\n", Convert_Variable_To_String(vb[0].RSnmpVar))
}

// Get nonexistent OID
vb, err = sess.SNMP_Get([]int{1,3,6,1,2,1,1,99,0})
if err != nil {
    snmpErr, _ := ParseError(err)
    fmt.Println(snmpErr.Oids[0].ErrorDescription)  // "1.3.6.1.2.1.1.99.0 (status=2): noSuchName"
    fmt.Println("Fatal:", snmpErr.IsFatal)         // true (atomic failure)
}

Usage patterns:

if err != nil {
    snmpErr, commonErr := ParseError(err)
    if commonErr != nil {
        log.Fatal("Network failure:", commonErr)  // timeout, auth fail
    }
    log.Printf("SNMP error: %s", snmpErr.Oids[0].ErrorDescription)
} else {
    // Safe to use vb[0] - guaranteed 1 valid VarBind
    processSingleResult(vb[0])
}

Note:

  • Always returns slice with exactly 1 VarBind (success) or error
  • Single OID semantics: partial response impossible → always fatal
  • ParseError() shows exact failed OID + SNMP status code
  • RFC3416 §4.2.1 compliant GET with SNMPvbNullValue

func (*SNMPv3Session) SNMP_GetMulti

func (SNMPparameters *SNMPv3Session) SNMP_GetMulti(OidVar []SNMP_Packet_V2_Decoded_VarBind) (SNMPretPacket []SNMP_Packet_V2_Decoded_VarBind, err error)

SNMP_GetMulti performs SNMP GET request for multiple OIDs (bulk-capable).

Core multi-OID GET implementation that dispatches to V2c/V3 based on session config. Supports partial responses - successful OIDs return data, failed OIDs return structured errors.

Arguments:

OidVar - Array of VarBind structures with OIDs to query
       - Uses SNMPvbNullValue for standard GET (RFC3416 §4.2.1)
       - Supports arbitrary order and mixed vendor OIDs

Returns:

SNMPretPacket - Array of decoded VarBind responses (same length as input)
              - Successful: valid RSnmpVar with data
              - Failed:     Null/empty values + SNMPne_Errors/SNMPfe_Errors
err - Structured SNMP error or network failure

Key features:

  • Partial response support: 3/4 success = 75% data + 1 failed OID details
  • Automatic V2c/V3 dispatch based on SNMPparams.SNMPversion
  • RFC3416 compliant GET PDU (PDU type = SNMPv2_REQUEST_GET)

Usage example:

oids := [][]int{{1,3,6,1,2,1,1,1,0}, {1,3,6,1,2,1,1,99,0}, {1,3,6,1,2,1,1,5,0}}
varbinds := make([]SNMP_Packet_V2_Decoded_VarBind, len(oids))
for i, oid := range oids {
    varbinds[i] = SNMP_Packet_V2_Decoded_VarBind{oid, SNMPvbNullValue}
}

Or:

 oid1 := "1.3.6.1.2.1.1.1.0"
	oid1int, _ := Convert_OID_StringToIntArray_RAW(oid1)
 oid2 := "1.3.6.1.2.1.1.5.0"
	oid2int, _ := PowerSNMP.Convert_OID_StringToIntArray_RAW(OidOK2)

	varbinds := []PowerSNMP.SNMP_Packet_V2_Decoded_VarBind{{Oid1int, SNMPvbNullValue}, {Oid2int, SNMPvbNullValue}}

		results, err := sess.SNMP_GetMulti(varbinds)
		if err != nil {
		    snmpErr, commonErr := ParseError(err)
		    if commonErr != nil {
		        log.Fatal("Network failure:", commonErr)
		    }
		    fmt.Printf("Partial: %d/%d failed\n", len(snmpErr.Oids), len(varbinds))
		    for _, failed := range snmpErr.Oids {
		        fmt.Println(failed.ErrorDescription)
		    }
		}

		// Process successful results
		for _, vb := range results {
		    if len(vb.RSnmpVar) > 0 {  // Valid response
		        fmt.Printf("%s = %s\n",
		            Convert_OID_IntArrayToString_RAW(vb.RSnmpOID),
		            Convert_Variable_To_String(vb.RSnmpVar))
		    }
		}

func (*SNMPv3Session) SNMP_Set

func (SNMPparameters *SNMPv3Session) SNMP_Set(Oid []int, VBvalue SNMPVar) (SNMPretPacket []SNMP_Packet_V2_Decoded_VarBind, err error)

SNMP_Set performs SNMP SET request for a single OID with specified value.

Convenience wrapper over SNMP_SetMulti for single-OID configuration changes. Returns response VarBind or structured error via ParseError().

Arguments:

Oid     - SNMP OID as []int (e.g.: []int{1,3,6,1,2,1,1,6,0} = sysLocation)
VBvalue - Value to SET (use helper functions):
          * SetSNMPVar_OctetString("new name")
          * SetSNMPVar_Integer(123)
          * SetSNMPVar_Gauge32(45678)
          * SetSNMPVar_IPAddress("192.168.1.1")

Returns:

[]SNMP_Packet_V2_Decoded_VarBind - response (1 element for 1 OID, new value on success)
error - SNMPfe_Errors (notWritable, wrongType), SNMPne_Errors (partial)
        or network error

Example:

// Set sysLocation
vb, err := sess.SNMP_Set([]int{1,3,6,1,2,1,1,6,0},
    SetSNMPVar_OctetString("DC1-Rack-A42"))
if err != nil {
    snmpErr, commonErr := ParseError(err)
    if commonErr != nil {
        log.Fatal("Network error:", commonErr)
    }
    fmt.Printf("SET failed: %s\n", snmpErr.Oids[0].ErrorDescription)
    // Typical: "sysLocation (status=17): notWritable"
} else {
    fmt.Printf("SET success: %s = %s\n",
        Convert_OID_IntArrayToString_RAW(vb[0].RSnmpOID),
        Convert_Variable_To_String(vb[0].RSnmpVar))
}

Common errors:

  • status=17 notWritable - RO object (sysDescr, sysUpTime)
  • status=4 wrongValue - type mismatch (Integer → OctetString)
  • status=12 wrongEncoding - invalid value format
  • Network timeout/no auth - CommonError

Note:

Always returns slice with exactly 1 VarBind matching input.
SET operations require write permissions (community "private" or v3 priv).

func (*SNMPv3Session) SNMP_SetMulti

func (SNMPparameters *SNMPv3Session) SNMP_SetMulti(OidVar []SNMP_Packet_V2_Decoded_VarBind) (SNMPretPacket []SNMP_Packet_V2_Decoded_VarBind, err error)

SNMP_SetMulti performs SNMP SET request for multiple OIDs (bulk configuration).

Core multi-OID SET implementation dispatching to V2c/V3 based on session config. Returns response for successful SETs or structured errors for failures.

Arguments:

OidVar - Array of VarBind structures with OIDs and VALUES to configure
       - Order preserved in response (RFC3416 §4.2.5)
       - Mixed success/failure supported via structured errors

Returns:

SNMPretPacket - Array of decoded VarBind responses (same length as input)
              - Successful SET: new value or Null confirmation
              - Failed SET:    Null/empty + SNMPfe_Errors details
err - Structured SNMP error (notWritable, wrongValue) or network failure

Key features:

  • Bulk configuration: configure 10+ interfaces simultaneously
  • Partial success: 8/10 interfaces configured = 80% success
  • Automatic V2c/V3 dispatch (SNMPv2_REQUEST_SET PDU type)
  • RFC3416 compliant SET processing

Usage example:

// Bulk configure interface descriptions
interfaces := [][]int{
    {1,3,6,1,2,1,2,2,1,8,1},   // ifDescr.1
    {1,3,6,1,2,1,2,2,1,8,2},   // ifDescr.2
    {1,3,6,1,2,1,2,2,1,8,999}, // nonexistent
}

varbinds := make([]SNMP_Packet_V2_Decoded_VarBind, len(interfaces))
for i, oid := range interfaces {
    varbinds[i] = SNMP_Packet_V2_Decoded_VarBind{
        RSnmpOID: oid,
        RSnmpVar: SetSNMPVar_OctetString(fmt.Sprintf("Interface-%d", i+1)),
    }
}

results, err := sess.SNMP_SetMulti(varbinds)
if err != nil {
    snmpErr, commonErr := ParseError(err)
    if commonErr != nil {
        log.Fatal("Network failure:", commonErr)
    }
    fmt.Printf("SET partial: %d/%d failed\n", len(snmpErr.Oids), len(varbinds))
    for _, failed := range snmpErr.Oids {
        fmt.Printf("Failed: %s\n", failed.ErrorDescription)
        // "ifDescr.999 (status=17): notWritable"
    }
}

// Process successful SET confirmations
for _, vb := range results {
    oidStr := Convert_OID_IntArrayToString_RAW(vb.RSnmpOID)
    if len(vb.RSnmpVar) > 0 {
        fmt.Printf("SET OK: %s = %s\n", oidStr, Convert_Variable_To_String(vb.RSnmpVar))
    }
}

Common SET errors:

  • status=17 notWritable - Read-only MIB object (sysDescr, ifAdminStatus=1)
  • status=4 wrongValue - Type mismatch (Gauge32 → IPAddress)
  • status=5 wrongLength - Buffer overflow (255+ chars to OctetString)
  • status=12 wrongEncoding - Invalid ASN.1 encoding

Requires:

  • Write community ("private") for V2c
  • Privileged SNMPv3 user (auth+priv)

func (*SNMPv3Session) SNMP_Walk

func (SNMPparameters *SNMPv3Session) SNMP_Walk(oid []int) (ReturnValue []SNMP_Packet_V2_Decoded_VarBind, err error)

SNMP_Walk performs complete SNMP WALK starting from base OID using GETNEXT.

Lexicographic traversal of entire MIB subtree using SNMPv2_GETNEXT PDUs (RFC3411 §4.2.3). Handles SNMP exceptions internally, continues walk until lexicographic boundary or PDU failure.

Arguments:

oid - Base OID defining subtree boundary (e.g.: []int{1,3,6,1,2,1,2,2,1} = ifTable)

Returns:

[]SNMP_Packet_V2_Decoded_VarBind - ALL successfully discovered objects (lexicographic order)
error - Network/PDU-level failures only (SNMPne_Errors for VarBind exceptions)

SNMP error handling:

  • VarBind exceptions (noSuchName, endOfMibView): WALK CONTINUES
  • PDU errors (authFailure, usmStatsWrongDigests): WALK STOPS
  • Nonexistent base OID: [] + nil (RFC3411, SNMP4J compatible)
  • Net-SNMP CLI diff: "No Such Object" (CLI-only user-friendly extension)

Examples:

// Complete ifTable walk
ifTableOID := []int{1,3,6,1,2,1,2,2,1}
results, err := sess.SNMP_Walk(ifTableOID)
if err != nil {
    snmpErr, commonErr := ParseError(err)
    if commonErr != nil {
        log.Fatal("Network/PDU failure:", commonErr)  // auth timeout
    }
    fmt.Printf("Walk partial: %d objects + %d exceptions\n",
        len(results), len(snmpErr.Oids))
    // Results contain ALL valid objects despite exceptions!
}

// Process complete results
for _, vb := range results {
    fmt.Printf("%s = %s\n",
        Convert_OID_IntArrayToString_RAW(vb.RSnmpOID),
        Convert_Variable_To_String(vb.RSnmpVar))
}

// Nonexistent base OID (normal completion)
badOID := []int{1,3,6,1,2,1,1,99,0}
results, err = sess.SNMP_Walk(badOID)
// len(results) == 0 && err == nil (SNMP4J identical)

Algorithm (RFC3411 §4.2.3):

  1. GETNEXT(current_oid) → lexicographic successor
  2. If result.OID startsWith(base_oid): add result, GOTO 1
  3. If lexicographic boundary reached: normal termination (no error)
  4. Per-VarBind SNMP errors → continue with next GETNEXT

Production usage patterns:

// Network discovery
sysObjectIDOIDs := []int{1,3,6,1,2,1,1,2,0}
walk, _ := sess.SNMP_Walk(sysObjectIDOIDs)
vendor := extractVendorOID(walk)

// Complete interface table for monitoring
ifTable, partialErr := sess.SNMP_Walk([]int{1,3,6,1,2,1,2,2,1})

Error scenarios:

  • Network timeout/disconnect → nil + error
  • PDU auth failure (usmStatsWrongDigests) → nil + SNMPfe_Errors
  • VarBind exceptions (noSuchName): INTERNAL HANDLING → walk continues
  • "unsupported SNMP version" → immediate failure

Performance characteristics:

  • N PDUs for N objects (classic GETNEXT, no bulk optimization)
  • Optimal for small-medium subtrees (<500 objects)
  • Results preserve discovery order (stable lexicographic)

vs other implementations:

  • Net-SNMP CLI: "No Such Object available..." (user-friendly CLI extension)
  • SNMP4J Java: [] + null (identical RFC3411 behavior)

func (*SNMPv3Session) SNMP_Walk_WCallback added in v1.1.1

func (SNMPparameters *SNMPv3Session) SNMP_Walk_WCallback(oid []int, callback func(ChanDataWErr))

func (*SNMPv3Session) SNMP_Walk_WChan

func (SNMPparameters *SNMPv3Session) SNMP_Walk_WChan(ctx context.Context, oid []int, CData chan<- ChanDataWErr)

SNMP_Walk_WChan performs streaming SNMP WALK operation with results delivered via channel.

Classic **GETNEXT-based lexicographic traversal** — the reliable, memory-efficient standard for SNMP walking. Streams VarBinds as discovered (1 object buffered at a time). Optimal for **small-medium MIB tables** (<1000 objects).

Arguments:

ctx  - Context for cancellation/timeout (recommended: context.WithTimeout)
oid  - Base OID to walk (ex: `[]int{1,3,6,1,2,1,2,2,1}` = ifTable)
CData - Output channel of `ChanDataWErr` (range-loop safe)

Channel contract (guaranteed semantics):

  • **Success**: `ChanDataWErr{Data: varbind, Error: nil}`
  • **Exception**: `ChanDataWErr{Data: nil, Error: snmpError}` (stream **continues**)
  • **End**: `close(CData)` on completion/PDU failure/cancellation
  • **Safe**: `for result := range CData {}` — goroutine-safe, multiple consumers OK

Production patterns:

┌──────────────────────────────────────┬─────────────────────────────────────┐ │ SNMP_Walk_WChan │ SNMP_BulkWalk_WChan │ ├──────────────────────────────────────┼─────────────────────────────────────┤ │ Small tables (<100 objs) │ Large tables (>1000 objs) │ │ Low latency (1 PDU) │ High throughput (25-50x faster) │ │ Memory: 1 object buffered │ Memory: bulk buffer │ │ sysUpTime, ifAlias, sysDescr │ ifTable, ipAddrTable, tcpConnTable │ │ Real-time dashboards │ Bulk collectors (Prometheus) │ └──────────────────────────────────────┴─────────────────────────────────────┘

Error resilience:

  • **VarBind errors** → logged, stream continues
  • **Network/PDU failure** → immediate `close(CData)`
  • **Context cancel** → clean shutdown, `close(CData)`
  • **Unsupported SNMP version** → single error + `close(CData)`

Use cases - PERFECT FOR:

  • Real-time monitoring dashboards (sysUpTime, ifAlias)
  • Memory-constrained environments (IoT, edge)
  • Debugging/verbose logging
  • Small MIB subtrees (<100 objects)
  • Fallback when BulkWalk fails (agent incompatibility)

Use SNMP_BulkWalk_WChan for ifTable/ipTable scale (1000+ objects).

type SNMPv3_DecodePacket

type SNMPv3_DecodePacket struct {
	Version          int
	GlobalData       SNMPv3_GlobalData
	SecuritySettings SNMPv3_SecSeq
	V3PDU            SNMPv3_DecodedPDU
	MessageType      int
}

type SNMPv3_DecodedPDU

type SNMPv3_DecodedPDU struct {
	ContextEngineId []byte
	ContextName     []byte
	V2VarBind       SNMP_Packet_V2_decoded_PDU
}

type SNMPv3_GlobalData

type SNMPv3_GlobalData struct {
	MsgID            int32
	MsgMaxSize       int
	MsgFlag          []byte
	MsgSecurityModel int
}

type SNMPv3_PDU

type SNMPv3_PDU struct {
	ContextEngineId []byte
	ContextName     []byte
	V2VarBind       ASNber.RawValue
}

type SNMPv3_Packet

type SNMPv3_Packet struct {
	Version          int
	GlobalData       ASNber.RawValue
	SecuritySettings []byte //asn1.RawValue
	PtData           ASNber.RawValue
}

type SNMPv3_SecSeq

type SNMPv3_SecSeq struct {
	AuthEng    []byte
	Boots      int32
	Time       int32
	User       []byte
	AuthParams []byte
	PrivParams []byte
}

func ParseTrapUsername

func ParseTrapUsername(packet []byte) (version int, username string, v3secdata SNMPv3_SecSeq, err error)

ParseTrapUsername extracts username/community from TRAP packets (version-blind).

Quick credential extraction for trap filtering/ACL without full decryption. Returns SNMPv2c community OR SNMPv3 userName + security parameters.

Arguments:

packet - Raw TRAP/INFORM bytes

Returns:

version    - 1(SNMPv2c), 3(SNMPv3)
username   - Community string OR userName
v3secdata  - Security parameters (SNMPv3 only, zeroed for v2c)
err        - ASN.1 decode errors

Production trap filter:

```go
version, user, _, err := ParseTrapUsername(pkt)
if err != nil { return }

switch user {
case "public":    dropPublicTraps(pkt)
case "admin":     processCriticalTraps(pkt)
case "monitor":   queueForGrafana(pkt)
}
```

Flow:

  • SNMPv2c → community string extraction
  • SNMPv3 → userName + USM parameters (secLevel, authP, privP)

Zero-copy for v2c, minimal ASN.1 unmarshaling for v3 header only.

type SNMPwrongReqID_MsgId_Errors

type SNMPwrongReqID_MsgId_Errors struct {
	ErrorStatusCode uint8
}

func (SNMPwrongReqID_MsgId_Errors) Error

Directories

Path Synopsis
cmd
snmpwalk command
trapreceiver command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL