Skip to main content

rama_haproxy/protocol/v2/
model.rs

1use crate::protocol::ip::{IPv4, IPv6};
2use crate::protocol::v2::error::ParseError;
3use std::borrow::Cow;
4use std::fmt;
5use std::net::SocketAddr;
6use std::ops::BitOr;
7
8/// The prefix of the PROXY protocol header.
9pub const PROTOCOL_PREFIX: &[u8] = b"\r\n\r\n\0\r\nQUIT\n";
10/// The minimum length in bytes of a PROXY protocol header.
11pub(crate) const MINIMUM_LENGTH: usize = 16;
12/// The minimum length in bytes of a Type-Length-Value payload.
13pub(crate) const MINIMUM_TLV_LENGTH: usize = 3;
14
15/// The number of bytes for an IPv4 addresses payload.
16const IPV4_ADDRESSES_BYTES: usize = 12;
17/// The number of bytes for an IPv6 addresses payload.
18const IPV6_ADDRESSES_BYTES: usize = 36;
19/// The number of bytes for a unix addresses payload.
20const UNIX_ADDRESSES_BYTES: usize = 216;
21
22/// A proxy protocol version 2 header.
23///
24/// ## Examples
25/// ```rust
26/// use rama_haproxy::protocol::v2::{Addresses, AddressFamily, Command, Header, IPv4, ParseError, Protocol, PROTOCOL_PREFIX, Type, TypeLengthValue, Version};
27/// let mut header = Vec::from(PROTOCOL_PREFIX);
28/// header.extend([
29///    0x21, 0x12, 0, 16, 127, 0, 0, 1, 192, 168, 1, 1, 0, 80, 1, 187, 4, 0, 1, 42
30/// ]);
31///
32/// let addresses: Addresses = IPv4::new([127, 0, 0, 1], [192, 168, 1, 1], 80, 443).into();
33/// let expected = Header {
34///    header: header.as_slice().into(),
35///    version: Version::Two,
36///    command: Command::Proxy,
37///    protocol: Protocol::Datagram,
38///    addresses
39/// };
40/// let actual = Header::try_from(header.as_slice()).unwrap();
41///
42/// assert_eq!(actual, expected);
43/// assert_eq!(actual.tlvs().collect::<Vec<Result<TypeLengthValue<'_>, ParseError>>>(), vec![Ok(TypeLengthValue::new(Type::NoOp, &[42]))]);
44/// ```
45#[derive(Clone, Debug, PartialEq, Eq, Hash)]
46pub struct Header<'a> {
47    /// The underlying byte slice this `Header` is built on.
48    pub header: Cow<'a, [u8]>,
49    /// The version of the PROXY protocol.
50    pub version: Version,
51    /// The command of the PROXY protocol.
52    pub command: Command,
53    /// The protocol of the PROXY protocol.
54    pub protocol: Protocol,
55    /// The source and destination addresses of the PROXY protocol.
56    pub addresses: Addresses,
57}
58
59/// The supported `Version`s for binary headers.
60#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
61pub enum Version {
62    /// Version two of the PROXY protocol.
63    Two = 0x20,
64}
65
66/// The supported `Command`s for a PROXY protocol header.
67#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
68pub enum Command {
69    /// The connection is a local connection.
70    Local = 0,
71    /// The connection is a proxy connection.
72    Proxy,
73}
74
75/// The supported `AddressFamily` for a PROXY protocol header.
76#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
77pub enum AddressFamily {
78    /// The address family is unspecified.
79    Unspecified = 0x00,
80    /// The address family is IPv4.
81    IPv4 = 0x10,
82    /// The address family is IPv6.
83    IPv6 = 0x20,
84    /// The address family is Unix.
85    Unix = 0x30,
86}
87
88/// The supported `Protocol`s for a PROXY protocol header.
89#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
90pub enum Protocol {
91    /// The protocol is unspecified.
92    Unspecified = 0,
93    /// The protocol is a stream.
94    Stream,
95    /// The protocol is a datagram.
96    Datagram,
97}
98
99/// The source and destination address information for a given `AddressFamily`.
100///
101/// ## Examples
102/// ```rust
103/// use rama_haproxy::protocol::v2::{Addresses, AddressFamily};
104/// use std::net::SocketAddr;
105///
106/// let addresses: Addresses = ("127.0.0.1:80".parse::<SocketAddr>().unwrap(), "192.168.1.1:443".parse::<SocketAddr>().unwrap()).into();
107///
108/// assert_eq!(addresses.address_family(), AddressFamily::IPv4);
109/// ```
110#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
111pub enum Addresses {
112    /// The source and destination addresses are unspecified.
113    Unspecified,
114    /// The source and destination addresses are IPv4.
115    IPv4(IPv4),
116    /// The source and destination addresses are IPv6.
117    IPv6(IPv6),
118    /// The source and destination addresses are Unix.
119    Unix(Unix),
120}
121
122/// The source and destination addresses of UNIX sockets.
123#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
124pub struct Unix {
125    /// The source address of the UNIX socket.
126    pub source: [u8; 108],
127    /// The destination address of the UNIX socket.
128    pub destination: [u8; 108],
129}
130
131/// An `Iterator` of `TypeLengthValue`s stored in a byte slice.
132#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
133pub struct TypeLengthValues<'a> {
134    bytes: &'a [u8],
135    offset: usize,
136}
137
138/// A Type-Length-Value payload.
139#[derive(Clone, Debug, PartialEq, Eq, Hash)]
140pub struct TypeLengthValue<'a> {
141    /// The type of the `TypeLengthValue`. Unknown wire kinds are preserved as
142    /// `Type::Unknown(u8)` for round-trip fidelity.
143    pub kind: Type,
144    /// The value of the `TypeLengthValue`.
145    pub value: Cow<'a, [u8]>,
146}
147
148rama_utils::macros::enums::enum_builder! {
149    /// Supported types for `TypeLengthValue` payloads.
150    ///
151    /// Unknown TLV kinds are preserved as `Type::Unknown(u8)` so that callers
152    /// can still inspect or forward vendor-specific TLVs (e.g. AWS VPC endpoint
153    /// 0xEA, Azure PRIVATELINK 0xEE, GCP PSC TLVs) without losing fidelity.
154    @U8
155    pub enum Type {
156        /// The ALPN of the connection.
157        ALPN => 0x01,
158        /// The authority of the connection (e.g. SNI host name).
159        Authority => 0x02,
160        /// The CRC32C checksum of the header.
161        CRC32C => 0x03,
162        /// `NoOp` — padding / alignment.
163        NoOp => 0x04,
164        /// The unique connection ID assigned by the upstream proxy.
165        UniqueId => 0x05,
166        /// SSL information block (carries sub-TLVs).
167        SSL => 0x20,
168        /// The SSL version.
169        SSLVersion => 0x21,
170        /// The SSL common name.
171        SSLCommonName => 0x22,
172        /// The SSL cipher.
173        SSLCipher => 0x23,
174        /// The SSL signature algorithm.
175        SSLSignatureAlgorithm => 0x24,
176        /// The SSL key algorithm.
177        SSLKeyAlgorithm => 0x25,
178        /// The Linux network namespace name.
179        NetworkNamespace => 0x30,
180    }
181}
182
183impl fmt::Display for Header<'_> {
184    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185        write!(
186            f,
187            "{:?} {:#X} {:#X} ({} bytes)",
188            PROTOCOL_PREFIX,
189            self.version | self.command,
190            self.protocol | self.address_family(),
191            self.length()
192        )
193    }
194}
195
196impl Header<'_> {
197    /// Creates an owned clone of this [`Header`].
198    #[must_use]
199    pub fn to_owned(&self) -> Header<'static> {
200        Header {
201            header: Cow::Owned(self.header.to_vec()),
202            version: self.version,
203            command: self.command,
204            protocol: self.protocol,
205            addresses: self.addresses,
206        }
207    }
208
209    /// The length of this `Header`'s payload in bytes.
210    #[must_use]
211    pub fn length(&self) -> usize {
212        self.header[MINIMUM_LENGTH..].len()
213    }
214
215    /// The total length of this `Header` in bytes.
216    #[must_use]
217    pub fn len(&self) -> usize {
218        self.header.len()
219    }
220
221    /// Tests whether this `Header`'s underlying byte slice is empty.
222    #[must_use]
223    pub fn is_empty(&self) -> bool {
224        self.header.is_empty()
225    }
226
227    /// The `AddressFamily` of this `Header`.
228    #[must_use]
229    pub fn address_family(&self) -> AddressFamily {
230        self.addresses.address_family()
231    }
232
233    /// The length in bytes of the address portion of the payload.
234    fn address_bytes_end(&self) -> usize {
235        let length = self.length();
236        let address_bytes = self.address_family().byte_length().unwrap_or(length);
237
238        MINIMUM_LENGTH + std::cmp::min(address_bytes, length)
239    }
240
241    /// The bytes of the address portion of the payload.
242    #[must_use]
243    pub fn address_bytes(&self) -> &[u8] {
244        &self.header[MINIMUM_LENGTH..self.address_bytes_end()]
245    }
246
247    /// The bytes of the `TypeLengthValue` portion of the payload.
248    #[must_use]
249    pub fn tlv_bytes(&self) -> &[u8] {
250        &self.header[self.address_bytes_end()..]
251    }
252
253    /// An `Iterator` of `TypeLengthValue`s.
254    #[must_use]
255    pub fn tlvs(&self) -> TypeLengthValues<'_> {
256        TypeLengthValues {
257            bytes: self.tlv_bytes(),
258            offset: 0,
259        }
260    }
261
262    /// The underlying byte slice this `Header` is built on.
263    #[must_use]
264    pub fn as_bytes(&self) -> &[u8] {
265        self.header.as_ref()
266    }
267
268    /// Outcome of the `PP2_TYPE_CRC32C` TLV verification.
269    ///
270    /// Distinct from a `bool` so callers can tell apart "no CRC TLV", "valid",
271    /// "invalid CRC value", and "we never reached a CRC TLV because the TLV
272    /// stream is broken". That last case must NOT be conflated with a bad
273    /// CRC: rejecting on it would mean a header without any CRC TLV gets
274    /// rejected as "CRC invalid" just because some other TLV is malformed.
275    #[must_use]
276    pub fn verify_crc32c(&self) -> Crc32cStatus {
277        // Reuse the public TLV iterator and track the absolute byte offset of
278        // each TLV's value field inside `self.header`. We need the offset to
279        // know which 4 bytes of the header to substitute with zeros during
280        // the CRC computation (per spec section 2.2.5).
281        //
282        // The computation is allocation-free: the CRC is streamed over the
283        // header in three pieces — bytes before the CRC value, four zero
284        // bytes (replacing the CRC field), and bytes after the CRC value.
285        let tlv_start = self.address_bytes_end();
286        let mut cursor = tlv_start;
287        for tlv in self.tlvs() {
288            let tlv = match tlv {
289                Ok(t) => t,
290                Err(e) => {
291                    rama_core::telemetry::tracing::debug!(
292                        error = %e,
293                        "haproxy v2: TLV stream malformed before CRC32C TLV could be located",
294                    );
295                    return Crc32cStatus::MalformedBeforeCrc;
296                }
297            };
298            let value_start = cursor + MINIMUM_TLV_LENGTH;
299            let value_end = value_start + tlv.value.len();
300            if tlv.kind == Type::CRC32C {
301                let Ok(value) = <&[u8; 4]>::try_from(tlv.value.as_ref()) else {
302                    rama_core::telemetry::tracing::debug!(
303                        len = tlv.value.len(),
304                        "haproxy v2: CRC32C TLV has unexpected value length (want 4)",
305                    );
306                    return Crc32cStatus::Invalid;
307                };
308                let expected = u32::from_be_bytes(*value);
309
310                // Stream the CRC over [..value_start] + [0,0,0,0] + [value_end..]
311                // without copying the header.
312                let mut hasher = super::Crc32cHasher::new();
313                hasher.update(&self.header[..value_start]);
314                hasher.update(&[0u8; 4]);
315                hasher.update(&self.header[value_end..]);
316                return if hasher.finalize() == expected {
317                    Crc32cStatus::Valid
318                } else {
319                    Crc32cStatus::Invalid
320                };
321            }
322            cursor = value_end;
323        }
324        Crc32cStatus::Absent
325    }
326}
327
328/// Result of [`Header::verify_crc32c`].
329///
330/// See the method docs for what each variant means.
331#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
332pub enum Crc32cStatus {
333    /// No `PP2_TYPE_CRC32C` TLV is present in this header.
334    Absent,
335    /// A CRC32C TLV is present and matches the recomputed value.
336    Valid,
337    /// A CRC32C TLV is present but its value does not match the recomputed
338    /// value, or its value length is not 4 bytes.
339    Invalid,
340    /// A CRC32C TLV may or may not be present — the TLV stream became
341    /// unparseable before we could decide. Callers should treat this as
342    /// "couldn't verify", not "verification failed".
343    MalformedBeforeCrc,
344}
345
346impl TypeLengthValues<'_> {
347    /// The underlying byte slice of the `TypeLengthValue`s portion of the `Header` payload.
348    #[must_use]
349    pub fn as_bytes(&self) -> &[u8] {
350        self.bytes
351    }
352}
353
354impl<'a> From<&'a [u8]> for TypeLengthValues<'a> {
355    fn from(bytes: &'a [u8]) -> Self {
356        TypeLengthValues { bytes, offset: 0 }
357    }
358}
359
360impl<'a> Iterator for TypeLengthValues<'a> {
361    type Item = Result<TypeLengthValue<'a>, ParseError>;
362
363    fn next(&mut self) -> Option<Self::Item> {
364        if self.offset >= self.bytes.len() {
365            return None;
366        }
367
368        let remaining = &self.bytes[self.offset..];
369
370        if remaining.len() < MINIMUM_TLV_LENGTH {
371            self.offset = self.bytes.len();
372            return Some(Err(ParseError::Leftovers(self.bytes.len())));
373        }
374
375        let tlv_type = remaining[0];
376        let length = u16::from_be_bytes([remaining[1], remaining[2]]);
377        let tlv_length = MINIMUM_TLV_LENGTH + length as usize;
378
379        if remaining.len() < tlv_length {
380            self.offset = self.bytes.len();
381            return Some(Err(ParseError::InvalidTLV(tlv_type, length)));
382        }
383
384        self.offset += tlv_length;
385
386        Some(Ok(TypeLengthValue {
387            kind: Type::from(tlv_type),
388            value: Cow::Borrowed(&remaining[MINIMUM_TLV_LENGTH..tlv_length]),
389        }))
390    }
391}
392
393impl TypeLengthValues<'_> {
394    /// The number of bytes in the `TypeLengthValue` portion of the `Header`.
395    #[must_use]
396    pub fn len(&self) -> u16 {
397        self.bytes.len() as u16
398    }
399
400    /// Whether there are any bytes to be interpreted as `TypeLengthValue`s.
401    #[must_use]
402    pub fn is_empty(&self) -> bool {
403        self.bytes.is_empty()
404    }
405}
406
407impl BitOr<Command> for Version {
408    type Output = u8;
409
410    fn bitor(self, command: Command) -> Self::Output {
411        (self as u8) | (command as u8)
412    }
413}
414
415impl BitOr<Version> for Command {
416    type Output = u8;
417
418    fn bitor(self, version: Version) -> Self::Output {
419        (self as u8) | (version as u8)
420    }
421}
422
423impl BitOr<Protocol> for AddressFamily {
424    type Output = u8;
425
426    fn bitor(self, protocol: Protocol) -> Self::Output {
427        (self as u8) | (protocol as u8)
428    }
429}
430
431impl AddressFamily {
432    /// The length in bytes for this `AddressFamily`.
433    /// `AddressFamily::Unspecified` does not require any bytes, and is represented as `None`.
434    #[must_use]
435    pub fn byte_length(&self) -> Option<usize> {
436        match self {
437            Self::IPv4 => Some(IPV4_ADDRESSES_BYTES),
438            Self::IPv6 => Some(IPV6_ADDRESSES_BYTES),
439            Self::Unix => Some(UNIX_ADDRESSES_BYTES),
440            Self::Unspecified => None,
441        }
442    }
443}
444
445impl From<AddressFamily> for u16 {
446    fn from(address_family: AddressFamily) -> Self {
447        address_family.byte_length().unwrap_or_default() as Self
448    }
449}
450
451impl From<(SocketAddr, SocketAddr)> for Addresses {
452    fn from(addresses: (SocketAddr, SocketAddr)) -> Self {
453        match addresses {
454            (SocketAddr::V4(source), SocketAddr::V4(destination)) => Self::IPv4(IPv4::new(
455                *source.ip(),
456                *destination.ip(),
457                source.port(),
458                destination.port(),
459            )),
460            (SocketAddr::V6(source), SocketAddr::V6(destination)) => Self::IPv6(IPv6::new(
461                *source.ip(),
462                *destination.ip(),
463                source.port(),
464                destination.port(),
465            )),
466            _ => Self::Unspecified,
467        }
468    }
469}
470
471impl From<IPv4> for Addresses {
472    fn from(addresses: IPv4) -> Self {
473        Self::IPv4(addresses)
474    }
475}
476
477impl From<IPv6> for Addresses {
478    fn from(addresses: IPv6) -> Self {
479        Self::IPv6(addresses)
480    }
481}
482
483impl From<Unix> for Addresses {
484    fn from(addresses: Unix) -> Self {
485        Self::Unix(addresses)
486    }
487}
488
489impl Addresses {
490    /// The `AddressFamily` for this `Addresses`.
491    #[must_use]
492    pub fn address_family(&self) -> AddressFamily {
493        match self {
494            Self::Unspecified => AddressFamily::Unspecified,
495            Self::IPv4(..) => AddressFamily::IPv4,
496            Self::IPv6(..) => AddressFamily::IPv6,
497            Self::Unix(..) => AddressFamily::Unix,
498        }
499    }
500
501    /// The length in bytes of the `Addresses` in the `Header`'s payload.
502    #[must_use]
503    pub fn len(&self) -> usize {
504        self.address_family().byte_length().unwrap_or_default()
505    }
506
507    /// Tests whether the `Addresses` consume any space in the `Header`'s payload.
508    /// `AddressFamily::Unspecified` does not require any bytes, and always returns true.
509    #[must_use]
510    pub fn is_empty(&self) -> bool {
511        self.address_family().byte_length().is_none()
512    }
513}
514
515impl Unix {
516    /// Creates a new instance of a source and destination address pair for Unix sockets.
517    #[must_use]
518    pub const fn new(source: [u8; 108], destination: [u8; 108]) -> Self {
519        Self {
520            source,
521            destination,
522        }
523    }
524}
525
526impl BitOr<AddressFamily> for Protocol {
527    type Output = u8;
528
529    fn bitor(self, address_family: AddressFamily) -> Self::Output {
530        (self as u8) | (address_family as u8)
531    }
532}
533
534impl<'a, T: Into<Type>> From<(T, &'a [u8])> for TypeLengthValue<'a> {
535    fn from((kind, value): (T, &'a [u8])) -> Self {
536        TypeLengthValue {
537            kind: kind.into(),
538            value: value.into(),
539        }
540    }
541}
542
543impl<'a> TypeLengthValue<'a> {
544    /// Creates an owned clone of this [`TypeLengthValue`].
545    #[must_use]
546    pub fn to_owned(&self) -> TypeLengthValue<'static> {
547        TypeLengthValue {
548            kind: self.kind,
549            value: Cow::Owned(self.value.to_vec()),
550        }
551    }
552
553    /// Creates a new instance of a `TypeLengthValue`, where the length is determine by the length of the byte slice.
554    /// No check is done to ensure the byte slice's length fits in a `u16`.
555    pub fn new<T: Into<Type>>(kind: T, value: &'a [u8]) -> Self {
556        TypeLengthValue {
557            kind: kind.into(),
558            value: value.into(),
559        }
560    }
561
562    /// The length in bytes of this `TypeLengthValue`'s value.
563    #[must_use]
564    pub fn len(&self) -> usize {
565        self.value.len()
566    }
567
568    /// Tests whether the value of this `TypeLengthValue` is empty.
569    #[must_use]
570    pub fn is_empty(&self) -> bool {
571        self.value.is_empty()
572    }
573}