Files
Jason Staack 9458dadc90 feat(18-01): add gosnmp dependency, SNMP types, and client builder
- Install gosnmp v1.43.2 as direct dependency
- Create snmp package with SNMPConfig, CompiledProfile, PollGroup types
- Implement BuildSNMPClient for v1, v2c, and v3 (all security levels)
- Map auth protocols (MD5, SHA, SHA224-512) and priv protocols (DES, AES128-256)
- MaxRepetitions set to 10 (not gosnmp default 50) for embedded devices
- Full test coverage: 9 tests covering all SNMP versions and protocol mappings

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:18:37 -05:00

103 lines
2.6 KiB
Go

package snmp
import (
"fmt"
"github.com/gosnmp/gosnmp"
"github.com/staack/the-other-dude/poller/internal/store"
"github.com/staack/the-other-dude/poller/internal/vault"
)
// BuildSNMPClient constructs a gosnmp.GoSNMP struct configured for the given
// device and credential. It does NOT call Connect — the caller is responsible
// for establishing the UDP session and closing it when done.
//
// This supports SNMP v1, v2c, and all three v3 security levels.
func BuildSNMPClient(dev store.Device, cred *vault.SNMPCredential, cfg SNMPConfig) (*gosnmp.GoSNMP, error) {
g := &gosnmp.GoSNMP{
Target: dev.IPAddress,
Port: uint16(dev.SNMPPort),
Timeout: cfg.Timeout,
Retries: cfg.Retries,
MaxRepetitions: cfg.MaxRepetitions,
}
switch cred.Version {
case "v1":
g.Version = gosnmp.Version1
g.Community = cred.Community
case "v2c":
g.Version = gosnmp.Version2c
g.Community = cred.Community
case "v3":
g.Version = gosnmp.Version3
g.SecurityModel = gosnmp.UserSecurityModel
g.MsgFlags = mapSecurityLevel(cred.SecurityLevel)
g.SecurityParameters = &gosnmp.UsmSecurityParameters{
UserName: cred.Username,
AuthenticationProtocol: mapAuthProto(cred.AuthProtocol),
AuthenticationPassphrase: cred.AuthPass,
PrivacyProtocol: mapPrivProto(cred.PrivProtocol),
PrivacyPassphrase: cred.PrivPass,
}
default:
return nil, fmt.Errorf("unsupported SNMP version: %q", cred.Version)
}
return g, nil
}
// mapSecurityLevel maps credential security level strings to gosnmp v3 message flags.
func mapSecurityLevel(level string) gosnmp.SnmpV3MsgFlags {
switch level {
case "auth_priv":
return gosnmp.AuthPriv
case "auth_no_priv":
return gosnmp.AuthNoPriv
case "no_auth_no_priv":
return gosnmp.NoAuthNoPriv
default:
return gosnmp.NoAuthNoPriv
}
}
// mapAuthProto maps credential auth protocol strings to gosnmp v3 auth protocol constants.
func mapAuthProto(proto string) gosnmp.SnmpV3AuthProtocol {
switch proto {
case "MD5":
return gosnmp.MD5
case "SHA":
return gosnmp.SHA
case "SHA224":
return gosnmp.SHA224
case "SHA256":
return gosnmp.SHA256
case "SHA384":
return gosnmp.SHA384
case "SHA512":
return gosnmp.SHA512
default:
return gosnmp.NoAuth
}
}
// mapPrivProto maps credential privacy protocol strings to gosnmp v3 privacy protocol constants.
func mapPrivProto(proto string) gosnmp.SnmpV3PrivProtocol {
switch proto {
case "DES":
return gosnmp.DES
case "AES128":
return gosnmp.AES
case "AES192":
return gosnmp.AES192
case "AES256":
return gosnmp.AES256
default:
return gosnmp.NoPriv
}
}