1use std::{fmt, os::unix::net::UnixDatagram, path::{Path, PathBuf}};
17
18use crate::{common, error::SyRes, throw_error};
19
20#[cfg(feature = "build_sync")]
21pub(super) use crate::sync::socket::{SyslogTap, Tap};
22
23#[cfg(feature = "async_enabled")]
24pub use crate::a_sync::{AsyncTap, AsyncSyslogTap};
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum DestinationType
28{
29 Local, Network, File
30}
31
32impl DestinationType
33{
34 #[inline]
35 pub
36 fn is_network(&self) -> bool
37 {
38 return self == &Self::Network;
39 }
40}
41
42#[cfg(feature = "build_sync")]
46pub trait SyslogDestination: fmt::Debug + fmt::Display + Send + Clone + SyslogDestMsg + 'static
47{
48 type SocketTap: SyslogTap<Self>;
50
51 const DEST_TYPE: DestinationType;
52}
53
54#[cfg(feature = "async_enabled")]
58pub trait AsyncSyslogDestination: fmt::Debug + fmt::Display + Send + Clone + SyslogDestMsg + 'static
59{
60 type SocketTap: AsyncSyslogTap<Self>;
62}
63
64pub trait SyslogDestMsg: fmt::Debug + fmt::Display + Send + Clone + 'static
67{
68 fn get_max_msg_len() -> usize;
70}
71
72
73#[derive(Debug, Clone)]
77pub struct SyslogLocal
78{
79 custom_remote_path: Option<PathBuf>,
81
82 use_alternative: bool,
84}
85
86
87impl fmt::Display for SyslogLocal
88{
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
90 {
91 write!(f, "custom_path: {:?}, alt: {}", self.custom_remote_path, self.use_alternative)
92 }
93}
94
95impl SyslogLocal
96{
97 fn new_internal(custom_path: Option<PathBuf>, use_alt_path: bool) -> SyRes<Self>
98 {
99 let remote_path: Option<PathBuf> =
100 if let Some(path) = custom_path
101 {
102 if use_alt_path == false
103 {
104 if path.exists() == false || path.is_file() == false
105 {
106 throw_error!("path either does not exists or not a file: '{}'", path.display());
107 }
108 }
109
110 Some(path.to_path_buf())
111 }
112 else
113 {
114 None
115 };
116
117 return Ok(
118 Self
119 {
120 custom_remote_path: remote_path,
121 use_alternative: use_alt_path,
122 }
123 );
124 }
125
126 pub
129 fn new() -> Self
130 {
131 return
132 Self::new_internal(None, false).unwrap();
133 }
134
135 pub
139 fn new_custom_path<P: Into<PathBuf>>(custom_path: P, use_alt_path: bool) -> SyRes<Self>
140 {
141 return
142 Self::new_internal(Some(custom_path.into()), use_alt_path);
143 }
144
145 #[inline]
146 pub
147 fn get_custom_remote_path(&self) -> Option<&Path>
148 {
149 return self.custom_remote_path.as_ref().map(|f| f.as_path());
150 }
151
152 #[inline]
153 pub
154 fn get_use_alternative(&self) -> bool
155 {
156 return self.use_alternative;
157 }
158}
159
160impl SyslogDestMsg for SyslogLocal
161{
162 fn get_max_msg_len() -> usize
163 {
164 if *common::RFC5424_MAX_DGRAM >= common::MAXLINE
165 {
166 return common::MAXLINE;
167 }
168 else
169 {
170 return *common::RFC5424_MAX_DGRAM;
171 };
172 }
173}
174
175#[cfg(feature = "build_async_tokio")]
176impl AsyncSyslogDestination for SyslogLocal
177{
178 type SocketTap = AsyncTap::<tokio::net::UnixDatagram, Self>;
179
180}
181
182#[cfg(feature = "build_async_smol")]
183impl AsyncSyslogDestination for SyslogLocal
184{
185 type SocketTap = AsyncTap::<smol::net::unix::UnixDatagram, Self>;
186}
187
188#[cfg(feature = "build_sync")]
189impl SyslogDestination for SyslogLocal
190{
191 type SocketTap = Tap::<UnixDatagram, Self>;
192
193 const DEST_TYPE: DestinationType = DestinationType::Local;
194}
195
196#[cfg(feature = "build_ext_net")]
197pub mod imp_syslog_net
198{
199 use std::{fmt, net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream, UdpSocket}, time::Duration};
200
201 use crate::{common, error::SyRes, map_error, SyslogDestMsg};
202
203 use super::*;
204
205 #[derive(Debug, Clone)]
207 pub struct SyslogNetTcp
208 {
209 remote_addr: SocketAddr,
211
212 bind_addr: SocketAddr,
214
215 conn_timeout: Option<Duration>
217 }
218
219 impl fmt::Display for SyslogNetTcp
220 {
221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
222 {
223 write!(f, "remote_addr: {}, bind_addr: {}, conn_timeout: {:?}", self.remote_addr,
224 self.bind_addr, self.conn_timeout)
225 }
226 }
227
228 impl SyslogNetTcp
229 {
230 pub
242 fn new<P>(remote: P, local: Option<P>, conn_timeout: Option<Duration>) -> SyRes<Self>
243 where P: AsRef<str>
244 {
245 let remote_addr: SocketAddr =
246 remote
247 .as_ref()
248 .parse()
249 .map_err(|e|
250 map_error!("failed parsing remote addr '{}', error: '{}'", remote.as_ref(), e)
251 )?;
252
253 let bind_addr: SocketAddr =
254 if let Some(bind) = local
255 {
256 bind
257 .as_ref()
258 .parse()
259 .map_err(|e|
260 map_error!("failed parsing bind addr '{}', error: '{}'", remote.as_ref(), e)
261 )?
262 }
263 else
264 {
265 SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)
266 };
267
268 return Ok(
269 Self
270 {
271 remote_addr: remote_addr,
272 bind_addr: bind_addr,
273 conn_timeout: conn_timeout
274 }
275 );
276 }
277
278 #[inline]
279 pub
280 fn get_remote_addr(&self) -> &SocketAddr
281 {
282 return &self.remote_addr;
283 }
284
285 #[inline]
286 pub
287 fn get_bind_addr(&self) -> &SocketAddr
288 {
289 return &self.bind_addr;
290 }
291
292 #[inline]
293 pub
294 fn get_conn_timeout(&self) -> Option<Duration>
295 {
296 return self.conn_timeout;
297 }
298 }
299
300 impl SyslogDestMsg for SyslogNetTcp
301 {
302 fn get_max_msg_len() -> usize
303 {
304 return common::RFC5424_TCP_MAX_PKT_LEN;
305 }
306 }
307
308 #[cfg(feature = "build_async_tokio")]
309 impl AsyncSyslogDestination for SyslogNetTcp
310 {
311 type SocketTap = AsyncTap::<tokio::net::TcpStream, Self>;
312 }
313
314 #[cfg(feature = "build_async_smol")]
315 impl AsyncSyslogDestination for SyslogNetTcp
316 {
317 type SocketTap = AsyncTap::<smol::net::TcpStream, Self>;
318 }
319
320 #[cfg(feature = "build_sync")]
321 impl SyslogDestination for SyslogNetTcp
322 {
323 type SocketTap = Tap::<TcpStream, Self>;
324
325 const DEST_TYPE: DestinationType = DestinationType::Network;
326 }
327
328
329 #[derive(Debug, Clone)]
331 pub struct SyslogNetUdp
332 {
333 remote_addr: SocketAddr,
334 bind_addr: SocketAddr
335 }
336
337 impl fmt::Display for SyslogNetUdp
338 {
339 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
340 {
341 write!(f, "remote_addr: {}, bind_addr: {}", self.remote_addr,
342 self.bind_addr)
343 }
344 }
345
346 impl SyslogNetUdp
347 {
348 pub
357 fn new<P>(dest_addr: P, local: Option<P>) -> SyRes<Self>
358 where P: AsRef<str>
359 {
360 let remote_addr: SocketAddr =
361 dest_addr
362 .as_ref()
363 .parse()
364 .map_err(|e|
365 map_error!("failed parsing remote addr '{}', error: '{}'", dest_addr.as_ref(), e)
366 )?;
367
368 let bind_addr: SocketAddr =
369 if let Some(bind) = local
370 {
371 bind
372 .as_ref()
373 .parse()
374 .map_err(|e|
375 map_error!("failed parsing bind addr '{}', error: '{}'", dest_addr.as_ref(), e)
376 )?
377 }
378 else
379 {
380 SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)
381 };
382
383 return Ok(
384 Self
385 {
386 remote_addr: remote_addr,
387 bind_addr: bind_addr
388 }
389 );
390 }
391
392 #[inline]
393 pub
394 fn get_remote_addr(&self) -> &SocketAddr
395 {
396 return &self.remote_addr;
397 }
398
399 #[inline]
400 pub
401 fn get_bind_addr(&self) -> &SocketAddr
402 {
403 return &self.bind_addr;
404 }
405 }
406
407 impl SyslogDestMsg for SyslogNetUdp
408 {
409 fn get_max_msg_len() -> usize
410 {
411 return common::RFC5424_UDP_MAX_PKT_LEN;
412 }
413 }
414
415 #[cfg(feature = "build_async_tokio")]
416 impl AsyncSyslogDestination for SyslogNetUdp
417 {
418 type SocketTap = AsyncTap::<tokio::net::UdpSocket, Self>;
419 }
420
421 #[cfg(feature = "build_async_smol")]
422 impl AsyncSyslogDestination for SyslogNetUdp
423 {
424 type SocketTap = AsyncTap::<smol::net::UdpSocket, Self>;
425 }
426
427 #[cfg(feature = "build_sync")]
428 impl SyslogDestination for SyslogNetUdp
429 {
430 type SocketTap = Tap::<UdpSocket, Self>;
431
432 const DEST_TYPE: DestinationType = DestinationType::Network;
433 }
434}
435
436#[cfg(feature = "build_ext_net")]
437pub use self::imp_syslog_net::SyslogNetTcp;
438
439#[cfg(feature = "build_ext_net")]
440pub use self::imp_syslog_net::SyslogNetUdp;
441
442#[cfg(feature = "build_ext_file")]
443pub mod imp_syslog_file
444{
445 use std::{fmt, fs::File, path::{Path, PathBuf}};
446
447 use crate::{common};
448
449 use super::*;
450
451 #[derive(Debug, Clone)]
453 pub struct SyslogFile
454 {
455 file_path: PathBuf
457 }
458
459 impl fmt::Display for SyslogFile
460 {
461 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
462 {
463 write!(f, "<file> path: {}", self.file_path.display())
464 }
465 }
466
467 impl SyslogFile
468 {
469 pub
471 fn new<P: Into<PathBuf>>(dest_path: P) -> Self
472 {
473 return
474 Self
475 {
476 file_path: dest_path.into()
477 };
478 }
479
480 #[inline]
481 pub
482 fn get_path(&self) -> &Path
483 {
484 return self.file_path.as_path();
485 }
486 }
487
488 impl SyslogDestMsg for SyslogFile
489 {
490 fn get_max_msg_len() -> usize
491 {
492 if *common::RFC5424_MAX_DGRAM >= common::MAXLINE
493 {
494 return common::MAXLINE;
495 }
496 else
497 {
498 return *common::RFC5424_MAX_DGRAM;
499 };
500 }
501 }
502
503 #[cfg(feature = "build_async_tokio")]
504 impl AsyncSyslogDestination for SyslogFile
505 {
506 type SocketTap = AsyncTap::<tokio::fs::File, Self>;
507 }
508
509 #[cfg(feature = "build_async_smol")]
510 impl AsyncSyslogDestination for SyslogFile
511 {
512 type SocketTap = AsyncTap::<smol::fs::File, Self>;
513 }
514
515 #[cfg(feature = "build_sync")]
516 impl SyslogDestination for SyslogFile
517 {
518 type SocketTap = Tap::<File, Self>;
519
520 const DEST_TYPE: DestinationType = DestinationType::File;
521 }
522}
523
524#[cfg(feature = "build_ext_file")]
525pub use self::imp_syslog_file::SyslogFile;
526
527#[cfg(feature = "build_ext_tls")]
528pub mod imp_syslog_tls
529{
530 use std::fmt;
531 use std::{net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream}, sync::Arc, time::Duration};
532
533 #[cfg(feature = "build_sync")]
534use rustls::lock::Mutex;
535 use rustls::{pki_types::{CertificateDer, ServerName}, ClientConfig, ClientConnection, RootCertStore, StreamOwned};
536
537 use crate::{common, error::SyRes, map_error};
538
539 use super::*;
540
541 #[derive(Debug, Clone)]
543 pub struct SyslogTls
544 {
545 remote_addr: SocketAddr,
547
548 bind_addr: SocketAddr,
550
551 serv_name: ServerName<'static>,
553
554 client_config: Arc<ClientConfig>,
556
557 conn_timeout: Option<Duration>,
559 }
560
561 impl fmt::Display for SyslogTls
562 {
563 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
564 {
565 write!(f, "remote: {}, bind: {}, serv_name: {:?}, client: {:?}, conn_timeout: {:?}", self.remote_addr,
566 self.bind_addr, self.serv_name, self.client_config, self.conn_timeout)
567 }
568 }
569
570 impl SyslogTls
571 {
572 pub
588 fn new<P>(remote: P, local: Option<P>, serv_name: impl Into<String>,
589 root_cert: Vec<u8>, conn_timeout: Option<Duration>) -> SyRes<Self>
590 where P: AsRef<str>
591 {
592 use rustls::pki_types::pem::PemObject;
593
594 let server_name = serv_name.into();
595
596 let remote_addr: SocketAddr =
597 remote
598 .as_ref()
599 .parse()
600 .map_err(|e|
601 map_error!("failed parsing remote addr '{}', error: '{}'", remote.as_ref(), e)
602 )?;
603
604 let cert =
605 CertificateDer::from_pem_slice(root_cert.as_slice())
606 .map_err(|e|
607 map_error!("certificate parse error: '{}'", e)
608 )?;
609
610 let mut root_store = RootCertStore::empty();
611 root_store
612 .add(cert)
613 .map_err(|e|
614 map_error!("can not add root ceritficate, error: '{}'", e)
615 )?;
616
617 let serv_name =
618 server_name
619 .try_into()
620 .map_err(|e|
621 map_error!("server name error: '{}'", e)
622 )?;
623
624 let client_config =
625 rustls::ClientConfig::builder()
626 .with_root_certificates(root_store)
627 .with_no_client_auth();
628
629 let bind_addr: SocketAddr =
630 if let Some(bind) = local
631 {
632 bind
633 .as_ref()
634 .parse()
635 .map_err(|e|
636 map_error!("failed parsing bind addr '{}', error: '{}'", remote.as_ref(), e)
637 )?
638 }
639 else
640 {
641 SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)
642 };
643
644 return Ok(
645 Self
646 {
647 remote_addr: remote_addr,
648 bind_addr: bind_addr,
649 serv_name: serv_name,
650 client_config: Arc::new(client_config),
651 conn_timeout: conn_timeout,
652 }
653 );
654 }
655
656 #[inline]
657 pub
658 fn get_remote_addr(&self) -> &SocketAddr
659 {
660 return &self.remote_addr;
661 }
662
663 #[inline]
664 pub
665 fn get_bind_addr(&self) -> &SocketAddr
666 {
667 return &self.bind_addr;
668 }
669
670 #[inline]
671 pub
672 fn get_serv_name(&self) -> ServerName<'static>
673 {
674 return self.serv_name.clone();
675 }
676
677 #[inline]
678 pub
679 fn get_client_config(&self) -> Arc<ClientConfig>
680 {
681 return self.client_config.clone();
682 }
683
684 #[inline]
685 pub
686 fn get_get_conn_timeout(&self) -> Option<Duration>
687 {
688 return self.conn_timeout.clone();
689 }
690 }
691
692 impl SyslogDestMsg for SyslogTls
693 {
694 fn get_max_msg_len() -> usize
695 {
696 return common::RFC5424_TCP_MAX_PKT_LEN;
697 }
698 }
699
700 #[cfg(feature = "build_async_tokio")]
701 impl AsyncSyslogDestination for SyslogTls
702 {
703 type SocketTap = AsyncTap::<tokio_rustls::client::TlsStream<tokio::net::TcpStream>, Self>;
704 }
705
706 #[cfg(feature = "build_async_smol")]
707 impl AsyncSyslogDestination for SyslogTls
708 {
709 type SocketTap = AsyncTap::<futures_rustls::client::TlsStream<smol::net::TcpStream>, Self>;
710 }
711
712 #[cfg(feature = "build_sync")]
713 impl SyslogDestination for SyslogTls
714 {
715 type SocketTap = Tap::<Mutex<StreamOwned<ClientConnection, TcpStream>>, Self>;
716
717 const DEST_TYPE: DestinationType = DestinationType::Network;
718 }
719}
720
721#[cfg(feature = "build_ext_tls")]
722pub use self::imp_syslog_tls::SyslogTls;