diff options
| author | diogo464 <[email protected]> | 2026-02-17 14:47:15 +0000 |
|---|---|---|
| committer | diogo464 <[email protected]> | 2026-02-17 14:47:15 +0000 |
| commit | a0a5cb22ecf4c1760a3eadaea5ed2c0a55aa62c7 (patch) | |
| tree | 880a2ca8992d4e621e5531b37f9a79afed9c93fc | |
| parent | 0c6a34024786d6117c238a0164218a4e718178f0 (diff) | |
add wireguard-show binary and optional handshake timestamps
| -rw-r--r-- | Cargo.toml | 4 | ||||
| -rw-r--r-- | bin/wireguard-show.rs | 80 | ||||
| -rw-r--r-- | src/view.rs | 33 |
3 files changed, 107 insertions, 10 deletions
| @@ -19,3 +19,7 @@ rtnetlink = "=0.20.0" | |||
| 19 | serde = "1.0.195" | 19 | serde = "1.0.195" |
| 20 | tokio = { version = "1.35.1", features = ["full"] } | 20 | tokio = { version = "1.35.1", features = ["full"] } |
| 21 | tracing = "0.1.40" | 21 | tracing = "0.1.40" |
| 22 | |||
| 23 | [[bin]] | ||
| 24 | name = "wireguard-show" | ||
| 25 | path = "bin/wireguard-show.rs" | ||
diff --git a/bin/wireguard-show.rs b/bin/wireguard-show.rs new file mode 100644 index 0000000..17476d6 --- /dev/null +++ b/bin/wireguard-show.rs | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | use anyhow::Result; | ||
| 2 | use wireguard::WireGuard; | ||
| 3 | |||
| 4 | #[tokio::main] | ||
| 5 | async fn main() -> Result<()> { | ||
| 6 | let mut wireguard = WireGuard::new().await?; | ||
| 7 | let devices = wireguard.view_devices().await?; | ||
| 8 | |||
| 9 | if devices.is_empty() { | ||
| 10 | println!("no wireguard devices found"); | ||
| 11 | return Ok(()); | ||
| 12 | } | ||
| 13 | |||
| 14 | for device in devices { | ||
| 15 | println!("device: {}", device.name); | ||
| 16 | println!(" ifindex: {}", device.ifindex); | ||
| 17 | println!(" private_key: {}", format_optional_key(device.private_key)); | ||
| 18 | println!(" public_key: {}", format_optional_key(device.public_key)); | ||
| 19 | println!(" listen_port: {}", device.listen_port); | ||
| 20 | println!(" fwmark: {}", device.fwmark); | ||
| 21 | println!(" peers: {}", device.peers.len()); | ||
| 22 | |||
| 23 | for (index, peer) in device.peers.iter().enumerate() { | ||
| 24 | println!(" peer {}:", index + 1); | ||
| 25 | println!(" public_key: {}", peer.public_key); | ||
| 26 | println!( | ||
| 27 | " preshared_key: {}", | ||
| 28 | format_optional_key(peer.preshared_key) | ||
| 29 | ); | ||
| 30 | println!( | ||
| 31 | " endpoint: {}", | ||
| 32 | peer.endpoint | ||
| 33 | .map(|endpoint| endpoint.to_string()) | ||
| 34 | .unwrap_or_else(|| "none".to_string()) | ||
| 35 | ); | ||
| 36 | println!( | ||
| 37 | " persistent_keepalive: {}", | ||
| 38 | peer.persistent_keepalive | ||
| 39 | .map(|keepalive| keepalive.to_string()) | ||
| 40 | .unwrap_or_else(|| "none".to_string()) | ||
| 41 | ); | ||
| 42 | println!( | ||
| 43 | " last_handshake: {}", | ||
| 44 | format_duration(peer.last_handshake) | ||
| 45 | ); | ||
| 46 | println!(" rx_bytes: {}", peer.rx_bytes); | ||
| 47 | println!(" tx_bytes: {}", peer.tx_bytes); | ||
| 48 | if peer.allowed_ips.is_empty() { | ||
| 49 | println!(" allowed_ips: none"); | ||
| 50 | } else { | ||
| 51 | let allowed_ips = peer | ||
| 52 | .allowed_ips | ||
| 53 | .iter() | ||
| 54 | .map(|ip| ip.to_string()) | ||
| 55 | .collect::<Vec<_>>() | ||
| 56 | .join(", "); | ||
| 57 | println!(" allowed_ips: {}", allowed_ips); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | println!(); | ||
| 62 | } | ||
| 63 | |||
| 64 | Ok(()) | ||
| 65 | } | ||
| 66 | |||
| 67 | fn format_optional_key(key: Option<wireguard::Key>) -> String { | ||
| 68 | key.map(|value| value.to_string()) | ||
| 69 | .unwrap_or_else(|| "none".to_string()) | ||
| 70 | } | ||
| 71 | |||
| 72 | fn format_duration(time: Option<std::time::SystemTime>) -> String { | ||
| 73 | match time { | ||
| 74 | Some(time) => match time.duration_since(std::time::UNIX_EPOCH) { | ||
| 75 | Ok(duration) => format!("{}.{}", duration.as_secs(), duration.subsec_nanos()), | ||
| 76 | Err(_) => "before-epoch".to_string(), | ||
| 77 | }, | ||
| 78 | None => "none".to_string(), | ||
| 79 | } | ||
| 80 | } | ||
diff --git a/src/view.rs b/src/view.rs index c0bd807..666f5d4 100644 --- a/src/view.rs +++ b/src/view.rs | |||
| @@ -28,7 +28,7 @@ pub struct PeerView { | |||
| 28 | pub preshared_key: Option<Key>, | 28 | pub preshared_key: Option<Key>, |
| 29 | pub endpoint: Option<SocketAddr>, | 29 | pub endpoint: Option<SocketAddr>, |
| 30 | pub persistent_keepalive: Option<u16>, | 30 | pub persistent_keepalive: Option<u16>, |
| 31 | pub last_handshake: SystemTime, | 31 | pub last_handshake: Option<SystemTime>, |
| 32 | pub rx_bytes: u64, | 32 | pub rx_bytes: u64, |
| 33 | pub tx_bytes: u64, | 33 | pub tx_bytes: u64, |
| 34 | pub allowed_ips: Vec<IpNet>, | 34 | pub allowed_ips: Vec<IpNet>, |
| @@ -103,20 +103,33 @@ fn peer_from_wg_peer(wg_peer: WireguardPeer) -> Result<PeerView> { | |||
| 103 | } | 103 | } |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | let last_handshake = last_handshake.ok_or_else(|| Error::message("missing last_handshake"))?; | ||
| 107 | let rx_bytes = rx_bytes.ok_or_else(|| Error::message("missing rx_bytes"))?; | ||
| 108 | let tx_bytes = tx_bytes.ok_or_else(|| Error::message("missing tx_bytes"))?; | ||
| 109 | |||
| 110 | let handshake_is_zero = last_handshake.seconds == 0 && last_handshake.nano_seconds == 0; | ||
| 111 | let last_handshake = if handshake_is_zero && (rx_bytes == 0 || tx_bytes == 0) { | ||
| 112 | None | ||
| 113 | } else { | ||
| 114 | let duration = Duration::new( | ||
| 115 | last_handshake.seconds as u64, | ||
| 116 | last_handshake.nano_seconds as u32, | ||
| 117 | ); | ||
| 118 | Some( | ||
| 119 | SystemTime::UNIX_EPOCH | ||
| 120 | .checked_add(duration) | ||
| 121 | .ok_or_else(|| Error::message("invalid last_handshake"))?, | ||
| 122 | ) | ||
| 123 | }; | ||
| 124 | |||
| 106 | Ok(PeerView { | 125 | Ok(PeerView { |
| 107 | public_key: public_key.ok_or_else(|| Error::message("missing public_key"))?, | 126 | public_key: public_key.ok_or_else(|| Error::message("missing public_key"))?, |
| 108 | preshared_key, | 127 | preshared_key, |
| 109 | endpoint, | 128 | endpoint, |
| 110 | persistent_keepalive, | 129 | persistent_keepalive, |
| 111 | last_handshake: last_handshake | 130 | last_handshake, |
| 112 | .map(|ts| { | 131 | rx_bytes, |
| 113 | SystemTime::UNIX_EPOCH | 132 | tx_bytes, |
| 114 | .checked_add(Duration::new(ts.seconds as u64, ts.nano_seconds as u32)) | ||
| 115 | .unwrap() | ||
| 116 | }) | ||
| 117 | .ok_or_else(|| Error::message("missing last_handshake"))?, | ||
| 118 | rx_bytes: rx_bytes.ok_or_else(|| Error::message("missing rx_bytes"))?, | ||
| 119 | tx_bytes: tx_bytes.ok_or_else(|| Error::message("missing tx_bytes"))?, | ||
| 120 | allowed_ips, | 133 | allowed_ips, |
| 121 | }) | 134 | }) |
| 122 | } | 135 | } |
