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:
parent
d336fb34ce
commit
21c31ad63d
@ -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?;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user