140 lines
3.3 KiB
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{}
|
|
})
|
|
}
|