1use std::fmt;
17
18#[cfg(feature = "build_sync")]
19pub(super) use crate::sync::socket::{SyslogTap, Tap};
20
21#[cfg(feature = "async_enabled")]
22pub use crate::a_sync::{AsyncTap, AsyncSyslogTap};
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum DestinationType
26{
27 Local, Network, File
28}
29
30impl DestinationType
31{
32 #[inline]
33 pub
34 fn is_network(&self) -> bool
35 {
36 return self == &Self::Network;
37 }
38}
39
40#[cfg(feature = "build_sync")]
44pub trait SyslogDestination: fmt::Debug + fmt::Display + Send + Clone + SyslogDestMsg + 'static
45{
46 type SocketTap: SyslogTap<Self>;
48
49 const DEST_TYPE: DestinationType;
50}
51
52#[cfg(feature = "async_enabled")]
56pub trait AsyncSyslogDestination: fmt::Debug + fmt::Display + Send + Clone + SyslogDestMsg + 'static
57{
58 type SocketTap: AsyncSyslogTap<Self>;
60}
61
62pub trait SyslogDestMsg: fmt::Debug + fmt::Display + Send + Clone + 'static
65{
66 fn get_max_msg_len() -> usize;
68}
69
70
71#[cfg(target_family = "windows")]
76pub mod imp_syslog_local
77{
78
79 use std::ffi::CString;
80
81 use crate::WINDOWS_EVENT_REPORT_MAX_PAYLOAD_LEN;
82 use crate::portable;
83 use crate::portable::EventLogLocal;
84
85 use crate::{error::SyRes, throw_error, map_error};
86
87 use super::*;
88
89 #[derive(Debug, Clone)]
96 pub struct WindowsEvent
97 {
98 service_name: CString,
100
101 unc_remote_server: Option<CString>,
103 }
104
105 impl fmt::Display for WindowsEvent
106 {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
108 {
109 write!(f, "name: {}, guid: {}",
110 unsafe { str::from_utf8_unchecked(self.service_name.as_bytes()) },
111 self.unc_remote_server.as_ref().map_or("NONE", |f| unsafe { str::from_utf8_unchecked(f.as_bytes()) })
112 )
113 }
114 }
115
116 impl SyslogDestMsg for WindowsEvent
117 {
118 fn get_max_msg_len() -> usize
119 {
120 return WINDOWS_EVENT_REPORT_MAX_PAYLOAD_LEN;
121 }
122 }
123
124 impl WindowsEvent
125 {
126 pub
131 fn new() -> Self
132 {
133 let service_name =
134 portable::p_getprogname()
135 .map(|v|
136 {
137 if v.is_empty() == true
138 {
139 "UnknownProgram".to_string()
140 }
141 else
142 {
143 v
144 }
145 }
146 )
147 .unwrap_or("UnknownProgram".to_string());
148
149 return
150 Self
151 {
152 service_name:
153 CString::new(service_name).unwrap(),
154 unc_remote_server:
155 None,
156 };
157 }
158
159 pub
181 fn new_custom(service_name: &str, unc_server: Option<&str>) -> SyRes<Self>
182 {
183 let service_name_cstr =
184 if service_name.is_empty() == true
185 {
186 throw_error!("service_name is empty");
187 }
188 else
189 {
190 CString::new(service_name)
191 .map_err(|e|
192 map_error!("service_name CString error: '{}'", e)
193 )?
194 };
195
196
197 let unc_serv_cstr =
198 if let Some(unc) = unc_server
199 {
200 if unc.is_empty() == true
201 {
202 throw_error!("service_name is empty");
203 }
204
205 Some(
206 CString::new(unc)
207 .map_err(|e|
208 map_error!("service_name CString error: '{}'", e)
209 )?
210 )
211 }
212 else
213 {
214 None
215 };
216
217 return Ok(
218 Self
219 {
220 service_name: service_name_cstr,
221 unc_remote_server: unc_serv_cstr
222 }
223 );
224 }
225
226 #[inline]
228 pub
229 fn get_server_unc(&self) -> Option<&CString>
230 {
231 return self.unc_remote_server.as_ref();
232 }
233
234 #[inline]
236 pub
237 fn get_service_name(&self) -> &CString
238 {
239 return &self.service_name;
240 }
241 }
242
243 #[cfg(feature = "build_async_tokio")]
244 impl AsyncSyslogDestination for WindowsEvent
245 {
246 type SocketTap = AsyncTap::<EventLogLocal, Self>;
247
248 }
249
250 #[cfg(feature = "build_async_smol")]
251 impl AsyncSyslogDestination for WindowsEvent
252 {
253 type SocketTap = AsyncTap::<EventLogLocal, Self>;
254 }
255
256 #[cfg(feature = "build_sync")]
257 impl SyslogDestination for WindowsEvent
258 {
259 type SocketTap = Tap::<EventLogLocal, Self>;
260
261 const DEST_TYPE: DestinationType = DestinationType::Local;
262 }
263}
264
265#[cfg(target_family = "windows")]
266pub use self::imp_syslog_local::WindowsEvent;
267
268#[cfg(target_family = "unix")]
269pub mod imp_syslog_local
270{
271 use std::{fmt, path::{Path, PathBuf}};
272
273 use crate::{common, error::SyRes, throw_error};
274
275 use std::os::unix::net::UnixDatagram;
276 use super::*;
277
278 #[derive(Debug, Clone)]
282 pub struct SyslogLocal
283 {
284 custom_remote_path: Option<PathBuf>,
286
287 use_alternative: bool,
289 }
290
291
292 impl fmt::Display for SyslogLocal
293 {
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
295 {
296 write!(f, "custom_path: {:?}, alt: {}", self.custom_remote_path, self.use_alternative)
297 }
298 }
299
300 impl SyslogLocal
301 {
302 fn new_internal(custom_path: Option<PathBuf>, use_alt_path: bool) -> SyRes<Self>
303 {
304 let remote_path: Option<PathBuf> =
305 if let Some(path) = custom_path
306 {
307 if use_alt_path == false
308 {
309 if path.exists() == false || path.is_file() == false
310 {
311 throw_error!("path either does not exists or not a file: '{}'", path.display());
312 }
313 }
314
315 Some(path.to_path_buf())
316 }
317 else
318 {
319 None
320 };
321
322 return Ok(
323 Self
324 {
325 custom_remote_path: remote_path,
326 use_alternative: use_alt_path,
327 }
328 );
329 }
330
331 pub
334 fn new() -> Self
335 {
336 return
337 Self::new_internal(None, false).unwrap();
338 }
339
340 pub
344 fn new_custom_path<P: Into<PathBuf>>(custom_path: P, use_alt_path: bool) -> SyRes<Self>
345 {
346 return
347 Self::new_internal(Some(custom_path.into()), use_alt_path);
348 }
349
350 #[inline]
351 pub
352 fn get_custom_remote_path(&self) -> Option<&Path>
353 {
354 return self.custom_remote_path.as_ref().map(|f| f.as_path());
355 }
356
357 #[inline]
358 pub
359 fn get_use_alternative(&self) -> bool
360 {
361 return self.use_alternative;
362 }
363 }
364
365 impl SyslogDestMsg for SyslogLocal
366 {
367 fn get_max_msg_len() -> usize
368 {
369 if *common::RFC5424_MAX_DGRAM >= common::MAXLINE
370 {
371 return common::MAXLINE;
372 }
373 else
374 {
375 return *common::RFC5424_MAX_DGRAM;
376 };
377 }
378 }
379
380 #[cfg(feature = "build_async_tokio")]
381 impl AsyncSyslogDestination for SyslogLocal
382 {
383 type SocketTap = AsyncTap::<tokio::net::UnixDatagram, Self>;
384
385 }
386
387 #[cfg(feature = "build_async_smol")]
388 impl AsyncSyslogDestination for SyslogLocal
389 {
390 type SocketTap = AsyncTap::<smol::net::unix::UnixDatagram, Self>;
391 }
392
393 #[cfg(feature = "build_sync")]
394 impl SyslogDestination for SyslogLocal
395 {
396 type SocketTap = Tap::<UnixDatagram, Self>;
397
398 const DEST_TYPE: DestinationType = DestinationType::Local;
399 }
400}
401
402
403#[cfg(target_family = "unix")]
404pub use self::imp_syslog_local::SyslogLocal;
405
406#[cfg(feature = "build_ext_net")]
407pub mod imp_syslog_net
408{
409 use std::{fmt, net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream, UdpSocket}, time::Duration};
410
411 use crate::{common, error::SyRes, map_error, SyslogDestMsg};
412
413 use super::*;
414
415 #[derive(Debug, Clone)]
417 pub struct SyslogNetTcp
418 {
419 remote_addr: SocketAddr,
421
422 bind_addr: SocketAddr,
424
425 conn_timeout: Option<Duration>
427 }
428
429 impl fmt::Display for SyslogNetTcp
430 {
431 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
432 {
433 write!(f, "remote_addr: {}, bind_addr: {}, conn_timeout: {:?}", self.remote_addr,
434 self.bind_addr, self.conn_timeout)
435 }
436 }
437
438 impl SyslogNetTcp
439 {
440 pub
452 fn new<P>(remote: P, local: Option<P>, conn_timeout: Option<Duration>) -> SyRes<Self>
453 where P: AsRef<str>
454 {
455 let remote_addr: SocketAddr =
456 remote
457 .as_ref()
458 .parse()
459 .map_err(|e|
460 map_error!("failed parsing remote addr '{}', error: '{}'", remote.as_ref(), e)
461 )?;
462
463 let bind_addr: SocketAddr =
464 if let Some(bind) = local
465 {
466 bind
467 .as_ref()
468 .parse()
469 .map_err(|e|
470 map_error!("failed parsing bind addr '{}', error: '{}'", remote.as_ref(), e)
471 )?
472 }
473 else
474 {
475 SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)
476 };
477
478 return Ok(
479 Self
480 {
481 remote_addr: remote_addr,
482 bind_addr: bind_addr,
483 conn_timeout: conn_timeout
484 }
485 );
486 }
487
488 #[inline]
489 pub
490 fn get_remote_addr(&self) -> &SocketAddr
491 {
492 return &self.remote_addr;
493 }
494
495 #[inline]
496 pub
497 fn get_bind_addr(&self) -> &SocketAddr
498 {
499 return &self.bind_addr;
500 }
501
502 #[inline]
503 pub
504 fn get_conn_timeout(&self) -> Option<Duration>
505 {
506 return self.conn_timeout;
507 }
508 }
509
510 impl SyslogDestMsg for SyslogNetTcp
511 {
512 fn get_max_msg_len() -> usize
513 {
514 return common::RFC5424_TCP_MAX_PKT_LEN;
515 }
516 }
517
518 #[cfg(feature = "build_async_tokio")]
519 impl AsyncSyslogDestination for SyslogNetTcp
520 {
521 type SocketTap = AsyncTap::<tokio::net::TcpStream, Self>;
522 }
523
524 #[cfg(feature = "build_async_smol")]
525 impl AsyncSyslogDestination for SyslogNetTcp
526 {
527 type SocketTap = AsyncTap::<smol::net::TcpStream, Self>;
528 }
529
530 #[cfg(feature = "build_sync")]
531 impl SyslogDestination for SyslogNetTcp
532 {
533 type SocketTap = Tap::<TcpStream, Self>;
534
535 const DEST_TYPE: DestinationType = DestinationType::Network;
536 }
537
538
539 #[derive(Debug, Clone)]
541 pub struct SyslogNetUdp
542 {
543 remote_addr: SocketAddr,
544 bind_addr: SocketAddr
545 }
546
547 impl fmt::Display for SyslogNetUdp
548 {
549 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
550 {
551 write!(f, "remote_addr: {}, bind_addr: {}", self.remote_addr,
552 self.bind_addr)
553 }
554 }
555
556 impl SyslogNetUdp
557 {
558 pub
567 fn new<P>(dest_addr: P, local: Option<P>) -> SyRes<Self>
568 where P: AsRef<str>
569 {
570 let remote_addr: SocketAddr =
571 dest_addr
572 .as_ref()
573 .parse()
574 .map_err(|e|
575 map_error!("failed parsing remote addr '{}', error: '{}'", dest_addr.as_ref(), e)
576 )?;
577
578 let bind_addr: SocketAddr =
579 if let Some(bind) = local
580 {
581 bind
582 .as_ref()
583 .parse()
584 .map_err(|e|
585 map_error!("failed parsing bind addr '{}', error: '{}'", dest_addr.as_ref(), e)
586 )?
587 }
588 else
589 {
590 SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)
591 };
592
593 return Ok(
594 Self
595 {
596 remote_addr: remote_addr,
597 bind_addr: bind_addr
598 }
599 );
600 }
601
602 #[inline]
603 pub
604 fn get_remote_addr(&self) -> &SocketAddr
605 {
606 return &self.remote_addr;
607 }
608
609 #[inline]
610 pub
611 fn get_bind_addr(&self) -> &SocketAddr
612 {
613 return &self.bind_addr;
614 }
615 }
616
617 impl SyslogDestMsg for SyslogNetUdp
618 {
619 fn get_max_msg_len() -> usize
620 {
621 return common::RFC5424_UDP_MAX_PKT_LEN;
622 }
623 }
624
625 #[cfg(feature = "build_async_tokio")]
626 impl AsyncSyslogDestination for SyslogNetUdp
627 {
628 type SocketTap = AsyncTap::<tokio::net::UdpSocket, Self>;
629 }
630
631 #[cfg(feature = "build_async_smol")]
632 impl AsyncSyslogDestination for SyslogNetUdp
633 {
634 type SocketTap = AsyncTap::<smol::net::UdpSocket, Self>;
635 }
636
637 #[cfg(feature = "build_sync")]
638 impl SyslogDestination for SyslogNetUdp
639 {
640 type SocketTap = Tap::<UdpSocket, Self>;
641
642 const DEST_TYPE: DestinationType = DestinationType::Network;
643 }
644}
645
646#[cfg(feature = "build_ext_net")]
647pub use self::imp_syslog_net::SyslogNetTcp;
648
649#[cfg(feature = "build_ext_net")]
650pub use self::imp_syslog_net::SyslogNetUdp;
651
652#[cfg(feature = "build_ext_file")]
653pub mod imp_syslog_file
654{
655 use std::{fmt, fs::File, path::{Path, PathBuf}};
656
657 use crate::{common};
658
659 use super::*;
660
661 #[derive(Debug, Clone)]
663 pub struct SyslogFile
664 {
665 file_path: PathBuf
667 }
668
669 impl fmt::Display for SyslogFile
670 {
671 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
672 {
673 write!(f, "<file> path: {}", self.file_path.display())
674 }
675 }
676
677 impl SyslogFile
678 {
679 pub
681 fn new<P: Into<PathBuf>>(dest_path: P) -> Self
682 {
683 return
684 Self
685 {
686 file_path: dest_path.into()
687 };
688 }
689
690 #[inline]
691 pub
692 fn get_path(&self) -> &Path
693 {
694 return self.file_path.as_path();
695 }
696 }
697
698 impl SyslogDestMsg for SyslogFile
699 {
700 fn get_max_msg_len() -> usize
701 {
702 if *common::RFC5424_MAX_DGRAM >= common::MAXLINE
703 {
704 return common::MAXLINE;
705 }
706 else
707 {
708 return *common::RFC5424_MAX_DGRAM;
709 };
710 }
711 }
712
713 #[cfg(feature = "build_async_tokio")]
714 impl AsyncSyslogDestination for SyslogFile
715 {
716 type SocketTap = AsyncTap::<tokio::fs::File, Self>;
717 }
718
719 #[cfg(feature = "build_async_smol")]
720 impl AsyncSyslogDestination for SyslogFile
721 {
722 type SocketTap = AsyncTap::<smol::fs::File, Self>;
723 }
724
725 #[cfg(feature = "build_sync")]
726 impl SyslogDestination for SyslogFile
727 {
728 type SocketTap = Tap::<File, Self>;
729
730 const DEST_TYPE: DestinationType = DestinationType::File;
731 }
732}
733
734#[cfg(feature = "build_ext_file")]
735pub use self::imp_syslog_file::SyslogFile;
736
737#[cfg(feature = "build_ext_tls")]
738pub mod imp_syslog_tls
739{
740 use std::fmt;
741 use std::{net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream}, sync::Arc, time::Duration};
742
743 #[cfg(feature = "build_sync")]
744use rustls::lock::Mutex;
745 use rustls::{pki_types::{CertificateDer, ServerName}, ClientConfig, ClientConnection, RootCertStore, StreamOwned};
746
747 use crate::{common, error::SyRes, map_error};
748
749 use super::*;
750
751 #[derive(Debug, Clone)]
753 pub struct SyslogTls
754 {
755 remote_addr: SocketAddr,
757
758 bind_addr: SocketAddr,
760
761 serv_name: ServerName<'static>,
763
764 client_config: Arc<ClientConfig>,
766
767 conn_timeout: Option<Duration>,
769 }
770
771 impl fmt::Display for SyslogTls
772 {
773 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
774 {
775 write!(f, "remote: {}, bind: {}, serv_name: {:?}, client: {:?}, conn_timeout: {:?}", self.remote_addr,
776 self.bind_addr, self.serv_name, self.client_config, self.conn_timeout)
777 }
778 }
779
780 impl SyslogTls
781 {
782 pub
798 fn new<P>(remote: P, local: Option<P>, serv_name: impl Into<String>,
799 root_cert: Vec<u8>, conn_timeout: Option<Duration>) -> SyRes<Self>
800 where P: AsRef<str>
801 {
802 use rustls::pki_types::pem::PemObject;
803
804 let server_name = serv_name.into();
805
806 let remote_addr: SocketAddr =
807 remote
808 .as_ref()
809 .parse()
810 .map_err(|e|
811 map_error!("failed parsing remote addr '{}', error: '{}'", remote.as_ref(), e)
812 )?;
813
814 let cert =
815 CertificateDer::from_pem_slice(root_cert.as_slice())
816 .map_err(|e|
817 map_error!("certificate parse error: '{}'", e)
818 )?;
819
820 let mut root_store = RootCertStore::empty();
821 root_store
822 .add(cert)
823 .map_err(|e|
824 map_error!("can not add root ceritficate, error: '{}'", e)
825 )?;
826
827 let serv_name =
828 server_name
829 .try_into()
830 .map_err(|e|
831 map_error!("server name error: '{}'", e)
832 )?;
833
834 let client_config =
835 rustls::ClientConfig::builder()
836 .with_root_certificates(root_store)
837 .with_no_client_auth();
838
839 let bind_addr: SocketAddr =
840 if let Some(bind) = local
841 {
842 bind
843 .as_ref()
844 .parse()
845 .map_err(|e|
846 map_error!("failed parsing bind addr '{}', error: '{}'", remote.as_ref(), e)
847 )?
848 }
849 else
850 {
851 SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)
852 };
853
854 return Ok(
855 Self
856 {
857 remote_addr: remote_addr,
858 bind_addr: bind_addr,
859 serv_name: serv_name,
860 client_config: Arc::new(client_config),
861 conn_timeout: conn_timeout,
862 }
863 );
864 }
865
866 #[inline]
867 pub
868 fn get_remote_addr(&self) -> &SocketAddr
869 {
870 return &self.remote_addr;
871 }
872
873 #[inline]
874 pub
875 fn get_bind_addr(&self) -> &SocketAddr
876 {
877 return &self.bind_addr;
878 }
879
880 #[inline]
881 pub
882 fn get_serv_name(&self) -> ServerName<'static>
883 {
884 return self.serv_name.clone();
885 }
886
887 #[inline]
888 pub
889 fn get_client_config(&self) -> Arc<ClientConfig>
890 {
891 return self.client_config.clone();
892 }
893
894 #[inline]
895 pub
896 fn get_get_conn_timeout(&self) -> Option<Duration>
897 {
898 return self.conn_timeout.clone();
899 }
900 }
901
902 impl SyslogDestMsg for SyslogTls
903 {
904 fn get_max_msg_len() -> usize
905 {
906 return common::RFC5424_TCP_MAX_PKT_LEN;
907 }
908 }
909
910 #[cfg(feature = "build_async_tokio")]
911 impl AsyncSyslogDestination for SyslogTls
912 {
913 type SocketTap = AsyncTap::<tokio_rustls::client::TlsStream<tokio::net::TcpStream>, Self>;
914 }
915
916 #[cfg(feature = "build_async_smol")]
917 impl AsyncSyslogDestination for SyslogTls
918 {
919 type SocketTap = AsyncTap::<futures_rustls::client::TlsStream<smol::net::TcpStream>, Self>;
920 }
921
922 #[cfg(feature = "build_sync")]
923 impl SyslogDestination for SyslogTls
924 {
925 type SocketTap = Tap::<Mutex<StreamOwned<ClientConnection, TcpStream>>, Self>;
926
927 const DEST_TYPE: DestinationType = DestinationType::Network;
928 }
929}
930
931#[cfg(feature = "build_ext_tls")]
932pub use self::imp_syslog_tls::SyslogTls;