telegraf/plugins/inputs/wireguard/wireguard.go

140 lines
3.3 KiB
Go

package wireguard
import (
"fmt"
"log"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/inputs"
"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
const (
measurementDevice = "wireguard_device"
measurementPeer = "wireguard_peer"
)
var (
deviceTypeNames = map[wgtypes.DeviceType]string{
wgtypes.Unknown: "unknown",
wgtypes.LinuxKernel: "linux_kernel",
wgtypes.Userspace: "userspace",
}
)
// Wireguard is an input that enumerates all Wireguard interfaces/devices on
// the host, and reports gauge metrics for the device itself and its peers.
type Wireguard struct {
Devices []string `toml:"devices"`
client *wgctrl.Client
}
func (wg *Wireguard) Description() string {
return "Collect Wireguard server interface and peer statistics"
}
func (wg *Wireguard) SampleConfig() string {
return `
## Optional list of Wireguard device/interface names to query.
## If omitted, all Wireguard interfaces are queried.
# devices = ["wg0"]
`
}
func (wg *Wireguard) Init() error {
var err error
wg.client, err = wgctrl.New()
return err
}
func (wg *Wireguard) Gather(acc telegraf.Accumulator) error {
devices, err := wg.enumerateDevices()
if err != nil {
return fmt.Errorf("error enumerating Wireguard devices: %v", err)
}
for _, device := range devices {
wg.gatherDeviceMetrics(acc, device)
for _, peer := range device.Peers {
wg.gatherDevicePeerMetrics(acc, device, peer)
}
}
return nil
}
func (wg *Wireguard) enumerateDevices() ([]*wgtypes.Device, error) {
var devices []*wgtypes.Device
// If no device names are specified, defer to the library to enumerate
// all of them
if len(wg.Devices) == 0 {
return wg.client.Devices()
}
// Otherwise, explicitly populate only device names specified in config
for _, name := range wg.Devices {
dev, err := wg.client.Device(name)
if err != nil {
log.Printf("W! [inputs.wireguard] No Wireguard device found with name %s", name)
continue
}
devices = append(devices, dev)
}
return devices, nil
}
func (wg *Wireguard) gatherDeviceMetrics(acc telegraf.Accumulator, device *wgtypes.Device) {
fields := map[string]interface{}{
"listen_port": device.ListenPort,
"firewall_mark": device.FirewallMark,
}
gauges := map[string]interface{}{
"peers": len(device.Peers),
}
tags := map[string]string{
"name": device.Name,
"type": deviceTypeNames[device.Type],
}
acc.AddFields(measurementDevice, fields, tags)
acc.AddGauge(measurementDevice, gauges, tags)
}
func (wg *Wireguard) gatherDevicePeerMetrics(acc telegraf.Accumulator, device *wgtypes.Device, peer wgtypes.Peer) {
fields := map[string]interface{}{
"persistent_keepalive_interval_ns": peer.PersistentKeepaliveInterval.Nanoseconds(),
"protocol_version": peer.ProtocolVersion,
"allowed_ips": len(peer.AllowedIPs),
}
gauges := map[string]interface{}{
"last_handshake_time_ns": peer.LastHandshakeTime.UnixNano(),
"rx_bytes": peer.ReceiveBytes,
"tx_bytes": peer.TransmitBytes,
}
tags := map[string]string{
"device": device.Name,
"public_key": peer.PublicKey.String(),
}
acc.AddFields(measurementPeer, fields, tags)
acc.AddGauge(measurementPeer, gauges, tags)
}
func init() {
inputs.Add("wireguard", func() telegraf.Input {
return &Wireguard{}
})
}