master
go 109 lines 2.57 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package wireguard
4
5 import (
6 "fmt"
7 "time"
8
9 "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
10 )
11
12 func (c *Collector) collect() (map[string]int64, error) {
13 if c.client == nil {
14 client, err := c.newWGClient()
15 if err != nil {
16 return nil, fmt.Errorf("creating WireGuard client: %v", err)
17 }
18 c.client = client
19 }
20
21 // TODO: probably we need to get a list of interfaces and query interfaces using client.Device()
22 // https://github.com/WireGuard/wgctrl-go/blob/3d4a969bb56bb6931f6661af606bc9c4195b4249/internal/wglinux/client_linux.go#L79-L80
23 devices, err := c.client.Devices()
24 if err != nil {
25 return nil, fmt.Errorf("retrieving WireGuard devices: %v", err)
26 }
27
28 if len(devices) == 0 {
29 c.Info("no WireGuard devices found on the host system")
30 }
31
32 now := time.Now()
33 if c.cleanupLastTime.IsZero() {
34 c.cleanupLastTime = now
35 }
36
37 mx := make(map[string]int64)
38
39 c.collectDevicesPeers(mx, devices, now)
40
41 if now.Sub(c.cleanupLastTime) > c.cleanupEvery {
42 c.cleanupLastTime = now
43 c.cleanupDevicesPeers(devices)
44 }
45
46 return mx, nil
47 }
48
49 func (c *Collector) collectDevicesPeers(mx map[string]int64, devices []*wgtypes.Device, now time.Time) {
50 for _, d := range devices {
51 if !c.devices[d.Name] {
52 c.devices[d.Name] = true
53 c.addNewDeviceCharts(d.Name)
54 }
55
56 mx["device_"+d.Name+"_peers"] = int64(len(d.Peers))
57 if len(d.Peers) == 0 {
58 mx["device_"+d.Name+"_receive"] = 0
59 mx["device_"+d.Name+"_transmit"] = 0
60 continue
61 }
62
63 for _, p := range d.Peers {
64 if p.LastHandshakeTime.IsZero() {
65 continue
66 }
67
68 pubKey := p.PublicKey.String()
69 id := peerID(d.Name, pubKey)
70
71 if !c.peers[id] {
72 c.peers[id] = true
73 c.addNewPeerCharts(id, d.Name, pubKey)
74 }
75
76 mx["device_"+d.Name+"_receive"] += p.ReceiveBytes
77 mx["device_"+d.Name+"_transmit"] += p.TransmitBytes
78 mx["peer_"+id+"_receive"] = p.ReceiveBytes
79 mx["peer_"+id+"_transmit"] = p.TransmitBytes
80 mx["peer_"+id+"_latest_handshake_ago"] = int64(now.Sub(p.LastHandshakeTime).Seconds())
81 }
82 }
83 }
84
85 func (c *Collector) cleanupDevicesPeers(devices []*wgtypes.Device) {
86 seenDevices, seenPeers := make(map[string]bool), make(map[string]bool)
87 for _, d := range devices {
88 seenDevices[d.Name] = true
89 for _, p := range d.Peers {
90 seenPeers[peerID(d.Name, p.PublicKey.String())] = true
91 }
92 }
93 for d := range c.devices {
94 if !seenDevices[d] {
95 delete(c.devices, d)
96 c.removeDeviceCharts(d)
97 }
98 }
99 for p := range c.peers {
100 if !seenPeers[p] {
101 delete(c.peers, p)
102 c.removePeerCharts(p)
103 }
104 }
105 }
106
107 func peerID(device, peerPublicKey string) string {
108 return device + "_" + peerPublicKey
109 }