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

View File

@ -2,6 +2,7 @@ package snmp_trap
import ( import (
"errors" "errors"
"fmt"
"strconv" "strconv"
"strings" "strings"
"testing" "testing"
@ -355,8 +356,8 @@ func TestReceiveTrapV3(t *testing.T) {
}{ }{
// ordinary v3 coldStart trap no auth and no priv // ordinary v3 coldStart trap no auth and no priv
{ {
name: "coldStart noAuthNoPriv", name: "noAuthNoPriv",
secName: "noAuthNoPriv", secName: "peter",
secLevel: "noAuthNoPriv", secLevel: "noAuthNoPriv",
contextName: "foo_context_name", contextName: "foo_context_name",
engineID: "bar_engine_id", engineID: "bar_engine_id",
@ -418,8 +419,8 @@ func TestReceiveTrapV3(t *testing.T) {
}, },
// ordinary v3 coldstart trap SHA auth and no priv // ordinary v3 coldstart trap SHA auth and no priv
{ {
name: "coldStart authShaNoPriv", name: "authNoPriv SHA",
secName: "authShaNoPriv", secName: "peter",
secLevel: "authNoPriv", secLevel: "authNoPriv",
authProto: "SHA", authProto: "SHA",
authPass: "passpass", authPass: "passpass",
@ -479,8 +480,8 @@ func TestReceiveTrapV3(t *testing.T) {
}, },
// ordinary v3 coldstart trap SHA224 auth and no priv // ordinary v3 coldstart trap SHA224 auth and no priv
{ {
name: "coldStart authShaNoPriv", name: "authNoPriv SHA224",
secName: "authSha224NoPriv", secName: "peter",
secLevel: "authNoPriv", secLevel: "authNoPriv",
authProto: "SHA224", authProto: "SHA224",
authPass: "passpass", authPass: "passpass",
@ -540,8 +541,8 @@ func TestReceiveTrapV3(t *testing.T) {
}, },
// ordinary v3 coldstart trap SHA256 auth and no priv // ordinary v3 coldstart trap SHA256 auth and no priv
{ {
name: "coldStart authSha256NoPriv", name: "authNoPriv SHA256",
secName: "authSha256NoPriv", secName: "peter",
secLevel: "authNoPriv", secLevel: "authNoPriv",
authProto: "SHA256", authProto: "SHA256",
authPass: "passpass", authPass: "passpass",
@ -601,8 +602,8 @@ func TestReceiveTrapV3(t *testing.T) {
}, },
// ordinary v3 coldstart trap SHA384 auth and no priv // ordinary v3 coldstart trap SHA384 auth and no priv
{ {
name: "coldStart authSha384NoPriv", name: "authNoPriv SHA384",
secName: "authSha384NoPriv", secName: "peter",
secLevel: "authNoPriv", secLevel: "authNoPriv",
authProto: "SHA384", authProto: "SHA384",
authPass: "passpass", authPass: "passpass",
@ -662,8 +663,8 @@ func TestReceiveTrapV3(t *testing.T) {
}, },
// ordinary v3 coldstart trap SHA512 auth and no priv // ordinary v3 coldstart trap SHA512 auth and no priv
{ {
name: "coldStart authShaNoPriv", name: "authNoPriv SHA512",
secName: "authSha512NoPriv", secName: "peter",
secLevel: "authNoPriv", secLevel: "authNoPriv",
authProto: "SHA512", authProto: "SHA512",
authPass: "passpass", 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 // ordinary v3 coldstart trap MD5 auth and no priv
{ {
name: "coldStart authMD5NoPriv", name: "authNoPriv MD5",
secName: "authMD5NoPriv", secName: "peter",
secLevel: "authNoPriv", secLevel: "authNoPriv",
authProto: "MD5", authProto: "MD5",
authPass: "passpass", authPass: "passpass",
@ -845,8 +785,8 @@ func TestReceiveTrapV3(t *testing.T) {
}, },
// ordinary v3 coldStart SHA trap auth and AES priv // ordinary v3 coldStart SHA trap auth and AES priv
{ {
name: "coldStart authSHAPrivAES", name: "authPriv SHA-AES",
secName: "authSHAPrivAES", secName: "peter",
secLevel: "authPriv", secLevel: "authPriv",
authProto: "SHA", authProto: "SHA",
authPass: "passpass", authPass: "passpass",
@ -908,8 +848,8 @@ func TestReceiveTrapV3(t *testing.T) {
}, },
// ordinary v3 coldStart SHA trap auth and DES priv // ordinary v3 coldStart SHA trap auth and DES priv
{ {
name: "coldStart authSHAPrivDES", name: "authPriv SHA-DES",
secName: "authSHAPrivDES", secName: "peter",
secLevel: "authPriv", secLevel: "authPriv",
authProto: "SHA", authProto: "SHA",
authPass: "passpass", authPass: "passpass",
@ -971,8 +911,8 @@ func TestReceiveTrapV3(t *testing.T) {
}, },
// ordinary v3 coldStart SHA trap auth and AES192 priv // ordinary v3 coldStart SHA trap auth and AES192 priv
{ {
name: "coldStart authSHAPrivAES192", name: "authPriv SHA-AES192",
secName: "authSHAPrivAES192", secName: "peter",
secLevel: "authPriv", secLevel: "authPriv",
authProto: "SHA", authProto: "SHA",
authPass: "passpass", authPass: "passpass",
@ -1034,8 +974,8 @@ func TestReceiveTrapV3(t *testing.T) {
}, },
// ordinary v3 coldStart SHA trap auth and AES192C priv // ordinary v3 coldStart SHA trap auth and AES192C priv
{ {
name: "coldStart authSHAPrivAES192C", name: "authPriv SHA-AES192C",
secName: "authSHAPrivAES192C", secName: "peter",
secLevel: "authPriv", secLevel: "authPriv",
authProto: "SHA", authProto: "SHA",
authPass: "passpass", authPass: "passpass",
@ -1097,8 +1037,8 @@ func TestReceiveTrapV3(t *testing.T) {
}, },
// ordinary v3 coldStart SHA trap auth and AES256 priv // ordinary v3 coldStart SHA trap auth and AES256 priv
{ {
name: "coldStart authSHAPrivAES256", name: "authPriv SHA-AES256",
secName: "authSHAPrivAES256", secName: "peter",
secLevel: "authPriv", secLevel: "authPriv",
authProto: "SHA", authProto: "SHA",
authPass: "passpass", authPass: "passpass",
@ -1160,8 +1100,8 @@ func TestReceiveTrapV3(t *testing.T) {
}, },
// ordinary v3 coldStart SHA trap auth and AES256C priv // ordinary v3 coldStart SHA trap auth and AES256C priv
{ {
name: "coldStart authSHAPrivAES256C", name: "authPriv SHA-AES256C",
secName: "authSHAPrivAES256C", secName: "peter",
secLevel: "authPriv", secLevel: "authPriv",
authProto: "SHA", authProto: "SHA",
authPass: "passpass", authPass: "passpass",
@ -1374,26 +1314,171 @@ func TestOidLookupFail(t *testing.T) {
require.True(t, found, "did not receive expected error message") require.True(t, found, "did not receive expected error message")
} }
type entry struct { func TestInvalidAuth(t *testing.T) {
oid string now := uint32(time.Now().Unix())
e snmp.MibEntry 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 { // If the first pdu isn't type TimeTicks, gosnmp.SendTrap() will
entries []entry // prepend one with time.Now()
fail chan bool 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 _, tt := range tests {
for _, entry := range t.entries { t.Run(tt.name, func(t *testing.T) {
if input == entry.oid { // We would prefer to specify port 0 and let the network
return snmp.MibEntry{MibName: entry.e.MibName, OidText: entry.e.OidText}, nil // 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 { security := createSecurityParameters(tt.authProto, tt.privProto, tt.user, tt.privPass, tt.authPass)
t.fail <- true
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 { func createSecurityParameters(authProto, privProto, username, privPass, authPass string) *gosnmp.UsmSecurityParameters {
@ -1448,3 +1533,42 @@ func createSecurityParameters(authProto, privProto, username, privPass, authPass
AuthenticationProtocol: authenticationProtocol, 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
}
}