1use std::io;
53
54use futures_util::{SinkExt, StreamExt};
55use tokio::sync::broadcast;
56use tokio_util::codec::Framed;
57
58use crate::auth::{AuthRetryMode, AuthType};
59use crate::client_deny::ClientDeny;
60use crate::codec::OvpnCodec;
61use crate::command::{OvpnCommand, RemoteEntryRange};
62use crate::kill_target::KillTarget;
63use crate::message::{Notification, OvpnMessage};
64use crate::need_ok::NeedOkResponse;
65use crate::parsed_response::{self, LoadStats, StateEntry};
66use crate::proxy_action::ProxyAction;
67use crate::redacted::Redacted;
68use crate::remote_action::RemoteAction;
69use crate::signal::Signal;
70use crate::status::{self, ClientStatistics, StatusResponse};
71use crate::status_format::StatusFormat;
72use crate::stream_mode::StreamMode;
73use crate::version_info::VersionInfo;
74
75#[derive(Debug, thiserror::Error)]
77pub enum ClientError {
78 #[error("transport error: {0}")]
80 Io(#[from] io::Error),
81
82 #[error("connection closed while awaiting response")]
84 ConnectionClosed,
85
86 #[error("server error: {0}")]
88 ServerError(String),
89
90 #[error("unexpected response: {0:?}")]
92 UnexpectedResponse(OvpnMessage),
93
94 #[error("response parse error: {0}")]
96 ParseResponse(#[from] parsed_response::ParseResponseError),
97
98 #[error("status parse error: {0}")]
100 ParseStatus(#[from] status::ParseStatusError),
101}
102
103pub struct ManagementClient<T> {
107 framed: Framed<T, OvpnCodec>,
108 notification_tx: broadcast::Sender<Notification>,
109}
110
111impl<T> ManagementClient<T>
112where
113 T: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin,
114{
115 pub fn new(
123 framed: Framed<T, OvpnCodec>,
124 notification_tx: broadcast::Sender<Notification>,
125 ) -> Self {
126 Self {
127 framed,
128 notification_tx,
129 }
130 }
131
132 pub fn into_framed(self) -> Framed<T, OvpnCodec> {
134 self.framed
135 }
136
137 async fn recv_response(&mut self) -> Result<OvpnMessage, ClientError> {
142 loop {
143 let msg = self
144 .framed
145 .next()
146 .await
147 .ok_or(ClientError::ConnectionClosed)??;
148
149 match msg {
150 OvpnMessage::Notification(notification) => {
151 self.notification_tx
153 .send(notification)
154 .inspect_err(|error| {
155 tracing::debug!(%error, "no notification subscribers");
156 })
157 .ok();
158 }
159 other => return Ok(other),
160 }
161 }
162 }
163
164 async fn send_and_recv(&mut self, cmd: OvpnCommand) -> Result<OvpnMessage, ClientError> {
167 self.framed.send(cmd).await?;
168 self.recv_response().await
169 }
170
171 async fn send_expect_success(&mut self, cmd: OvpnCommand) -> Result<String, ClientError> {
173 match self.send_and_recv(cmd).await? {
174 OvpnMessage::Success(payload) => Ok(payload),
175 OvpnMessage::Error(msg) => Err(ClientError::ServerError(msg)),
176 other => Err(ClientError::UnexpectedResponse(other)),
177 }
178 }
179
180 async fn send_expect_multi_line(
182 &mut self,
183 cmd: OvpnCommand,
184 ) -> Result<Vec<String>, ClientError> {
185 match self.send_and_recv(cmd).await? {
186 OvpnMessage::MultiLine(lines) => Ok(lines),
187 OvpnMessage::Error(msg) => Err(ClientError::ServerError(msg)),
188 other => Err(ClientError::UnexpectedResponse(other)),
189 }
190 }
191
192 async fn send_expect_ok(&mut self, cmd: OvpnCommand) -> Result<(), ClientError> {
194 self.send_expect_success(cmd).await?;
195 Ok(())
196 }
197
198 async fn send_stream_command(
203 &mut self,
204 mode: StreamMode,
205 cmd: OvpnCommand,
206 ) -> Result<Option<Vec<String>>, ClientError> {
207 if mode.returns_history() {
208 Ok(Some(self.send_expect_multi_line(cmd).await?))
209 } else {
210 self.send_expect_ok(cmd).await?;
211 Ok(None)
212 }
213 }
214
215 pub async fn status_raw(&mut self, format: StatusFormat) -> Result<Vec<String>, ClientError> {
224 self.send_expect_multi_line(OvpnCommand::Status(format))
225 .await
226 }
227
228 pub async fn status(&mut self, format: StatusFormat) -> Result<StatusResponse, ClientError> {
230 let lines = self.status_raw(format).await?;
231 Ok(status::parse_status(&lines)?)
232 }
233
234 pub async fn client_statistics(
236 &mut self,
237 format: StatusFormat,
238 ) -> Result<ClientStatistics, ClientError> {
239 let lines = self.status_raw(format).await?;
240 Ok(status::parse_client_statistics(&lines)?)
241 }
242
243 pub async fn state(&mut self) -> Result<Vec<StateEntry>, ClientError> {
245 let lines = self.send_expect_multi_line(OvpnCommand::State).await?;
246 Ok(parsed_response::parse_state_history(&lines)?)
247 }
248
249 pub async fn current_state(&mut self) -> Result<StateEntry, ClientError> {
251 let lines = self.send_expect_multi_line(OvpnCommand::State).await?;
252 Ok(parsed_response::parse_current_state(&lines)?)
253 }
254
255 pub async fn state_stream(
260 &mut self,
261 mode: StreamMode,
262 ) -> Result<Option<Vec<StateEntry>>, ClientError> {
263 match self
264 .send_stream_command(mode, OvpnCommand::StateStream(mode))
265 .await?
266 {
267 Some(lines) => Ok(Some(parsed_response::parse_state_history(&lines)?)),
268 None => Ok(None),
269 }
270 }
271
272 pub async fn version(&mut self) -> Result<VersionInfo, ClientError> {
274 let lines = self.send_expect_multi_line(OvpnCommand::Version).await?;
275 Ok(parsed_response::parse_version(&lines))
276 }
277
278 pub async fn set_version(&mut self, version: u32) -> Result<(), ClientError> {
283 let cmd = OvpnCommand::SetVersion(version);
284 if version < 4 {
285 self.framed.send(cmd).await?;
286 Ok(())
287 } else {
288 self.send_expect_ok(cmd).await
289 }
290 }
291
292 pub async fn pid(&mut self) -> Result<u32, ClientError> {
294 let payload = self.send_expect_success(OvpnCommand::Pid).await?;
295 Ok(parsed_response::parse_pid(&payload)?)
296 }
297
298 pub async fn help(&mut self) -> Result<Vec<String>, ClientError> {
300 self.send_expect_multi_line(OvpnCommand::Help).await
301 }
302
303 pub async fn verb(&mut self, level: Option<u8>) -> Result<String, ClientError> {
305 self.send_expect_success(OvpnCommand::Verb(level)).await
306 }
307
308 pub async fn mute(&mut self, threshold: Option<u32>) -> Result<String, ClientError> {
310 self.send_expect_success(OvpnCommand::Mute(threshold)).await
311 }
312
313 pub async fn net(&mut self) -> Result<Vec<String>, ClientError> {
315 self.send_expect_multi_line(OvpnCommand::Net).await
316 }
317
318 pub async fn log(&mut self, mode: StreamMode) -> Result<Option<Vec<String>>, ClientError> {
324 self.send_stream_command(mode, OvpnCommand::Log(mode)).await
325 }
326
327 pub async fn echo(&mut self, mode: StreamMode) -> Result<Option<Vec<String>>, ClientError> {
329 self.send_stream_command(mode, OvpnCommand::Echo(mode))
330 .await
331 }
332
333 pub async fn bytecount(&mut self, interval: u32) -> Result<(), ClientError> {
336 self.send_expect_ok(OvpnCommand::ByteCount(interval)).await
337 }
338
339 pub async fn signal(&mut self, signal: Signal) -> Result<(), ClientError> {
343 self.send_expect_ok(OvpnCommand::Signal(signal)).await
344 }
345
346 pub async fn kill(&mut self, target: KillTarget) -> Result<(), ClientError> {
348 self.send_expect_ok(OvpnCommand::Kill(target)).await
349 }
350
351 pub async fn hold_query(&mut self) -> Result<bool, ClientError> {
353 let payload = self.send_expect_success(OvpnCommand::HoldQuery).await?;
354 Ok(parsed_response::parse_hold(&payload)?)
355 }
356
357 pub async fn hold_on(&mut self) -> Result<(), ClientError> {
359 self.send_expect_ok(OvpnCommand::HoldOn).await
360 }
361
362 pub async fn hold_off(&mut self) -> Result<(), ClientError> {
364 self.send_expect_ok(OvpnCommand::HoldOff).await
365 }
366
367 pub async fn hold_release(&mut self) -> Result<(), ClientError> {
369 self.send_expect_ok(OvpnCommand::HoldRelease).await
370 }
371
372 pub async fn username(
376 &mut self,
377 auth_type: AuthType,
378 value: impl Into<String>,
379 ) -> Result<(), ClientError> {
380 self.send_expect_ok(OvpnCommand::Username {
381 auth_type,
382 value: Redacted::new(value.into()),
383 })
384 .await
385 }
386
387 pub async fn password(
389 &mut self,
390 auth_type: AuthType,
391 value: impl Into<String>,
392 ) -> Result<(), ClientError> {
393 self.send_expect_ok(OvpnCommand::Password {
394 auth_type,
395 value: Redacted::new(value.into()),
396 })
397 .await
398 }
399
400 pub async fn auth_retry(&mut self, mode: AuthRetryMode) -> Result<(), ClientError> {
402 self.send_expect_ok(OvpnCommand::AuthRetry(mode)).await
403 }
404
405 pub async fn forget_passwords(&mut self) -> Result<(), ClientError> {
407 self.send_expect_ok(OvpnCommand::ForgetPasswords).await
408 }
409
410 pub async fn challenge_response(
412 &mut self,
413 state_id: impl Into<String>,
414 response: impl Into<String>,
415 ) -> Result<(), ClientError> {
416 self.send_expect_ok(OvpnCommand::ChallengeResponse {
417 state_id: state_id.into(),
418 response: Redacted::new(response.into()),
419 })
420 .await
421 }
422
423 pub async fn static_challenge_response(
425 &mut self,
426 password_b64: impl Into<String>,
427 response_b64: impl Into<String>,
428 ) -> Result<(), ClientError> {
429 self.send_expect_ok(OvpnCommand::StaticChallengeResponse {
430 password_b64: Redacted::new(password_b64.into()),
431 response_b64: Redacted::new(response_b64.into()),
432 })
433 .await
434 }
435
436 pub async fn cr_response(&mut self, response: impl Into<String>) -> Result<(), ClientError> {
438 self.send_expect_ok(OvpnCommand::CrResponse {
439 response: Redacted::new(response.into()),
440 })
441 .await
442 }
443
444 pub async fn need_ok(
448 &mut self,
449 name: impl Into<String>,
450 response: NeedOkResponse,
451 ) -> Result<(), ClientError> {
452 self.send_expect_ok(OvpnCommand::NeedOk {
453 name: name.into(),
454 response,
455 })
456 .await
457 }
458
459 pub async fn need_str(
461 &mut self,
462 name: impl Into<String>,
463 value: impl Into<String>,
464 ) -> Result<(), ClientError> {
465 self.send_expect_ok(OvpnCommand::NeedStr {
466 name: name.into(),
467 value: value.into(),
468 })
469 .await
470 }
471
472 pub async fn pkcs11_id_count(&mut self) -> Result<String, ClientError> {
476 self.send_expect_success(OvpnCommand::Pkcs11IdCount).await
477 }
478
479 pub async fn pkcs11_id_get(&mut self, index: u32) -> Result<String, ClientError> {
481 self.send_expect_success(OvpnCommand::Pkcs11IdGet(index))
482 .await
483 }
484
485 pub async fn rsa_sig(&mut self, base64_lines: Vec<String>) -> Result<(), ClientError> {
489 self.send_expect_ok(OvpnCommand::RsaSig { base64_lines })
490 .await
491 }
492
493 pub async fn pk_sig(&mut self, base64_lines: Vec<String>) -> Result<(), ClientError> {
495 self.send_expect_ok(OvpnCommand::PkSig { base64_lines })
496 .await
497 }
498
499 pub async fn certificate(&mut self, pem_lines: Vec<String>) -> Result<(), ClientError> {
501 self.send_expect_ok(OvpnCommand::Certificate { pem_lines })
502 .await
503 }
504
505 pub async fn client_auth(
509 &mut self,
510 cid: u64,
511 kid: u64,
512 config_lines: Vec<String>,
513 ) -> Result<(), ClientError> {
514 self.send_expect_ok(OvpnCommand::ClientAuth {
515 cid,
516 kid,
517 config_lines,
518 })
519 .await
520 }
521
522 pub async fn client_auth_nt(&mut self, cid: u64, kid: u64) -> Result<(), ClientError> {
524 self.send_expect_ok(OvpnCommand::ClientAuthNt { cid, kid })
525 .await
526 }
527
528 pub async fn client_deny(&mut self, deny: ClientDeny) -> Result<(), ClientError> {
530 self.send_expect_ok(OvpnCommand::ClientDeny(deny)).await
531 }
532
533 pub async fn client_kill(
535 &mut self,
536 cid: u64,
537 message: Option<String>,
538 ) -> Result<(), ClientError> {
539 self.send_expect_ok(OvpnCommand::ClientKill { cid, message })
540 .await
541 }
542
543 pub async fn client_pending_auth(
545 &mut self,
546 cid: u64,
547 kid: u64,
548 extra: impl Into<String>,
549 timeout: u32,
550 ) -> Result<(), ClientError> {
551 self.send_expect_ok(OvpnCommand::ClientPendingAuth {
552 cid,
553 kid,
554 extra: extra.into(),
555 timeout,
556 })
557 .await
558 }
559
560 pub async fn remote(&mut self, action: RemoteAction) -> Result<(), ClientError> {
564 self.send_expect_ok(OvpnCommand::Remote(action)).await
565 }
566
567 pub async fn proxy(&mut self, action: ProxyAction) -> Result<(), ClientError> {
569 self.send_expect_ok(OvpnCommand::Proxy(action)).await
570 }
571
572 pub async fn load_stats(&mut self) -> Result<LoadStats, ClientError> {
576 let payload = self.send_expect_success(OvpnCommand::LoadStats).await?;
577 Ok(parsed_response::parse_load_stats(&payload)?)
578 }
579
580 pub async fn env_filter(&mut self, level: u32) -> Result<(), ClientError> {
584 self.send_expect_ok(OvpnCommand::EnvFilter(level)).await
585 }
586
587 pub async fn remote_entry_count(&mut self) -> Result<Vec<String>, ClientError> {
591 self.send_expect_multi_line(OvpnCommand::RemoteEntryCount)
592 .await
593 }
594
595 pub async fn remote_entry_get(
597 &mut self,
598 range: RemoteEntryRange,
599 ) -> Result<Vec<String>, ClientError> {
600 self.send_expect_multi_line(OvpnCommand::RemoteEntryGet(range))
601 .await
602 }
603
604 pub async fn push_update_broad(
608 &mut self,
609 options: impl Into<String>,
610 ) -> Result<(), ClientError> {
611 self.send_expect_ok(OvpnCommand::PushUpdateBroad {
612 options: options.into(),
613 })
614 .await
615 }
616
617 pub async fn push_update_cid(
619 &mut self,
620 cid: u64,
621 options: impl Into<String>,
622 ) -> Result<(), ClientError> {
623 self.send_expect_ok(OvpnCommand::PushUpdateCid {
624 cid,
625 options: options.into(),
626 })
627 .await
628 }
629
630 pub async fn management_password(
634 &mut self,
635 password: impl Into<String>,
636 ) -> Result<(), ClientError> {
637 self.send_expect_ok(OvpnCommand::ManagementPassword(Redacted::new(
638 password.into(),
639 )))
640 .await
641 }
642
643 pub async fn exit(mut self) -> Result<(), ClientError> {
648 self.framed.send(OvpnCommand::Exit).await?;
649 Ok(())
650 }
651
652 pub async fn raw(&mut self, command: impl Into<String>) -> Result<String, ClientError> {
656 self.send_expect_success(OvpnCommand::Raw(command.into()))
657 .await
658 }
659
660 pub async fn raw_multi_line(
662 &mut self,
663 command: impl Into<String>,
664 ) -> Result<Vec<String>, ClientError> {
665 self.send_expect_multi_line(OvpnCommand::RawMultiLine(command.into()))
666 .await
667 }
668}
669
670#[cfg(test)]
671mod tests {
672 use super::*;
673 use tokio::io::{AsyncReadExt, AsyncWriteExt, DuplexStream};
674
675 fn mock_client() -> (
678 ManagementClient<DuplexStream>,
679 broadcast::Sender<Notification>,
680 DuplexStream,
681 ) {
682 let (client_stream, server_stream) = tokio::io::duplex(4096);
683 let framed = Framed::new(client_stream, OvpnCodec::new());
684 let (notification_tx, _) = broadcast::channel(64);
685 let client = ManagementClient::new(framed, notification_tx.clone());
686 (client, notification_tx, server_stream)
687 }
688
689 async fn server_respond(server: &mut DuplexStream, lines: &[&str]) {
691 for line in lines {
692 server.write_all(line.as_bytes()).await.unwrap();
693 server.write_all(b"\r\n").await.unwrap();
694 }
695 }
696
697 #[tokio::test]
698 async fn pid_returns_parsed_value() {
699 let (mut client, _notif, mut server) = mock_client();
700
701 let handle = tokio::spawn(async move {
702 let mut buf = vec![0u8; 64];
703 let _n = server.read(&mut buf).await.unwrap();
704 server_respond(&mut server, &["SUCCESS: pid=42"]).await;
705 server
706 });
707
708 let pid = client.pid().await.unwrap();
709 assert_eq!(pid, 42);
710 handle.await.unwrap();
711 }
712
713 #[tokio::test]
714 async fn notifications_forwarded_during_command() {
715 let (mut client, notif_tx, mut server) = mock_client();
716 let mut rx = notif_tx.subscribe();
717
718 let handle = tokio::spawn(async move {
719 let mut buf = vec![0u8; 64];
720 let _n = server.read(&mut buf).await.unwrap();
721 server_respond(&mut server, &[">BYTECOUNT:1024,2048", "SUCCESS: pid=99"]).await;
723 server
724 });
725
726 let pid = client.pid().await.unwrap();
727 assert_eq!(pid, 99);
728
729 let notif = rx.try_recv().unwrap();
731 assert!(
732 matches!(
733 notif,
734 Notification::ByteCount {
735 bytes_in: 1024,
736 bytes_out: 2048
737 }
738 ),
739 "expected ByteCount, got {notif:?}"
740 );
741
742 handle.await.unwrap();
743 }
744
745 #[tokio::test]
746 async fn server_error_maps_to_client_error() {
747 let (mut client, _notif, mut server) = mock_client();
748
749 let handle = tokio::spawn(async move {
750 let mut buf = vec![0u8; 64];
751 let _n = server.read(&mut buf).await.unwrap();
752 server_respond(&mut server, &["ERROR: command not allowed"]).await;
753 server
754 });
755
756 let err = client.hold_release().await.unwrap_err();
757 assert!(
758 matches!(&err, ClientError::ServerError(msg) if msg == "command not allowed"),
759 "expected ServerError, got {err:?}"
760 );
761
762 handle.await.unwrap();
763 }
764
765 #[tokio::test]
766 async fn version_returns_parsed_info() {
767 let (mut client, _notif, mut server) = mock_client();
768
769 let handle = tokio::spawn(async move {
770 let mut buf = vec![0u8; 64];
771 let _n = server.read(&mut buf).await.unwrap();
772 server_respond(
773 &mut server,
774 &[
775 "OpenVPN Version: OpenVPN 2.6.9 x86_64-pc-linux-gnu",
776 "Management Interface Version: 5",
777 "END",
778 ],
779 )
780 .await;
781 server
782 });
783
784 let info = client.version().await.unwrap();
785 assert_eq!(info.management_version(), Some(5));
786 assert!(info.openvpn_version_line().unwrap().contains("2.6.9"));
787
788 handle.await.unwrap();
789 }
790
791 #[tokio::test]
792 async fn connection_closed_returns_error() {
793 let (mut client, _notif, server) = mock_client();
794
795 drop(server);
797
798 let err = client.pid().await.unwrap_err();
799 assert!(
801 matches!(&err, ClientError::ConnectionClosed | ClientError::Io(_)),
802 "expected connection error, got {err:?}"
803 );
804 }
805
806 #[tokio::test]
807 async fn multiple_notification_subscribers() {
808 let (mut client, notif_tx, mut server) = mock_client();
809 let mut rx1 = notif_tx.subscribe();
810 let mut rx2 = notif_tx.subscribe();
811
812 let handle = tokio::spawn(async move {
813 let mut buf = vec![0u8; 64];
814 let _n = server.read(&mut buf).await.unwrap();
815 server_respond(
816 &mut server,
817 &[">HOLD:Waiting for hold release:5", "SUCCESS: pid=1"],
818 )
819 .await;
820 server
821 });
822
823 let pid = client.pid().await.unwrap();
824 assert_eq!(pid, 1);
825
826 let n1 = rx1.try_recv().unwrap();
828 let n2 = rx2.try_recv().unwrap();
829 assert!(matches!(n1, Notification::Hold { .. }));
830 assert!(matches!(n2, Notification::Hold { .. }));
831
832 handle.await.unwrap();
833 }
834
835 #[tokio::test]
836 async fn load_stats_parsed() {
837 let (mut client, _notif, mut server) = mock_client();
838
839 let handle = tokio::spawn(async move {
840 let mut buf = vec![0u8; 64];
841 let _n = server.read(&mut buf).await.unwrap();
842 server_respond(
843 &mut server,
844 &["SUCCESS: nclients=3,bytesin=100000,bytesout=50000"],
845 )
846 .await;
847 server
848 });
849
850 let stats = client.load_stats().await.unwrap();
851 assert_eq!(stats.nclients, 3);
852 assert_eq!(stats.bytesin, 100_000);
853 assert_eq!(stats.bytesout, 50_000);
854
855 handle.await.unwrap();
856 }
857
858 #[tokio::test]
859 async fn hold_query_parsed() {
860 let (mut client, _notif, mut server) = mock_client();
861
862 let handle = tokio::spawn(async move {
863 let mut buf = vec![0u8; 64];
864 let _n = server.read(&mut buf).await.unwrap();
865 server_respond(&mut server, &["SUCCESS: hold=1"]).await;
866 server
867 });
868
869 assert!(client.hold_query().await.unwrap());
870
871 handle.await.unwrap();
872 }
873}