├── .clog.toml
├── .github
├── FUNDING.yml
└── workflows
│ ├── ci.yml
│ ├── lint.yml
│ ├── release.yml
│ ├── release_nightly.yml
│ └── security_audit.yml
├── .gitignore
├── CHANGELOG.md
├── Cargo.lock
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── build.rs
└── src
├── cli.rs
├── macros.rs
├── main.rs
├── metrics.rs
└── wireguard.rs
/.clog.toml:
--------------------------------------------------------------------------------
1 | [clog]
2 | repository = "https://github.com/kbknapp/iptables_exporter"
3 | subtitle = "iptables_exporter Release"
4 |
5 | [sections]
6 | Documentation = ["docs", "doc"]
7 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: kbknapp
4 | patreon: kbknapp
5 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | ---
2 | on:
3 | push:
4 | branches: main
5 | pull_request:
6 | paths:
7 | - src/**
8 | - Cargo.toml
9 | - Cargo.lock
10 | - build.rs
11 |
12 | name: Continuous Integration
13 |
14 | jobs:
15 | ci:
16 | runs-on: ubuntu-latest
17 | strategy:
18 | matrix:
19 | rust:
20 | - stable
21 | - nightly
22 | - 1.58.1 # MSRV
23 |
24 | steps:
25 | - uses: actions/checkout@v2
26 |
27 | - uses: actions-rs/toolchain@v1
28 | with:
29 | profile: minimal
30 | toolchain: ${{ matrix.rust }}
31 | override: true
32 |
33 | - uses: actions-rs/cargo@v1
34 | with:
35 | command: build
36 |
37 | - uses: actions-rs/cargo@v1
38 | with:
39 | command: test
40 |
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | ---
2 | on:
3 | pull_request:
4 | paths:
5 | - src/**/*.rs
6 | - build.rs
7 |
8 | name: PR Lints
9 | jobs:
10 | lints:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v2
14 |
15 | - uses: actions-rs/toolchain@v1
16 | with:
17 | profile: minimal
18 | toolchain: nightly
19 | override: true
20 | components: clippy, rustfmt
21 |
22 | - uses: actions-rs/clippy-check@v1
23 | with:
24 | token: ${{ secrets.GITHUB_TOKEN }}
25 | args: --all-features
26 |
27 | - uses: actions-rs/cargo@v1
28 | with:
29 | command: fmt
30 | args: --all -- --check
31 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | ---
2 | on:
3 | push:
4 | tags:
5 | - 'v*.*.*'
6 |
7 | name: Create Release
8 |
9 | env:
10 | RELEASE_BIN: wireguard_exporter
11 | RELEASE_ADDS: >-
12 | README.md
13 | LICENSE-MIT
14 | LICENSE-APACHE
15 | CHANGELOG.md
16 |
17 | jobs:
18 | release:
19 | name: Release
20 |
21 | runs-on: ubuntu-latest
22 |
23 | steps:
24 | - uses: actions/checkout@v2
25 | - uses: actions-rs/toolchain@v1
26 | with:
27 | profile: minimal
28 | toolchain: stable
29 | override: true
30 | target: x86_64-unknown-linux-musl
31 |
32 | - name: Get the version
33 | id: get_version
34 | run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
35 |
36 | - uses: actions-rs/cargo@v1
37 | with:
38 | command: build
39 | args: --release --target x86_64-unknown-linux-musl
40 |
41 | - name: Make artifacts dir
42 | run: mkdir -p artifacts/
43 |
44 | - name: Copy all artifacts into dir
45 | run: cp target/x86_64-unknown-linux-musl/release/${{ env.RELEASE_BIN }} ${{ env.RELEASE_ADDS }} artifacts/
46 |
47 | - name: Create archive for Linux
48 | run: cd artifacts/ && tar czf ../${{ env.RELEASE_BIN }}-${{ steps.get_version.outputs.VERSION }}-x86_64-linux-musl.tar.gz ./*
49 |
50 | - name: Release
51 | uses: softprops/action-gh-release@v1
52 | with:
53 | body_path: CHANGELOG.md
54 | files: |
55 | ${{ env.RELEASE_BIN }}-${{ steps.get_version.outputs.VERSION }}-x86_64-linux-musl.tar.gz
56 | env:
57 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
58 | GITHUB_REPOSITORY: kbknapp/wireguard_exporter
59 |
--------------------------------------------------------------------------------
/.github/workflows/release_nightly.yml:
--------------------------------------------------------------------------------
1 | ---
2 | on:
3 | push:
4 | branches: main
5 | workflow_call:
6 |
7 | name: Nightly Release
8 |
9 | env:
10 | RELEASE_BIN: wireguard_exporter
11 | RELEASE_ADDS: >-
12 | LICENSE-APACHE
13 | LICENSE-MIT
14 | nightly-CHANGELOG.md
15 | README.md
16 |
17 | jobs:
18 | nightly-release:
19 | name: Nightly Release
20 |
21 | runs-on: ubuntu-latest
22 |
23 | steps:
24 | - uses: actions/checkout@v2
25 | - uses: actions-rs/toolchain@v1
26 | with:
27 | profile: minimal
28 | toolchain: nightly
29 | override: true
30 | target: x86_64-unknown-linux-musl
31 |
32 | - name: Compile
33 | uses: actions-rs/cargo@v1
34 | with:
35 | command: build
36 | args: --release --target x86_64-unknown-linux-musl
37 |
38 | - name: Install CLOG
39 | uses: actions-rs/cargo@v1
40 | with:
41 | command: install
42 | args: clog-cli
43 |
44 | - name: Generate Changelog
45 | run: clog -F -o nightly-CHANGELOG.md -i /dev/null
46 |
47 | - name: Make artifacts dir
48 | run: mkdir -p artifacts/
49 |
50 | - name: Copy all artifacts into dir
51 | run: cp target/x86_64-unknown-linux-musl/release/${{ env.RELEASE_BIN }} ${{ env.RELEASE_ADDS }} artifacts/
52 |
53 | - uses: benjlevesque/short-sha@v1.2
54 | id: short-sha
55 |
56 | - name: Create archive for Linux
57 | run: cd artifacts/ && tar czf ../${{ env.RELEASE_BIN }}-${{ env.SHA }}-x86_64-linux-musl.tar.gz ./*
58 | env:
59 | SHA: ${{ steps.short-sha.outputs.sha }}
60 |
61 | - name: Remove previous Nightly Release
62 | uses: dev-drprasad/delete-tag-and-release@v1.0.1
63 | with:
64 | delete_release: true
65 | tag_name: nightly
66 | repo: kbknapp/wireguard_exporter
67 | env:
68 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
69 |
70 | - name: Create Nightly Release
71 | uses: softprops/action-gh-release@v1
72 | with:
73 | name: wireguard_exporter Nightly (${{ env.SHA }})
74 | tag_name: nightly
75 | prerelease: true
76 | body_path: nightly-CHANGELOG.md
77 | files: |
78 | ${{ env.RELEASE_BIN }}-${{ env.SHA }}-x86_64-linux-musl.tar.gz
79 | env:
80 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
81 | GITHUB_REPOSITORY: kbknapp/wireguard_exporter
82 | SHA: ${{ steps.short-sha.outputs.sha }}
83 |
--------------------------------------------------------------------------------
/.github/workflows/security_audit.yml:
--------------------------------------------------------------------------------
1 | ---
2 | on:
3 | push:
4 | paths:
5 | - '**/Cargo.toml'
6 | - '**/Cargo.lock'
7 |
8 | name: Security audit
9 |
10 | jobs:
11 | security_audit:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v1
15 | - uses: actions-rs/audit-check@v1
16 | with:
17 | token: ${{ secrets.GITHUB_TOKEN }}
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled files
2 | *.o
3 | *.so
4 | *.rlib
5 | *.dll
6 |
7 | # Executables
8 | *.exe
9 |
10 | # Generated by Cargo
11 | target/
12 |
13 | # Temp files
14 | .*~
15 |
16 | # Backup files
17 | *.bak
18 | *.bk
19 | *.orig
20 |
21 | # Project files
22 | .vscode/*
23 | .idea/*
24 |
25 | # ctags
26 | **/*.vi
27 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### Features
4 |
5 | - Can now lookup country geoip lookup for endpoint addresses via MaxMindDB ([#6](https://github.com/kbknapp/wireguard_exporter/pull/6)) (Thanks to [@furmur](https://github.com/furmur))
6 |
7 | ### Important Changes
8 |
9 | - bump MSRV to 1.58.1 (3713673)[https://github.com/kbknapp/wireguard_exporter/commit/3713673adc0b1391076086eb41c4b2d14403b43e]
10 |
11 |
12 | ## 0.2.0 Initial Release (2024-03-28)
13 |
14 | ### Features
15 |
16 | - Adds metrics for peer endpoints ([#5](https://github.com/kbknapp/wireguard_exporter/pull/5)) (Thanks to [@furmur](https://github.com/furmur))
17 | - Adds peer aliases ([#1](https://github.com/kbknapp/wireguard_exporter/pull/1))
18 |
19 | ### Maintanance
20 |
21 | - Switch crate `chrono` for `time` ([#3](https://github.com/kbknapp/wireguard_exporter/pull/3))
22 |
23 | ### Documentation
24 |
25 | - Fix links in README ([#2](https://github.com/kbknapp/wireguard_exporter/pull/2))
26 |
27 |
28 | ## 0.1.0 Initial Release (2021-11-20)
29 |
30 | - Initial Release
31 |
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "addr2line"
7 | version = "0.17.0"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
10 | dependencies = [
11 | "gimli",
12 | ]
13 |
14 | [[package]]
15 | name = "adler"
16 | version = "1.0.2"
17 | source = "registry+https://github.com/rust-lang/crates.io-index"
18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
19 |
20 | [[package]]
21 | name = "ansi_term"
22 | version = "0.12.1"
23 | source = "registry+https://github.com/rust-lang/crates.io-index"
24 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
25 | dependencies = [
26 | "winapi",
27 | ]
28 |
29 | [[package]]
30 | name = "atty"
31 | version = "0.2.14"
32 | source = "registry+https://github.com/rust-lang/crates.io-index"
33 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
34 | dependencies = [
35 | "hermit-abi",
36 | "libc",
37 | "winapi",
38 | ]
39 |
40 | [[package]]
41 | name = "autocfg"
42 | version = "1.0.1"
43 | source = "registry+https://github.com/rust-lang/crates.io-index"
44 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
45 |
46 | [[package]]
47 | name = "backtrace"
48 | version = "0.3.63"
49 | source = "registry+https://github.com/rust-lang/crates.io-index"
50 | checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6"
51 | dependencies = [
52 | "addr2line",
53 | "cc",
54 | "cfg-if",
55 | "libc",
56 | "miniz_oxide",
57 | "object",
58 | "rustc-demangle",
59 | ]
60 |
61 | [[package]]
62 | name = "base64"
63 | version = "0.13.0"
64 | source = "registry+https://github.com/rust-lang/crates.io-index"
65 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
66 |
67 | [[package]]
68 | name = "bitflags"
69 | version = "1.3.2"
70 | source = "registry+https://github.com/rust-lang/crates.io-index"
71 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
72 |
73 | [[package]]
74 | name = "bytes"
75 | version = "1.1.0"
76 | source = "registry+https://github.com/rust-lang/crates.io-index"
77 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
78 |
79 | [[package]]
80 | name = "cc"
81 | version = "1.0.72"
82 | source = "registry+https://github.com/rust-lang/crates.io-index"
83 | checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
84 |
85 | [[package]]
86 | name = "cfg-if"
87 | version = "1.0.0"
88 | source = "registry+https://github.com/rust-lang/crates.io-index"
89 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
90 |
91 | [[package]]
92 | name = "clap"
93 | version = "3.0.0-beta.5"
94 | source = "registry+https://github.com/rust-lang/crates.io-index"
95 | checksum = "feff3878564edb93745d58cf63e17b63f24142506e7a20c87a5521ed7bfb1d63"
96 | dependencies = [
97 | "atty",
98 | "bitflags",
99 | "clap_derive",
100 | "indexmap",
101 | "lazy_static",
102 | "os_str_bytes",
103 | "strsim",
104 | "termcolor",
105 | "textwrap",
106 | "unicase",
107 | ]
108 |
109 | [[package]]
110 | name = "clap_derive"
111 | version = "3.0.0-beta.5"
112 | source = "registry+https://github.com/rust-lang/crates.io-index"
113 | checksum = "8b15c6b4f786ffb6192ffe65a36855bc1fc2444bcd0945ae16748dcd6ed7d0d3"
114 | dependencies = [
115 | "heck",
116 | "proc-macro-error",
117 | "proc-macro2",
118 | "quote",
119 | "syn",
120 | ]
121 |
122 | [[package]]
123 | name = "color-eyre"
124 | version = "0.5.11"
125 | source = "registry+https://github.com/rust-lang/crates.io-index"
126 | checksum = "1f1885697ee8a177096d42f158922251a41973117f6d8a234cee94b9509157b7"
127 | dependencies = [
128 | "backtrace",
129 | "eyre",
130 | "indenter",
131 | "once_cell",
132 | "owo-colors",
133 | ]
134 |
135 | [[package]]
136 | name = "eyre"
137 | version = "0.6.5"
138 | source = "registry+https://github.com/rust-lang/crates.io-index"
139 | checksum = "221239d1d5ea86bf5d6f91c9d6bc3646ffe471b08ff9b0f91c44f115ac969d2b"
140 | dependencies = [
141 | "indenter",
142 | "once_cell",
143 | ]
144 |
145 | [[package]]
146 | name = "fnv"
147 | version = "1.0.7"
148 | source = "registry+https://github.com/rust-lang/crates.io-index"
149 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
150 |
151 | [[package]]
152 | name = "futures-channel"
153 | version = "0.3.17"
154 | source = "registry+https://github.com/rust-lang/crates.io-index"
155 | checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888"
156 | dependencies = [
157 | "futures-core",
158 | ]
159 |
160 | [[package]]
161 | name = "futures-core"
162 | version = "0.3.17"
163 | source = "registry+https://github.com/rust-lang/crates.io-index"
164 | checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d"
165 |
166 | [[package]]
167 | name = "futures-task"
168 | version = "0.3.17"
169 | source = "registry+https://github.com/rust-lang/crates.io-index"
170 | checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99"
171 |
172 | [[package]]
173 | name = "futures-util"
174 | version = "0.3.17"
175 | source = "registry+https://github.com/rust-lang/crates.io-index"
176 | checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481"
177 | dependencies = [
178 | "autocfg",
179 | "futures-core",
180 | "futures-task",
181 | "pin-project-lite",
182 | "pin-utils",
183 | ]
184 |
185 | [[package]]
186 | name = "gimli"
187 | version = "0.26.1"
188 | source = "registry+https://github.com/rust-lang/crates.io-index"
189 | checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
190 |
191 | [[package]]
192 | name = "hashbrown"
193 | version = "0.11.2"
194 | source = "registry+https://github.com/rust-lang/crates.io-index"
195 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
196 |
197 | [[package]]
198 | name = "heck"
199 | version = "0.3.3"
200 | source = "registry+https://github.com/rust-lang/crates.io-index"
201 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
202 | dependencies = [
203 | "unicode-segmentation",
204 | ]
205 |
206 | [[package]]
207 | name = "hermit-abi"
208 | version = "0.1.19"
209 | source = "registry+https://github.com/rust-lang/crates.io-index"
210 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
211 | dependencies = [
212 | "libc",
213 | ]
214 |
215 | [[package]]
216 | name = "http"
217 | version = "0.2.5"
218 | source = "registry+https://github.com/rust-lang/crates.io-index"
219 | checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
220 | dependencies = [
221 | "bytes",
222 | "fnv",
223 | "itoa",
224 | ]
225 |
226 | [[package]]
227 | name = "http-body"
228 | version = "0.4.4"
229 | source = "registry+https://github.com/rust-lang/crates.io-index"
230 | checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6"
231 | dependencies = [
232 | "bytes",
233 | "http",
234 | "pin-project-lite",
235 | ]
236 |
237 | [[package]]
238 | name = "httparse"
239 | version = "1.5.1"
240 | source = "registry+https://github.com/rust-lang/crates.io-index"
241 | checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503"
242 |
243 | [[package]]
244 | name = "httpdate"
245 | version = "1.0.2"
246 | source = "registry+https://github.com/rust-lang/crates.io-index"
247 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
248 |
249 | [[package]]
250 | name = "hyper"
251 | version = "0.14.15"
252 | source = "registry+https://github.com/rust-lang/crates.io-index"
253 | checksum = "436ec0091e4f20e655156a30a0df3770fe2900aa301e548e08446ec794b6953c"
254 | dependencies = [
255 | "bytes",
256 | "futures-channel",
257 | "futures-core",
258 | "futures-util",
259 | "http",
260 | "http-body",
261 | "httparse",
262 | "httpdate",
263 | "itoa",
264 | "pin-project-lite",
265 | "socket2",
266 | "tokio",
267 | "tower-service",
268 | "tracing",
269 | "want",
270 | ]
271 |
272 | [[package]]
273 | name = "indenter"
274 | version = "0.3.3"
275 | source = "registry+https://github.com/rust-lang/crates.io-index"
276 | checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
277 |
278 | [[package]]
279 | name = "indexmap"
280 | version = "1.7.0"
281 | source = "registry+https://github.com/rust-lang/crates.io-index"
282 | checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
283 | dependencies = [
284 | "autocfg",
285 | "hashbrown",
286 | ]
287 |
288 | [[package]]
289 | name = "instant"
290 | version = "0.1.12"
291 | source = "registry+https://github.com/rust-lang/crates.io-index"
292 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
293 | dependencies = [
294 | "cfg-if",
295 | ]
296 |
297 | [[package]]
298 | name = "ipnetwork"
299 | version = "0.20.0"
300 | source = "registry+https://github.com/rust-lang/crates.io-index"
301 | checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e"
302 | dependencies = [
303 | "serde",
304 | ]
305 |
306 | [[package]]
307 | name = "itoa"
308 | version = "0.4.8"
309 | source = "registry+https://github.com/rust-lang/crates.io-index"
310 | checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
311 |
312 | [[package]]
313 | name = "lazy_static"
314 | version = "1.4.0"
315 | source = "registry+https://github.com/rust-lang/crates.io-index"
316 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
317 |
318 | [[package]]
319 | name = "libc"
320 | version = "0.2.107"
321 | source = "registry+https://github.com/rust-lang/crates.io-index"
322 | checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
323 |
324 | [[package]]
325 | name = "lock_api"
326 | version = "0.4.5"
327 | source = "registry+https://github.com/rust-lang/crates.io-index"
328 | checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
329 | dependencies = [
330 | "scopeguard",
331 | ]
332 |
333 | [[package]]
334 | name = "log"
335 | version = "0.4.14"
336 | source = "registry+https://github.com/rust-lang/crates.io-index"
337 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
338 | dependencies = [
339 | "cfg-if",
340 | ]
341 |
342 | [[package]]
343 | name = "maxminddb"
344 | version = "0.24.0"
345 | source = "registry+https://github.com/rust-lang/crates.io-index"
346 | checksum = "d6087e5d8ea14861bb7c7f573afbc7be3798d3ef0fae87ec4fd9a4de9a127c3c"
347 | dependencies = [
348 | "ipnetwork",
349 | "log",
350 | "memchr",
351 | "serde",
352 | ]
353 |
354 | [[package]]
355 | name = "memchr"
356 | version = "2.4.1"
357 | source = "registry+https://github.com/rust-lang/crates.io-index"
358 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
359 |
360 | [[package]]
361 | name = "miniz_oxide"
362 | version = "0.4.4"
363 | source = "registry+https://github.com/rust-lang/crates.io-index"
364 | checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
365 | dependencies = [
366 | "adler",
367 | "autocfg",
368 | ]
369 |
370 | [[package]]
371 | name = "mio"
372 | version = "0.7.14"
373 | source = "registry+https://github.com/rust-lang/crates.io-index"
374 | checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc"
375 | dependencies = [
376 | "libc",
377 | "log",
378 | "miow",
379 | "ntapi",
380 | "winapi",
381 | ]
382 |
383 | [[package]]
384 | name = "miow"
385 | version = "0.3.7"
386 | source = "registry+https://github.com/rust-lang/crates.io-index"
387 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
388 | dependencies = [
389 | "winapi",
390 | ]
391 |
392 | [[package]]
393 | name = "ntapi"
394 | version = "0.3.6"
395 | source = "registry+https://github.com/rust-lang/crates.io-index"
396 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
397 | dependencies = [
398 | "winapi",
399 | ]
400 |
401 | [[package]]
402 | name = "num_cpus"
403 | version = "1.13.0"
404 | source = "registry+https://github.com/rust-lang/crates.io-index"
405 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
406 | dependencies = [
407 | "hermit-abi",
408 | "libc",
409 | ]
410 |
411 | [[package]]
412 | name = "object"
413 | version = "0.27.1"
414 | source = "registry+https://github.com/rust-lang/crates.io-index"
415 | checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
416 | dependencies = [
417 | "memchr",
418 | ]
419 |
420 | [[package]]
421 | name = "once_cell"
422 | version = "1.8.0"
423 | source = "registry+https://github.com/rust-lang/crates.io-index"
424 | checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
425 |
426 | [[package]]
427 | name = "os_str_bytes"
428 | version = "4.2.0"
429 | source = "registry+https://github.com/rust-lang/crates.io-index"
430 | checksum = "addaa943333a514159c80c97ff4a93306530d965d27e139188283cd13e06a799"
431 | dependencies = [
432 | "memchr",
433 | ]
434 |
435 | [[package]]
436 | name = "owo-colors"
437 | version = "1.3.0"
438 | source = "registry+https://github.com/rust-lang/crates.io-index"
439 | checksum = "2386b4ebe91c2f7f51082d4cefa145d030e33a1842a96b12e4885cc3c01f7a55"
440 |
441 | [[package]]
442 | name = "parking_lot"
443 | version = "0.11.2"
444 | source = "registry+https://github.com/rust-lang/crates.io-index"
445 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
446 | dependencies = [
447 | "instant",
448 | "lock_api",
449 | "parking_lot_core",
450 | ]
451 |
452 | [[package]]
453 | name = "parking_lot_core"
454 | version = "0.8.5"
455 | source = "registry+https://github.com/rust-lang/crates.io-index"
456 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
457 | dependencies = [
458 | "cfg-if",
459 | "instant",
460 | "libc",
461 | "redox_syscall",
462 | "smallvec",
463 | "winapi",
464 | ]
465 |
466 | [[package]]
467 | name = "pin-project-lite"
468 | version = "0.2.7"
469 | source = "registry+https://github.com/rust-lang/crates.io-index"
470 | checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
471 |
472 | [[package]]
473 | name = "pin-utils"
474 | version = "0.1.0"
475 | source = "registry+https://github.com/rust-lang/crates.io-index"
476 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
477 |
478 | [[package]]
479 | name = "proc-macro-error"
480 | version = "1.0.4"
481 | source = "registry+https://github.com/rust-lang/crates.io-index"
482 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
483 | dependencies = [
484 | "proc-macro-error-attr",
485 | "proc-macro2",
486 | "quote",
487 | "syn",
488 | "version_check",
489 | ]
490 |
491 | [[package]]
492 | name = "proc-macro-error-attr"
493 | version = "1.0.4"
494 | source = "registry+https://github.com/rust-lang/crates.io-index"
495 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
496 | dependencies = [
497 | "proc-macro2",
498 | "quote",
499 | "version_check",
500 | ]
501 |
502 | [[package]]
503 | name = "proc-macro2"
504 | version = "1.0.32"
505 | source = "registry+https://github.com/rust-lang/crates.io-index"
506 | checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
507 | dependencies = [
508 | "unicode-xid",
509 | ]
510 |
511 | [[package]]
512 | name = "prometheus"
513 | version = "0.13.0"
514 | source = "registry+https://github.com/rust-lang/crates.io-index"
515 | checksum = "b7f64969ffd5dd8f39bd57a68ac53c163a095ed9d0fb707146da1b27025a3504"
516 | dependencies = [
517 | "cfg-if",
518 | "fnv",
519 | "lazy_static",
520 | "memchr",
521 | "parking_lot",
522 | "protobuf",
523 | "thiserror",
524 | ]
525 |
526 | [[package]]
527 | name = "prometheus-hyper"
528 | version = "0.1.3"
529 | source = "registry+https://github.com/rust-lang/crates.io-index"
530 | checksum = "c2c8d04467323c4bc0ef47e86764e7e9525560be8347f98df248e6eab34794f2"
531 | dependencies = [
532 | "hyper",
533 | "prometheus",
534 | "tokio",
535 | "tracing",
536 | ]
537 |
538 | [[package]]
539 | name = "protobuf"
540 | version = "2.25.2"
541 | source = "registry+https://github.com/rust-lang/crates.io-index"
542 | checksum = "47c327e191621a2158159df97cdbc2e7074bb4e940275e35abf38eb3d2595754"
543 |
544 | [[package]]
545 | name = "quote"
546 | version = "1.0.10"
547 | source = "registry+https://github.com/rust-lang/crates.io-index"
548 | checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
549 | dependencies = [
550 | "proc-macro2",
551 | ]
552 |
553 | [[package]]
554 | name = "redox_syscall"
555 | version = "0.2.10"
556 | source = "registry+https://github.com/rust-lang/crates.io-index"
557 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
558 | dependencies = [
559 | "bitflags",
560 | ]
561 |
562 | [[package]]
563 | name = "rustc-demangle"
564 | version = "0.1.21"
565 | source = "registry+https://github.com/rust-lang/crates.io-index"
566 | checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
567 |
568 | [[package]]
569 | name = "scopeguard"
570 | version = "1.1.0"
571 | source = "registry+https://github.com/rust-lang/crates.io-index"
572 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
573 |
574 | [[package]]
575 | name = "serde"
576 | version = "1.0.136"
577 | source = "registry+https://github.com/rust-lang/crates.io-index"
578 | checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
579 | dependencies = [
580 | "serde_derive",
581 | ]
582 |
583 | [[package]]
584 | name = "serde_derive"
585 | version = "1.0.136"
586 | source = "registry+https://github.com/rust-lang/crates.io-index"
587 | checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
588 | dependencies = [
589 | "proc-macro2",
590 | "quote",
591 | "syn",
592 | ]
593 |
594 | [[package]]
595 | name = "sharded-slab"
596 | version = "0.1.4"
597 | source = "registry+https://github.com/rust-lang/crates.io-index"
598 | checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
599 | dependencies = [
600 | "lazy_static",
601 | ]
602 |
603 | [[package]]
604 | name = "signal-hook-registry"
605 | version = "1.4.0"
606 | source = "registry+https://github.com/rust-lang/crates.io-index"
607 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
608 | dependencies = [
609 | "libc",
610 | ]
611 |
612 | [[package]]
613 | name = "smallvec"
614 | version = "1.7.0"
615 | source = "registry+https://github.com/rust-lang/crates.io-index"
616 | checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
617 |
618 | [[package]]
619 | name = "socket2"
620 | version = "0.4.2"
621 | source = "registry+https://github.com/rust-lang/crates.io-index"
622 | checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516"
623 | dependencies = [
624 | "libc",
625 | "winapi",
626 | ]
627 |
628 | [[package]]
629 | name = "strsim"
630 | version = "0.10.0"
631 | source = "registry+https://github.com/rust-lang/crates.io-index"
632 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
633 |
634 | [[package]]
635 | name = "syn"
636 | version = "1.0.81"
637 | source = "registry+https://github.com/rust-lang/crates.io-index"
638 | checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
639 | dependencies = [
640 | "proc-macro2",
641 | "quote",
642 | "unicode-xid",
643 | ]
644 |
645 | [[package]]
646 | name = "termcolor"
647 | version = "1.1.2"
648 | source = "registry+https://github.com/rust-lang/crates.io-index"
649 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
650 | dependencies = [
651 | "winapi-util",
652 | ]
653 |
654 | [[package]]
655 | name = "textwrap"
656 | version = "0.14.2"
657 | source = "registry+https://github.com/rust-lang/crates.io-index"
658 | checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
659 | dependencies = [
660 | "unicode-width",
661 | ]
662 |
663 | [[package]]
664 | name = "thiserror"
665 | version = "1.0.30"
666 | source = "registry+https://github.com/rust-lang/crates.io-index"
667 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
668 | dependencies = [
669 | "thiserror-impl",
670 | ]
671 |
672 | [[package]]
673 | name = "thiserror-impl"
674 | version = "1.0.30"
675 | source = "registry+https://github.com/rust-lang/crates.io-index"
676 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
677 | dependencies = [
678 | "proc-macro2",
679 | "quote",
680 | "syn",
681 | ]
682 |
683 | [[package]]
684 | name = "thread_local"
685 | version = "1.1.3"
686 | source = "registry+https://github.com/rust-lang/crates.io-index"
687 | checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
688 | dependencies = [
689 | "once_cell",
690 | ]
691 |
692 | [[package]]
693 | name = "time"
694 | version = "0.3.5"
695 | source = "registry+https://github.com/rust-lang/crates.io-index"
696 | checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad"
697 | dependencies = [
698 | "libc",
699 | ]
700 |
701 | [[package]]
702 | name = "tokio"
703 | version = "1.14.0"
704 | source = "registry+https://github.com/rust-lang/crates.io-index"
705 | checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144"
706 | dependencies = [
707 | "autocfg",
708 | "bytes",
709 | "libc",
710 | "memchr",
711 | "mio",
712 | "num_cpus",
713 | "once_cell",
714 | "parking_lot",
715 | "pin-project-lite",
716 | "signal-hook-registry",
717 | "tokio-macros",
718 | "winapi",
719 | ]
720 |
721 | [[package]]
722 | name = "tokio-macros"
723 | version = "1.6.0"
724 | source = "registry+https://github.com/rust-lang/crates.io-index"
725 | checksum = "c9efc1aba077437943f7515666aa2b882dfabfbfdf89c819ea75a8d6e9eaba5e"
726 | dependencies = [
727 | "proc-macro2",
728 | "quote",
729 | "syn",
730 | ]
731 |
732 | [[package]]
733 | name = "tower-service"
734 | version = "0.3.1"
735 | source = "registry+https://github.com/rust-lang/crates.io-index"
736 | checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
737 |
738 | [[package]]
739 | name = "tracing"
740 | version = "0.1.29"
741 | source = "registry+https://github.com/rust-lang/crates.io-index"
742 | checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
743 | dependencies = [
744 | "cfg-if",
745 | "pin-project-lite",
746 | "tracing-attributes",
747 | "tracing-core",
748 | ]
749 |
750 | [[package]]
751 | name = "tracing-attributes"
752 | version = "0.1.18"
753 | source = "registry+https://github.com/rust-lang/crates.io-index"
754 | checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e"
755 | dependencies = [
756 | "proc-macro2",
757 | "quote",
758 | "syn",
759 | ]
760 |
761 | [[package]]
762 | name = "tracing-core"
763 | version = "0.1.21"
764 | source = "registry+https://github.com/rust-lang/crates.io-index"
765 | checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4"
766 | dependencies = [
767 | "lazy_static",
768 | ]
769 |
770 | [[package]]
771 | name = "tracing-log"
772 | version = "0.1.2"
773 | source = "registry+https://github.com/rust-lang/crates.io-index"
774 | checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3"
775 | dependencies = [
776 | "lazy_static",
777 | "log",
778 | "tracing-core",
779 | ]
780 |
781 | [[package]]
782 | name = "tracing-subscriber"
783 | version = "0.3.1"
784 | source = "registry+https://github.com/rust-lang/crates.io-index"
785 | checksum = "80a4ddde70311d8da398062ecf6fc2c309337de6b0f77d6c27aff8d53f6fca52"
786 | dependencies = [
787 | "ansi_term",
788 | "sharded-slab",
789 | "smallvec",
790 | "thread_local",
791 | "tracing-core",
792 | "tracing-log",
793 | ]
794 |
795 | [[package]]
796 | name = "try-lock"
797 | version = "0.2.3"
798 | source = "registry+https://github.com/rust-lang/crates.io-index"
799 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
800 |
801 | [[package]]
802 | name = "unicase"
803 | version = "2.6.0"
804 | source = "registry+https://github.com/rust-lang/crates.io-index"
805 | checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
806 | dependencies = [
807 | "version_check",
808 | ]
809 |
810 | [[package]]
811 | name = "unicode-segmentation"
812 | version = "1.8.0"
813 | source = "registry+https://github.com/rust-lang/crates.io-index"
814 | checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
815 |
816 | [[package]]
817 | name = "unicode-width"
818 | version = "0.1.9"
819 | source = "registry+https://github.com/rust-lang/crates.io-index"
820 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
821 |
822 | [[package]]
823 | name = "unicode-xid"
824 | version = "0.2.2"
825 | source = "registry+https://github.com/rust-lang/crates.io-index"
826 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
827 |
828 | [[package]]
829 | name = "version_check"
830 | version = "0.9.3"
831 | source = "registry+https://github.com/rust-lang/crates.io-index"
832 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
833 |
834 | [[package]]
835 | name = "want"
836 | version = "0.3.0"
837 | source = "registry+https://github.com/rust-lang/crates.io-index"
838 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
839 | dependencies = [
840 | "log",
841 | "try-lock",
842 | ]
843 |
844 | [[package]]
845 | name = "winapi"
846 | version = "0.3.9"
847 | source = "registry+https://github.com/rust-lang/crates.io-index"
848 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
849 | dependencies = [
850 | "winapi-i686-pc-windows-gnu",
851 | "winapi-x86_64-pc-windows-gnu",
852 | ]
853 |
854 | [[package]]
855 | name = "winapi-i686-pc-windows-gnu"
856 | version = "0.4.0"
857 | source = "registry+https://github.com/rust-lang/crates.io-index"
858 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
859 |
860 | [[package]]
861 | name = "winapi-util"
862 | version = "0.1.5"
863 | source = "registry+https://github.com/rust-lang/crates.io-index"
864 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
865 | dependencies = [
866 | "winapi",
867 | ]
868 |
869 | [[package]]
870 | name = "winapi-x86_64-pc-windows-gnu"
871 | version = "0.4.0"
872 | source = "registry+https://github.com/rust-lang/crates.io-index"
873 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
874 |
875 | [[package]]
876 | name = "wireguard_exporter"
877 | version = "0.3.0"
878 | dependencies = [
879 | "base64",
880 | "clap",
881 | "color-eyre",
882 | "maxminddb",
883 | "prometheus",
884 | "prometheus-hyper",
885 | "time",
886 | "tokio",
887 | "tracing",
888 | "tracing-subscriber",
889 | ]
890 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "wireguard_exporter"
3 | version = "0.3.0"
4 | edition = "2021"
5 | authors = [
6 | "Kevin K. ",
7 | ]
8 | description = "A Prometheus exporter for WireGuard"
9 | repository = "https://github.com/kbknapp/wireguard_exporter"
10 | keywords = [
11 | "prometheus",
12 | "wireguard",
13 | "exporter",
14 | "prometheus_exporter",
15 | ]
16 | categories = ["command-line-utilities"]
17 | license = "MIT OR Apache-2.0"
18 | readme = "README.md"
19 |
20 | [badges]
21 | is-it-maintained-issue-resolution = { repository = "kbknapp/wireguard_exporter" }
22 | is-it-maintained-open-issues = { repository = "kbknapp/wireguard_exporter" }
23 | maintenance = {status = "actively-developed"}
24 |
25 | [dependencies]
26 | color-eyre = { version = "0.5.11", default-features = false }
27 | clap = "3.0.0-beta.5"
28 | prometheus = "0.13.0"
29 | prometheus-hyper = "0.1.3"
30 | tokio = { version = "1.5.0", features = ["full"] }
31 | tracing = "0.1.25"
32 | tracing-subscriber = "0.3.1"
33 | base64 = "0.13.0"
34 | time = { version = "0.3.5", features = ["local-offset"] }
35 | maxminddb = "0.24.0"
36 |
37 | [build-dependencies]
38 | clap = "3.0.0-beta.5"
39 |
40 | [features]
41 |
--------------------------------------------------------------------------------
/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2021 Kevin B. Knapp
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # `wireguard_exporter`
2 |
3 | ![Rust Version][rustc-image]
4 | [![crates.io][crate-image]][crate-link]
5 | [![Dependency Status][deps-image]][deps-link]
6 |
7 | An asynchronous Prometheus exporter for `wireguard`
8 |
9 | `wireguard_exporter` runs `wg show [..]` and scrapes the output to
10 | build Prometheus metrics. Because `wg` requires `root` privileges,
11 | this tool must be run as `root` (or via `sudo`) or with the following
12 | capabilities in both the ambient and bounding set:
13 |
14 | - CAP_DAC_READ_SEARCH
15 | - CAP_NET_ADMIN
16 | - CAP_NET_RAW
17 |
18 | # Metrics Provided
19 |
20 | - Total number of bytes transferred in/out per peer
21 | - Total number of bytes transferred in/out per interface
22 | - Metrics with the info for each connected peer
23 | - Time since last handshake per peer
24 | - Scrape duration in milliseconds
25 | - Scrape success
26 |
27 | # Installation
28 |
29 | `wireguard_exporter` is a single binary that must be placed somewhere in your
30 | `$PATH`. One can either download 64-bit Linux binaries from [the Release Page](https://github.com/kbknapp/wireguard_exporter/releases)
31 | or one can also compile from source.
32 |
33 | ## Compile from Source
34 |
35 | Ensure you have a [Rust toolchain installed](https://rustup.rs). Some of the
36 | dependencies also require `gcc` to be installed.
37 |
38 | ```
39 | $ git clone https://github.com/kbknapp/wireguard_exporter
40 | $ cd wireguard_exporter
41 | $ cargo build --release
42 | $ sudo cp target/release/wireguard_exporter /usr/local/bin/
43 | ```
44 |
45 | # Usage
46 |
47 | ## Command Line Interface
48 |
49 | ```
50 | USAGE:
51 | wireguard_exporter [OPTIONS]
52 |
53 | OPTIONS:
54 | -a, --alias ... Add an alias for a given public key in the form of
55 | 'pubkey:alias' (separate multiple with commas)
56 | --collect-interval How often metrics are gathered [default: 5]
57 | -h, --help Print help information
58 | -l, --listen-address The listen address scraping metrics [default: 0.0.0.0]
59 | -p, --listen-port The listen port for scraping metrics [default: 9586]
60 | -q, --quiet Supress output at a level or lower. -q: INFO, -qq: WARN, -qqq:
61 | ERROR (i.e. everything)
62 | -v, --verbose Show verbose output at a level or higher. -v: DEBUG, -vv:
63 | TRACE
64 | -V, --version Print version information
65 | ```
66 |
67 | To run with the default options, and the binary is installed somewhere in your
68 | `$PATH`:
69 |
70 | ```
71 | $ sudo wireguard_exporter
72 | ```
73 |
74 | # Prometheus Configuration
75 |
76 | You can add the following scrape configs to Prometheus:
77 |
78 | ```yaml
79 | scrape_configs:
80 | - job_name: 'wireguard'
81 | static_configs:
82 | - targets:
83 | - 'localhost:9586'
84 | - 'other_host:9586'
85 |
86 | relabel_configs:
87 | - source_labels: [ '__address__' ]
88 | regex: '(.*):\d+'
89 | target_label: instance
90 | ```
91 |
92 | # Example Metrics
93 |
94 | ```
95 | # HELP wireguard_bytes_total Total number of bytes per direction per interface
96 | # TYPE wireguard_bytes_total counter
97 | wireguard_bytes_total{direction="rx",interface="custom"} 19576636452
98 | wireguard_bytes_total{direction="rx",interface="wg0"} 1091996152
99 | wireguard_bytes_total{direction="tx",interface="custom"} 3919310388
100 | wireguard_bytes_total{direction="tx",interface="wg0"} 2393043528
101 | # HELP wireguard_duration_since_latest_handshake During since latest handshake for a peer
102 | # TYPE wireguard_duration_since_latest_handshake gauge
103 | wireguard_duration_since_latest_handshake{interface="custom",peer="q2JWEKWfLPU5UjG2Sq31xx2GsSjdhKNtdT/X/tFVyjs=",alias="kevin"} 51405
104 | wireguard_duration_since_latest_handshake{interface="custom",peer="2ELWFmGnqhtRpu4r2PUKc0cw+ELtuMPLd6l0KsoCUBQ=",alias="jane"} 88405
105 | wireguard_duration_since_latest_handshake{interface="custom",peer="duVVziZbyIiIPoRprisE69K0By198Cn8dPwY5bFecEk=",alias="robert"} 116405
106 | wireguard_duration_since_latest_handshake{interface="custom",peer="nwj+Zw49AbYrzUAPzeRf8hhll/1dz8SjoOYZuB+JdT4="} 15296341405
107 | wireguard_duration_since_latest_handshake{interface="custom",peer="QF01u5CZhH9+CWcVY9pbsuTu3QsTcSqFvni3VfOiL2s="} 34405
108 | wireguard_duration_since_latest_handshake{interface="custom",peer="N5UQp3XbysLBAavUm1Cpv7xxjk99LwJD99z5//PsyCc="} 95405
109 | wireguard_duration_since_latest_handshake{interface="custom",peer="QlgHHfYP3aMlRG7d6/Zp9IhUOLrpT5G2GIdODODaUHQ="} 10690033405
110 | wireguard_duration_since_latest_handshake{interface="custom",peer="FtUeMGdNxgkVN0G9lpvOc5jtAQQ1m9DpvZPDCUdKBx0="} 96405
111 | wireguard_duration_since_latest_handshake{interface="wg0",peer="bRQZOyOZUvHMhBvCWq2sXO0VsRu6Aq5LCACi/R3AJk8="} 42405
112 | # HELP wireguard_interfaces_total Total number of interfaces
113 | # TYPE wireguard_interfaces_total gauge
114 | wireguard_interfaces_total 2
115 | # HELP wireguard_peer_bytes_total Total number of bytes per direction for a peer
116 | # TYPE wireguard_peer_bytes_total counter
117 | wireguard_peer_bytes_total{direction="rx",interface="custom",peer=q2JWEKWfLPU5UjG2Sq31xx2GsSjdhKNtdT/X/tFVyjs="",alias="kevin"} 0
118 | wireguard_peer_bytes_total{direction="rx",interface="custom",peer="2ELWFmGnqhtRpu4r2PUKc0cw+ELtuMPLd6l0KsoCUBQ=",alias="jane"} 1240506784
119 | wireguard_peer_bytes_total{direction="rx",interface="custom",peer="duVVziZbyIiIPoRprisE69K0By198Cn8dPwY5bFecEk=",alias="robert"} 1312403276
120 | wireguard_peer_bytes_total{direction="rx",interface="custom",peer="nwj+Zw49AbYrzUAPzeRf8hhll/1dz8SjoOYZuB+JdT4="} 11962543712
121 | wireguard_peer_bytes_total{direction="rx",interface="custom",peer="QF01u5CZhH9+CWcVY9pbsuTu3QsTcSqFvni3VfOiL2s="} 0
122 | wireguard_peer_bytes_total{direction="rx",interface="custom",peer="N5UQp3XbysLBAavUm1Cpv7xxjk99LwJD99z5//PsyCc="} 0
123 | wireguard_peer_bytes_total{direction="rx",interface="custom",peer="QlgHHfYP3aMlRG7d6/Zp9IhUOLrpT5G2GIdODODaUHQ="} 353261276
124 | wireguard_peer_bytes_total{direction="rx",interface="custom",peer="FtUeMGdNxgkVN0G9lpvOc5jtAQQ1m9DpvZPDCUdKBx0="} 2150081456
125 | wireguard_peer_bytes_total{direction="rx",interface="wg0",peer=""} 1091996152
126 | wireguard_peer_bytes_total{direction="tx",interface="custom",peer="q2JWEKWfLPU5UjG2Sq31xx2GsSjdhKNtdT/X/tFVyjs=",alias="kevin"} 0
127 | wireguard_peer_bytes_total{direction="tx",interface="custom",peer="2ELWFmGnqhtRpu4r2PUKc0cw+ELtuMPLd6l0KsoCUBQ=",alias="jane"} 708900060
128 | wireguard_peer_bytes_total{direction="tx",interface="custom",peer="duVVziZbyIiIPoRprisE69K0By198Cn8dPwY5bFecEk=",alias="robert"} 714718444
129 | wireguard_peer_bytes_total{direction="tx",interface="custom",peer="nwj+Zw49AbYrzUAPzeRf8hhll/1dz8SjoOYZuB+JdT4="} 1171658320
130 | wireguard_peer_bytes_total{direction="tx",interface="custom",peer="QF01u5CZhH9+CWcVY9pbsuTu3QsTcSqFvni3VfOiL2s="} 0
131 | wireguard_peer_bytes_total{direction="tx",interface="custom",peer="N5UQp3XbysLBAavUm1Cpv7xxjk99LwJD99z5//PsyCc="} 0
132 | wireguard_peer_bytes_total{direction="tx",interface="custom",peer="QlgHHfYP3aMlRG7d6/Zp9IhUOLrpT5G2GIdODODaUHQ="} 88648
133 | wireguard_peer_bytes_total{direction="tx",interface="custom",peer="FtUeMGdNxgkVN0G9lpvOc5jtAQQ1m9DpvZPDCUdKBx0="} 480852300
134 | wireguard_peer_bytes_total{direction="tx",interface="wg0",peer="bRQZOyOZUvHMhBvCWq2sXO0VsRu6Aq5LCACi/R3AJk8="} 2393043528
135 | # HELP wireguard_peer_endpoint Peers info. static value
136 | # TYPE wireguard_peer_endpoint gauge
137 | wireguard_peer_endpoint{alias="kevin",endpoint_ip="1.1.1.1",interface="custom",peer="q2JWEKWfLPU5UjG2Sq31xx2GsSjdhKNtdT/X/tFVyjs="} 1
138 | wireguard_peer_endpoint{alias="jane",endpoint_ip="8.8.8.8",interface="custom",peer="2ELWFmGnqhtRpu4r2PUKc0cw+ELtuMPLd6l0KsoCUBQ="} 1
139 | wireguard_peer_endpoint{alias="robert",endpoint_ip="127.0.0.1",interface="custom",peer="duVVziZbyIiIPoRprisE69K0By198Cn8dPwY5bFecEk="} 1
140 | # HELP wireguard_peers_total Total number of peers per interfaces
141 | # TYPE wireguard_peers_total gauge
142 | wireguard_peers_total{interface="custom"} 7
143 | wireguard_peers_total{interface="wg0"} 1
144 | # HELP wireguard_scrape_duration_milliseconds Duration in milliseconds of the scrape
145 | # TYPE wireguard_scrape_duration_milliseconds gauge
146 | wireguard_scrape_duration_milliseconds 1
147 | # HELP wireguard_scrape_success If the scrape was a success
148 | # TYPE wireguard_scrape_success gauge
149 | wireguard_scrape_success 1
150 | ```
151 |
152 | # License
153 |
154 | This crate is licensed under either of
155 |
156 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
157 | * [MIT license](http://opensource.org/licenses/MIT)
158 |
159 | at your option.
160 |
161 | ## Contribution
162 |
163 | Unless you explicitly state otherwise, any contribution intentionally submitted
164 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
165 | dual licensed as above, without any additional terms or conditions.
166 |
167 | [//]: # (badges)
168 |
169 | [rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg
170 | [crate-image]: https://img.shields.io/crates/v/wireguard_exporter.svg
171 | [crate-link]: https://crates.io/crates/wireguard_exporter
172 | [deps-image]: https://deps.rs/repo/github/kbknapp/wireguard_exporter/status.svg
173 | [deps-link]: https://deps.rs/repo/github/kbknapp/wireguard_exporter
174 |
175 |
176 | [//]: # (Links)
177 |
178 |
--------------------------------------------------------------------------------
/build.rs:
--------------------------------------------------------------------------------
1 | use std::process::Command;
2 |
3 | use clap::crate_version;
4 |
5 | fn main() {
6 | let output = Command::new("git")
7 | .args(&["rev-parse", "HEAD"])
8 | .output()
9 | .unwrap();
10 | let git_hash = String::from_utf8(output.stdout).unwrap();
11 | println!(
12 | "cargo:rustc-env=VERSION_WITH_GIT_HASH='v{} ({})'",
13 | crate_version!(),
14 | &git_hash[..10]
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/src/cli.rs:
--------------------------------------------------------------------------------
1 | use std::{collections::HashMap, env, net::IpAddr, path::PathBuf, str::FromStr};
2 |
3 | use clap::{crate_authors, Parser};
4 |
5 | static VERSION: &str = env!("VERSION_WITH_GIT_HASH");
6 | static AUTHORS: &str = crate_authors!();
7 |
8 | /// A Prometheus exporter for WireGuard
9 | #[derive(Parser)]
10 | #[clap(author = AUTHORS, version = VERSION)]
11 | pub struct Args {
12 | /// How often metrics are gathered
13 | #[clap(long, default_value = "5", value_name = "SECS")]
14 | pub collect_interval: u64,
15 | /// The listen port for scraping metrics
16 | #[clap(short = 'p', long, default_value = "9586", value_name = "PORT")]
17 | pub listen_port: u16,
18 | /// The listen address scraping metrics
19 | #[clap(short, long, default_value = "0.0.0.0", value_name = "ADDR")]
20 | pub listen_address: IpAddr,
21 | /// Show verbose output at a level or higher. -v: DEBUG, -vv: TRACE
22 | #[clap(long, short, parse(from_occurrences))]
23 | pub verbose: u8,
24 | /// Supress output at a level or lower. -q: INFO, -qq: WARN, -qqq: ERROR (i.e. everything)
25 | #[clap(long, short, overrides_with = "verbose", parse(from_occurrences))]
26 | pub quiet: u8,
27 | /// Add an alias for a given public key in the form of 'pubkey:alias' (separate multiple with commas)
28 | #[clap(long, short, value_delimiter = ',', multiple_occurrences = true)]
29 | pub alias: Vec,
30 | /// Do geoip lookup using Country MMDB from the PATH for 'endpoint_ip' attribute in the 'wireguard_peer_endpoint' metric and add attribute 'endpoint_country'
31 | #[clap(short, long, value_name = "PATH")]
32 | pub geoip_path: Option,
33 | }
34 |
35 | impl Args {
36 | pub fn aliases(&self) -> HashMap<&str, &str> {
37 | let mut map = HashMap::new();
38 | for alias in &self.alias {
39 | let Alias {
40 | inner: (pubkey, alias),
41 | } = alias;
42 | map.insert(pubkey.as_ref(), alias.as_ref());
43 | }
44 |
45 | map
46 | }
47 | }
48 |
49 | #[derive(Clone, Debug)]
50 | pub struct Alias {
51 | // A base64 encoded public key and a human readable alias
52 | // (pubkey, alias)
53 | pub inner: (String, String),
54 | }
55 |
56 | impl FromStr for Alias {
57 | type Err = String;
58 | fn from_str(s: &str) -> Result {
59 | let mut parts = s.split(':');
60 | let pubkey = parts.next();
61 | let alias = parts.next();
62 |
63 | match (pubkey, alias) {
64 | (Some(pubkey), None) => Err(format!(
65 | "must be in the format 'PUBKEY:ALIAS' but found '{}'",
66 | pubkey
67 | )),
68 | (None, _) => unreachable!(),
69 | (Some(pubkey), Some(alias)) => {
70 | if pubkey.is_empty() || alias.is_empty() {
71 | return Err(format!(
72 | "\t\nMust be in the format 'PUBKEY:ALIAS' but found '{}:{}'",
73 | pubkey, alias
74 | ));
75 | }
76 |
77 | if pubkey.len() != 44 {
78 | return Err(format!("\t\nPUBKEY '{}' has an invalid length", pubkey,));
79 | }
80 |
81 | if base64::decode(pubkey).is_err() {
82 | return Err(format!("\n\t'{}' is not a valid public key", pubkey,));
83 | }
84 |
85 | Ok(Alias {
86 | inner: (pubkey.into(), alias.into()),
87 | })
88 | }
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/macros.rs:
--------------------------------------------------------------------------------
1 | macro_rules! unwrap_or_exit {
2 | ($e:expr) => {{
3 | use std::process;
4 | use tracing::error;
5 | ($e).map_err(|e| {
6 | error!("{}", e);
7 | eprintln!("error: {}", e);
8 | process::exit(1);
9 | })
10 | .unwrap()
11 | }};
12 | }
13 |
--------------------------------------------------------------------------------
/src/main.rs:
--------------------------------------------------------------------------------
1 | use std::{
2 | env,
3 | net::SocketAddr,
4 | sync::{
5 | atomic::{AtomicBool, Ordering},
6 | Arc,
7 | },
8 | };
9 |
10 | use clap::Parser;
11 | use color_eyre::{
12 | config::{HookBuilder, Theme},
13 | eyre::Result,
14 | };
15 | use maxminddb;
16 | use prometheus::{IntGauge, Registry};
17 | use prometheus_hyper::Server;
18 | use tokio::time::{Duration, Instant};
19 | use tracing::{debug, info};
20 |
21 | #[macro_use]
22 | mod macros;
23 | mod cli;
24 | mod metrics;
25 | mod wireguard;
26 |
27 | use cli::Args;
28 | use metrics::Metrics;
29 | use wireguard::WireguardState;
30 |
31 | #[tokio::main(flavor = "current_thread")]
32 | async fn main() -> Result<()> {
33 | let args = cli::Args::parse();
34 |
35 | HookBuilder::blank()
36 | .theme(Theme::new())
37 | .panic_section(
38 | "consider reporting the bug at https://github.com/kbknapp/wireguard_exporter",
39 | )
40 | .install()?;
41 |
42 | match args.verbose {
43 | 0 => match args.quiet {
44 | 0 => env::set_var("RUST_LOG", "wireguard_exporter=info"),
45 | 1 => env::set_var("RUST_LOG", "wireguard_exporter=warn"),
46 | 2 => env::set_var("RUST_LOG", "wireguard_exporter=error"),
47 | _ => env::set_var("RUST_LOG", "wireguard_exporter=off"),
48 | },
49 | 1 => env::set_var("RUST_LOG", "wireguard_exporter=debug"),
50 | _ => env::set_var("RUST_LOG", "wireguard_exporter=trace"),
51 | }
52 |
53 | try_main(args).await
54 | }
55 |
56 | async fn try_main(args: Args) -> Result<()> {
57 | tracing_subscriber::fmt::init();
58 |
59 | let aliases = args.aliases();
60 |
61 | let maxminddb_reader = args.geoip_path.as_ref().map_or(None, |path| {
62 | Some(unwrap_or_exit!(maxminddb::Reader::open_readfile(path)))
63 | });
64 |
65 | let running = Arc::new(AtomicBool::new(true));
66 |
67 | info!("Registering metrics...");
68 | let registry = Arc::new(Registry::new());
69 | let mut metrics = unwrap_or_exit!(Metrics::new(®istry, maxminddb_reader));
70 | let scrape_duration = unwrap_or_exit!(IntGauge::new(
71 | "wireguard_scrape_duration_milliseconds",
72 | "Duration in milliseconds of the scrape",
73 | ));
74 |
75 | let scrape_success = unwrap_or_exit!(IntGauge::new(
76 | "wireguard_scrape_success",
77 | "If the scrape was a success"
78 | ));
79 | debug!("Registering scrape metrics...");
80 | unwrap_or_exit!(registry.register(Box::new(scrape_duration.clone())));
81 | unwrap_or_exit!(registry.register(Box::new(scrape_success.clone())));
82 |
83 | info!("Spawning server...");
84 | tokio::spawn(Server::run(
85 | Arc::clone(®istry),
86 | SocketAddr::new(args.listen_address, args.listen_port),
87 | shutdown_signal(Arc::clone(&running)),
88 | ));
89 |
90 | let mut collect_int = tokio::time::interval(Duration::from_secs(args.collect_interval));
91 | while running.load(Ordering::Relaxed) {
92 | info!("Collecting metrics...");
93 | let before = Instant::now();
94 |
95 | debug!("Updating metrics...");
96 | metrics
97 | .update(&WireguardState::scrape(&aliases).await?)
98 | .await;
99 | let after = Instant::now();
100 |
101 | let elapsed = after.duration_since(before);
102 | scrape_duration.set((elapsed.as_secs() * 1000 + elapsed.subsec_millis() as u64) as i64);
103 | scrape_success.set(1);
104 |
105 | debug!("Sleeping...");
106 | collect_int.tick().await;
107 | }
108 | info!("Stopped the exporter");
109 |
110 | Ok(())
111 | }
112 |
113 | async fn shutdown_signal(running: Arc) {
114 | // Wait for the CTRL+C Signal
115 | tokio::signal::ctrl_c()
116 | .await
117 | .expect("Failed to install CTRL+C signal handler");
118 | running.store(false, Ordering::Relaxed);
119 | }
120 |
--------------------------------------------------------------------------------
/src/metrics.rs:
--------------------------------------------------------------------------------
1 | use color_eyre::eyre::Result;
2 | use maxminddb::geoip2;
3 | use prometheus::{IntCounterVec, IntGaugeVec, Opts, Registry};
4 | use time::OffsetDateTime;
5 | use tracing::{debug, trace};
6 |
7 | use crate::wireguard::WireguardState;
8 |
9 | pub struct Metrics {
10 | interfaces_total: IntGaugeVec,
11 | peers_total: IntGaugeVec,
12 | peer_endpoint: IntGaugeVec,
13 | bytes_total: IntCounterVec,
14 | peer_bytes_total: IntCounterVec,
15 | duration_since_latest_handshake: IntGaugeVec,
16 | maxminddb_reader: Option>>,
17 | }
18 |
19 | impl Metrics {
20 | pub fn new(r: &Registry, maxminddb_reader: Option>>) -> Result {
21 | trace!("Metrics::new");
22 |
23 | let interfaces_total = IntGaugeVec::new(
24 | Opts::new("wireguard_interfaces_total", "Total number of interfaces"),
25 | &[],
26 | )?;
27 |
28 | let peers_total = IntGaugeVec::new(
29 | Opts::new(
30 | "wireguard_peers_total",
31 | "Total number of peers per interfaces",
32 | ),
33 | &["interface"],
34 | )?;
35 |
36 | let peer_endpoint = IntGaugeVec::new(
37 | Opts::new("wireguard_peer_endpoint", "Peers info. static value"),
38 | match maxminddb_reader {
39 | Some(_) => &[
40 | "interface",
41 | "endpoint_ip",
42 | "endpoint_country",
43 | "peer",
44 | "alias",
45 | ],
46 | None => &["interface", "endpoint_ip", "peer", "alias"],
47 | },
48 | )?;
49 |
50 | let bytes_total = IntCounterVec::new(
51 | Opts::new(
52 | "wireguard_bytes_total",
53 | "Total number of bytes per direction per interface",
54 | ),
55 | &["interface", "direction"],
56 | )?;
57 |
58 | let peer_bytes_total = IntCounterVec::new(
59 | Opts::new(
60 | "wireguard_peer_bytes_total",
61 | "Total number of bytes per direction for a peer",
62 | ),
63 | &["interface", "peer", "direction", "alias"],
64 | )?;
65 |
66 | let duration_since_latest_handshake = IntGaugeVec::new(
67 | Opts::new(
68 | "wireguard_duration_since_latest_handshake",
69 | "Duration in milliseconds since latest handshake for a peer",
70 | ),
71 | &["interface", "peer", "alias"],
72 | )?;
73 |
74 | debug!("Registering wireguard metrics");
75 | r.register(Box::new(interfaces_total.clone()))?;
76 | r.register(Box::new(peers_total.clone()))?;
77 | r.register(Box::new(peer_endpoint.clone()))?;
78 | r.register(Box::new(bytes_total.clone()))?;
79 | r.register(Box::new(peer_bytes_total.clone()))?;
80 | r.register(Box::new(duration_since_latest_handshake.clone()))?;
81 |
82 | Ok(Self {
83 | interfaces_total,
84 | bytes_total,
85 | peers_total,
86 | peer_endpoint,
87 | peer_bytes_total,
88 | duration_since_latest_handshake,
89 | maxminddb_reader,
90 | })
91 | }
92 |
93 | pub async fn update(&mut self, state: &WireguardState) {
94 | let it = self.interfaces_total.with_label_values(&[]);
95 | it.set(state.interfaces.len() as i64);
96 |
97 | for (i, iface) in state.interfaces.iter().enumerate() {
98 | let pt = self.peers_total.with_label_values(&[iface]);
99 | pt.set(
100 | state
101 | .peers
102 | .iter()
103 | .filter(|peer| peer.interface == i)
104 | .count() as i64,
105 | );
106 |
107 | let btt = self.bytes_total.with_label_values(&[iface, "tx"]);
108 | let diff = state
109 | .peers
110 | .iter()
111 | .filter(|peer| peer.interface == i)
112 | .map(|peer| peer.tx_bytes)
113 | .sum::()
114 | - btt.get();
115 | btt.inc_by(diff);
116 |
117 | let btr = self.bytes_total.with_label_values(&[iface, "rx"]);
118 | let diff = state
119 | .peers
120 | .iter()
121 | .filter(|peer| peer.interface == i)
122 | .map(|peer| peer.rx_bytes)
123 | .sum::()
124 | - btr.get();
125 | btr.inc_by(diff);
126 | }
127 |
128 | self.peer_endpoint.reset();
129 |
130 | for p in &state.peers {
131 | assert!(p.interface < state.interfaces.len());
132 |
133 | if let Some(endpoint) = p.endpoint {
134 | match &self.maxminddb_reader {
135 | Some(reader) => {
136 | let endpoint_country = match reader.lookup::(endpoint.ip())
137 | {
138 | Ok(reader_response) => {
139 | reader_response.country.map_or_else(String::new, |c| {
140 | c.iso_code
141 | .map(|code| code.to_string())
142 | .unwrap_or_else(String::new)
143 | })
144 | }
145 | _ => String::new(),
146 | };
147 |
148 | self.peer_endpoint.with_label_values(&[
149 | &state.interfaces[p.interface],
150 | &endpoint.ip().to_string(),
151 | &endpoint_country.to_string(),
152 | &p.pubkey,
153 | &p.alias
154 | .as_ref()
155 | .map(ToOwned::to_owned)
156 | .unwrap_or_else(String::new),
157 | ])
158 | }
159 | None => self.peer_endpoint.with_label_values(&[
160 | &state.interfaces[p.interface],
161 | &endpoint.ip().to_string(),
162 | &p.pubkey,
163 | &p.alias
164 | .as_ref()
165 | .map(ToOwned::to_owned)
166 | .unwrap_or_else(String::new),
167 | ]),
168 | }
169 | .set(1);
170 | };
171 |
172 | let pbtt = self.peer_bytes_total.with_label_values(&[
173 | &state.interfaces[p.interface],
174 | &p.pubkey,
175 | "tx",
176 | &p.alias
177 | .as_ref()
178 | .map(ToOwned::to_owned)
179 | .unwrap_or_else(String::new),
180 | ]);
181 | let diff = p.tx_bytes - pbtt.get();
182 | pbtt.inc_by(diff);
183 |
184 | let pbtr = self.peer_bytes_total.with_label_values(&[
185 | &state.interfaces[p.interface],
186 | &p.pubkey,
187 | "rx",
188 | &p.alias
189 | .as_ref()
190 | .map(ToOwned::to_owned)
191 | .unwrap_or_else(String::new),
192 | ]);
193 | let diff = p.rx_bytes - pbtr.get();
194 | pbtr.inc_by(diff);
195 |
196 | if let Some(latest_hs_ts) = p.handshake_timestamp {
197 | let now = OffsetDateTime::now_local()
198 | .expect("Failed to get local offset time")
199 | .unix_timestamp();
200 |
201 | let elapsed = now - latest_hs_ts as i64;
202 |
203 | self.duration_since_latest_handshake
204 | .with_label_values(&[
205 | &state.interfaces[p.interface],
206 | &p.pubkey,
207 | &p.alias
208 | .as_ref()
209 | .map(ToOwned::to_owned)
210 | .unwrap_or_else(String::new),
211 | ])
212 | .set(elapsed * 1000);
213 | }
214 | }
215 | }
216 | }
217 |
--------------------------------------------------------------------------------
/src/wireguard.rs:
--------------------------------------------------------------------------------
1 | use color_eyre::eyre::{Result, WrapErr};
2 | use std::{collections::HashMap, net::SocketAddr, str::FromStr};
3 | use tokio::process::Command;
4 |
5 | pub async fn wg_show_dump() -> Result {
6 | String::from_utf8(
7 | Command::new("wg")
8 | .args(&["show", "all", "dump"])
9 | .output()
10 | .await
11 | .wrap_err("Failed to run 'wg show'")?
12 | .stdout,
13 | )
14 | .wrap_err("Failed wg show output to valid UTF-8")
15 | }
16 |
17 | #[derive(Debug)]
18 | pub struct WireguardState {
19 | pub interfaces: Vec,
20 | pub peers: Vec,
21 | }
22 |
23 | impl WireguardState {
24 | pub async fn scrape(aliases: &HashMap<&str, &str>) -> Result {
25 | let mut peers = Vec::with_capacity(32); // Picked by fair dice roll
26 | let mut interfaces = Vec::new();
27 |
28 | for line in wg_show_dump().await?.lines() {
29 | // Peer lines:
30 | // INT PUBKEY PSK ENDPOINT ALLOWED-IPS HANDSHAKE TX RX KA
31 | //
32 | // Interface Lines:
33 | // INT PRIVKEY PUBKEY PORT FWMARK
34 | let mut segs = line.split('\t');
35 | let f1 = segs.next();
36 | let f2 = segs.next();
37 | let f3 = segs.next();
38 | let f4 = segs.next();
39 | let f5 = segs.next();
40 | let f6 = segs.next();
41 | let f7 = segs.next();
42 | let f8 = segs.next();
43 | let f9 = segs.next();
44 |
45 | match (f1, f2, f3, f4, f5, f6, f7, f8, f9) {
46 | (
47 | Some(_iface),
48 | Some(pubkey),
49 | Some(_psk),
50 | Some(endpoint),
51 | Some(_allowed_ips),
52 | Some(handshake_ts),
53 | Some(tx_bytes),
54 | Some(rx_bytes),
55 | Some(_keepalives),
56 | ) => {
57 | let ts = handshake_ts.parse()?;
58 | peers.push(Peer {
59 | interface: interfaces.len() - 1,
60 | alias: aliases.get(pubkey).map(|&s| s.into()),
61 | pubkey: pubkey.into(),
62 | endpoint: SocketAddr::from_str(endpoint).ok(),
63 | handshake_timestamp: if ts == 0 { None } else { Some(ts) },
64 | tx_bytes: tx_bytes.parse()?,
65 | rx_bytes: rx_bytes.parse()?,
66 | });
67 | }
68 | (
69 | Some(iface),
70 | Some(_privkey),
71 | Some(_pubkey),
72 | Some(_port),
73 | Some(_fwmark),
74 | None,
75 | None,
76 | None,
77 | None,
78 | ) => interfaces.push(iface.into()),
79 | _ => todo!("return Err on invalid line from parse_line"),
80 | }
81 | }
82 |
83 | Ok(Self { interfaces, peers })
84 | }
85 | }
86 |
87 | #[derive(Clone, PartialEq, Debug, Default)]
88 | pub struct Peer {
89 | pub pubkey: String,
90 | pub endpoint: Option,
91 | pub alias: Option,
92 | pub interface: usize,
93 | pub tx_bytes: u64,
94 | pub rx_bytes: u64,
95 | pub handshake_timestamp: Option,
96 | }
97 |
--------------------------------------------------------------------------------