From 70f59f46efe85e56877751cdcc7d07b828960626 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 17 Sep 2023 21:53:51 +0100 Subject: [PATCH] add no-op SSL TLV --- actix-proxy-protocol/Cargo.toml | 8 ++-- actix-proxy-protocol/src/tlv.rs | 73 +++++++++++++++++++++++++++++++-- actix-proxy-protocol/src/v2.rs | 6 +-- 3 files changed, 77 insertions(+), 10 deletions(-) diff --git a/actix-proxy-protocol/Cargo.toml b/actix-proxy-protocol/Cargo.toml index f9996979..452041cf 100755 --- a/actix-proxy-protocol/Cargo.toml +++ b/actix-proxy-protocol/Cargo.toml @@ -8,15 +8,17 @@ description = "PROXY protocol utilities" keywords = ["proxy", "protocol", "network", "haproxy", "tcp"] categories = ["network-programming", "asynchronous"] homepage = "https://actix.rs" -repository = "https://github.com/actix/actix-net.git" -license = "MIT OR Apache-2.0" -edition = "2018" +repository = "https://github.com/actix/actix-net" +license.workspace = true +edition.workspace = true +rust-version.workspace = true [dependencies] actix-service = "2" actix-utils = "3" arrayvec = "0.7" +bitflags = "2" crc32fast = "1" futures-core = { version = "0.3.17", default-features = false, features = ["std"] } futures-util = { version = "0.3.17", default-features = false, features = ["std"] } diff --git a/actix-proxy-protocol/src/tlv.rs b/actix-proxy-protocol/src/tlv.rs index 3de965c3..31ea98d9 100644 --- a/actix-proxy-protocol/src/tlv.rs +++ b/actix-proxy-protocol/src/tlv.rs @@ -1,7 +1,7 @@ use std::{borrow::Cow, convert::TryFrom, str}; -const PP2_TYPE_ALPN: u8 = 0x01; -const PP2_TYPE_AUTHORITY: u8 = 0x02; +const PP2_TYPE_ALPN: u8 = 0x01; // done +const PP2_TYPE_AUTHORITY: u8 = 0x02; // done const PP2_TYPE_CRC32C: u8 = 0x03; // done const PP2_TYPE_NOOP: u8 = 0x04; // done const PP2_TYPE_UNIQUE_ID: u8 = 0x05; // done @@ -100,7 +100,7 @@ impl Tlv for Authority { } fn value_bytes(&self) -> Cow<'_, [u8]> { - Cow::Borrowed(&self.authority.as_bytes()) + Cow::Borrowed(self.authority.as_bytes()) } } @@ -178,11 +178,15 @@ impl UniqueId { /// /// /// # Panics - /// Panics if `value` is empty (i.e., has length of 0). + /// Panics if `value` is 0 bytes or larger than 128 bytes. pub fn new(id: impl Into>) -> Self { let value = id.into(); assert!(!value.is_empty(), "UniqueId TLV `value` cannot be empty"); + assert!( + value.len() < 128, + "UniqueId TLV `value` cannot be larger than 128 bytes" + ); Self { value } } @@ -202,6 +206,67 @@ impl Tlv for UniqueId { } } +bitflags::bitflags! { + #[derive(Debug, Clone, PartialEq, Eq)] + struct SslClientFlags: u8 { + const PP2_CLIENT_SSL = 0x01; + const PP2_CLIENT_CERT_CONN = 0x02; + const PP2_CLIENT_CERT_SESS = 0x04; + } +} + +/// TLS (SSL). +/// +/// Heckin broken atm. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Ssl { + /// The field is made of a bit field indicating which element is present. + /// + /// Note, that each of these elements may lead to extra data being appended to + /// this TLV using a second level of TLV encapsulation. It is thus possible to + /// find multiple TLV values after this field. The total length of the pp2_tlv_ssl + /// TLV will reflect this. + client: SslClientFlags, + + /// The field will be zero if the client presented a certificate + /// and it was successfully verified, and non-zero otherwise. + verify: bool, + + /// Sub-TLVs. + tlvs: Vec, +} + +impl Tlv for Ssl { + const TYPE: u8 = PP2_TYPE_SSL; + + fn try_from_value(value: &[u8]) -> Option { + /// The PP2_CLIENT_SSL flag indicates that the client connected over SSL/TLS. When + /// this field is present, the US-ASCII string representation of the TLS version is + /// appended at the end of the field in the TLV format using the type + /// PP2_SUBTYPE_SSL_VERSION. + const PP2_CLIENT_SSL: u8 = 0x01; + + /// PP2_CLIENT_CERT_CONN indicates that the client provided a certificate over the + /// current connection. + const PP2_CLIENT_CERT_CONN: u8 = 0x02; + + /// PP2_CLIENT_CERT_SESS indicates that the client provided a + /// certificate at least once over the TLS session this connection belongs to. + const PP2_CLIENT_CERT_SESS: u8 = 0x04; + + // TODO: finish parsing + + None + } + + fn value_bytes(&self) -> Cow<'_, [u8]> { + Cow::Borrowed(&[]) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +struct SslTlv {} + #[cfg(test)] mod tests { use super::*; diff --git a/actix-proxy-protocol/src/v2.rs b/actix-proxy-protocol/src/v2.rs index 3e3244c1..ac92c61e 100644 --- a/actix-proxy-protocol/src/v2.rs +++ b/actix-proxy-protocol/src/v2.rs @@ -110,7 +110,7 @@ impl Header { for (typ, value) in &self.tlvs { wrt.write_all(&[*typ])?; wrt.write_all(&(value.len() as u16).to_be_bytes())?; - wrt.write_all(&value)?; + wrt.write_all(value)?; } Ok(()) @@ -170,7 +170,7 @@ impl Header { let crc_sent = self .tlvs .iter() - .filter_map(|(typ, value)| Crc32c::try_from_parts(*typ, &value)) + .filter_map(|(typ, value)| Crc32c::try_from_parts(*typ, value)) .next()?; // If the checksum is provided as part of the PROXY header and the checksum @@ -185,7 +185,7 @@ impl Header { let mut this = self.clone(); for (typ, value) in this.tlvs.iter_mut() { - if Crc32c::try_from_parts(*typ, &value).is_some() { + if Crc32c::try_from_parts(*typ, value).is_some() { value.fill(0); } }