1
0
Fork 0
telegraf/plugins/inputs/wireguard/wireguard.go

143 lines
3.3 KiB
Go
Raw Normal View History

//go:generate ../../../tools/readme_config_includer/generator
package wireguard
import (
_ "embed"
"fmt"
"strings"
"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/inputs"
)
//go:embed sample.conf
var sampleConfig string
var (
deviceTypeNames = map[wgtypes.DeviceType]string{
wgtypes.Unknown: "unknown",
wgtypes.LinuxKernel: "linux_kernel",
wgtypes.Userspace: "userspace",
}
)
const (
measurementDevice = "wireguard_device"
measurementPeer = "wireguard_peer"
)
type Wireguard struct {
Devices []string `toml:"devices"`
Log telegraf.Logger `toml:"-"`
client *wgctrl.Client
}
func (*Wireguard) SampleConfig() string {
return sampleConfig
}
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: %w", err)
}
for _, device := range devices {
gatherDeviceMetrics(acc, device)
for _, peer := range device.Peers {
gatherDevicePeerMetrics(acc, device, peer)
}
}
return nil
}
func (wg *Wireguard) enumerateDevices() ([]*wgtypes.Device, error) {
// 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
devices := make([]*wgtypes.Device, 0, len(wg.Devices))
for _, name := range wg.Devices {
dev, err := wg.client.Device(name)
if err != nil {
wg.Log.Warnf("No Wireguard device found with name %s", name)
continue
}
devices = append(devices, dev)
}
return devices, nil
}
func 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 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),
}
if len(peer.AllowedIPs) > 0 {
cidrs := make([]string, 0, len(peer.AllowedIPs))
for _, ip := range peer.AllowedIPs {
cidrs = append(cidrs, ip.String())
}
fields["allowed_peer_cidr"] = strings.Join(cidrs, ",")
}
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{}
})
}