-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit af5619d
Showing
8 changed files
with
385 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# practice-go-snmptrap | ||
|
||
## references | ||
|
||
- https://github.com/sleepinggenius2/gosmi/ | ||
- https://github.com/gosnmp/gosnmp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package main | ||
|
||
type MIB struct { | ||
Directory []string `yaml:"directory"` | ||
LoadModules []string `yaml:"modules"` | ||
} | ||
|
||
type TrapServer struct { | ||
Address string `yaml:"addr"` | ||
Port string `yaml:"port"` | ||
} | ||
|
||
type Trap struct { | ||
Ident string `yaml:"ident"` | ||
Format string `yaml:"format"` | ||
} | ||
|
||
type Config struct { | ||
MIB *MIB `yaml:"mib"` | ||
TrapServer *TrapServer `yaml:"snmp"` | ||
Trap []*Trap `yaml:"trap"` | ||
Debug bool `yaml:"debug"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
snmp: | ||
addr: 0.0.0.0 | ||
port: 9162 | ||
mib: | ||
directory: | ||
- "/var/lib/snmp/mibs/ietf/" | ||
modules: | ||
- SNMPv2-MIB | ||
- IF-MIB | ||
# - CISCO-CONFIG-MAN-MIB | ||
# - CISCO-GENERAL-TRAPS | ||
# - CISCO-SYSLOG-MIB | ||
debug: false | ||
trap: | ||
# - ident: .1.3.6.1.4.1.9.9.41.2.0.1 | ||
# format: '[{{ addr }}] {{ read "CISCO-SYSLOG-MIB::clogHistFacility" }} is msg:{{ read "CISCO-SYSLOG-MIB::clogHistMsgName" }} text:{{ read "CISCO-SYSLOG-MIB::clogHistMsgText" }}' | ||
- ident: .1.3.6.1.6.3.1.1.5.1 | ||
format: '{{ addr }} is cold started' | ||
- ident: .1.3.6.1.6.3.1.1.5.2 | ||
format: '{{ addr }} is warm started' | ||
- ident: .1.3.6.1.6.3.1.1.5.3 | ||
format: '{{ addr }} {{ read "IF-MIB::ifDescr" }} is linkdown' | ||
- ident: .1.3.6.1.6.3.1.1.5.4 | ||
format: '{{ addr }} {{ read "IF-MIB::ifDescr" }} is linkup' | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
module github.com/yseto/practice-go-snmptrap | ||
|
||
go 1.19 | ||
|
||
require ( | ||
github.com/gosnmp/gosnmp v1.35.0 | ||
github.com/sleepinggenius2/gosmi v0.4.4 | ||
gopkg.in/yaml.v3 v3.0.1 | ||
) | ||
|
||
require github.com/alecthomas/participle v0.4.1 // indirect |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
github.com/alecthomas/go-thrift v0.0.0-20170109061633-7914173639b2/go.mod h1:CxCgO+NdpMdi9SsTlGbc0W+/UNxO3I0AabOEJZ3w61w= | ||
github.com/alecthomas/kong v0.2.1/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI= | ||
github.com/alecthomas/participle v0.4.1 h1:P2PJWzwrSpuCWXKnzqvw0b0phSfH1kJo4p2HvLynVsI= | ||
github.com/alecthomas/participle v0.4.1/go.mod h1:T8u4bQOSMwrkTWOSyt8/jSFPEnRtd0FKFMjVfYBlqPs= | ||
github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= | ||
github.com/alecthomas/repr v0.0.0-20210301060118-828286944d6a/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= | ||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= | ||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/gosnmp/gosnmp v1.35.0 h1:EuWWNPxTCdAUx2/NbQcSa3WdNxjzpy4Phv57b4MWpJM= | ||
github.com/gosnmp/gosnmp v1.35.0/go.mod h1:2AvKZ3n9aEl5TJEo/fFmf/FGO4Nj4cVeEc5yuk88CYc= | ||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | ||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/sleepinggenius2/gosmi v0.4.4 h1:xgu+Mt7CptuB10IPt3SVXBAA9tARToT4B9xGzjjxQX8= | ||
github.com/sleepinggenius2/gosmi v0.4.4/go.mod h1:l8OniPmd3bJzw0MXP2/qh7AhP/e+bTY2CNivIhsnDT0= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | ||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= | ||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/sleepinggenius2/gosmi" | ||
"github.com/sleepinggenius2/gosmi/types" | ||
) | ||
|
||
type SMI struct { | ||
Modules []string | ||
Paths []string | ||
} | ||
|
||
func (s *SMI) Init() error { | ||
gosmi.Init() | ||
|
||
for _, path := range s.Paths { | ||
gosmi.AppendPath(path) | ||
} | ||
for i, module := range s.Modules { | ||
moduleName, err := gosmi.LoadModule(module) | ||
if err != nil { | ||
return err | ||
} | ||
s.Modules[i] = moduleName | ||
} | ||
return nil | ||
} | ||
|
||
func (s *SMI) Close() { | ||
gosmi.Exit() | ||
} | ||
|
||
type Node struct { | ||
Readable string | ||
Node gosmi.SmiNode | ||
} | ||
|
||
func (s *SMI) FromOID(oid string) (*Node, error) { | ||
var node gosmi.SmiNode | ||
var err error | ||
if (oid[0] >= '0' && oid[0] <= '9') || oid[0] == '.' { | ||
node, err = gosmi.GetNodeByOID(types.OidMustFromString(oid)) | ||
} else { | ||
node, err = gosmi.GetNode(oid) | ||
} | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
subtree := node.GetSubtree() | ||
|
||
if len(subtree) != 1 { | ||
return nil, fmt.Errorf("mismatch oid : %q, len : %d", oid, len(subtree)) | ||
} | ||
|
||
if !subtree[0].Oid.ParentOf(types.OidMustFromString(oid)) { | ||
return nil, fmt.Errorf("mismatch oid. : %q", oid) | ||
} | ||
|
||
// readable | ||
readable := strings.Replace( | ||
types.OidMustFromString(oid).String(), | ||
subtree[0].RenderNumeric(), | ||
subtree[0].RenderQualified(), | ||
1, | ||
) | ||
|
||
return &Node{Readable: readable, Node: subtree[0]}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
|
||
g "github.com/gosnmp/gosnmp" | ||
) | ||
|
||
func main() { | ||
g.Default.Target = "127.0.0.1" | ||
g.Default.Port = 9162 | ||
g.Default.Version = g.Version2c | ||
g.Default.Community = "public" | ||
// g.Default.Logger = g.NewLogger(log.New(os.Stdout, "", 0)) | ||
err := g.Default.Connect() | ||
if err != nil { | ||
log.Fatalf("Connect() err: %v", err) | ||
} | ||
defer g.Default.Conn.Close() | ||
|
||
trap := g.SnmpTrap{ | ||
Variables: []g.SnmpPDU{ | ||
{Value: ".1.3.6.1.6.3.1.1.5.3", Name: ".1.3.6.1.6.3.1.1.4.1.0", Type: g.ObjectIdentifier}, | ||
{Value: 9, Name: ".1.3.6.1.2.1.2.2.1.1.9", Type: g.Integer}, | ||
{Value: []byte("dum0"), Name: ".1.3.6.1.2.1.2.2.1.2.9", Type: g.OctetString}, | ||
{Value: 6, Name: ".1.3.6.1.2.1.2.2.1.3.9", Type: g.Integer}, | ||
{Value: 2, Name: ".1.3.6.1.2.1.2.2.1.7.9", Type: g.Integer}, | ||
{Value: 2, Name: ".1.3.6.1.2.1.2.2.1.8.9", Type: g.Integer}, | ||
{Value: ".1.3.6.1.4.1.8072.3.2.10", Name: ".1.3.6.1.6.3.1.1.4.3.0", Type: g.ObjectIdentifier}, | ||
}, | ||
} | ||
/* | ||
trap := g.SnmpTrap{ | ||
Variables: []g.SnmpPDU{ | ||
// {Name: ".1.3.6.1.6.3.1.1.4.1.0", Type: g.ObjectIdentifier, Value: ".1.3.6.1.6.3.1.1.5.1"}, | ||
{Name: ".1.3.6.1.6.3.1.1.4.1.0", Type: g.ObjectIdentifier, Value: ".1.3.6.1.6.3.1.1.5.2"}, | ||
}, | ||
} | ||
*/ | ||
|
||
/* | ||
trap := g.SnmpTrap{ | ||
Variables: []g.SnmpPDU{ | ||
{Value: ".1.3.6.1.4.1.9.9.43.2.0.1", Name: ".1.3.6.1.6.3.1.1.4.1.0", Type: g.ObjectIdentifier}, | ||
{Value: 1, Name: ".1.3.6.1.4.1.9.9.43.1.1.6.1.3.10", Type: g.Integer}, | ||
{Value: 2, Name: ".1.3.6.1.4.1.9.9.43.1.1.6.1.4.10", Type: g.Integer}, | ||
{Value: 3, Name: ".1.3.6.1.4.1.9.9.43.1.1.6.1.5.10", Type: g.Integer}, | ||
}, | ||
} | ||
*/ | ||
|
||
/* | ||
trap := g.SnmpTrap{ | ||
Variables: []g.SnmpPDU{ | ||
{Value: ".1.3.6.1.4.1.9.9.41.2.0.1", Name: ".1.3.6.1.6.3.1.1.4.1.0", Type: g.ObjectIdentifier}, | ||
{Value: []byte("DOT11"), Name: ".1.3.6.1.4.1.9.9.41.1.2.3.1.2.1414", Type: g.OctetString}, | ||
{Value: 5, Name: ".1.3.6.1.4.1.9.9.41.1.2.3.1.3.1414", Type: g.Integer}, | ||
{Value: []byte("MAXRETRIES"), Name: ".1.3.6.1.4.1.9.9.41.1.2.3.1.4.1414", Type: g.OctetString}, | ||
{Value: []byte("Packet to client e28c.c759.c887 reached max retries, removing the client"), Name: ".1.3.6.1.4.1.9.9.41.1.2.3.1.5.1414", Type: g.OctetString}, | ||
{Value: uint32(79758314), Name: ".1.3.6.1.4.1.9.9.41.1.2.3.1.6.1414", Type: g.TimeTicks}, | ||
}, | ||
} | ||
*/ | ||
|
||
_, err = g.Default.SendTrap(trap) | ||
if err != nil { | ||
log.Fatalf("SendTrap() err: %v", err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"net" | ||
"os" | ||
"strings" | ||
"text/template" | ||
|
||
g "github.com/gosnmp/gosnmp" | ||
"github.com/sleepinggenius2/gosmi/types" | ||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
const SnmpTrapOIDPrefix = ".1.3.6.1.6.3.1.1.4.1" | ||
|
||
var mibParser SMI | ||
var c Config | ||
|
||
func main() { | ||
defer func() { | ||
mibParser.Close() | ||
}() | ||
|
||
// TODO args. | ||
f, err := os.ReadFile("config.yaml") | ||
|
||
err = yaml.Unmarshal(f, &c) | ||
if err != nil { | ||
log.Fatalf("error: %v", err) | ||
} | ||
|
||
mibParser.Modules = c.MIB.LoadModules | ||
mibParser.Paths = c.MIB.Directory | ||
mibParser.Init() | ||
|
||
// template tests. | ||
funcmap := template.FuncMap{ | ||
"read": func(key string) string { | ||
return "dummy" | ||
}, | ||
"addr": func() string { | ||
return "dummy" | ||
}, | ||
} | ||
|
||
var tmpl = template.New("").Funcs(funcmap) | ||
|
||
for i := range c.Trap { | ||
if _, err := tmpl.Parse(c.Trap[i].Format); err != nil { | ||
log.Fatalln(err) | ||
} | ||
} | ||
|
||
trapListner := g.NewTrapListener() | ||
trapListner.OnNewTrap = trapHandler | ||
trapListner.Params = g.Default | ||
if c.Debug { | ||
trapListner.Params.Logger = g.NewLogger(log.New(os.Stdout, "<GOSNMP DEBUG LOGGER>", 0)) | ||
} | ||
|
||
err = trapListner.Listen(net.JoinHostPort(c.TrapServer.Address, c.TrapServer.Port)) | ||
if err != nil { | ||
log.Fatalf("error in listen: %s", err) | ||
} | ||
} | ||
|
||
func trapHandler(packet *g.SnmpPacket, addr *net.UDPAddr) { | ||
// log.Printf("got trapdata from %s\n", addr.IP) | ||
|
||
var pad = make(map[string]string) | ||
var specificTrapFormat string | ||
|
||
for _, v := range packet.Variables { | ||
if strings.HasPrefix(v.Name, SnmpTrapOIDPrefix) { | ||
for i := range c.Trap { | ||
if strings.HasPrefix(v.Value.(string), c.Trap[i].Ident) { | ||
specificTrapFormat = c.Trap[i].Format | ||
} | ||
} | ||
} | ||
|
||
var padKey, padValue string | ||
padKey = v.Name | ||
node, err := mibParser.FromOID(v.Name) | ||
if err != nil { | ||
fmt.Printf("%+v\n", err) | ||
} else { | ||
if node != nil { | ||
padKey = node.Node.RenderQualified() | ||
} | ||
|
||
if node.Node.Type != nil && node.Node.Type.BaseType == types.BaseTypeEnum { | ||
i, ok := v.Value.(int) | ||
if ok { | ||
padValue = node.Node.Type.Enum.Name(int64(i)) | ||
} | ||
} | ||
} | ||
if padValue == "" { | ||
switch v.Type { | ||
case g.OctetString: | ||
b := v.Value.([]byte) | ||
padValue = string(b) | ||
// fmt.Printf("OID: %s, string: %s\n", v.Name, string(b)) | ||
case g.ObjectIdentifier: | ||
valNode, err := mibParser.FromOID(v.Value.(string)) | ||
if err != nil { | ||
fmt.Printf("%+v\n", err) | ||
padValue = v.Value.(string) | ||
} else { | ||
padValue = valNode.Node.Name | ||
} | ||
// fmt.Printf("OID: %s, value: %s ObjectIdentifier: %s\n", v.Name, v.Value.(string), valNode.Node.Name) | ||
default: | ||
// fmt.Printf("trap: %+v\n", v) | ||
padValue = fmt.Sprintf("%v", v.Value) | ||
} | ||
} | ||
|
||
if padKey != "" && padValue != "" { | ||
pad[padKey] = padValue | ||
} | ||
} | ||
|
||
if specificTrapFormat == "" { | ||
if c.Debug { | ||
log.Printf("skip because nothing template : %+v\n", pad) | ||
} | ||
return | ||
} | ||
|
||
funcmap := template.FuncMap{ | ||
"read": func(key string) string { | ||
return fmt.Sprintf("%s", pad[key]) | ||
}, | ||
"addr": func() string { | ||
return addr.IP.String() | ||
}, | ||
} | ||
|
||
// fmt.Printf("%+v\n", pad) | ||
|
||
var tpl = template.New("").Funcs(funcmap) | ||
|
||
if err := template.Must(tpl.Parse(specificTrapFormat)).Execute(os.Stdout, pad); err != nil { | ||
log.Println(err) | ||
} | ||
} |