132 lines
2.6 KiB
Go
132 lines
2.6 KiB
Go
package fail2ban
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"strconv"
|
|
|
|
"github.com/influxdata/telegraf"
|
|
"github.com/influxdata/telegraf/plugins/inputs"
|
|
)
|
|
|
|
var (
|
|
execCommand = exec.Command // execCommand is used to mock commands in tests.
|
|
)
|
|
|
|
type Fail2ban struct {
|
|
path string
|
|
UseSudo bool
|
|
}
|
|
|
|
var sampleConfig = `
|
|
## Use sudo to run fail2ban-client
|
|
use_sudo = false
|
|
`
|
|
|
|
var metricsTargets = []struct {
|
|
target string
|
|
field string
|
|
}{
|
|
{
|
|
target: "Currently failed:",
|
|
field: "failed",
|
|
},
|
|
{
|
|
target: "Currently banned:",
|
|
field: "banned",
|
|
},
|
|
}
|
|
|
|
func (f *Fail2ban) Description() string {
|
|
return "Read metrics from fail2ban."
|
|
}
|
|
|
|
func (f *Fail2ban) SampleConfig() string {
|
|
return sampleConfig
|
|
}
|
|
|
|
func (f *Fail2ban) Gather(acc telegraf.Accumulator) error {
|
|
if len(f.path) == 0 {
|
|
return errors.New("fail2ban-client not found: verify that fail2ban is installed and that fail2ban-client is in your PATH")
|
|
}
|
|
|
|
name := f.path
|
|
var arg []string
|
|
|
|
if f.UseSudo {
|
|
name = "sudo"
|
|
arg = append(arg, f.path)
|
|
}
|
|
|
|
args := append(arg, "status")
|
|
|
|
cmd := execCommand(name, args...)
|
|
out, err := cmd.Output()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to run command %s: %s - %s", strings.Join(cmd.Args, " "), err, string(out))
|
|
}
|
|
lines := strings.Split(string(out), "\n")
|
|
const targetString = "Jail list:"
|
|
var jails []string
|
|
for _, line := range lines {
|
|
idx := strings.LastIndex(line, targetString)
|
|
if idx < 0 {
|
|
// not target line, skip.
|
|
continue
|
|
}
|
|
jails = strings.Split(strings.TrimSpace(line[idx+len(targetString):]), ", ")
|
|
break
|
|
}
|
|
|
|
for _, jail := range jails {
|
|
fields := make(map[string]interface{})
|
|
args := append(arg, "status", jail)
|
|
cmd := execCommand(name, args...)
|
|
out, err := cmd.Output()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to run command %s: %s - %s", strings.Join(cmd.Args, " "), err, string(out))
|
|
}
|
|
|
|
lines := strings.Split(string(out), "\n")
|
|
for _, line := range lines {
|
|
key, value := extractCount(line)
|
|
if key != "" {
|
|
fields[key] = value
|
|
}
|
|
}
|
|
acc.AddFields("fail2ban", fields, map[string]string{"jail": jail})
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func extractCount(line string) (string, int) {
|
|
for _, metricsTarget := range metricsTargets {
|
|
idx := strings.LastIndex(line, metricsTarget.target)
|
|
if idx < 0 {
|
|
continue
|
|
}
|
|
ban := strings.TrimSpace(line[idx+len(metricsTarget.target):])
|
|
banCount, err := strconv.Atoi(ban)
|
|
if err != nil {
|
|
return "", -1
|
|
}
|
|
return metricsTarget.field, banCount
|
|
}
|
|
return "", -1
|
|
}
|
|
|
|
func init() {
|
|
f := Fail2ban{}
|
|
path, _ := exec.LookPath("fail2ban-client")
|
|
if len(path) > 0 {
|
|
f.path = path
|
|
}
|
|
inputs.Add("fail2ban", func() telegraf.Input {
|
|
f := f
|
|
return &f
|
|
})
|
|
}
|