From 4390ab8cb9f18d954d2813fe27803f383ec6acb5 Mon Sep 17 00:00:00 2001 From: kbacke Date: Thu, 14 Mar 2019 12:41:40 -0400 Subject: [PATCH] Add the capability to send traps via TCP. Update trapdebug. --- README.md | 2 +- snmptrapper/send_trap.go | 14 ++++- trapdebug/trapdebug.go | 128 +++++++++++++++++++++++++++++++++------ 3 files changed, 123 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index ec4ba6c..229d63d 100644 --- a/README.md +++ b/README.md @@ -45,5 +45,5 @@ Command-line flags ------------------ - **-snmpcommunity**: The SNMP community string (_default_ = `public`) - **-snmpretries**: The number of times to retry sending traps (_default_ = `1`) -- **-snmptrapaddress**: The address to send traps to (_default_ = `127.0.0.1:162`) +- **-snmptrapaddress**: The address to send traps to (_default_ = `127.0.0.1:162`)IP address to send traps to in the form w.x.y.x:port. Default is UDP. For TCP traps, use the form tcp:w.x.y.x:port. Valid types are udp,udp4,udp6,tcp,tcp4,tcp6 - **-webhookaddress**: The address to listen for incoming webhooks on (_default_ = `0.0.0.0:9099`) diff --git a/snmptrapper/send_trap.go b/snmptrapper/send_trap.go index fc5809c..9025e7e 100644 --- a/snmptrapper/send_trap.go +++ b/snmptrapper/send_trap.go @@ -12,12 +12,24 @@ import ( func sendTrap(alert types.Alert) { // Prepare an SNMP handler: + + var network = "udp" + var trapaddress = myConfig.SNMPTrapAddress + if strings.Count(trapaddress, ":") > 1 { + var sl1 []string = strings.SplitAfterN(trapaddress, ":", 2) + network = strings.TrimSuffix(strings.ToLower(sl1[0]), ":") + trapaddress = sl1[1] + } + snmp, err := snmpgo.NewSNMP(snmpgo.SNMPArguments{ + Version: snmpgo.V2c, - Address: myConfig.SNMPTrapAddress, + Address: trapaddress, + Network: network, Retries: myConfig.SNMPRetries, Community: myConfig.SNMPCommunity, }) + if err != nil { log.WithFields(logrus.Fields{"error": err}).Error("Failed to create snmpgo.SNMP object") return diff --git a/trapdebug/trapdebug.go b/trapdebug/trapdebug.go index bce478b..8775233 100644 --- a/trapdebug/trapdebug.go +++ b/trapdebug/trapdebug.go @@ -3,6 +3,9 @@ package main import ( "flag" "net" + "strconv" + "strings" + "os" logrus "github.com/Sirupsen/logrus" gosnmptrap "github.com/ebookbug/gosnmptrap" @@ -10,6 +13,8 @@ import ( var ( listenPort = flag.Int("listenport", 162, "Port to listen for traps on") + listenType = flag.String("listentype", "udp", "Network udp|udp4|udp6|tcp|tcp4|tcp6") + log = logrus.WithFields(logrus.Fields{"logger": "trapdebug-listener"}) ) func init() { @@ -23,36 +28,93 @@ func init() { func main() { - logrus.WithFields(logrus.Fields{"port": *listenPort}).Info("Starting SNMP TrapDebugger") + *listenType = strings.ToLower(*listenType) - // Open a UDP socket: - socket, err := net.ListenUDP("udp4", &net.UDPAddr{ - IP: net.IPv4(0, 0, 0, 0), - Port: *listenPort, - }) - if err != nil { - logrus.WithFields(logrus.Fields{"error": err}).Fatal("Error opening socket") + // UDP + if (*listenType == "udp" || *listenType == "udp4" || *listenType == "udp6") { + + // Open a UDP listener: + log.WithFields(logrus.Fields{"Protocol": *listenType, "Port": *listenPort}).Info("Open a UDP listener") + + udpAddr, err := net.ResolveUDPAddr(*listenType, ":"+strconv.Itoa(*listenPort)) + if err != nil { + logrus.WithFields(logrus.Fields{"error": err}).Fatal("Error creating UDPAddr") + } + + listen, err := net.ListenUDP(*listenType, udpAddr) + if err != nil { + logrus.WithFields(logrus.Fields{"error": err}).Fatal("Error opening UDP listener") + } + + defer listen.Close() + log.WithFields(logrus.Fields{"network": *listenType, "port": *listenPort}).Info("UDP listener started") + + // Loop forever: + for { + // Make a buffer to read into: + buf := make([]byte, 2048) + + // Read from the listener + read, from, _ := listen.ReadFromUDP(buf) + + // Report that we have data: + logrus.WithFields(logrus.Fields{"client": from.IP}).Debug("Data received") + + // Handle the data: + go HandleSNMPdata(buf[:read]) + } } - defer socket.Close() - // Loop forever: - for { - // Make a buffer to read into: - buf := make([]byte, 2048) + // TCP + if (*listenType == "tcp" || *listenType == "tcp4" || *listenType == "tcp6") { + + // Open a TCP listener: + log.WithFields(logrus.Fields{"Protocol": *listenType, "Port": *listenPort}).Info("Open a TCP listener") - // Read from the socket: - read, from, _ := socket.ReadFromUDP(buf) + tcpAddr, err := net.ResolveTCPAddr(*listenType, ":"+strconv.Itoa(*listenPort)) + if err != nil { + logrus.WithFields(logrus.Fields{"error": err}).Fatal("Error creating TCPAddr") + } + listen, err := net.ListenTCP(*listenType, tcpAddr) + if err != nil { + logrus.WithFields(logrus.Fields{"error": err}).Error("Open TCP listener failed") + return + } + + defer listen.Close() + log.WithFields(logrus.Fields{"network": *listenType, "port": *listenPort}).Info("TCP listener started") + + // loop forever + for { + conn, err := listen.Accept() + if err != nil { + logrus.WithFields(logrus.Fields{"error": err}).Error("TCP listener failed") + continue + } // Report that we have data: - logrus.WithFields(logrus.Fields{"client": from.IP}).Debug("Data received") + logrus.WithFields(logrus.Fields{"port": *listenPort}).Debug("Data received") - // Handle the data: - go HandleUdp(buf[:read]) + go HandleTCPdata(conn) + } } } +// handle TCP data +func HandleTCPdata(conn net.Conn) { + + defer conn.Close() + + buf := make([]byte, 2048) + n, err := conn.Read(buf) + if err != nil { + log.WithFields(logrus.Fields{"Error": err}).Error("error reading from TCP connection") + } + go HandleSNMPdata(buf[:n]) +} + // Handle SNMP data: -func HandleUdp(data []byte) { +func HandleSNMPdata(data []byte) { // Attempt to parse the SNMP data: trap, err := gosnmptrap.ParseUdp(data) @@ -69,4 +131,32 @@ func HandleUdp(data []byte) { for trapOID, trapValue := range trap.Values { logrus.WithFields(logrus.Fields{"OID": trapOID, "value": trapValue}).Info("Trap variable") } + go writeToFile(string(data[:len(data)])) +} + +// write notification to file +func writeToFile(data string) { + + filename := "/tmp/snmptrap.txt" + log.WithFields(logrus.Fields{"File": filename}).Info("creating file") + + f, err := os.Create(filename) + if err != nil { + log.WithFields(logrus.Fields{"Error": err}).Error("error creating file") + return + } + + l, err := f.WriteString(strconv.Quote(data)) + if err != nil { + log.WithFields(logrus.Fields{"Error": err}).Error("error writing data") + f.Close() + return + } + + log.WithFields(logrus.Fields{"Length": l}).Info("bytes written successfully") + err = f.Close() + if err != nil { + log.WithFields(logrus.Fields{"Error": err}).Error("error closing file") + return + } }