Skip to content

Commit

Permalink
Split interface name from peer configuration file (#26)
Browse files Browse the repository at this point in the history
Split interface name from peer configuration file
  • Loading branch information
Francesco Cogno committed Apr 7, 2020
1 parent f2a11f0 commit 2013f8b
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 116 deletions.
94 changes: 47 additions & 47 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "prometheus_wireguard_exporter"
version = "3.2.4"
version = "3.3.0"
authors = ["Francesco Cogno <francesco.cogno@outlook.com>"]
description = "Prometheus WireGuard Exporter"
edition = "2018"
Expand Down
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,25 @@

[![Crate](https://img.shields.io/crates/v/prometheus_wireguard_exporter.svg)](https://crates.io/crates/prometheus_wireguard_exporter) [![cratedown](https://img.shields.io/crates/d/prometheus_wireguard_exporter.svg)](https://crates.io/crates/prometheus_wireguard_exporter) [![cratelastdown](https://img.shields.io/crates/dv/prometheus_wireguard_exporter.svg)](https://crates.io/crates/prometheus_wireguard_exporter)

[![release](https://img.shields.io/github/release/MindFlavor/prometheus_wireguard_exporter.svg)](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.2.4)
[![tag](https://img.shields.io/github/tag/mindflavor/prometheus_wireguard_exporter.svg)](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.2.4)
[![release](https://img.shields.io/github/release/MindFlavor/prometheus_wireguard_exporter.svg)](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.3.0)
[![tag](https://img.shields.io/github/tag/mindflavor/prometheus_wireguard_exporter.svg)](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.3.0)

[![Build Status](https://travis-ci.org/MindFlavor/prometheus_wireguard_exporter.svg?branch=master)](https://travis-ci.org/MindFlavor/prometheus_wireguard_exporter)
[![commitssince](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.2.4.svg)](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.2.4.svg)
[![commitssince](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.3.0.svg)](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.3.0.svg)

## Intro

A Prometheus exporter for [WireGuard](https://www.wireguard.com), written in Rust. This tool exports the `wg show all dump` (or `wg show <interface> dump` if you specify a config file) results in a format that [Prometheus](https://prometheus.io/) can understand. The exporter is very light on your server resources, both in terms of memory and CPU usage.

Starting from release [2.0.2](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/2.0.2) this exporter supports IPv6 addressess too (thanks to [Maximilian Bosch](https://github.com/Ma27)'s PR [#5](https://github.com/MindFlavor/prometheus_wireguard_exporter/pull/5)).
From release [3.0.0](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.0.0) the exporter allows two label modes: one is to dump every allowed ip in a single label (called `allowed_ips`) along with their subnets. The second one is to create a pair of labels for each allowed ip/subnet pair (called `allowed_ip_0`/`allowed_subnet_0`, `allowed_ip_1`/`allowed_subnet_1` and so on for every allowed ip). The default if the single label mode but you can enable the second mode by specifying the `-s` switch at startup. Thank you [Toon Schoenmakers](https://github.com/schoentoon) for this solution (see [https://github.com/MindFlavor/prometheus_wireguard_exporter/issues/8](https://github.com/MindFlavor/prometheus_wireguard_exporter/issues/8)).

![](extra/01.png)

## Changelog

* **BREAKING** Starting from release [3.3.0](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.3.0) the exporter allows you to specify a different interface from the file name. Previously if you specified the file name (the `-n` flag) the program would infer the interface name from the file name. Now the two items are decoupled: you need to specify the file name (with `-n`) and the interface name (with `-i`) separately. Thank you [Vincent Debergue](https://github.com/vdebergue) for helping with this (see issue [#22](https://github.com/MindFlavor/prometheus_wireguard_exporter/issues/22)). Upgrading from [3.2.4](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.2.4): Please note that the `-n` flag no longer infer automatically the interface name from the file name. We now have the `-i` parameter for that. In order to keep the previous behaviour (if you use the `-n` flag) please add the `-i` flag to the command line arguments as well. For example, if you had `prometheus_wireguard_exporter -n /etc/wireguard/wg0.conf` you must specify `prometheus_wireguard_exporter -n /etc/wireguard/wg0.conf -i wg0` to keep the same behaviour.
* Starting from release [2.0.2](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/2.0.2) this exporter supports IPv6 addresses too (thanks to [Maximilian Bosch](https://github.com/Ma27)'s PR [#5](https://github.com/MindFlavor/prometheus_wireguard_exporter/pull/5)).
* From release [3.0.0](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.0.0) the exporter allows two label modes: one is to dump every allowed ip in a single label (called `allowed_ips`) along with their subnets. The second one is to create a pair of labels for each allowed ip/subnet pair (called `allowed_ip_0`/`allowed_subnet_0`, `allowed_ip_1`/`allowed_subnet_1` and so on for every allowed ip). The default if the single label mode but you can enable the second mode by specifying the `-s` switch at startup. Thank you [Toon Schoenmakers](https://github.com/schoentoon) for this solution (see issue [#8](https://github.com/MindFlavor/prometheus_wireguard_exporter/issues/8)).


## Prerequisites

* You need [Rust](https://www.rust-lang.org/) to compile this code. Simply follow the instructions on Rust's website to install the toolchain. If you get weird errors while compiling please try and update your Rust version first (I have developed it on `rustc 1.35.0-nightly (8159f389f 2019-04-06)`).
Expand Down Expand Up @@ -52,6 +56,7 @@ Start the binary with `-h` to get the complete syntax. The parameters are:
| `-n` | no | path to the wireguard configuration file | | This flag adds the *friendly_name* attribute to the exported entries. See [Friendly names](#friendly-names) for more details.
| `-s` | no | <switch> | off | Enable the allowed ip + subnet split mode for the labels.
| `-r` | no | <switch> | off | Exports peer's remote ip and port as labels (if available).
| `-i` | no | your interface name | `all` | Specifies the interface passed to the `wg show <interface> dump` parameter.

Once started, the tool will listen on the specified port (or the default one, 9586, if not specified) and return a Prometheus valid response at the url `/metrics`. So to check if the tool is working properly simply browse the `http://localhost:9586/metrics` (or whichever port you choose).

Expand Down Expand Up @@ -193,7 +198,7 @@ After=network-online.target
User=root
Group=root
Type=simple
ExecStart=/usr/local/bin/prometheus_wireguard_exporter -n /etc/wireguard/wg0.conf
ExecStart=/usr/local/bin/prometheus_wireguard_exporter -n /etc/wireguard/wg0.conf -i wg0
[Install]
WantedBy=multi-user.target
Expand Down
12 changes: 6 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
extern crate serde_json;
#[macro_use]
extern crate failure;
use clap;
use clap::{crate_authors, crate_name, crate_version, Arg};
use hyper::{Body, Request};
use log::{debug, info, trace};
Expand Down Expand Up @@ -42,13 +41,9 @@ async fn perform_request(
options: Arc<Options>,
) -> Result<String, failure::Error> {
trace!("perform_request");
// this is needed to satisfy the borrow checker
let options = options.clone();
debug!("options == {:?}", options);

//let interface = options.get_interface();

let interface_str = match options.get_interface() {
let interface_str = match &options.interface {
Some(interface_str) => interface_str,
None => "all",
}
Expand Down Expand Up @@ -145,6 +140,11 @@ async fn main() {
.short("n")
.help("If set, the exporter will look in the specified WireGuard config file for peer names (must be in [Peer] definition and be a comment)")
.takes_value(true))
.arg(
Arg::with_name("interface")
.short("i")
.help("If set specifies the interface passed to the wg show command. In not specified, all will be passed.")
.takes_value(true))
.get_matches();

let options = Options::from_claps(&matches);
Expand Down
60 changes: 9 additions & 51 deletions src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,67 +3,25 @@ pub(crate) struct Options {
pub verbose: bool,
pub separate_allowed_ips: bool,
pub extract_names_config_file: Option<String>,
pub interface: Option<String>,
pub export_remote_ip_and_port: bool,
}

impl Options {
pub fn from_claps(matches: &clap::ArgMatches<'_>) -> Options {
if let Some(e) = matches.value_of("extract_names_config_file") {
Options {
verbose: matches.is_present("verbose"),
separate_allowed_ips: matches.is_present("separate_allowed_ips"),
extract_names_config_file: Some(e.to_owned()),
export_remote_ip_and_port: matches.is_present("export_remote_ip_and_port"),
}
} else {
Options {
verbose: matches.is_present("verbose"),
separate_allowed_ips: matches.is_present("separate_allowed_ips"),
extract_names_config_file: None,
export_remote_ip_and_port: matches.is_present("export_remote_ip_and_port"),
}
}
}

pub fn get_interface(&self) -> Option<&str> {
if let Some(config_file) = &self.extract_names_config_file {
let path = std::path::Path::new(config_file);
if let Some(file_stem) = path.file_stem() {
file_stem.to_str()
} else {
None
}
} else {
None
Options {
verbose: matches.is_present("verbose"),
separate_allowed_ips: matches.is_present("separate_allowed_ips"),
extract_names_config_file: matches
.value_of("extract_names_config_file")
.map(|e| e.to_owned()),
interface: matches.value_of("interface").map(|e| e.to_owned()),
export_remote_ip_and_port: matches.is_present("export_remote_ip_and_port"),
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_interface_some() {
let options = Options {
verbose: true,
separate_allowed_ips: false,
extract_names_config_file: Some("/etc/wireguard/wg0.conf".to_owned()),
export_remote_ip_and_port: true,
};

assert_eq!(options.get_interface(), Some("wg0"));
}

#[test]
fn test_interface_none() {
let options = Options {
verbose: true,
separate_allowed_ips: false,
extract_names_config_file: None,
export_remote_ip_and_port: true,
};

assert_eq!(options.get_interface(), None);
}
}
5 changes: 3 additions & 2 deletions src/wireguard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,10 @@ impl WireGuard {
.collect();

for (idx, (ip, subnet)) in v_ip_and_subnet.iter().enumerate() {
attributes_owned.push((format!("allowed_ip_{}", idx), ip.to_string()));
attributes_owned
.push((format!("allowed_subnet_{}", idx), subnet.to_string()));
.push((format!("allowed_ip_{}", idx), (*ip).to_string()));
attributes_owned
.push((format!("allowed_subnet_{}", idx), (*subnet).to_string()));
}
debug!(
"WireGuard::render_with_names attributes == {:?}",
Expand Down
4 changes: 2 additions & 2 deletions src/wireguard_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ impl<'a> TryFrom<&[&'a str]> for PeerEntry<'a> {
if public_key == "" {
// we return a owned String for ergonomics. This will allocate but it's ok since it's not supposed
// to happen :)
let lines_owned: Vec<String> = lines.iter().map(|line| line.to_string()).collect();
let lines_owned: Vec<String> = lines.iter().map(|line| (*line).to_string()).collect();
Err(PeerEntryParseError::PublicKeyNotFound { lines: lines_owned })
} else if allowed_ips == "" {
let lines_owned: Vec<String> = lines.iter().map(|line| line.to_string()).collect();
let lines_owned: Vec<String> = lines.iter().map(|line| (*line).to_string()).collect();
Err(PeerEntryParseError::AllowedIPsEntryNotFound { lines: lines_owned })
} else {
let pe = PeerEntry {
Expand Down

0 comments on commit 2013f8b

Please sign in to comment.