1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
use std::{
net::SocketAddr,
time::{Duration, SystemTime},
};
use ipnet::IpNet;
use netlink_packet_wireguard::{
WireguardAllowedIp, WireguardAllowedIpAttr, WireguardAttribute, WireguardMessage,
WireguardPeer, WireguardPeerAttribute,
};
use super::{Error, Key, Result};
#[derive(Debug, Clone)]
pub struct DeviceView {
pub name: String,
pub ifindex: u32,
pub private_key: Option<Key>,
pub public_key: Option<Key>,
pub listen_port: u16,
pub fwmark: u32,
pub peers: Vec<PeerView>,
}
#[derive(Debug, Clone)]
pub struct PeerView {
pub public_key: Key,
pub preshared_key: Option<Key>,
pub endpoint: Option<SocketAddr>,
pub persistent_keepalive: Option<u16>,
pub last_handshake: SystemTime,
pub rx_bytes: u64,
pub tx_bytes: u64,
pub allowed_ips: Vec<IpNet>,
}
pub(super) fn device_view_from_payload(wg: WireguardMessage) -> Result<DeviceView> {
let mut if_index = None;
let mut if_name = None;
let mut private_key = None;
let mut public_key = None;
let mut listen_port = None;
let mut fwmark = None;
let mut peers = None;
for attr in wg.attributes {
match attr {
WireguardAttribute::IfIndex(v) => if_index = Some(v),
WireguardAttribute::IfName(v) => if_name = Some(v),
WireguardAttribute::PrivateKey(v) => private_key = Some(Key::from(v)),
WireguardAttribute::PublicKey(v) => public_key = Some(Key::from(v)),
WireguardAttribute::ListenPort(v) => listen_port = Some(v),
WireguardAttribute::Fwmark(v) => fwmark = Some(v),
WireguardAttribute::Peers(v) => peers = Some(peers_from_wg_peers(v)?),
_ => {}
}
}
Ok(DeviceView {
name: if_name.ok_or_else(|| Error::message("missing if_name"))?,
ifindex: if_index.ok_or_else(|| Error::message("missing if_index"))?,
private_key,
public_key,
listen_port: listen_port.ok_or_else(|| Error::message("missing listen_port"))?,
fwmark: fwmark.ok_or_else(|| Error::message("missing fwmark"))?,
peers: peers.unwrap_or_default(),
})
}
fn peers_from_wg_peers(wg_peers: Vec<WireguardPeer>) -> Result<Vec<PeerView>> {
let mut peers = Vec::with_capacity(wg_peers.len());
for wg_peer in wg_peers {
peers.push(peer_from_wg_peer(wg_peer)?);
}
Ok(peers)
}
fn peer_from_wg_peer(wg_peer: WireguardPeer) -> Result<PeerView> {
let mut public_key = None;
let mut preshared_key = None;
let mut endpoint = None;
let mut persistent_keepalive = None;
let mut last_handshake = None;
let mut rx_bytes = None;
let mut tx_bytes = None;
let mut allowed_ips = Vec::default();
for attr in wg_peer.iter() {
match attr {
WireguardPeerAttribute::PublicKey(v) => public_key = Some(Key::from(v)),
WireguardPeerAttribute::PresharedKey(v) => preshared_key = Some(Key::from(v)),
WireguardPeerAttribute::Endpoint(v) => endpoint = Some(*v),
WireguardPeerAttribute::PersistentKeepalive(v) => persistent_keepalive = Some(*v),
WireguardPeerAttribute::LastHandshake(v) => last_handshake = Some(*v),
WireguardPeerAttribute::RxBytes(v) => rx_bytes = Some(*v),
WireguardPeerAttribute::TxBytes(v) => tx_bytes = Some(*v),
WireguardPeerAttribute::AllowedIps(v) => {
for ip in v {
allowed_ips.push(ipnet_from_wg(ip)?);
}
}
_ => {}
}
}
Ok(PeerView {
public_key: public_key.ok_or_else(|| Error::message("missing public_key"))?,
preshared_key,
endpoint,
persistent_keepalive,
last_handshake: last_handshake
.map(|ts| SystemTime::now() - Duration::new(ts.seconds as u64, ts.nano_seconds as u32))
.ok_or_else(|| Error::message("missing last_handshake"))?,
rx_bytes: rx_bytes.ok_or_else(|| Error::message("missing rx_bytes"))?,
tx_bytes: tx_bytes.ok_or_else(|| Error::message("missing tx_bytes"))?,
allowed_ips,
})
}
fn ipnet_from_wg(wg: &WireguardAllowedIp) -> Result<IpNet> {
let mut ip = None;
let mut prefix = None;
for attr in wg.iter() {
match attr {
WireguardAllowedIpAttr::IpAddr(v) => ip = Some(*v),
WireguardAllowedIpAttr::Cidr(v) => prefix = Some(*v),
_ => {}
}
}
Ok(IpNet::new(
ip.ok_or_else(|| Error::message("missing ip"))?,
prefix.ok_or_else(|| Error::message("missing prefix"))?,
)
.map_err(|e| Error::with_message(e, "invalid ipnet"))?)
}
|