mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Adding wireguard application support (#14625)
This commit is contained in:
@@ -2718,6 +2718,44 @@ chmod +x /etc/snmp/voipmon-stats.sh
|
||||
extend voipmon /etc/snmp/voipmon-stats.sh
|
||||
```
|
||||
|
||||
## Wireguard
|
||||
|
||||
The wireguard application polls the Wireguard service and scrapes all client statistics for all interfaces configured as Wireguard interfaces.
|
||||
|
||||
### SNMP Extend
|
||||
|
||||
1. Copy the python script, wireguard.py, to the desired host
|
||||
```
|
||||
wget https://github.com/librenms/librenms-agent/raw/master/snmp/wireguard.py -O /etc/snmp/wireguard.py
|
||||
```
|
||||
|
||||
2. Make the script executable
|
||||
```
|
||||
chmod +x /etc/snmp/wireguard.py
|
||||
```
|
||||
|
||||
3. Edit your snmpd.conf file and add:
|
||||
```
|
||||
extend wireguard /etc/snmp/wireguard.py
|
||||
```
|
||||
|
||||
4. Create a /etc/snmp/wireguard.json file and specify:
|
||||
a.) (optional) "wg_cmd" - String path to the wg binary ["/usr/bin/wg"]
|
||||
b.) "public_key_to_arbitrary_name" - A dictionary to convert between the publickey assigned to the client (specified in the wireguard interface conf file) to an arbitrary, friendly name. The friendly names MUST be unique within each interface. Also note that the interface name and friendly names are used in the RRD filename, so using special characters is highly discouraged.
|
||||
```
|
||||
{
|
||||
"wg_cmd": "/bin/wg",
|
||||
"public_key_to_arbitrary_name": {
|
||||
"wg0": {
|
||||
"z1iSIymFEFi/PS8rR19AFBle7O4tWowMWuFzHO7oRlE=": "client1",
|
||||
"XqWJRE21Fw1ke47mH1yPg/lyWqCCfjkIXiS6JobuhTI=": "server.domain.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
5. Restart snmpd.
|
||||
|
||||
## ZFS
|
||||
|
||||
### SNMP Extend
|
||||
|
41
includes/html/graphs/application/wireguard_time.inc.php
Normal file
41
includes/html/graphs/application/wireguard_time.inc.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
$name = 'wireguard';
|
||||
$polling_type = 'app';
|
||||
|
||||
if (isset($vars['interface']) && isset($vars['client'])) {
|
||||
$interface = $vars['interface'];
|
||||
$client = $vars['client'];
|
||||
$interface_client = $vars['interface'] . '-' . $vars['client'];
|
||||
} else {
|
||||
$interface_client_list = Rrd::getRrdApplicationArrays($device, $app->app_id, $name);
|
||||
$interface_client = $interface_client_list[0] ?? '';
|
||||
}
|
||||
|
||||
$unit_text = 'Minutes';
|
||||
$colours = 'psychedelic';
|
||||
|
||||
$rrdArray = [
|
||||
'minutes_since_last_handshake' => ['descr' => 'Last Handshake'],
|
||||
];
|
||||
|
||||
$rrd_filename = Rrd::name($device['hostname'], [
|
||||
$polling_type,
|
||||
$name,
|
||||
$app->app_id,
|
||||
$interface_client,
|
||||
]);
|
||||
|
||||
if (Rrd::checkRrdExists($rrd_filename)) {
|
||||
foreach ($rrdArray as $rrdVar => $rrdValues) {
|
||||
$rrd_list[] = [
|
||||
'filename' => $rrd_filename,
|
||||
'descr' => $rrdValues['descr'],
|
||||
'ds' => $rrdVar,
|
||||
];
|
||||
}
|
||||
} else {
|
||||
d_echo('RRD ' . $rrd_filename . ' not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_multi_line_exact_numbers.inc.php';
|
44
includes/html/graphs/application/wireguard_traffic.inc.php
Normal file
44
includes/html/graphs/application/wireguard_traffic.inc.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
$name = 'wireguard';
|
||||
$polling_type = 'app';
|
||||
|
||||
if (isset($vars['interface']) && isset($vars['client'])) {
|
||||
$interface = $vars['interface'];
|
||||
$client = $vars['client'];
|
||||
$interface_client = $vars['interface'] . '-' . $vars['client'];
|
||||
} else {
|
||||
$interface_client_list = Rrd::getRrdApplicationArrays($device, $app->app_id, $name);
|
||||
$interface_client = $interface_client_list[0] ?? '';
|
||||
}
|
||||
|
||||
$unit_text = 'Bytes';
|
||||
|
||||
$ds_in = 'bytes_rcvd';
|
||||
$in_text = 'Rcvd';
|
||||
$ds_out = 'bytes_sent';
|
||||
$out_text = 'Sent';
|
||||
|
||||
$format = 'bytes';
|
||||
$print_total = true;
|
||||
|
||||
$colour_area_in = 'FF3300';
|
||||
$colour_line_in = 'FF0000';
|
||||
$colour_area_out = 'FF6633';
|
||||
$colour_line_out = 'CC3300';
|
||||
|
||||
$colour_area_in_max = 'FF6633';
|
||||
$colour_area_out_max = 'FF9966';
|
||||
|
||||
$rrd_filename = Rrd::name($device['hostname'], [
|
||||
$polling_type,
|
||||
$name,
|
||||
$app->app_id,
|
||||
$interface_client,
|
||||
]);
|
||||
|
||||
if (! Rrd::checkRrdExists($rrd_filename)) {
|
||||
d_echo('RRD ' . $rrd_filename . ' not found');
|
||||
}
|
||||
|
||||
require 'includes/html/graphs/generic_duplex.inc.php';
|
78
includes/html/pages/device/apps/wireguard.inc.php
Normal file
78
includes/html/pages/device/apps/wireguard.inc.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
$link_array = [
|
||||
'page' => 'device',
|
||||
'device' => $device['device_id'],
|
||||
'tab' => 'apps',
|
||||
'app' => 'wireguard',
|
||||
];
|
||||
|
||||
print_optionbar_start();
|
||||
|
||||
echo generate_link('All Interfaces', $link_array);
|
||||
echo ' | Interfaces: ';
|
||||
|
||||
$interface_client_map = $app->data['mappings'] ?? [];
|
||||
|
||||
// generate interface links
|
||||
$i = 0;
|
||||
foreach ($interface_client_map as $interface => $client_list) {
|
||||
$label =
|
||||
$vars['interface'] == $interface
|
||||
? '<span class="pagemenu-selected">' . $interface . '</span>'
|
||||
: $interface;
|
||||
|
||||
echo generate_link($label, $link_array, ['interface' => $interface]);
|
||||
|
||||
if ($i < count(array_keys($interface_client_map)) - 1) {
|
||||
echo ', ';
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
print_optionbar_end();
|
||||
|
||||
// build the interface/client -> graph map
|
||||
foreach ($interface_client_map as $interface => $client_list) {
|
||||
if (
|
||||
! isset($vars['interface']) ||
|
||||
(isset($vars['interface']) && $interface == $vars['interface'])
|
||||
) {
|
||||
foreach ($client_list as $client) {
|
||||
$interface_client_map[$interface][$client] = [
|
||||
'wireguard_traffic' => $interface . ' ' . $client . ' Traffic',
|
||||
'wireguard_time' => $interface .
|
||||
' ' .
|
||||
$client .
|
||||
' Minutes Since Last Handshake',
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generate graphs on a per-interface, per-client basis
|
||||
foreach ($interface_client_map as $interface => $client_list) {
|
||||
foreach ($client_list as $client => $graphs) {
|
||||
foreach ($graphs as $gtype => $gtext) {
|
||||
$graph_type = $gtype;
|
||||
$graph_array['height'] = '100';
|
||||
$graph_array['width'] = '215';
|
||||
$graph_array['to'] = time();
|
||||
$graph_array['id'] = $app['app_id'];
|
||||
$graph_array['type'] = 'application_' . $gtype;
|
||||
$graph_array['interface'] = $interface;
|
||||
$graph_array['client'] = $client;
|
||||
|
||||
echo '<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">' . $gtext . '</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">';
|
||||
include 'includes/html/print-graphrow.inc.php';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
}
|
118
includes/polling/applications/wireguard.inc.php
Normal file
118
includes/polling/applications/wireguard.inc.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
use LibreNMS\Exceptions\JsonAppException;
|
||||
use LibreNMS\Exceptions\JsonAppMissingKeysException;
|
||||
use LibreNMS\RRD\RrdDefinition;
|
||||
|
||||
$name = 'wireguard';
|
||||
$output = 'OK';
|
||||
$polling_type = 'app';
|
||||
|
||||
try {
|
||||
$interface_client_map = json_app_get($device, $name, 1)['data'];
|
||||
} catch (JsonAppMissingKeysException $e) {
|
||||
$interface_client_map = $e->getParsedJson();
|
||||
} catch (JsonAppException $e) {
|
||||
echo PHP_EOL . $name . ':' . $e->getCode() . ':' . $e->getMessage() . PHP_EOL;
|
||||
update_application($app, $e->getCode() . ':' . $e->getMessage(), []);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$rrd_name = [$polling_type, $name, $app->app_id];
|
||||
$rrd_def = RrdDefinition::make()
|
||||
->addDataset('bytes_rcvd', 'DERIVE', 0, 125000000000)
|
||||
->addDataset('bytes_sent', 'DERIVE', 0, 125000000000)
|
||||
->addDataset('minutes_since_last_handshake', 'GAUGE', 0);
|
||||
|
||||
$metrics = [];
|
||||
$mappings = [];
|
||||
|
||||
// Parse json data for interfaces and their respective clients' metrics.
|
||||
foreach ($interface_client_map as $interface => $client_list) {
|
||||
$finterface = is_string($interface) ? filter_var($interface, FILTER_SANITIZE_STRING) : null;
|
||||
|
||||
if (is_null($finterface)) {
|
||||
echo PHP_EOL . $name . ':' . ' Invalid or no interface found.' . PHP_EOL;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$mappings[$finterface] = [];
|
||||
foreach ($client_list as $client => $client_data) {
|
||||
$fclient = is_string($client) ? filter_var($client, FILTER_SANITIZE_STRING) : null;
|
||||
|
||||
if (is_null($fclient)) {
|
||||
echo PHP_EOL . $name . ':' . ' Invalid or no client found.' . PHP_EOL;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
array_push($mappings[$finterface], $fclient);
|
||||
$bytes_rcvd = is_int($client_data['bytes_rcvd'])
|
||||
? $client_data['bytes_rcvd']
|
||||
: null;
|
||||
$bytes_sent = is_int($client_data['bytes_sent'])
|
||||
? $client_data['bytes_sent']
|
||||
: null;
|
||||
$minutes_since_last_handshake = is_int($client_data['minutes_since_last_handshake'])
|
||||
? $client_data['minutes_since_last_handshake']
|
||||
: null;
|
||||
|
||||
$rrd_name = [$polling_type, $name, $app->app_id, $finterface, $fclient];
|
||||
|
||||
$fields = [
|
||||
'bytes_rcvd' => $bytes_rcvd,
|
||||
'bytes_sent' => $bytes_sent,
|
||||
'minutes_since_last_handshake' => $minutes_since_last_handshake,
|
||||
];
|
||||
|
||||
// create flattened metrics
|
||||
$metrics[$finterface . '_' . $fclient] = $fields;
|
||||
$tags = [
|
||||
'name' => $name,
|
||||
'app_id' => $app->app_id,
|
||||
'rrd_def' => $rrd_def,
|
||||
'rrd_name' => $rrd_name,
|
||||
];
|
||||
data_update($device, $polling_type, $tags, $fields);
|
||||
}
|
||||
}
|
||||
|
||||
// variable tracks whether we updated mappings so it only happens once
|
||||
$mappings_updated = false;
|
||||
|
||||
// get old mappings
|
||||
$old_mappings = $app->data['mappings'] ?? [];
|
||||
|
||||
// check for interface changes
|
||||
$added_interfaces = array_diff_key($mappings, $old_mappings);
|
||||
$removed_interfaces = array_diff_key($old_mappings, $mappings);
|
||||
if (count($added_interfaces) > 0 || count($removed_interfaces) > 0) {
|
||||
$app->data = ['mappings' => $mappings];
|
||||
$mappings_updated = true;
|
||||
$log_message = 'Wireguard Interfaces Change:';
|
||||
$log_message .= count($added_interfaces) > 0 ? ' Added ' . implode(',', $added_interfaces) : '';
|
||||
$log_message .= count($removed_interfaces) > 0 ? ' Removed ' . implode(',', $removed_interfaces) : '';
|
||||
log_event($log_message, $device, 'application');
|
||||
}
|
||||
|
||||
// check for client changes
|
||||
foreach ($mappings as $interface => $client_list) {
|
||||
$old_client_list = $old_mappings[$interface] ?? [];
|
||||
|
||||
$added_clients = array_diff($client_list, $old_client_list);
|
||||
$removed_clients = array_diff($old_client_list, $client_list);
|
||||
if (count($added_clients) > 0 || count($removed_clients) > 0) {
|
||||
if (! $mappings_updated) {
|
||||
$app->data = ['mappings' => $mappings];
|
||||
$mappings_updated = true;
|
||||
}
|
||||
$log_message = 'Wireguard Interface ' . $interface . ' Clients Change:';
|
||||
$log_message .= count($added_clients) > 0 ? ' Added ' . implode(',', $added_clients) : '';
|
||||
$log_message .= count($removed_clients) > 0 ? ' Removed ' . implode(',', $removed_clients) : '';
|
||||
log_event($log_message, $device, 'application');
|
||||
}
|
||||
}
|
||||
|
||||
update_application($app, $output, $metrics);
|
143
tests/data/linux_wireguard-v1.json
Normal file
143
tests/data/linux_wireguard-v1.json
Normal file
@@ -0,0 +1,143 @@
|
||||
{
|
||||
"os": {
|
||||
"discovery": {
|
||||
"devices": [
|
||||
{
|
||||
"sysName": "<private>",
|
||||
"sysObjectID": ".1.3.6.1.4.1.8072.3.2.10",
|
||||
"sysDescr": "Linux server 3.10.0-693.5.2.el7.x86_64 #1 SMP Fri Oct 20 20:32:50 UTC 2017 x86_64",
|
||||
"sysContact": "<private>",
|
||||
"version": "3.10.0-693.5.2.el7.x86_64",
|
||||
"hardware": "Generic x86 64-bit",
|
||||
"features": null,
|
||||
"location": "<private>",
|
||||
"os": "linux",
|
||||
"type": "server",
|
||||
"serial": null,
|
||||
"icon": "linux.svg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"poller": "matches discovery"
|
||||
},
|
||||
"applications": {
|
||||
"discovery": {
|
||||
"applications": [
|
||||
{
|
||||
"app_type": "wireguard",
|
||||
"app_state": "UNKNOWN",
|
||||
"discovered": 1,
|
||||
"app_state_prev": null,
|
||||
"app_status": "",
|
||||
"app_instance": "",
|
||||
"data": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"poller": {
|
||||
"applications": [
|
||||
{
|
||||
"app_type": "wireguard",
|
||||
"app_state": "OK",
|
||||
"discovered": 1,
|
||||
"app_state_prev": "UNKNOWN",
|
||||
"app_status": "",
|
||||
"app_instance": "",
|
||||
"data": "{\"mappings\":{\"wg0\":[\"client1.domain.com\",\"client2\",\"my_phone\",\"it_admin.domain.org\",\"computer\"]}}"
|
||||
}
|
||||
],
|
||||
"application_metrics": [
|
||||
{
|
||||
"metric": "wg0_client1.domain.com_bytes_rcvd",
|
||||
"value": 1534068,
|
||||
"value_prev": null,
|
||||
"app_type": "wireguard"
|
||||
},
|
||||
{
|
||||
"metric": "wg0_client1.domain.com_bytes_sent",
|
||||
"value": 97772,
|
||||
"value_prev": null,
|
||||
"app_type": "wireguard"
|
||||
},
|
||||
{
|
||||
"metric": "wg0_client1.domain.com_minutes_since_last_handshake",
|
||||
"value": 1,
|
||||
"value_prev": null,
|
||||
"app_type": "wireguard"
|
||||
},
|
||||
{
|
||||
"metric": "wg0_client2_bytes_rcvd",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "wireguard"
|
||||
},
|
||||
{
|
||||
"metric": "wg0_client2_bytes_sent",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "wireguard"
|
||||
},
|
||||
{
|
||||
"metric": "wg0_client2_minutes_since_last_handshake",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "wireguard"
|
||||
},
|
||||
{
|
||||
"metric": "wg0_computer_bytes_rcvd",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "wireguard"
|
||||
},
|
||||
{
|
||||
"metric": "wg0_computer_bytes_sent",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "wireguard"
|
||||
},
|
||||
{
|
||||
"metric": "wg0_computer_minutes_since_last_handshake",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "wireguard"
|
||||
},
|
||||
{
|
||||
"metric": "wg0_it_admin.domain.org_bytes_rcvd",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "wireguard"
|
||||
},
|
||||
{
|
||||
"metric": "wg0_it_admin.domain.org_bytes_sent",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "wireguard"
|
||||
},
|
||||
{
|
||||
"metric": "wg0_it_admin.domain.org_minutes_since_last_handshake",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "wireguard"
|
||||
},
|
||||
{
|
||||
"metric": "wg0_my_phone_bytes_rcvd",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "wireguard"
|
||||
},
|
||||
{
|
||||
"metric": "wg0_my_phone_bytes_sent",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "wireguard"
|
||||
},
|
||||
{
|
||||
"metric": "wg0_my_phone_minutes_since_last_handshake",
|
||||
"value": 0,
|
||||
"value_prev": null,
|
||||
"app_type": "wireguard"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
10
tests/snmpsim/linux_wireguard-v1.snmprec
Normal file
10
tests/snmpsim/linux_wireguard-v1.snmprec
Normal file
@@ -0,0 +1,10 @@
|
||||
1.3.6.1.2.1.1.1.0|4|Linux server 3.10.0-693.5.2.el7.x86_64 #1 SMP Fri Oct 20 20:32:50 UTC 2017 x86_64
|
||||
1.3.6.1.2.1.1.2.0|6|1.3.6.1.4.1.8072.3.2.10
|
||||
1.3.6.1.2.1.1.3.0|67|77550514
|
||||
1.3.6.1.2.1.1.4.0|4|<private>
|
||||
1.3.6.1.2.1.1.5.0|4|<private>
|
||||
1.3.6.1.2.1.1.6.0|4|<private>
|
||||
1.3.6.1.2.1.25.1.1.0|67|77552962
|
||||
1.3.6.1.4.1.8072.1.3.2.2.1.21.6.100.105.115.116.114.111|2|1
|
||||
1.3.6.1.4.1.8072.1.3.2.2.1.21.9.119.105.114.101.103.117.97.114.100|2|1
|
||||
1.3.6.1.4.1.8072.1.3.2.3.1.2.9.119.105.114.101.103.117.97.114.100|4x|7b226572726f72537472696e67223a2022222c20226572726f72223a20302c202276657273696f6e223a20312c202264617461223a207b22776730223a207b22636c69656e74312e646f6d61696e2e636f6d223a207b226d696e757465735f73696e63655f6c6173745f68616e647368616b65223a20312c202262797465735f72637664223a20313533343036382c202262797465735f73656e74223a2039373737327d2c2022636c69656e7432223a207b226d696e757465735f73696e63655f6c6173745f68616e647368616b65223a206e756c6c2c202262797465735f72637664223a20302c202262797465735f73656e74223a20307d2c20226d795f70686f6e65223a207b226d696e757465735f73696e63655f6c6173745f68616e647368616b65223a206e756c6c2c202262797465735f72637664223a20302c202262797465735f73656e74223a20307d2c202269745f61646d696e2e646f6d61696e2e6f7267223a207b226d696e757465735f73696e63655f6c6173745f68616e647368616b65223a206e756c6c2c202262797465735f72637664223a20302c202262797465735f73656e74223a20307d2c2022636f6d7075746572223a207b226d696e757465735f73696e63655f6c6173745f68616e647368616b65223a206e756c6c2c202262797465735f72637664223a20302c202262797465735f73656e74223a20307d7d7d7d0a
|
Reference in New Issue
Block a user