forked from influxdata/telegraf
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
plugins/inputs: New input for Wireguard server (influxdata#6367)
- Loading branch information
Showing
8 changed files
with
338 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# Wireguard Input Plugin | ||
|
||
The Wireguard input plugin collects statistics on the local Wireguard server | ||
using the [`wgctrl`](https://github.com/WireGuard/wgctrl-go) library. It | ||
reports gauge metrics for Wireguard interface device(s) and its peers. | ||
|
||
### Configuration | ||
|
||
```toml | ||
# Collect Wireguard server interface and peer statistics | ||
[[inputs.wireguard]] | ||
## Optional list of Wireguard device/interface names to query. | ||
## If omitted, all Wireguard interfaces are queried. | ||
# devices = ["wg0"] | ||
``` | ||
|
||
### Metrics | ||
|
||
- `wireguard_device` | ||
- tags: | ||
- `name` (interface device name, e.g. `wg0`) | ||
- `type` (Wireguard tunnel type, e.g. `linux_kernel` or `userspace`) | ||
- fields: | ||
- `listen_port` (int, UDP port on which the interface is listening) | ||
- `firewall_mark` (int, device's current firewall mark) | ||
- `peers` (int, number of peers associated with the device) | ||
|
||
- `wireguard_peer` | ||
- tags: | ||
- `device` (associated interface device name, e.g. `wg0`) | ||
- `public_key` (peer public key, e.g. `NZTRIrv/ClTcQoNAnChEot+WL7OH7uEGQmx8oAN9rWE=`) | ||
- fields: | ||
- `persistent_keepalive_interval_ns` (int, keepalive interval in nanoseconds; 0 if unset) | ||
- `protocol_version` (int, Wireguard protocol version number) | ||
- `allowed_ips` (int, number of allowed IPs for this peer) | ||
- `last_handshake_time_ns` (int, Unix timestamp of the last handshake for this peer in nanoseconds) | ||
- `rx_bytes` (int, number of bytes received from this peer) | ||
- `tx_bytes` (int, number of bytes transmitted to this peer) | ||
|
||
### Troubleshooting | ||
|
||
#### Error: `operation not permitted` | ||
|
||
When the kernelspace implementation of Wireguard is in use (as opposed to its | ||
userspace implementations), Telegraf communicates with the module over netlink. | ||
This requires Telegraf to either run as root, or for the Telegraf binary to | ||
have the `CAP_NET_ADMIN` capability. | ||
|
||
To add this capability to the Telegraf binary (to allow this communication under | ||
the default user `telegraf`): | ||
|
||
```bash | ||
$ sudo setcap CAP_NET_ADMIN+epi $(which telegraf) | ||
``` | ||
|
||
N.B.: This capability is a filesystem attribute on the binary itself. The | ||
attribute needs to be re-applied if the Telegraf binary is rotated (e.g. | ||
on installation of new a Telegraf version from the system package manager). | ||
|
||
#### Error: `error enumerating Wireguard devices` | ||
|
||
This usually happens when the device names specified in config are invalid. | ||
Ensure that `sudo wg show` succeeds, and that the device names in config match | ||
those printed by this command. | ||
|
||
### Example Output | ||
|
||
``` | ||
wireguard_device,host=WGVPN,name=wg0,type=linux_kernel firewall_mark=51820i,listen_port=58216i 1582513589000000000 | ||
wireguard_device,host=WGVPN,name=wg0,type=linux_kernel peers=1i 1582513589000000000 | ||
wireguard_peer,device=wg0,host=WGVPN,public_key=NZTRIrv/ClTcQoNAnChEot+WL7OH7uEGQmx8oAN9rWE= allowed_ips=2i,persistent_keepalive_interval_ns=60000000000i,protocol_version=1i 1582513589000000000 | ||
wireguard_peer,device=wg0,host=WGVPN,public_key=NZTRIrv/ClTcQoNAnChEot+WL7OH7uEGQmx8oAN9rWE= last_handshake_time_ns=1582513584530013376i,rx_bytes=6484i,tx_bytes=13540i 1582513589000000000 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
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{} | ||
}) | ||
} |
Oops, something went wrong.