github.com/netdata/go.d.plugin@v0.58.1/modules/wireguard/collect.go (about)

     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 (w *WireGuard) collect() (map[string]int64, error) {
    13  	if w.client == nil {
    14  		client, err := w.newWGClient()
    15  		if err != nil {
    16  			return nil, fmt.Errorf("creating WireGuard client: %v", err)
    17  		}
    18  		w.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 := w.client.Devices()
    24  	if err != nil {
    25  		return nil, fmt.Errorf("retrieving WireGuard devices: %v", err)
    26  	}
    27  
    28  	if len(devices) == 0 {
    29  		w.Info("no WireGuard devices found on the host system")
    30  	}
    31  
    32  	now := time.Now()
    33  	if w.cleanupLastTime.IsZero() {
    34  		w.cleanupLastTime = now
    35  	}
    36  
    37  	mx := make(map[string]int64)
    38  
    39  	w.collectDevicesPeers(mx, devices, now)
    40  
    41  	if now.Sub(w.cleanupLastTime) > w.cleanupEvery {
    42  		w.cleanupLastTime = now
    43  		w.cleanupDevicesPeers(devices)
    44  	}
    45  
    46  	return mx, nil
    47  }
    48  
    49  func (w *WireGuard) collectDevicesPeers(mx map[string]int64, devices []*wgtypes.Device, now time.Time) {
    50  	for _, d := range devices {
    51  		if !w.devices[d.Name] {
    52  			w.devices[d.Name] = true
    53  			w.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 !w.peers[id] {
    72  				w.peers[id] = true
    73  				w.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 (w *WireGuard) 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 w.devices {
    94  		if !seenDevices[d] {
    95  			delete(w.devices, d)
    96  			w.removeDeviceCharts(d)
    97  		}
    98  	}
    99  	for p := range w.peers {
   100  		if !seenPeers[p] {
   101  			delete(w.peers, p)
   102  			w.removePeerCharts(p)
   103  		}
   104  	}
   105  }
   106  
   107  func peerID(device, peerPublicKey string) string {
   108  	return device + "_" + peerPublicKey
   109  }