1
0
mirror of https://github.com/fafhrd91/actix-net synced 2024-11-23 21:51:06 +01:00

add alpn and authority TLVs

This commit is contained in:
Rob Ede 2022-10-31 19:48:47 +00:00
parent d336fb34ce
commit 21c31ad63d
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
3 changed files with 118 additions and 13 deletions

View File

@ -76,7 +76,9 @@ async fn wrap_with_proxy_protocol_v2(mut stream: TcpStream) -> io::Result<()> {
proxy_header.add_typed_tlv(tlv::UniqueId::new("4269")); // UNIQUE_ID
proxy_header.add_typed_tlv(tlv::Noop::new("NOOP m8")); // NOOP
proxy_header.add_crc23c_checksum_tlv();
proxy_header.add_typed_tlv(tlv::Authority::new("localhost")); // NOOP
proxy_header.add_typed_tlv(tlv::Alpn::new("http/1.1")); // NOOP
proxy_header.add_crc23c_checksum();
proxy_header.write_to_tokio(&mut upstream).await?;

View File

@ -1,4 +1,17 @@
use std::{borrow::Cow, convert::TryFrom};
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;
@ -16,13 +29,90 @@ pub trait Tlv: Sized {
}
}
/// 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 = 0x03;
const TYPE: u8 = PP2_TYPE_CRC32C;
fn try_from_value(value: &[u8]) -> Option<Self> {
let checksum_bytes = <[u8; 4]>::try_from(value).ok()?;
@ -37,7 +127,10 @@ impl Tlv for Crc32c {
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
/// 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>,
}
@ -46,7 +139,7 @@ impl Noop {
///
///
/// # Panics
/// Panics if value is empty (i.e., has length of 0).
/// Panics if `value` is empty (i.e., has length of 0).
pub fn new(value: impl Into<Vec<u8>>) -> Self {
let value = value.into();
@ -57,7 +150,7 @@ impl Noop {
}
impl Tlv for Noop {
const TYPE: u8 = 0x04;
const TYPE: u8 = PP2_TYPE_NOOP;
fn try_from_value(value: &[u8]) -> Option<Self> {
Some(Self {
@ -70,7 +163,13 @@ impl Tlv for Noop {
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
/// 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>,
}
@ -79,9 +178,9 @@ impl UniqueId {
///
///
/// # 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();
/// 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");
@ -90,7 +189,7 @@ impl UniqueId {
}
impl Tlv for UniqueId {
const TYPE: u8 = 0x05;
const TYPE: u8 = PP2_TYPE_UNIQUE_ID;
fn try_from_value(value: &[u8]) -> Option<Self> {
Some(Self {

View File

@ -132,8 +132,12 @@ impl Header {
self.tlvs.iter().any(|&(typ, _)| typ == T::TYPE)
}
/// Calculates and adds a crc32c TLV to the PROXY header.
///
/// Uses method defined in spec.
///
/// If this is not called last thing it will be wrong.
pub fn add_crc23c_checksum_tlv(&mut self) {
pub fn add_crc23c_checksum(&mut self) {
// don't add a checksum if it is already set
if self.has_tlv::<Crc32c>() {
return;
@ -285,7 +289,7 @@ mod tests {
);
// add crc32c TLV to header
header.add_crc23c_checksum_tlv();
header.add_crc23c_checksum();
assert_eq!(header.v2_len(), 12 + 7);
assert_eq!(header.to_vec(), exp);