1use super::state::{ParsePeerState, ParseState};
2use crate::get;
3use crate::get::{DeviceBuilderError, ParseAllowedIpError, PeerBuilderError};
4use crate::xplatform::protocol::{GetKey, ParseKeyError};
5use std::net::AddrParseError;
6use std::num::ParseIntError;
7use std::{str::FromStr, time::Duration};
8use take_until::TakeUntilExt;
9use thiserror::Error;
10
11#[derive(Error, Debug)]
12pub enum ParseGetResponseError {
13 #[error("Failed to read line from socket: `{0}`")]
14 ReadLineIoError(#[source] std::io::Error),
15
16 #[error("Received non-zero error number in response: `{0}`")]
17 ServerError(String),
18 #[error("Received incomplete response")]
19 IncompleteResponse,
20 #[error("Received empty response")]
21 EmptyResponse,
22 #[error("Get responses require an empty line. None found.")]
23 MissingEndOfResponseNewline,
24
25 #[error("Encountered unknown key `{0}`")]
26 UnknownKey(String),
27 #[error("Missing value for key `{0}`")]
28 MissingValueForKey(GetKey),
29
30 #[error("{0}")]
31 InternalBuildGetDeviceError(DeviceBuilderError),
32 #[error("{0}")]
33 InternalBuildGetPeerError(PeerBuilderError),
34
35 #[error("Invalid private_key")]
36 InvalidPrivateKey,
37 #[error("Invalid public_key: `{0}`")]
38 InvalidPublicKey(String),
39 #[error("Invalid preshared_key: `{0}`")]
40 InvalidPresharedKey(String),
41 #[error("{0}")]
42 InvalidListenPort(#[source] ParseIntError),
43 #[error("{0}")]
44 InvalidFwmark(#[source] ParseIntError),
45 #[error("{0}")]
46 InvalidEndpoint(#[source] AddrParseError),
47 #[error("{0}")]
48 InvalidPersistentKeepaliveInterval(#[source] ParseIntError),
49 #[error(transparent)]
50 InvalidAllowedIp(#[from] ParseAllowedIpError),
51 #[error("{0}")]
52 InvalidRxBytes(#[source] ParseIntError),
53 #[error("{0}")]
54 InvalidTxBytes(#[source] ParseIntError),
55 #[error("{0}")]
56 InvalidLastHandhsakeTimeSec(#[source] ParseIntError),
57 #[error("{0}")]
58 InvalidLastHandhsakeTimeNsec(#[source] ParseIntError),
59 #[error("{0}")]
60 InvalidProtocolVersion(#[source] ParseIntError),
61
62 #[error("Expected `private_key=...` or `listen_port=...`. Observed key: `{0}`")]
64 InvalidStartOfResponse(GetKey),
65 #[error("private_key was ambiguously specified twice in response.")]
66 AmbiguousPrivateKey,
67 #[error("Observed peer-level key `{0}` before public_key was specified")]
68 PeerLevelKeyBeforePublicKey(GetKey),
69 #[error("Observed interface-level key `{0}` after a peer-level key")]
70 InterfaceLevelKeyAfterPeerLevelKey(GetKey),
71 #[error("Observed key after end of response")]
72 DataAfterEndOfResponse(GetKey),
73}
74
75impl From<ParseKeyError> for ParseGetResponseError {
76 fn from(err: ParseKeyError) -> Self {
77 Self::UnknownKey(err.unknown_key)
78 }
79}
80
81pub fn parse(
82 lines: impl Iterator<Item = Result<String, std::io::Error>>,
83) -> Result<get::Device, ParseGetResponseError> {
84 let initial_state = {
85 let mut device_builder = get::DeviceBuilder::default();
86 device_builder.ifindex(0);
87 device_builder.ifname("".to_string());
88 device_builder.fwmark(0);
89 ParseState::Initial(device_builder)
90 };
91 let parse_state = lines
92 .take_until(|result| matches!(result.as_ref().map(String::as_str), Ok("")))
99 .try_fold(initial_state, process_line)?;
100
101 match parse_state {
102 ParseState::Initial(_) => Err(ParseGetResponseError::EmptyResponse),
103 ParseState::InterfaceLevelKeys(_) | ParseState::PeerLevelKeys(_) => {
104 Err(ParseGetResponseError::MissingEndOfResponseNewline)
105 }
106 ParseState::Finish(device) => Ok(device),
107 }
108}
109
110fn process_line(
111 state: ParseState,
112 line: std::io::Result<String>,
113) -> Result<ParseState, ParseGetResponseError> {
114 type ParseErr = ParseGetResponseError;
115
116 let line = line.map_err(ParseErr::ReadLineIoError)?;
117
118 if line.is_empty() {
120 return match state {
121 ParseState::Initial(_) => Err(ParseGetResponseError::IncompleteResponse),
122 ParseState::InterfaceLevelKeys(device_builder) => device_builder
123 .build()
124 .map_err(ParseGetResponseError::InternalBuildGetDeviceError)
125 .map(ParseState::Finish),
126 ParseState::PeerLevelKeys(state) => Ok(ParseState::Finish(state.coalesce())),
127 ParseState::Finish(device) => Ok(ParseState::Finish(device)),
128 };
129 }
130
131 let (key, raw_val) = {
132 let mut tokens = line.trim().splitn(2, '=');
133
134 let raw_key = tokens.next().unwrap();
136 let key = GetKey::from_str(raw_key)?;
137
138 let raw_val = match tokens.next() {
139 Some(val) => val,
140 None => return Err(ParseErr::MissingValueForKey(key)),
141 };
142
143 (key, raw_val)
144 };
145
146 match state {
147 ParseState::Initial(mut device_builder) => match key {
148 GetKey::PrivateKey => {
149 let private_key: [u8; 32] = hex::decode(raw_val)
150 .ok()
151 .and_then(|buf| parse_device_key(&buf))
152 .ok_or(ParseErr::InvalidPrivateKey)?;
153 device_builder.private_key(Some(private_key));
154 Ok(ParseState::InterfaceLevelKeys(device_builder))
155 }
156 GetKey::ListenPort => {
157 let listen_port = raw_val.parse().map_err(ParseErr::InvalidListenPort)?;
158 device_builder.listen_port(listen_port);
159 Ok(ParseState::InterfaceLevelKeys(device_builder))
160 }
161 GetKey::Errno => match raw_val {
162 "0" => Ok(ParseState::Initial(device_builder)),
163 _ => Err(ParseErr::ServerError(raw_val.to_string())),
164 },
165 _ => Err(ParseErr::InvalidStartOfResponse(key)),
166 },
167
168 ParseState::InterfaceLevelKeys(mut device_builder) => match key {
169 GetKey::PrivateKey => Err(ParseErr::AmbiguousPrivateKey),
170 GetKey::ListenPort => {
171 let listen_port = raw_val.parse().map_err(ParseErr::InvalidListenPort)?;
172 device_builder.listen_port(listen_port);
173 Ok(ParseState::InterfaceLevelKeys(device_builder))
174 }
175 GetKey::Fwmark => {
176 let fwmark = raw_val.parse().map_err(ParseErr::InvalidFwmark)?;
177 device_builder.fwmark(fwmark);
178 Ok(ParseState::InterfaceLevelKeys(device_builder))
179 }
180
181 GetKey::PublicKey => {
184 let mut peer_builder = get::PeerBuilder::default();
185 let public_key = hex::decode(raw_val)
186 .ok()
187 .and_then(|buf| parse_device_key(&buf))
188 .ok_or_else(|| ParseErr::InvalidPublicKey(raw_val.to_string()))?;
189 peer_builder.public_key(public_key);
190 peer_builder.preshared_key([0u8; 32]);
191 peer_builder.persistent_keepalive_interval(0);
192 peer_builder.tx_bytes(0);
193 peer_builder.rx_bytes(0);
194 peer_builder.protocol_version(1);
195 Ok(ParseState::PeerLevelKeys(Box::new(ParsePeerState {
196 device_builder,
197 peers: vec![],
198 peer_builder,
199 allowed_ips: vec![],
200 last_handshake_time_sec: None,
201 last_handshake_time_nsec: None,
202 })))
203 }
204
205 GetKey::PresharedKey
206 | GetKey::Endpoint
207 | GetKey::PersistentKeepaliveInterval
208 | GetKey::AllowedIp
209 | GetKey::RxBytes
210 | GetKey::TxBytes
211 | GetKey::LastHandshakeTimeSec
212 | GetKey::LastHandshakeTimeNsec
213 | GetKey::ProtocolVersion => Err(ParseErr::PeerLevelKeyBeforePublicKey(key)),
214
215 GetKey::Errno => match raw_val {
216 "0" => Ok(ParseState::InterfaceLevelKeys(device_builder)),
217 _ => Err(ParseErr::ServerError(raw_val.to_string())),
218 },
219 },
220
221 ParseState::PeerLevelKeys(mut state) => match key {
222 GetKey::PrivateKey | GetKey::ListenPort | GetKey::Fwmark => {
223 Err(ParseErr::InterfaceLevelKeyAfterPeerLevelKey(key))
224 }
225
226 GetKey::PublicKey => {
227 state.peer_builder.allowed_ips(state.allowed_ips);
228 let last_handshake_time = Duration::new(
229 state.last_handshake_time_sec.unwrap_or(0),
230 state.last_handshake_time_nsec.unwrap_or(0),
231 );
232 state.peer_builder.last_handshake_time(last_handshake_time);
233 let peer = state
234 .peer_builder
235 .build()
236 .map_err(ParseErr::InternalBuildGetPeerError)?;
237 state.peers.push(peer);
238
239 state.peer_builder = get::PeerBuilder::default();
240 let public_key = hex::decode(raw_val)
241 .ok()
242 .and_then(|buf| parse_device_key(&buf))
243 .ok_or_else(|| ParseErr::InvalidPublicKey(raw_val.to_string()))?;
244 state.peer_builder.public_key(public_key);
245 state.peer_builder.preshared_key([0u8; 32]);
246 state.peer_builder.persistent_keepalive_interval(0);
247 state.peer_builder.tx_bytes(0);
248 state.peer_builder.rx_bytes(0);
249 state.peer_builder.protocol_version(1);
250 state.allowed_ips = vec![];
251
252 Ok(ParseState::PeerLevelKeys(state))
253 }
254 GetKey::PresharedKey => {
255 let preshared_key = hex::decode(raw_val)
256 .ok()
257 .and_then(|buf| parse_device_key(&buf))
258 .ok_or_else(|| ParseErr::InvalidPresharedKey(raw_val.to_string()))?;
259 state.peer_builder.preshared_key(preshared_key);
260 Ok(ParseState::PeerLevelKeys(state))
261 }
262 GetKey::Endpoint => {
263 let endpoint = raw_val.parse().map_err(ParseErr::InvalidEndpoint)?;
264 state.peer_builder.endpoint(Some(endpoint));
265 Ok(ParseState::PeerLevelKeys(state))
266 }
267 GetKey::PersistentKeepaliveInterval => {
268 let interval = raw_val
269 .parse()
270 .map_err(ParseErr::InvalidPersistentKeepaliveInterval)?;
271 state.peer_builder.persistent_keepalive_interval(interval);
272 Ok(ParseState::PeerLevelKeys(state))
273 }
274 GetKey::AllowedIp => {
275 let allowed_ip: get::AllowedIp = raw_val.parse()?;
276 state.allowed_ips.push(allowed_ip);
277 Ok(ParseState::PeerLevelKeys(state))
278 }
279 GetKey::RxBytes => {
280 let rx_bytes = raw_val.parse().map_err(ParseErr::InvalidRxBytes)?;
281 state.peer_builder.rx_bytes(rx_bytes);
282 Ok(ParseState::PeerLevelKeys(state))
283 }
284 GetKey::TxBytes => {
285 let tx_bytes = raw_val.parse().map_err(ParseErr::InvalidTxBytes)?;
286 state.peer_builder.tx_bytes(tx_bytes);
287 Ok(ParseState::PeerLevelKeys(state))
288 }
289 GetKey::LastHandshakeTimeSec => {
290 let sec = raw_val
291 .parse()
292 .map_err(ParseErr::InvalidLastHandhsakeTimeSec)?;
293 state.last_handshake_time_sec = Some(sec);
294 Ok(ParseState::PeerLevelKeys(state))
295 }
296 GetKey::LastHandshakeTimeNsec => {
297 let nsec = raw_val
298 .parse()
299 .map_err(ParseErr::InvalidLastHandhsakeTimeNsec)?;
300 state.last_handshake_time_nsec = Some(nsec);
301 Ok(ParseState::PeerLevelKeys(state))
302 }
303 GetKey::ProtocolVersion => {
304 let protocol_version = raw_val.parse().map_err(ParseErr::InvalidProtocolVersion)?;
305 state.peer_builder.protocol_version(protocol_version);
306 Ok(ParseState::PeerLevelKeys(state))
307 }
308 GetKey::Errno => match raw_val {
309 "0" => Ok(ParseState::PeerLevelKeys(state)),
310 _ => Err(ParseErr::ServerError(raw_val.to_string())),
311 },
312 },
313
314 ParseState::Finish(_) => Err(ParseErr::DataAfterEndOfResponse(key)),
315 }
316}
317
318pub fn parse_device_key(buf: &[u8]) -> Option<[u8; 32]> {
320 if buf.len() != 32 {
321 return None;
322 }
323
324 let mut key = [0u8; 32];
325 key.copy_from_slice(buf);
326 Some(key)
327}
328
329#[cfg(test)]
330mod tests {
331 use super::{parse, parse_device_key};
332 use crate::get;
333 use std::time::Duration;
334
335 #[test]
336 fn parse_basic() -> anyhow::Result<()> {
337 let response = "\
338 private_key=18aa10c05a531f5c537a18426b376387fc2cbd701ae1b9b4271e327aaade9d4f\n\
339 listen_port=56137\n\
340 public_key=913ea0e20e28c12b5c5f5a858b93a05e686dc3ce524e16f3143bbb1023679751\n\
341 preshared_key=0000000000000000000000000000000000000000000000000000000000000000\n\
342 protocol_version=1\n\
343 endpoint=192.168.64.73:51820\n\
344 last_handshake_time_sec=1590459201\n\
345 last_handshake_time_nsec=283546000\n\
346 tx_bytes=824\n\
347 rx_bytes=696\n\
348 persistent_keepalive_interval=110\n\
349 allowed_ip=10.24.24.3/32\n\
350 errno=0\n\
351 \n";
352 let expected = get::Device {
353 ifindex: 0,
354 ifname: "".to_string(),
355 private_key: parse_device_key(&base64::decode(
356 "GKoQwFpTH1xTehhCazdjh/wsvXAa4bm0Jx4yeqrenU8=",
357 )?),
358 public_key: None,
359 listen_port: 56137,
360 fwmark: 0,
361 peers: vec![get::Peer {
362 public_key: parse_device_key(&base64::decode(
363 "kT6g4g4owStcX1qFi5OgXmhtw85SThbzFDu7ECNnl1E=",
364 )?)
365 .unwrap(),
366 preshared_key: [0u8; 32],
367 endpoint: Some("192.168.64.73:51820".parse()?),
368 last_handshake_time: Duration::new(1_590_459_201, 283_546_000),
369 tx_bytes: 824,
370 rx_bytes: 696,
371 persistent_keepalive_interval: 110,
372 allowed_ips: vec![get::AllowedIp {
373 family: 2,
374 ipaddr: "10.24.24.3".parse()?,
375 cidr_mask: 32,
376 }],
377 protocol_version: 1,
378 }],
379 };
380
381 let actual = parse(response.lines().map(String::from).map(Ok))?;
382 assert_eq!(actual, expected);
383
384 Ok(())
385 }
386
387 #[test]
388 fn parse_device_with_no_peers() -> anyhow::Result<()> {
389 let response = "\
390 private_key=18aa10c05a531f5c537a18426b376387fc2cbd701ae1b9b4271e327aaade9d4f\n\
391 listen_port=56137\n\
392 errno=0\n\
393 \n";
394 let expected = get::Device {
395 ifindex: 0,
396 ifname: "".to_string(),
397 private_key: parse_device_key(&base64::decode(
398 "GKoQwFpTH1xTehhCazdjh/wsvXAa4bm0Jx4yeqrenU8=",
399 )?),
400 public_key: None,
401 listen_port: 56137,
402 fwmark: 0,
403 peers: vec![],
404 };
405
406 let actual = parse(response.lines().map(String::from).map(Ok))?;
407 assert_eq!(actual, expected);
408
409 Ok(())
410 }
411
412 #[test]
413 fn parse_website_example() -> anyhow::Result<()> {
414 let response = "\
418 private_key=e84b5a6d2717c1003a13b431570353dbaca9146cf150c5f8575680feba52027a\n\
419 listen_port=12912\n\
420 public_key=b85996fecc9c7f1fc6d2572a76eda11d59bcd20be8e543b15ce4bd85a8e75a33\n\
421 preshared_key=188515093e952f5f22e865cef3012e72f8b5f0b598ac0309d5dacce3b70fcf52\n\
422 allowed_ip=192.168.4.4/32\n\
423 endpoint=[abcd:23::33]:51820\n\
424 public_key=58402e695ba1772b1cc9309755f043251ea77fdcf10fbe63989ceb7e19321376\n\
425 tx_bytes=38333\n\
426 rx_bytes=2224\n\
427 allowed_ip=192.168.4.6/32\n\
428 persistent_keepalive_interval=111\n\
429 endpoint=182.122.22.19:3233\n\
430 public_key=662e14fd594556f522604703340351258903b64f35553763f19426ab2a515c58\n\
431 endpoint=5.152.198.39:51820\n\
432 allowed_ip=192.168.4.10/32\n\
433 allowed_ip=192.168.4.11/32\n\
434 tx_bytes=1212111\n\
435 rx_bytes=1929999999\n\
436 protocol_version=1\n\
437 errno=0\n\
438 \n";
439
440 let expected = get::Device {
441 ifindex: 0,
442 ifname: "".to_string(),
443 private_key: parse_device_key(&base64::decode(
444 "6EtabScXwQA6E7QxVwNT26ypFGzxUMX4V1aA/rpSAno=",
445 )?),
446 public_key: None,
447 listen_port: 12912,
448 fwmark: 0,
449 peers: vec![
450 get::Peer {
451 public_key: parse_device_key(&base64::decode(
452 "uFmW/sycfx/G0lcqdu2hHVm80gvo5UOxXOS9hajnWjM=",
453 )?)
454 .unwrap(),
455 preshared_key: parse_device_key(&base64::decode(
456 "GIUVCT6VL18i6GXO8wEucvi18LWYrAMJ1drM47cPz1I=",
457 )?)
458 .unwrap(),
459 endpoint: Some("[abcd:23::33]:51820".parse()?),
460 last_handshake_time: Duration::new(0, 0),
461 tx_bytes: 0,
462 rx_bytes: 0,
463 persistent_keepalive_interval: 0,
464 allowed_ips: vec![get::AllowedIp {
465 family: 2,
466 ipaddr: "192.168.4.4".parse()?,
467 cidr_mask: 32,
468 }],
469 protocol_version: 1,
470 },
471 get::Peer {
472 public_key: parse_device_key(&base64::decode(
473 "WEAuaVuhdyscyTCXVfBDJR6nf9zxD75jmJzrfhkyE3Y=",
474 )?)
475 .unwrap(),
476 preshared_key: [0u8; 32],
477 endpoint: Some("182.122.22.19:3233".parse()?),
478 last_handshake_time: Duration::new(0, 0),
479 tx_bytes: 38333,
480 rx_bytes: 2224,
481 persistent_keepalive_interval: 111,
482 allowed_ips: vec![get::AllowedIp {
483 family: 2,
484 ipaddr: "192.168.4.6".parse()?,
485 cidr_mask: 32,
486 }],
487 protocol_version: 1,
488 },
489 get::Peer {
490 public_key: parse_device_key(&base64::decode(
491 "Zi4U/VlFVvUiYEcDNANRJYkDtk81VTdj8ZQmqypRXFg=",
492 )?)
493 .unwrap(),
494 preshared_key: [0u8; 32],
495 endpoint: Some("5.152.198.39:51820".parse()?),
496 last_handshake_time: Duration::new(0, 0),
497 tx_bytes: 1_212_111,
498 rx_bytes: 1_929_999_999,
499 persistent_keepalive_interval: 0,
500 allowed_ips: vec![
501 get::AllowedIp {
502 family: 2,
503 ipaddr: "192.168.4.10".parse()?,
504 cidr_mask: 32,
505 },
506 get::AllowedIp {
507 family: 2,
508 ipaddr: "192.168.4.11".parse()?,
509 cidr_mask: 32,
510 },
511 ],
512 protocol_version: 1,
513 },
514 ],
515 };
516
517 let actual = parse(response.lines().map(String::from).map(Ok))?;
518 assert_eq!(actual, expected);
519
520 Ok(())
521 }
522}