|
package suricata |
|
|
|
// suricata.go |
|
|
|
/* |
|
tested with: |
|
|
|
vagrant@foo:~$ uname -a |
|
Linux foo 3.13.0-65-generic #105-Ubuntu SMP Mon Sep 21 18:50:58 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux |
|
|
|
vagrant@foo:~$ suricata -V |
|
This is Suricata version 1.4.7 RELEASE |
|
|
|
vagrant@foo:~$ suricata -V |
|
This is Suricata version 2.1beta4 RELEASE |
|
|
|
vagrant@foo:~$ /opt/telegraf/telegraf -version |
|
Telegraf - Version v0.1.9-48-g81539c4 |
|
|
|
*/ |
|
|
|
|
|
import ( |
|
|
|
"time" |
|
"net" |
|
"io" |
|
"encoding/json" |
|
"errors" |
|
"github.com/influxdb/telegraf/plugins" |
|
) |
|
|
|
type Suricata struct { |
|
SocketName string `toml:"socket"` |
|
SendZeros bool `toml:"zeros"` |
|
} |
|
|
|
func (s *Suricata) Description() string { |
|
return "a suricata plugin" |
|
} |
|
|
|
func (s *Suricata) SampleConfig() string { |
|
return ` |
|
# suricata unix socket name |
|
socket = "/var/run/suricata/suricata-command.socket" |
|
#send measurments if value is zero |
|
zeros = true |
|
` |
|
} |
|
|
|
func (s *Suricata) Gather(acc plugins.Accumulator) error { |
|
r,e := getCountersFromSocket(s.SocketName) |
|
if e != nil { |
|
return e |
|
} |
|
for k,i := range r { |
|
v := i.(map[string]interface{}) |
|
for kk,vv := range v { |
|
if vv == 0.0 && s.SendZeros != true { |
|
continue |
|
} |
|
//convert floats to ints |
|
i := int(vv.(float64)) |
|
f := float64(i) |
|
if (vv == f) {vv = i} |
|
// add thread name as tag |
|
if k != "Detect" && k != "FlowManagerThread" { |
|
tags := map[string]string{"thread": k} |
|
acc.Add(kk, vv, tags) |
|
} else { |
|
acc.Add(kk, vv, nil) |
|
} |
|
} |
|
} |
|
return nil |
|
} |
|
|
|
type Response struct { |
|
ReturnCode string `json:"return"` |
|
Message map[string]interface{} `json:"message"` |
|
} |
|
|
|
func getCountersFromSocket(socketName string) (counts map[string]interface{}, err error) { |
|
conn, err := net.Dial("unix", socketName) |
|
if err != nil { |
|
return nil, err |
|
} |
|
defer conn.Close() |
|
|
|
// see https://github.com/inliniac/suricata/blob/94571c5dd28858ff68c44b648fd41c5d87c0e28d/src/unix-manager.c#L288 |
|
_, err = conn.Write([]byte("{\"version\": \"0.1\"}")) |
|
if err != nil { |
|
return nil, errors.New("can not send version :: "+err.Error()) |
|
} |
|
time.Sleep(100 * time.Millisecond) |
|
var buf [128]byte |
|
_, err = conn.Read(buf[0:]) |
|
if err != nil { |
|
// see https://github.com/inliniac/suricata/blob/94571c5dd28858ff68c44b648fd41c5d87c0e28d/src/unix-manager.c#L319 |
|
return nil, errors.New("got kick on version :: "+err.Error()) |
|
} |
|
_, err = conn.Write([]byte("{\"command\": \"dump-counters\"}")) |
|
if err != nil { |
|
return nil, errors.New("can not send command :: "+err.Error()) |
|
} |
|
time.Sleep(100 * time.Millisecond) |
|
data := "" |
|
// read anser for command |
|
// see https://github.com/inliniac/suricata/blob/672049632431bb695f56798c9c5f196afcf2fb27/scripts/suricatasc/src/suricatasc.py#L83 |
|
for i := 0; i < 16; i++ { |
|
var buf2 [4096]byte |
|
result2, err := conn.Read(buf2[0:]) |
|
if err != nil { |
|
if err != io.EOF { |
|
return nil, err |
|
} |
|
} |
|
data = data + string(buf2[:result2]) |
|
var isJson Response |
|
jerr := json.Unmarshal([]byte(data), &isJson) |
|
if jerr == nil { |
|
if isJson.ReturnCode == "OK" { |
|
return isJson.Message, nil |
|
} else { |
|
return nil, errors.New(isJson.ReturnCode) |
|
} |
|
|
|
} else { |
|
expect := "unexpected end of JSON input" |
|
if jerr.Error() != expect { |
|
// is json but not our counters |
|
return nil, jerr |
|
} |
|
} |
|
time.Sleep(10 * time.Millisecond) |
|
} |
|
return nil, errors.New("max limit for loop") |
|
} |
|
|
|
func init() { |
|
plugins.Add("suricata", func() plugins.Plugin { return &Suricata{} }) |
|
} |