chore(deps): Bump github.com/gosmnp/gosnmp from 1.39.0 to 1.40.0 (#16660)

This commit is contained in:
Sven Rebhan 2025-05-01 11:10:18 -05:00 committed by GitHub
parent 387f38dbd0
commit db2c2d8638
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 242 additions and 116 deletions

View File

@ -90,6 +90,10 @@ func (s *SnmpTrap) Init() error {
// Setup the SNMP parameters
params := *gosnmp.Default
if s.Log.Level().Includes(telegraf.Trace) {
params.Logger = gosnmp.NewLogger(&logger{s.Log})
}
switch s.Version {
case "1":
params.Version = gosnmp.Version1
@ -99,7 +103,6 @@ func (s *SnmpTrap) Init() error {
params.Version = gosnmp.Version3
// Setup the security for v3
var security gosnmp.UsmSecurityParameters
params.SecurityModel = gosnmp.UserSecurityModel
// Set security mechanisms
@ -115,6 +118,7 @@ func (s *SnmpTrap) Init() error {
}
// Set authentication
var security gosnmp.UsmSecurityParameters
switch strings.ToLower(s.AuthProtocol) {
case "":
security.AuthenticationProtocol = gosnmp.NoAuth
@ -162,13 +166,6 @@ func (s *SnmpTrap) Init() error {
security.UserName = secnameSecret.String()
secnameSecret.Destroy()
privPasswdSecret, err := s.PrivPassword.Get()
if err != nil {
return fmt.Errorf("getting priv-password failed: %w", err)
}
security.PrivacyPassphrase = privPasswdSecret.String()
privPasswdSecret.Destroy()
authPasswdSecret, err := s.AuthPassword.Get()
if err != nil {
return fmt.Errorf("getting auth-password failed: %w", err)
@ -176,13 +173,18 @@ func (s *SnmpTrap) Init() error {
security.AuthenticationPassphrase = authPasswdSecret.String()
authPasswdSecret.Destroy()
privPasswdSecret, err := s.PrivPassword.Get()
if err != nil {
return fmt.Errorf("getting priv-password failed: %w", err)
}
security.PrivacyPassphrase = privPasswdSecret.String()
privPasswdSecret.Destroy()
// Enable security settings
params.SecurityParameters = &security
default:
return fmt.Errorf("unknown version %q", s.Version)
}
if s.Log.Level().Includes(telegraf.Trace) {
params.Logger = gosnmp.NewLogger(&logger{s.Log})
}
// Initialize the listener
s.listener = gosnmp.NewTrapListener()

View File

@ -2,6 +2,7 @@ package snmp_trap
import (
"errors"
"fmt"
"strconv"
"strings"
"testing"
@ -355,8 +356,8 @@ func TestReceiveTrapV3(t *testing.T) {
}{
// ordinary v3 coldStart trap no auth and no priv
{
name: "coldStart noAuthNoPriv",
secName: "noAuthNoPriv",
name: "noAuthNoPriv",
secName: "peter",
secLevel: "noAuthNoPriv",
contextName: "foo_context_name",
engineID: "bar_engine_id",
@ -418,8 +419,8 @@ func TestReceiveTrapV3(t *testing.T) {
},
// ordinary v3 coldstart trap SHA auth and no priv
{
name: "coldStart authShaNoPriv",
secName: "authShaNoPriv",
name: "authNoPriv SHA",
secName: "peter",
secLevel: "authNoPriv",
authProto: "SHA",
authPass: "passpass",
@ -479,8 +480,8 @@ func TestReceiveTrapV3(t *testing.T) {
},
// ordinary v3 coldstart trap SHA224 auth and no priv
{
name: "coldStart authShaNoPriv",
secName: "authSha224NoPriv",
name: "authNoPriv SHA224",
secName: "peter",
secLevel: "authNoPriv",
authProto: "SHA224",
authPass: "passpass",
@ -540,8 +541,8 @@ func TestReceiveTrapV3(t *testing.T) {
},
// ordinary v3 coldstart trap SHA256 auth and no priv
{
name: "coldStart authSha256NoPriv",
secName: "authSha256NoPriv",
name: "authNoPriv SHA256",
secName: "peter",
secLevel: "authNoPriv",
authProto: "SHA256",
authPass: "passpass",
@ -601,8 +602,8 @@ func TestReceiveTrapV3(t *testing.T) {
},
// ordinary v3 coldstart trap SHA384 auth and no priv
{
name: "coldStart authSha384NoPriv",
secName: "authSha384NoPriv",
name: "authNoPriv SHA384",
secName: "peter",
secLevel: "authNoPriv",
authProto: "SHA384",
authPass: "passpass",
@ -662,8 +663,8 @@ func TestReceiveTrapV3(t *testing.T) {
},
// ordinary v3 coldstart trap SHA512 auth and no priv
{
name: "coldStart authShaNoPriv",
secName: "authSha512NoPriv",
name: "authNoPriv SHA512",
secName: "peter",
secLevel: "authNoPriv",
authProto: "SHA512",
authPass: "passpass",
@ -721,71 +722,10 @@ func TestReceiveTrapV3(t *testing.T) {
),
},
},
// ordinary v3 coldstart trap SHA auth and no priv
{
name: "coldStart authShaNoPriv",
secName: "authShaNoPriv",
secLevel: "authNoPriv",
authProto: "SHA",
authPass: "passpass",
trap: gosnmp.SnmpTrap{
Variables: []gosnmp.SnmpPDU{
{
Name: ".1.3.6.1.2.1.1.3.0",
Type: gosnmp.TimeTicks,
Value: now,
},
{
Name: ".1.3.6.1.6.3.1.1.4.1.0", // SNMPv2-MIB::snmpTrapOID.0
Type: gosnmp.ObjectIdentifier,
Value: ".1.3.6.1.6.3.1.1.5.1", // coldStart
},
},
},
entries: []entry{
{
oid: ".1.3.6.1.6.3.1.1.4.1.0",
e: snmp.MibEntry{
MibName: "SNMPv2-MIB",
OidText: "snmpTrapOID.0",
},
},
{
oid: ".1.3.6.1.6.3.1.1.5.1",
e: snmp.MibEntry{
MibName: "SNMPv2-MIB",
OidText: "coldStart",
},
},
{
oid: ".1.3.6.1.2.1.1.3.0",
e: snmp.MibEntry{
MibName: "UNUSED_MIB_NAME",
OidText: "sysUpTimeInstance",
},
},
},
expected: []telegraf.Metric{
metric.New(
"snmp_trap", // name
map[string]string{ // tags
"oid": ".1.3.6.1.6.3.1.1.5.1",
"name": "coldStart",
"mib": "SNMPv2-MIB",
"version": "3",
"source": "127.0.0.1",
},
map[string]interface{}{ // fields
"sysUpTimeInstance": now,
},
time.Unix(0, 0),
),
},
},
// ordinary v3 coldstart trap MD5 auth and no priv
{
name: "coldStart authMD5NoPriv",
secName: "authMD5NoPriv",
name: "authNoPriv MD5",
secName: "peter",
secLevel: "authNoPriv",
authProto: "MD5",
authPass: "passpass",
@ -845,8 +785,8 @@ func TestReceiveTrapV3(t *testing.T) {
},
// ordinary v3 coldStart SHA trap auth and AES priv
{
name: "coldStart authSHAPrivAES",
secName: "authSHAPrivAES",
name: "authPriv SHA-AES",
secName: "peter",
secLevel: "authPriv",
authProto: "SHA",
authPass: "passpass",
@ -908,8 +848,8 @@ func TestReceiveTrapV3(t *testing.T) {
},
// ordinary v3 coldStart SHA trap auth and DES priv
{
name: "coldStart authSHAPrivDES",
secName: "authSHAPrivDES",
name: "authPriv SHA-DES",
secName: "peter",
secLevel: "authPriv",
authProto: "SHA",
authPass: "passpass",
@ -971,8 +911,8 @@ func TestReceiveTrapV3(t *testing.T) {
},
// ordinary v3 coldStart SHA trap auth and AES192 priv
{
name: "coldStart authSHAPrivAES192",
secName: "authSHAPrivAES192",
name: "authPriv SHA-AES192",
secName: "peter",
secLevel: "authPriv",
authProto: "SHA",
authPass: "passpass",
@ -1034,8 +974,8 @@ func TestReceiveTrapV3(t *testing.T) {
},
// ordinary v3 coldStart SHA trap auth and AES192C priv
{
name: "coldStart authSHAPrivAES192C",
secName: "authSHAPrivAES192C",
name: "authPriv SHA-AES192C",
secName: "peter",
secLevel: "authPriv",
authProto: "SHA",
authPass: "passpass",
@ -1097,8 +1037,8 @@ func TestReceiveTrapV3(t *testing.T) {
},
// ordinary v3 coldStart SHA trap auth and AES256 priv
{
name: "coldStart authSHAPrivAES256",
secName: "authSHAPrivAES256",
name: "authPriv SHA-AES256",
secName: "peter",
secLevel: "authPriv",
authProto: "SHA",
authPass: "passpass",
@ -1160,8 +1100,8 @@ func TestReceiveTrapV3(t *testing.T) {
},
// ordinary v3 coldStart SHA trap auth and AES256C priv
{
name: "coldStart authSHAPrivAES256C",
secName: "authSHAPrivAES256C",
name: "authPriv SHA-AES256C",
secName: "peter",
secLevel: "authPriv",
authProto: "SHA",
authPass: "passpass",
@ -1374,26 +1314,171 @@ func TestOidLookupFail(t *testing.T) {
require.True(t, found, "did not receive expected error message")
}
type entry struct {
oid string
e snmp.MibEntry
func TestInvalidAuth(t *testing.T) {
now := uint32(time.Now().Unix())
trap := gosnmp.SnmpTrap{
Variables: []gosnmp.SnmpPDU{
{
Name: ".1.3.6.1.2.1.1.3.0",
Type: gosnmp.TimeTicks,
Value: now,
},
{
Name: ".1.3.6.1.6.3.1.1.4.1.0", // SNMPv2-MIB::snmpTrapOID.0
Type: gosnmp.ObjectIdentifier,
Value: ".1.3.6.1.6.3.1.1.5.1", // coldStart
},
},
}
translator := &testTranslator{entries: []entry{
{
oid: ".1.3.6.1.6.3.1.1.4.1.0",
e: snmp.MibEntry{
MibName: "SNMPv2-MIB",
OidText: "snmpTrapOID.0",
},
},
{
oid: ".1.3.6.1.6.3.1.1.5.1",
e: snmp.MibEntry{
MibName: "SNMPv2-MIB",
OidText: "coldStart",
},
},
{
oid: ".1.3.6.1.2.1.1.3.0",
e: snmp.MibEntry{
MibName: "UNUSED_MIB_NAME",
OidText: "sysUpTimeInstance",
},
},
},
}
type testTranslator struct {
entries []entry
fail chan bool
// If the first pdu isn't type TimeTicks, gosnmp.SendTrap() will
// prepend one with time.Now()
var tests = []struct {
name string
user string // v3 username
secLevel string // v3 security level
authProto string // Auth protocol: "", MD5 or SHA
authPass string // Auth passphrase
privProto string // Priv protocol: "", DES or AES
privPass string // Priv passphrase
expected string
}{
{
name: "no authentication",
user: "franz",
secLevel: "NoAuthNoPriv",
},
{
name: "wrong username",
user: "foo",
secLevel: "authPriv",
authProto: "sha",
authPass: "what a nice day",
privProto: "aes",
privPass: "for my privacy",
},
{
name: "wrong password",
user: "franz",
secLevel: "authPriv",
authProto: "sha",
authPass: "passpass",
privProto: "aes",
privPass: "for my privacy",
},
{
name: "wrong auth protocol",
user: "franz",
secLevel: "authPriv",
authProto: "md5",
authPass: "what a nice day",
privProto: "aes",
privPass: "for my privacy",
},
}
func (t *testTranslator) lookup(input string) (snmp.MibEntry, error) {
for _, entry := range t.entries {
if input == entry.oid {
return snmp.MibEntry{MibName: entry.e.MibName, OidText: entry.e.OidText}, nil
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// We would prefer to specify port 0 and let the network
// stack choose an unused port for us but TrapListener
// doesn't have a way to return the autoselected port.
// Instead, we'll use an unusual port and hope it's
// unused.
const port = 12399
// Set up the service input plugin
plugin := &SnmpTrap{
ServiceAddress: "udp://:" + strconv.Itoa(port),
Version: "3",
SecName: config.NewSecret([]byte("franz")),
SecLevel: "authPriv",
AuthProtocol: "sha",
AuthPassword: config.NewSecret([]byte("what a nice day")),
PrivProtocol: "aes",
PrivPassword: config.NewSecret([]byte("for my privacy")),
Log: testutil.Logger{},
transl: translator,
}
require.NoError(t, plugin.Init())
// Inject special logger
found := make(chan bool, 1)
plugin.listener.Params.Logger = gosnmp.NewLogger(
&testLogger{matcher: "incoming packet is not authentic", out: found},
)
var acc testutil.Accumulator
require.NoError(t, plugin.Start(&acc))
defer plugin.Stop()
// Create a v3 client and send the trap
var msgFlags gosnmp.SnmpV3MsgFlags
switch strings.ToLower(tt.secLevel) {
case "noauthnopriv", "":
msgFlags = gosnmp.NoAuthNoPriv
case "authnopriv":
msgFlags = gosnmp.AuthNoPriv
case "authpriv":
msgFlags = gosnmp.AuthPriv
default:
require.FailNowf(t, "unknown security level %q", tt.secLevel)
}
if t.fail != nil {
t.fail <- true
security := createSecurityParameters(tt.authProto, tt.privProto, tt.user, tt.privPass, tt.authPass)
client := &gosnmp.GoSNMP{
Port: port,
Version: gosnmp.Version3,
Timeout: 2 * time.Second,
Retries: 1,
MaxOids: gosnmp.MaxOids,
Target: "127.0.0.1",
SecurityParameters: security,
SecurityModel: gosnmp.UserSecurityModel,
MsgFlags: msgFlags,
ContextName: "context-name",
ContextEngineID: "engine no 5",
}
require.NoError(t, client.Connect(), "connecting failed")
defer client.Conn.Close()
_, err := client.SendTrap(trap)
require.NoError(t, err)
require.NoError(t, client.Conn.Close(), "closing failed")
// Wait for error to be logged
select {
case <-found:
case <-time.After(3 * time.Second):
t.Fatal("timed out waiting for unauthenticated log")
}
// Verify plugin output
require.Empty(t, acc.GetTelegrafMetrics())
})
}
return snmp.MibEntry{}, errors.New("unexpected oid")
}
func createSecurityParameters(authProto, privProto, username, privPass, authPass string) *gosnmp.UsmSecurityParameters {
@ -1448,3 +1533,42 @@ func createSecurityParameters(authProto, privProto, username, privPass, authPass
AuthenticationProtocol: authenticationProtocol,
}
}
type entry struct {
oid string
e snmp.MibEntry
}
type testTranslator struct {
entries []entry
fail chan bool
}
func (t *testTranslator) lookup(input string) (snmp.MibEntry, error) {
for _, entry := range t.entries {
if input == entry.oid {
return snmp.MibEntry{MibName: entry.e.MibName, OidText: entry.e.OidText}, nil
}
}
if t.fail != nil {
t.fail <- true
}
return snmp.MibEntry{}, errors.New("unexpected oid")
}
type testLogger struct {
matcher string
out chan bool
}
func (l *testLogger) Print(v ...interface{}) {
if strings.Contains(fmt.Sprint(v...), l.matcher) {
l.out <- true
}
}
func (l *testLogger) Printf(format string, v ...interface{}) {
if strings.Contains(fmt.Sprintf(format, v...), l.matcher) {
l.out <- true
}
}