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