|
| 1 | +use std::borrow::Cow; |
| 2 | +use std::io; |
| 3 | +use std::io::BufWriter; |
| 4 | +use std::net::TcpStream; |
| 5 | +use std::net::ToSocketAddrs; |
| 6 | + |
| 7 | +use native_tls::TlsStream; |
| 8 | +use native_tls::{TlsConnector, TlsConnectorBuilder}; |
| 9 | + |
| 10 | +use crate::format::SyslogContext; |
| 11 | +use crate::sender::internal::impl_syslog_sender_common; |
| 12 | +use crate::sender::internal::impl_syslog_stream_send_formatted; |
| 13 | + |
| 14 | +/// Create a TLS sender that sends messages to the well-known port (6514). |
| 15 | +/// |
| 16 | +/// See also [RFC-5425] §4.1 Port Assignment. |
| 17 | +/// |
| 18 | +/// [RFC-5425]: https://datatracker.ietf.org/doc/html/rfc5425#section-4.1 |
| 19 | +pub fn tls_well_known<S: AsRef<str>>(domain: S) -> io::Result<TlsSender> { |
| 20 | + let domain = domain.as_ref(); |
| 21 | + tls(format!("{domain}:6514"), domain) |
| 22 | +} |
| 23 | + |
| 24 | +/// Create a TLS sender that sends messages to the given address. |
| 25 | +pub fn tls<A: ToSocketAddrs, S: AsRef<str>>(addr: A, domain: S) -> io::Result<TlsSender> { |
| 26 | + tls_with(addr, domain, TlsConnector::builder()) |
| 27 | +} |
| 28 | + |
| 29 | +/// Create a TLS sender that sends messages to the given address with certificate builder. |
| 30 | +pub fn tls_with<A: ToSocketAddrs, S: AsRef<str>>( |
| 31 | + addr: A, |
| 32 | + domain: S, |
| 33 | + builder: TlsConnectorBuilder, |
| 34 | +) -> io::Result<TlsSender> { |
| 35 | + TlsSender::connect(addr, domain, builder) |
| 36 | +} |
| 37 | + |
| 38 | +/// A syslog sender that sends messages to a TCP socket over TLS. |
| 39 | +#[derive(Debug)] |
| 40 | +pub struct TlsSender { |
| 41 | + writer: BufWriter<TlsStream<TcpStream>>, |
| 42 | + context: SyslogContext, |
| 43 | + postfix: Cow<'static, str>, |
| 44 | +} |
| 45 | + |
| 46 | +impl TlsSender { |
| 47 | + /// Connect to a TCP socket over TLS at the given address. |
| 48 | + pub fn connect<A: ToSocketAddrs, S: AsRef<str>>( |
| 49 | + addr: A, |
| 50 | + domain: S, |
| 51 | + builder: TlsConnectorBuilder, |
| 52 | + ) -> io::Result<Self> { |
| 53 | + let domain = domain.as_ref(); |
| 54 | + let stream = TcpStream::connect(addr)?; |
| 55 | + let connector = builder.build().map_err(io::Error::other)?; |
| 56 | + let stream = connector |
| 57 | + .connect(domain, stream) |
| 58 | + .map_err(io::Error::other)?; |
| 59 | + Ok(Self { |
| 60 | + writer: BufWriter::new(stream), |
| 61 | + context: SyslogContext::default(), |
| 62 | + postfix: Cow::Borrowed("\r\n"), |
| 63 | + }) |
| 64 | + } |
| 65 | + |
| 66 | + /// Set the postfix when formatting Syslog message. |
| 67 | + /// |
| 68 | + /// This is generally '\r\n' as defined in [RFC-6587] §3.4.2. |
| 69 | + /// |
| 70 | + /// [RFC-6587]: https://datatracker.ietf.org/doc/html/rfc6587 |
| 71 | + pub fn set_postfix(&mut self, postfix: impl Into<Cow<'static, str>>) { |
| 72 | + self.postfix = postfix.into(); |
| 73 | + } |
| 74 | + |
| 75 | + /// Set the context when formatting Syslog message. |
| 76 | + pub fn set_context(mut self, context: SyslogContext) { |
| 77 | + self.context = context; |
| 78 | + } |
| 79 | + |
| 80 | + /// Mutate the context when formatting Syslog message. |
| 81 | + pub fn mut_context(&mut self) -> &mut SyslogContext { |
| 82 | + &mut self.context |
| 83 | + } |
| 84 | +} |
| 85 | + |
| 86 | +impl_syslog_sender_common!(TlsSender); |
| 87 | +impl_syslog_stream_send_formatted!(TlsSender); |
0 commit comments