use std::{fmt};
use crate::{error::SyRes, TapType};
use crate::SyslogDestination;
use crate::common::*;
pub trait SyslogTap<D: SyslogDestination>: fmt::Debug + Send + Clone
{
fn new(req_tap: D) -> SyRes<Self> where Self: Sized;
fn connectlog(&mut self) -> SyRes<()>;
fn send(&self, msg: &[u8]) -> std::io::Result<usize>;
fn disconnectlog(&mut self) -> SyRes<()>;
fn is_connected(&self) -> bool;
fn get_type(&self) -> TapType;
fn get_max_msg_size() -> usize;
fn update_tap_data(&mut self, tap_data: D);
}
#[derive(Debug)]
pub struct Tap<T, D: SyslogDestination>
{
sock: Option<T>,
tap_data: D,
cur_tap_type: TapType,
}
impl<T, D: SyslogDestination> Clone for Tap<T, D>
{
fn clone(&self) -> Self
{
return
Self
{
sock: None,
tap_data: self.tap_data.clone(),
cur_tap_type: TapType::None
};
}
}
impl<T, D: SyslogDestination> Drop for Tap<T, D>
{
fn drop(&mut self)
{
let _ = self.sock.take();
}
}
#[cfg(feature = "build_ext_tls")]
mod with_tls
{
use std::{io::Write, net::TcpStream};
use std::io::ErrorKind;
use rustls::{lock::Mutex, ClientConnection, StreamOwned};
use socket2::{Domain, Protocol, Socket, Type};
use crate::{SyslogDestMsg, map_error_os};
use super::*;
impl SyslogTap<crate::SyslogTls> for Tap<Mutex<StreamOwned<ClientConnection, TcpStream>>, crate::SyslogTls>
{
fn new(req_tap: crate::SyslogTls) -> SyRes<Self>
{
let ret =
Self
{
sock: None,
tap_data: req_tap,
cur_tap_type: TapType::NetTcp,
};
return Ok(ret);
}
fn connectlog(&mut self) -> SyRes<()>
{
use crate::map_error;
let tls_conn =
ClientConnection
::new(self.tap_data.get_client_config(), self.tap_data.get_serv_name())
.map_err(|e|
map_error!("can not connect to tcp '{}', error: {}", self.tap_data.get_remote_addr(), e)
)?;
let socket =
if self.tap_data.get_remote_addr().is_ipv4() == true
{
Socket::new(Domain::IPV4, Type::STREAM, Some(Protocol::TCP))
}
else
{
Socket::new(Domain::IPV6, Type::STREAM, Some(Protocol::TCP))
}
.map_err(|e|
map_error_os!(e, "cannot create socket TCP to '{}', error: {}", self.tap_data.get_remote_addr(), e)
)?;
if self.tap_data.get_bind_addr().ip().is_unspecified() == false
{
socket
.bind(&(*self.tap_data.get_bind_addr()).into())
.map_err(|e|
map_error_os!(e, "cannot bind tpc to '{}', error: {}", self.tap_data.get_remote_addr(), e)
)?;
}
if let Some(c_timeout) = self.tap_data.get_get_conn_timeout()
{
socket.connect_timeout(&(*self.tap_data.get_remote_addr()).into(), c_timeout)
}
else
{
socket.connect(&(*self.tap_data.get_remote_addr()).into())
}
.map_err(|e|
map_error_os!(e, "can not connect to tcp '{}', error: {}", self.tap_data.get_remote_addr(), e)
)?;
let tcp_steam: TcpStream = socket.into();
let tls = StreamOwned::new(tls_conn, tcp_steam);
self.sock = Some(Mutex::new(tls));
return Ok(());
}
fn send(&self, msg: &[u8]) -> std::io::Result<usize>
{
let mut sock =
self
.sock
.as_ref()
.ok_or_else(||
std::io::Error::new(ErrorKind::NotConnected, "no connection")
)?
.lock()
.ok_or_else(||
std::io::Error::new(ErrorKind::Deadlock, "failed to lock mutex")
)?;
let res = sock.write(msg)?;
sock.flush()?;
return Ok(res);
}
fn disconnectlog(&mut self) -> SyRes<()>
{
match self.sock.take()
{
Some(s) =>
{
drop(s);
Ok(())
},
None =>
{
Ok(())
}
}
}
#[inline]
fn is_connected(&self) -> bool
{
return self.sock.is_some();
}
#[inline]
fn get_type(&self) -> TapType
{
return self.cur_tap_type;
}
#[inline]
fn get_max_msg_size() -> usize
{
return crate::SyslogTls::get_max_msg_len();
}
#[inline]
fn update_tap_data(&mut self, tap_data: crate::SyslogTls)
{
self.tap_data = tap_data;
}
}
}
#[cfg(feature = "build_ext_net")]
mod with_net
{
use std::{io::Write, net::{TcpStream, UdpSocket}};
use std::io::ErrorKind;
use socket2::{Domain, Protocol, Socket, Type};
use crate::{SyslogDestMsg, map_error_os};
use super::*;
impl SyslogTap<crate::SyslogNetTcp> for Tap<TcpStream, crate::SyslogNetTcp>
{
fn new(req_tap: crate::SyslogNetTcp) -> SyRes<Self>
{
let ret =
Self
{
sock: None,
tap_data: req_tap,
cur_tap_type: TapType::NetTcp,
};
return Ok(ret);
}
fn connectlog(&mut self) -> SyRes<()>
{
let socket =
if self.tap_data.get_remote_addr().is_ipv4() == true
{
Socket::new(Domain::IPV4, Type::STREAM, Some(Protocol::TCP))
}
else
{
Socket::new(Domain::IPV6, Type::STREAM, Some(Protocol::TCP))
}
.map_err(|e|
map_error_os!(e, "cannot create socket TCP to '{}', error: {}", self.tap_data.get_remote_addr(), e)
)?;
if self.tap_data.get_bind_addr().ip().is_unspecified() == false
{
socket
.bind(&(*self.tap_data.get_bind_addr()).into())
.map_err(|e|
map_error_os!(e, "cannot bind tpc to '{}', error: {}", self.tap_data.get_remote_addr(), e)
)?;
}
if let Some(c_timeout) = self.tap_data.get_conn_timeout()
{
socket.connect_timeout(&(*self.tap_data.get_remote_addr()).into(), c_timeout)
}
else
{
socket.connect(&(*self.tap_data.get_remote_addr()).into())
}
.map_err(|e|
map_error_os!(e, "can not connect to tcp '{}', error: {}", self.tap_data.get_remote_addr(), e)
)?;
socket
.shutdown(std::net::Shutdown::Read)
.map_err(|e|
map_error_os!(e, "can not shutdown read portion, error: '{}'", e)
)?;
self.sock = Some(socket.into());
return Ok(());
}
fn send(&self, msg: &[u8]) -> std::io::Result<usize>
{
let mut sock =
self.sock
.as_ref()
.ok_or_else(||
std::io::Error::new(ErrorKind::NotConnected, "no connection")
)?;
let res = sock.write(msg)?;
sock.flush()?;
return Ok(res);
}
fn disconnectlog(&mut self) -> SyRes<()>
{
match self.sock.take()
{
Some(s) =>
{
drop(s);
Ok(())
},
None =>
{
Ok(())
}
}
}
#[inline]
fn is_connected(&self) -> bool
{
return self.sock.is_some();
}
#[inline]
fn get_type(&self) -> TapType
{
return self.cur_tap_type;
}
#[inline]
fn get_max_msg_size() -> usize
{
return crate::SyslogNetTcp::get_max_msg_len();
}
#[inline]
fn update_tap_data(&mut self, tap_data: crate::SyslogNetTcp)
{
self.tap_data = tap_data;
}
}
impl SyslogTap<crate::SyslogNetUdp> for Tap<UdpSocket, crate::SyslogNetUdp>
{
fn new(req_tap: crate::SyslogNetUdp) -> SyRes<Self>
{
let ret =
Self
{
sock: None,
tap_data: req_tap,
cur_tap_type: TapType::NetUdp,
};
return Ok(ret);
}
fn connectlog(&mut self) -> SyRes<()>
{
let socket =
UdpSocket
::bind(self.tap_data.get_bind_addr())
.map_err(|e|
map_error_os!(e, "can not bind udp '{}', error: '{}'", self.tap_data.get_bind_addr(), e)
)?;
socket
.connect(self.tap_data.get_remote_addr())
.map_err(|e|
map_error_os!(e, "can not connect to udp '{}', error: '{}'", self.tap_data.get_remote_addr(), e)
)?;
self.sock = Some(socket);
return Ok(());
}
fn send(&self, msg: &[u8]) -> std::io::Result<usize>
{
let sock =
self
.sock
.as_ref()
.ok_or_else(||
std::io::Error::new(ErrorKind::NotConnected, "no connection")
)?;
return sock.send(msg);
}
fn disconnectlog(&mut self) -> SyRes<()>
{
match self.sock.take()
{
Some(s) =>
{
drop(s);
Ok(())
},
None =>
{
Ok(())
}
}
}
fn is_connected(&self) -> bool
{
return self.sock.is_some();
}
fn get_type(&self) -> TapType
{
return self.cur_tap_type;
}
#[inline]
fn get_max_msg_size() -> usize
{
return crate::SyslogNetUdp::get_max_msg_len();
}
fn update_tap_data(&mut self, tap_data: crate::SyslogNetUdp)
{
self.tap_data = tap_data;
}
}
}
#[cfg(target_family = "unix")]
mod with_unix_syslog
{
use std::io::ErrorKind;
use std::os::unix::net::UnixDatagram;
use nix::errno::Errno;
use crate::{error::SyRes, TapType};
use crate::
{
SyslogDestMsg, SyslogLocal, SyslogTap, Tap, map_error_os, throw_error_errno, throw_error_os
};
use crate::common::*;
impl SyslogTap<SyslogLocal> for Tap<UnixDatagram, SyslogLocal>
{
fn new(req_tap: SyslogLocal) -> SyRes<Self>
{
return Ok(
Self
{
sock: None,
tap_data: req_tap,
cur_tap_type: TapType::None,
}
);
}
fn connectlog(&mut self) -> SyRes<()>
{
let sock =
UnixDatagram
::unbound()
.map_err(|e|
map_error_os!(e, "unbounded unix datagram initialization failure, error: '{}'", e)
)?;
let tap_type =
if self.tap_data.get_use_alternative() == false && self.tap_data.get_custom_remote_path().is_some() == true
{
if let Err(e) = sock.connect(self.tap_data.get_custom_remote_path().as_ref().unwrap())
{
throw_error_os!(e, "failed to open connection to syslog server at '{}'",
self.tap_data.get_custom_remote_path().as_ref().unwrap().display());
}
else
{
TapType::CustomLog
}
}
else if self.tap_data.get_custom_remote_path().is_some() == true &&
sock.connect(self.tap_data.get_custom_remote_path().as_ref().unwrap()).is_ok() == true
{
TapType::CustomLog
}
else if let Ok(_) = sock.connect(PATH_LOG_PRIV)
{
TapType::Priv
}
else if let Ok(_) = sock.connect(PATH_LOG)
{
TapType::UnPriv
}
else if let Ok(_) = sock.connect(PATH_OLDLOG)
{
TapType::OldLog
}
else if let Ok(_) = sock.connect(PATH_OSX)
{
TapType::Priv
}
else
{
throw_error_errno!(Errno::last(), "failed to open connection to syslog server");
};
#[cfg(any(
target_os = "freebsd",
target_os = "dragonfly",
target_os = "openbsd",
target_os = "netbsd",
target_os = "macos"
))]
{
use std::os::fd::AsRawFd;
let mut len: std::mem::MaybeUninit<nix::libc::socklen_t> = std::mem::MaybeUninit::uninit();
let res =
unsafe
{
nix::libc::getsockopt(
sock.as_raw_fd(),
nix::libc::SOL_SOCKET,
nix::libc::SO_SNDBUF,
len.as_mut_ptr() as *mut nix::libc::c_void,
&mut {
std::mem::size_of::<nix::libc::socklen_t>() as nix::libc::socklen_t
}
)
};
if res == 0
{
let mut len = unsafe { len.assume_init() } as usize;
if len < MAXLINE
{
len = MAXLINE;
unsafe {
nix::libc::setsockopt(
sock.as_raw_fd(),
nix::libc::SOL_SOCKET,
nix::libc::SO_SNDBUF,
&len as *const _ as *const nix::libc::c_void,
std::mem::size_of::<nix::libc::socklen_t>() as nix::libc::socklen_t
)
};
}
}
}
sock
.shutdown(std::net::Shutdown::Read)
.map_err(|e|
map_error_os!(e, "can not shutdown read portion, error: '{}'", e)
)?;
self.sock = Some(sock);
self.cur_tap_type = tap_type;
return Ok(());
}
fn send(&self, msg: &[u8]) -> std::io::Result<usize>
{
let sock =
self
.sock
.as_ref()
.ok_or_else(||
std::io::Error::new(ErrorKind::NotConnected, "no connection")
)?;
return sock.send(msg);
}
fn disconnectlog(&mut self) -> SyRes<()>
{
match self.sock.take()
{
Some(s) =>
{
self.cur_tap_type = TapType::None;
drop(s);
Ok(())
},
None =>
{
self.cur_tap_type = TapType::None;
Ok(())
}
}
}
#[inline]
fn is_connected(&self) -> bool
{
return self.sock.is_some();
}
#[inline]
fn get_type(&self) -> TapType
{
return self.cur_tap_type;
}
#[inline]
fn get_max_msg_size() -> usize
{
return SyslogLocal::get_max_msg_len();
}
#[inline]
fn update_tap_data(&mut self, tap_data: SyslogLocal)
{
self.tap_data = tap_data;
}
}
}
#[cfg(feature = "build_ext_file")]
mod with_file
{
use std::fs::File;
use std::io::ErrorKind;
use crate::{SyslogDestMsg, SyslogFile, map_error_code, map_error_os};
use super::*;
impl SyslogTap<crate::SyslogFile> for Tap<File, SyslogFile>
{
fn new(req_tap: crate::SyslogFile) -> SyRes<Self>
{
let ret =
Self
{
sock: None,
tap_data: req_tap,
cur_tap_type: TapType::LocalFile,
};
return Ok(ret);
}
fn connectlog(&mut self) -> SyRes<()>
{
let file =
File::options()
.append(true)
.read(false)
.write(true)
.create(true)
.open(self.tap_data.get_path())
.map_err(|e|
map_error_os!(e, "can not open file '{}' to write, error: '{}'",
self.tap_data.get_path().display(), e)
)?;
self.sock = Some(file);
return Ok(());
}
fn send(&self, msg: &[u8]) -> std::io::Result<usize>
{
use std::io::Write;
let mut sock =
self
.sock
.as_ref()
.ok_or_else(||
std::io::Error::new(ErrorKind::NotConnected, "no connection")
)?;
sock.write_all(msg)?;
return Ok(msg.len());
}
fn disconnectlog(&mut self) -> SyRes<()>
{
match self.sock.take()
{
Some(file) =>
{
file
.sync_data()
.map_err(|e|
map_error_os!(e, "d")
)?;
drop(file);
return Ok(());
},
None =>
{
return Ok(())
}
}
}
#[inline]
fn is_connected(&self) -> bool
{
return self.sock.is_some();
}
#[inline]
fn get_type(&self) -> TapType
{
return self.cur_tap_type;
}
#[inline]
fn get_max_msg_size() -> usize
{
return SyslogFile::get_max_msg_len();
}
#[inline]
fn update_tap_data(&mut self, tap_data: SyslogFile)
{
self.tap_data = tap_data;
}
}
}
#[cfg(target_family = "windows")]
mod with_windows_eventlog
{
use std::io::ErrorKind;
use crate::portable::{EventLogLocal};
use crate::{error::SyRes, TapType};
use crate::
{
SyslogDestMsg, WindowsEvent, SyslogTap, Tap, map_error_os
};
impl SyslogTap<WindowsEvent> for Tap<EventLogLocal, WindowsEvent>
{
fn new(req_tap: WindowsEvent) -> SyRes<Self>
{
return Ok(
Self
{
sock: None,
tap_data: req_tap,
cur_tap_type: TapType::None,
}
);
}
fn connectlog(&mut self) -> SyRes<()>
{
let sock =
EventLogLocal::new(&self.tap_data)
.map_err(|e|
map_error_os!(e, "EventRegister error: '{}'", e)
)?;
self.sock = Some(sock);
self.cur_tap_type = TapType::WindowsEventLog;
return Ok(());
}
fn send(&self, msg: &[u8]) -> std::io::Result<usize>
{
let sock =
self
.sock
.as_ref()
.ok_or_else(||
std::io::Error::new(ErrorKind::NotConnected, "no connection")
)?;
return sock.send(msg);
}
fn disconnectlog(&mut self) -> SyRes<()>
{
match self.sock.take()
{
Some(s) =>
{
self.cur_tap_type = TapType::None;
drop(s);
Ok(())
},
None =>
{
self.cur_tap_type = TapType::None;
Ok(())
}
}
}
#[inline]
fn is_connected(&self) -> bool
{
return self.sock.is_some();
}
#[inline]
fn get_type(&self) -> TapType
{
return self.cur_tap_type;
}
#[inline]
fn get_max_msg_size() -> usize
{
return WindowsEvent::get_max_msg_len();
}
#[inline]
fn update_tap_data(&mut self, tap_data: WindowsEvent)
{
self.tap_data = tap_data;
}
}
}