forked from influxdata/telegraf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ipset.go
127 lines (111 loc) · 3.03 KB
/
ipset.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package ipset
import (
"bufio"
"bytes"
"fmt"
"os/exec"
"strconv"
"strings"
"time"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/inputs"
)
// Ipsets is a telegraf plugin to gather packets and bytes counters from ipset
type Ipset struct {
IncludeUnmatchedSets bool
UseSudo bool
Timeout config.Duration
lister setLister
}
type setLister func(Timeout config.Duration, UseSudo bool) (*bytes.Buffer, error)
const measurement = "ipset"
var defaultTimeout = config.Duration(time.Second)
// Description returns a short description of the plugin
func (i *Ipset) Description() string {
return "Gather packets and bytes counters from Linux ipsets"
}
// SampleConfig returns sample configuration options.
func (i *Ipset) SampleConfig() string {
return `
## By default, we only show sets which have already matched at least 1 packet.
## set include_unmatched_sets = true to gather them all.
include_unmatched_sets = false
## Adjust your sudo settings appropriately if using this option ("sudo ipset save")
use_sudo = false
## The default timeout of 1s for ipset execution can be overridden here:
# timeout = "1s"
`
}
func (i *Ipset) Gather(acc telegraf.Accumulator) error {
out, e := i.lister(i.Timeout, i.UseSudo)
if e != nil {
acc.AddError(e)
}
scanner := bufio.NewScanner(out)
for scanner.Scan() {
line := scanner.Text()
// Ignore sets created without the "counters" option
nocomment := strings.Split(line, "\"")[0]
if !(strings.Contains(nocomment, "packets") &&
strings.Contains(nocomment, "bytes")) {
continue
}
data := strings.Fields(line)
if len(data) < 7 {
acc.AddError(fmt.Errorf("error parsing line (expected at least 7 fields): %s", line))
continue
}
if data[0] == "add" && (data[4] != "0" || i.IncludeUnmatchedSets) {
tags := map[string]string{
"set": data[1],
"rule": data[2],
}
packetsTotal, err := strconv.ParseUint(data[4], 10, 64)
if err != nil {
acc.AddError(err)
}
bytesTotal, err := strconv.ParseUint(data[6], 10, 64)
if err != nil {
acc.AddError(err)
}
fields := map[string]interface{}{
"packets_total": packetsTotal,
"bytes_total": bytesTotal,
}
acc.AddCounter(measurement, fields, tags)
}
}
return nil
}
func setList(timeout config.Duration, useSudo bool) (*bytes.Buffer, error) {
// Is ipset installed ?
ipsetPath, err := exec.LookPath("ipset")
if err != nil {
return nil, err
}
var args []string
cmdName := ipsetPath
if useSudo {
cmdName = "sudo"
args = append(args, ipsetPath)
}
args = append(args, "save")
cmd := exec.Command(cmdName, args...)
var out bytes.Buffer
cmd.Stdout = &out
err = internal.RunTimeout(cmd, time.Duration(timeout))
if err != nil {
return &out, fmt.Errorf("error running ipset save: %s", err)
}
return &out, nil
}
func init() {
inputs.Add("ipset", func() telegraf.Input {
return &Ipset{
lister: setList,
Timeout: defaultTimeout,
}
})
}