mirror of https://github.com/fafhrd91/actix-net
228 lines
5.8 KiB
Rust
228 lines
5.8 KiB
Rust
use std::{borrow::Cow, convert::TryFrom, str};
|
|
|
|
const PP2_TYPE_ALPN: u8 = 0x01;
|
|
const PP2_TYPE_AUTHORITY: u8 = 0x02;
|
|
const PP2_TYPE_CRC32C: u8 = 0x03; // done
|
|
const PP2_TYPE_NOOP: u8 = 0x04; // done
|
|
const PP2_TYPE_UNIQUE_ID: u8 = 0x05; // done
|
|
const PP2_TYPE_SSL: u8 = 0x20;
|
|
const PP2_SUBTYPE_SSL_VERSION: u8 = 0x21;
|
|
const PP2_SUBTYPE_SSL_CN: u8 = 0x22;
|
|
const PP2_SUBTYPE_SSL_CIPHER: u8 = 0x23;
|
|
const PP2_SUBTYPE_SSL_SIG_ALG: u8 = 0x24;
|
|
const PP2_SUBTYPE_SSL_KEY_ALG: u8 = 0x25;
|
|
const PP2_TYPE_NETNS: u8 = 0x30;
|
|
|
|
pub trait Tlv: Sized {
|
|
const TYPE: u8;
|
|
|
|
fn try_from_value(value: &[u8]) -> Option<Self>;
|
|
|
|
fn value_bytes(&self) -> Cow<'_, [u8]>;
|
|
|
|
fn try_from_parts(typ: u8, value: &[u8]) -> Option<Self> {
|
|
if typ != Self::TYPE {
|
|
return None;
|
|
}
|
|
|
|
Self::try_from_value(value)
|
|
}
|
|
}
|
|
|
|
/// Application-Layer Protocol Negotiation (ALPN). It is a byte sequence defining
|
|
/// the upper layer protocol in use over the connection. The most common use case
|
|
/// will be to pass the exact copy of the ALPN extension of the Transport Layer
|
|
/// Security (TLS) protocol as defined by RFC7301 [9].
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub struct Alpn {
|
|
alpn: Vec<u8>,
|
|
}
|
|
|
|
impl Alpn {
|
|
///
|
|
///
|
|
/// # Panics
|
|
/// Panics if `alpn` is empty (i.e., has length of 0).
|
|
pub fn new(alpn: impl Into<Vec<u8>>) -> Self {
|
|
let alpn = alpn.into();
|
|
|
|
assert!(!alpn.is_empty(), "ALPN TLV value cannot be empty");
|
|
|
|
Self { alpn }
|
|
}
|
|
}
|
|
|
|
impl Tlv for Alpn {
|
|
const TYPE: u8 = PP2_TYPE_ALPN;
|
|
|
|
fn try_from_value(value: &[u8]) -> Option<Self> {
|
|
Some(Self {
|
|
alpn: value.to_owned(),
|
|
})
|
|
}
|
|
|
|
fn value_bytes(&self) -> Cow<'_, [u8]> {
|
|
Cow::Borrowed(&self.alpn)
|
|
}
|
|
}
|
|
|
|
/// Contains the host name value passed by the client, as an UTF8-encoded string.
|
|
/// In case of TLS being used on the client connection, this is the exact copy of
|
|
/// the "server_name" extension as defined by RFC3546 [10], section 3.1, often
|
|
/// referred to as "SNI". There are probably other situations where an authority
|
|
/// can be mentioned on a connection without TLS being involved at all.
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub struct Authority {
|
|
authority: String,
|
|
}
|
|
|
|
impl Authority {
|
|
/// A UTF-8
|
|
///
|
|
/// # Panics
|
|
/// Panics if `authority` is an empty string.
|
|
pub fn new(authority: impl Into<String>) -> Self {
|
|
let authority = authority.into();
|
|
|
|
assert!(!authority.is_empty(), "Authority TLV value cannot be empty");
|
|
|
|
Self { authority }
|
|
}
|
|
}
|
|
|
|
impl Tlv for Authority {
|
|
const TYPE: u8 = PP2_TYPE_AUTHORITY;
|
|
|
|
fn try_from_value(value: &[u8]) -> Option<Self> {
|
|
Some(Self {
|
|
authority: str::from_utf8(value).ok()?.to_owned(),
|
|
})
|
|
}
|
|
|
|
fn value_bytes(&self) -> Cow<'_, [u8]> {
|
|
Cow::Borrowed(&self.authority.as_bytes())
|
|
}
|
|
}
|
|
|
|
/// The value of the type PP2_TYPE_CRC32C is a 32-bit number storing the CRC32c
|
|
/// checksum of the PROXY protocol header.
|
|
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
|
pub struct Crc32c {
|
|
pub(crate) checksum: u32,
|
|
}
|
|
|
|
impl Tlv for Crc32c {
|
|
const TYPE: u8 = PP2_TYPE_CRC32C;
|
|
|
|
fn try_from_value(value: &[u8]) -> Option<Self> {
|
|
let checksum_bytes = <[u8; 4]>::try_from(value).ok()?;
|
|
|
|
Some(Self {
|
|
checksum: u32::from_be_bytes(checksum_bytes),
|
|
})
|
|
}
|
|
|
|
fn value_bytes(&self) -> Cow<'_, [u8]> {
|
|
Cow::Owned(self.checksum.to_be_bytes().to_vec())
|
|
}
|
|
}
|
|
|
|
/// The TLV of this type should be ignored when parsed. The value is zero or more
|
|
/// bytes. Can be used for data padding or alignment. Note that it can be used
|
|
/// to align only by 3 or more bytes because a TLV can not be smaller than that.
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub struct Noop {
|
|
value: Vec<u8>,
|
|
}
|
|
|
|
impl Noop {
|
|
///
|
|
///
|
|
/// # Panics
|
|
/// Panics if `value` is empty (i.e., has length of 0).
|
|
pub fn new(value: impl Into<Vec<u8>>) -> Self {
|
|
let value = value.into();
|
|
|
|
assert!(!value.is_empty(), "Noop TLV `value` cannot be empty");
|
|
|
|
Self { value }
|
|
}
|
|
}
|
|
|
|
impl Tlv for Noop {
|
|
const TYPE: u8 = PP2_TYPE_NOOP;
|
|
|
|
fn try_from_value(value: &[u8]) -> Option<Self> {
|
|
Some(Self {
|
|
value: value.to_owned(),
|
|
})
|
|
}
|
|
|
|
fn value_bytes(&self) -> Cow<'_, [u8]> {
|
|
Cow::Borrowed(&self.value)
|
|
}
|
|
}
|
|
|
|
/// The value of the type PP2_TYPE_UNIQUE_ID is an opaque byte sequence of up to
|
|
/// 128 bytes generated by the upstream proxy that uniquely identifies the
|
|
/// connection.
|
|
///
|
|
/// The unique ID can be used to easily correlate connections across multiple
|
|
/// layers of proxies, without needing to look up IP addresses and port numbers.
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub struct UniqueId {
|
|
value: Vec<u8>,
|
|
}
|
|
|
|
impl UniqueId {
|
|
///
|
|
///
|
|
/// # Panics
|
|
/// Panics if `value` is empty (i.e., has length of 0).
|
|
pub fn new(id: impl Into<Vec<u8>>) -> Self {
|
|
let value = id.into();
|
|
|
|
assert!(!value.is_empty(), "UniqueId TLV `value` cannot be empty");
|
|
|
|
Self { value }
|
|
}
|
|
}
|
|
|
|
impl Tlv for UniqueId {
|
|
const TYPE: u8 = PP2_TYPE_UNIQUE_ID;
|
|
|
|
fn try_from_value(value: &[u8]) -> Option<Self> {
|
|
Some(Self {
|
|
value: value.to_owned(),
|
|
})
|
|
}
|
|
|
|
fn value_bytes(&self) -> Cow<'_, [u8]> {
|
|
Cow::Borrowed(&self.value)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
// #[test]
|
|
// #[should_panic]
|
|
// fn tlv_zero_len() {
|
|
// Tlv::new(0x00, vec![]);
|
|
// }
|
|
|
|
#[test]
|
|
fn tlv_as_crc32c() {
|
|
// noop
|
|
assert_eq!(Crc32c::try_from_parts(0x04, &[0x00]), None);
|
|
|
|
assert_eq!(
|
|
Crc32c::try_from_parts(0x03, &[0x08, 0x70, 0x17, 0x7b]),
|
|
Some(Crc32c {
|
|
checksum: 141563771
|
|
})
|
|
);
|
|
}
|
|
}
|