haprox_rs/protocol/
protocol.rs

1/*-
2 * haprox-rs - a HaProxy protocol parser.
3 * 
4 * Copyright 2025 Aleksandr Morozov
5 * The scram-rs crate can be redistributed and/or modified
6 * under the terms of either of the following licenses:
7 *
8 *   1. the Mozilla Public License Version 2.0 (the “MPL”) OR
9 *                     
10 *   2. EUROPEAN UNION PUBLIC LICENCE v. 1.2 EUPL © the European Union 2007, 2016
11 */
12
13use std::borrow::Cow;
14use std::ffi::CStr;
15use std::fmt;
16use std::io::{Cursor, Read, Write};
17use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
18use std::ops::RangeInclusive;
19use std::os::unix::ffi::OsStrExt;
20use std::os::unix::net;
21use std::str::FromStr;
22
23use bitflags::bitflags;
24use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
25
26use crate::{common, map_error, return_error};
27use crate::error::{HaProxErr, HaProxRes};
28
29use super::protocol_raw::{self, HEADER_UNIX_ADDR_LEN};
30
31// -----
32// The following range of 16 type values is reserved for application-specific
33// data and will be never used by the PROXY Protocol. If you need more values
34// consider extending the range with a type field in your TLVs.
35
36/// values is reserved for application-specific data and will be never 
37/// used by the PROXY Protocol (minimal type)
38pub const PP2_TYPE_MIN_CUSTOM: u8 = 0xE0;
39
40/// values is reserved for application-specific data and will be never 
41/// used by the PROXY Protocol (max type)
42pub const PP2_TYPE_MAX_CUSTOM: u8 = 0xEF;
43
44// ----
45// The following range of 8 values is reserved for future use, potentially to
46// extend the protocol with multibyte type values.
47
48/// reserved for temporary experimental use by application developers and protocol 
49/// designers (min range)
50pub const PP2_TYPE_MIN_EXPERIMENT: u8 = 0xF0;
51
52/// reserved for temporary experimental use by application developers and protocol 
53/// designers (max range)
54pub const PP2_TYPE_MAX_EXPERIMENT: u8 = 0xF7;
55
56// ----
57// The following range of 8 values is reserved for future use, potentially to
58// extend the protocol with multibyte type values.
59
60/// reserved for future use (min range)
61pub const PP2_TYPE_MIN_FUTURE: u8 = 0xF8;
62
63/// reserved for future use (max range)
64pub const PP2_TYPE_MAX_FUTURE: u8 = 0xFF;
65
66
67//----
68/// Max length of the TLV's payload uniq ID.
69pub const MAX_UNIQ_ID_LEN_BYTES: u16 = 128;
70
71/// Header length of TLV
72pub const TLV_HEADER_LEN: u16 = 3;
73
74
75
76// https://www.haproxy.org/download/3.2/doc/proxy-protocol.txt
77// https://datatracker.ietf.org/doc/html/rfc7301
78
79/// An OP codes definotions.
80#[repr(u8)]
81#[derive(Clone, Copy, PartialEq, Eq, Debug)]
82pub enum HdrV2Command
83{
84    LOCAL = 0,
85    PROXY = 1,
86    UNKNOWN,
87}
88
89impl From<HdrV2Command> for u8
90{
91    fn from(value: HdrV2Command) -> Self 
92    {
93        if value == HdrV2Command::UNKNOWN
94        {
95            panic!("can not encode the unknown command");
96        }
97
98        return value as u8;
99    }
100}
101
102impl HdrV2Command
103{
104    pub(crate)
105    fn decode(raw: u8) -> Self
106    {
107        match raw & protocol_raw::ProxyHdrV2::COMMAND_MASK
108        {
109            r if r == HdrV2Command::LOCAL.into() => return Self::LOCAL,
110            r if r == HdrV2Command::PROXY.into() => return Self::PROXY,
111            _ => return Self::UNKNOWN,
112        }
113    }
114}
115
116/// Defines the protocol versions.
117#[repr(u8)]
118#[derive(Clone, Copy, PartialEq, Eq, Debug)]
119pub enum ProtocolVersion
120{
121    V1 = 1,
122    V2 = 2,
123    UNKNOWN,
124}
125
126impl From<ProtocolVersion> for u8
127{
128    fn from(value: ProtocolVersion) -> Self 
129    {
130        if value == ProtocolVersion::UNKNOWN
131        {
132            panic!("can not encode the unknown version");
133        }
134
135        return (value as u8) << 4;
136    }
137}
138
139impl ProtocolVersion
140{
141    pub(crate)
142    fn decode(raw: u8) -> Self
143    {
144        match raw >> 4
145        {
146            1 => return Self::V1,
147            2 => return Self::V2,
148            _ => return Self::UNKNOWN,
149        }
150    }
151}
152
153bitflags! {
154    /// A client flags.
155    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
156    pub struct PP2TlvClient: u8 
157    {
158        /// client connected over SSL/TLS
159        const PP2_CLIENT_SSL = 0x01;
160        
161        /// client provided a certificate over the current connection
162        const PP2_CLIENT_CERT_CONN = 0x02;
163
164        /// client provided a certificate at least once over the TLS session this 
165        /// connection belongs to
166        const PP2_CLIENT_CERT_SESS = 0x04;
167    }
168}
169
170/// A specific for PP2Tlv SSL.
171#[derive(Clone, Debug, PartialEq, Eq)]
172pub struct PP2TlvsTypeSsl
173{
174    /// client came with something
175    pub(crate) client: PP2TlvClient, 
176                
177    /// field will be zero if the client presented a certificate
178    /// and it was successfully verified, and non-zero otherwise.
179    pub(crate) verify: u32, 
180
181    /// included sub TLVs
182    pub(crate) sub_tlv: Vec<PP2Tlvs>
183}
184
185impl fmt::Display for PP2TlvsTypeSsl
186{
187    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
188    {
189        write!(f, "CLIENT: {:?}, VERIFY: {}, TLVs: {}", 
190            self.client, self.verify, 
191            self.sub_tlv.iter().map(|t| t.to_string()).collect::<Vec<String>>().join(", "))
192    }
193}
194
195/*
196impl From<PP2TlvsTypeSsl> for PP2Tlvs
197{
198    fn from(value: PP2TlvsTypeSsl) -> Self where Self: PP2TlvDump
199    {
200        return Self::TypeSsl(value);
201    }
202}*/
203
204/// Can be used for testing.
205#[repr(u8)]
206#[derive(Clone, Debug, PartialEq, Eq)]
207pub enum PP2Tlvs
208{
209    /// Application-Layer Protocol Negotiation (ALPN).
210    TypeAlpn(Vec<Vec<u8>>) = Self::TYPE_ALPN,
211
212    /// "SNI" i.e the "server_name" extension as defined by RFC3546
213    /// UTF8-encoded string
214    TypeAuthority(String) = Self::TYPE_AUTHORITY,
215
216    /// 32-bit number storing the CRC32c checksum of the PROXY protocol header
217    TypeCrc32c(u32) = Self::TYPE_CRC32C,
218
219    /// The TLV of this type should be ignored when parsed. The value is zero or more
220    /// bytes. Can be used for data padding or alignment. Note that it can be used
221    /// to align only by 3 or more bytes because a TLV can not be smaller than that.
222    TypeNoop = Self::TYPE_NOOP,
223
224    /// opaque byte sequence of up to 128 bytes generated by the upstream proxy 
225    /// that uniquely identifies the connection.
226    TypeUniqId(Vec<u8>) = Self::TYPE_UNIQID,
227
228    /// SSL properties
229    TypeSsl
230    {
231        client: PP2TlvClient,
232        verify: u32,
233    } = Self::TYPE_SSL,
234
235    /// US-ASCII string representation of the TLS version (format?)
236    TypeSubtypeSslVersion(Cow<'static, str>) = Self::TYPE_SUBTYPE_SSL_VERSION,
237
238    /// In all cases, the string representation (in UTF8) of the Common Name field
239    /// (OID: 2.5.4.3) of the client certificate's Distinguished Name, is appended
240    /// using the TLV format and the type PP2_SUBTYPE_SSL_CN. E.g. "example.com".
241    TypeSubtypeSslCn(Cow<'static, str>) = Self::TYPE_SUBTYPE_SSL_CN,
242    
243    /// US-ASCII string name of the used cipher, for example "ECDHE-RSA-AES128-GCM-SHA256".
244    TypeSubtypeSslCipher(Cow<'static, str>) = Self::TYPE_SUBTYPE_SSL_CIPHER,
245
246    /// US-ASCII string name of the algorithm used to sign the certificate presented by the 
247    /// frontend when the incoming connection was made over an SSL/TLS transport layer, for example
248    /// "SHA256".
249    TypeSubtypeSslSigAlg(Cow<'static, str>) = Self::TYPE_SUBTYPE_SSL_SIGALG,
250
251    /// US-ASCII string name of the algorithm used to generate the key of the certificate 
252    /// presented by the frontend when the incoming connection was made over an SSL/TLS 
253    /// transport layer, for example "RSA2048".
254    TypeSubtypeSslKeyAlg(Cow<'static, str>) = Self::TYPE_SUBTYPE_SSL_KEYALG,
255
256    /// US-ASCII string representation of the namespace's name
257    TypeNetNs(String) = Self::TYPE_NETNS,
258}
259
260impl fmt::Display for PP2Tlvs
261{
262    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
263    {
264        let id : u8= self.into();
265
266        match self
267        {
268            PP2Tlvs::TypeAlpn(alpns) => 
269            {
270                let alpns_dec = 
271                    alpns
272                        .iter()
273                        .map(
274                            |a| 
275                            std
276                                ::str
277                                ::from_utf8(a)
278                                    .map_err(|e| map_error!(MalformedData, "{}", e))
279                        )
280                        .collect::<HaProxRes<Vec<&str>>>()
281                        .map_err(|_e| fmt::Error)?
282                        .join(",");
283
284                write!(f, "ALPNS({:02X}): {}", id, alpns_dec)
285            },
286            PP2Tlvs::TypeAuthority(sni) => 
287                write!(f, "SNI({:02X}): {}", id, sni),
288            PP2Tlvs::TypeCrc32c(crc) => 
289                write!(f, "CRC({:02X}): {}", id, crc),
290            PP2Tlvs::TypeNoop => 
291                write!(f, "NOOP({:02X})", id),
292            PP2Tlvs::TypeUniqId(items) => 
293                write!(f, "UNIQID({:02X}): {:02X?}", id, items),
294            PP2Tlvs::TypeSsl{client, verify} => 
295                write!(f, "SSL({:02X}): client: {:?}, verify: {}", id, client, verify),
296            PP2Tlvs::TypeSubtypeSslVersion(ver) => 
297                write!(f, "SSL VERSION({:02X}): {}", id, ver),
298            PP2Tlvs::TypeSubtypeSslCn(cn) => 
299                write!(f, "SSL CN({:02X}): {}", id, cn),
300            PP2Tlvs::TypeSubtypeSslCipher(c) => 
301                write!(f, "SSL CIPHER({:02X}): {}", id, c),
302            PP2Tlvs::TypeSubtypeSslSigAlg(sa) => 
303                write!(f, "SSL SIGALG({:02X}): {}", id, sa),
304            PP2Tlvs::TypeSubtypeSslKeyAlg(ka) => 
305                write!(f, "SSL KEYALG({:02X}): {}", id, ka),
306            PP2Tlvs::TypeNetNs(ns) => 
307                write!(f, "NETNS({:02X}): {}", id, ns),
308        }
309    }
310}
311
312impl From<PP2Tlvs> for u8
313{
314    fn from(value: PP2Tlvs) -> Self 
315    {
316        return (&value).into();
317    }
318}
319
320impl From<&PP2Tlvs> for u8
321{
322    fn from(value: &PP2Tlvs) -> Self 
323    {
324        return unsafe { *<*const _>::from(value).cast::<Self>() };
325    }
326}
327
328
329
330impl PP2Tlvs
331{
332    /// A constraints by range of all types.
333    pub const TLV_TYPE_MAIN_RANGES: &'static [RangeInclusive<u8>] = 
334        &[
335            Self::TYPE_ALPN..=Self::TYPE_SSL,  
336            Self::TYPE_NETNS ..= Self::TYPE_NETNS
337        ];
338
339    /// A constraints for the SSL subtypes.
340    pub const TLV_TYPE_SSL_SUB_RANGE: &'static [RangeInclusive<u8>] = 
341        &[Self::TYPE_SUBTYPE_SSL_VERSION ..= Self::TYPE_SUBTYPE_SSL_KEYALG];
342
343    pub const TYPE_ALPN: u8 = 0x01;
344
345    pub const TYPE_AUTHORITY: u8 = 0x02;
346
347    pub const TYPE_CRC32C: u8 = 0x03;
348
349    pub const TYPE_NOOP: u8 = 0x04;
350
351    pub const TYPE_UNIQID: u8 = 0x05;
352
353    pub const TYPE_SSL: u8 = 0x20;
354
355    pub const TYPE_SUBTYPE_SSL_VERSION: u8 = 0x21;
356
357    pub const TYPE_SUBTYPE_SSL_CN: u8 = 0x22;
358    
359    pub const TYPE_SUBTYPE_SSL_CIPHER: u8 = 0x23;
360
361    pub const TYPE_SUBTYPE_SSL_SIGALG: u8 = 0x24;
362
363    pub const TYPE_SUBTYPE_SSL_KEYALG: u8 = 0x25;
364
365    pub const TYPE_NETNS: u8 = 0x30;
366
367    pub 
368    fn contains_subtype(&self) -> bool
369    {
370        let Self::TypeSsl{ .. } = self else { return false };
371
372        return true;
373    }
374
375    pub 
376    fn conntains_subtype_discr(discr: u8) -> bool
377    {
378        return discr == Self::TYPE_SSL;
379    }
380}
381
382/// A quote from protocol descr:
383/// > other values are unspecified and must not be emitted in version 2 of this
384/// > protocol and must be rejected as invalid by receivers.
385#[repr(u8)]
386#[derive(Clone, Copy, Debug, PartialEq, Eq)]
387pub enum ProxyV2AddrType
388{
389    /// A quote from protocol descr:
390    /// > the connection is forwarded for an unknown, unspecified
391    /// > or unsupported protocol. The sender should use this family when sending
392    /// > LOCAL commands or when dealing with unsupported protocol families. The
393    /// > receiver is free to accept the connection anyway and use the real endpoint
394    /// > addresses or to reject it. The receiver should ignore address information.
395    AfUnspec = 0x00,
396
397    /// A quote from protocol descr:
398    /// > the forwarded connection uses the AF_INET address family
399    /// > (IPv4). The addresses are exactly 4 bytes each in network byte order,
400    /// > followed by transport protocol information (typically ports).
401    AfInet = 0x01,
402
403    /// A quote from protocol descr:
404    /// > the forwarded connection uses the AF_INET6 address family
405    /// > (IPv6). The addresses are exactly 16 bytes each in network byte order,
406    /// > followed by transport protocol information (typically ports).
407    AfInet6 = 0x02,
408
409    /// A quote from protocol descr:
410    /// > the forwarded connection uses the AF_UNIX address family
411    /// > (UNIX). The addresses are exactly 108 bytes each.
412    AfUnix = 0x03,
413}
414
415impl From<ProxyV2AddrType> for u8
416{
417    fn from(value: ProxyV2AddrType) -> Self 
418    {
419        return value as u8;
420    }
421}
422
423impl ProxyV2AddrType
424{
425    pub const DEF_IPV4_ADDR_LEN: u16 = 12;
426    pub const DEF_IPV6_ADDR_LEN: u16 = 36;
427    pub const DEF_UNIX_ADDR_LEN: u16 = 216;
428
429    pub(crate) 
430    fn decode(raw: u8) -> HaProxRes<Self>
431    {
432        match raw >> 4
433        {
434            r if r == ProxyV2AddrType::AfUnspec.into() => 
435                return Ok(Self::AfUnspec),
436            r if r == ProxyV2AddrType::AfInet.into() => 
437                return Ok(Self::AfInet),
438            r if r == ProxyV2AddrType::AfInet6.into() => 
439                return Ok(Self::AfInet6),
440            r if r == ProxyV2AddrType::AfUnix.into() => 
441                return Ok(Self::AfUnix),
442            r => 
443                return_error!(ProtocolUnknownData, "can not decode address type: '{:02X}'", r),
444        }
445    }
446
447    pub 
448    fn get_size_by_addr_family(&self) -> Option<u16>
449    {
450        match self
451        {
452            Self::AfUnspec => 
453                return None,
454            Self::AfInet => 
455                return Some(Self::DEF_IPV4_ADDR_LEN),
456            Self::AfInet6 => 
457                return Some(Self::DEF_IPV6_ADDR_LEN),
458            Self::AfUnix => 
459                return Some(Self::DEF_UNIX_ADDR_LEN),
460        }
461    }
462}
463
464
465/// An address re-representation. Can be initialized using `TryFrom` 
466/// implementations.
467/// 
468/// TryFrom("ip:port", "ip:port")
469/// TryFrom(IpAddr, u16, IpAddr, u16)
470/// TryFrom(net::SocketAddr, net::SocketAddr)
471/// TryFrom(SocketAddr, SocketAddr)
472/// 
473/// The type will be determined automatically.
474#[derive(Clone, Debug)]
475pub enum ProxyV2Addr
476{
477    /// AF_INET, AF_INET6
478    Ip
479    {
480        src: SocketAddr,
481        dst: SocketAddr,
482    },
483
484    /// AF_UNIX
485    Unix
486    {
487        src: net::SocketAddr,
488        dst: net::SocketAddr,
489    }
490}
491
492impl Eq for ProxyV2Addr {}
493
494impl PartialEq for ProxyV2Addr
495{
496    fn eq(&self, other: &Self) -> bool 
497    {
498        match (self, other) 
499        {
500            (
501                Self::Ip { src: l_src, dst: l_dst }, 
502                Self::Ip { src: r_src, dst: r_dst }
503            ) => 
504                l_src == r_src && l_dst == r_dst,
505
506            (
507                Self::Unix { src: l_src, dst: l_dst }, 
508                Self::Unix { src: r_src, dst: r_dst }
509            ) => 
510                l_src.as_pathname() == r_src.as_pathname() && l_dst.as_pathname() == r_dst.as_pathname(),
511            _ => false,
512        }
513    }
514}
515
516impl fmt::Display for ProxyV2Addr
517{
518    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
519    {
520        match self
521        {
522            ProxyV2Addr::Ip{ src, dst } => 
523                write!(f, "SRC: {}, DST: {}", src, dst),
524            ProxyV2Addr::Unix{ src, dst } => 
525                write!(f, "SRC: {:?}, DST: {:?}", src, dst)
526        }
527    }
528}
529
530impl TryFrom<(IpAddr, u16, IpAddr, u16)> for ProxyV2Addr
531{
532    type Error = HaProxErr;
533
534    /// # Arguments
535    /// 
536    /// * `value.0` - source IP address [IpAddr]
537    /// 
538    /// * `value.1` - source port [u16]
539    /// 
540    /// * `value.2` - destination IP address [IpAddr]
541    /// 
542    /// * `value.3` - destination port [u16]
543    fn try_from(value: (IpAddr, u16, IpAddr, u16)) -> Result<Self, Self::Error> 
544    {
545        let src = SocketAddr::new(value.0, value.1);
546        let dst = SocketAddr::new(value.2, value.3);
547
548        return Ok(Self::Ip{ src: src, dst: dst });
549    }
550}
551
552impl TryFrom<(SocketAddr, SocketAddr)> for ProxyV2Addr
553{
554    type Error = HaProxErr;
555
556    /// # Arguments
557    /// 
558    /// * `value.0` - source address [SocketAddr]
559    /// 
560    /// * `value.1` - destination address [SocketAddr]
561    fn try_from(value: (SocketAddr, SocketAddr)) -> Result<Self, Self::Error> 
562    {
563        return Ok(Self::Ip{ src: value.0, dst: value.1 });
564    }
565}
566
567/// Attempts to convert from tuple (source, dst) from [net::SocketAddr] into [ProxyV2Addr].  
568impl TryFrom<(net::SocketAddr, net::SocketAddr)> for ProxyV2Addr
569{
570    type Error = HaProxErr;
571
572    /// # Arguments
573    /// 
574    /// * `value.0` - source address [net::SocketAddr]
575    /// 
576    /// * `value.1` - destination address [net::SocketAddr]
577    fn try_from(value: (net::SocketAddr, net::SocketAddr)) -> Result<Self, Self::Error> 
578    {
579        return Ok(Self::Unix{ src: value.0, dst: value.1 });
580    }
581}
582
583/// Attempts to convert tuple (source, destination) from [str] into [ProxyV2Addr].
584impl TryFrom<(&str, &str)> for ProxyV2Addr
585{
586    type Error = HaProxErr;
587
588    /// # Arguments
589    /// 
590    /// * `value.0` - source address [str]
591    /// 
592    /// * `value.1` - destination address [str]
593    fn try_from(value: (&str, &str)) -> Result<Self, Self::Error> 
594    {
595        if let Ok(src) = SocketAddr::from_str(value.0)
596        {
597            let Ok(dst) = SocketAddr::from_str(value.1)
598            else 
599            {
600                return_error!(ArgumentEinval, "can not convert '{}' to SocketAddr", 
601                    common::sanitize_str_unicode(value.1));
602            };
603
604            return Ok(Self::Ip{ src: src, dst: dst });
605        }
606        else if let Ok(src) = net::SocketAddr::from_pathname(value.0)
607        {
608            let Ok(dst) = net::SocketAddr::from_pathname(value.1)
609            else 
610            {
611                return_error!(ArgumentEinval, "can not convert '{}' to net::SocketAddr", 
612                    common::sanitize_str_unicode(value.1));
613            };
614
615            return Ok(Self::Unix{ src: src, dst: dst });
616        }
617        else
618        {
619            return_error!(ArgumentEinval, "can not convert '{}' to either SocketAddr or net::SocketAddr", 
620                common::sanitize_str_unicode(value.0));
621        }
622    }
623}
624
625impl ProxyV2Addr
626{
627    /// Returns the length in bytes for the current address. It returns full size, but not
628    /// the actual ocupied length (for unix addresses).
629    #[inline]
630    pub 
631    fn get_len(&self) -> u16
632    {
633        return self.as_addr_family().get_size_by_addr_family().unwrap();
634    }
635
636    /// Returns the address type.
637    #[inline]
638    pub 
639    fn as_addr_family(&self) -> ProxyV2AddrType
640    {
641        match self
642        {
643            ProxyV2Addr::Ip{ src, .. } => 
644            {
645                if src.is_ipv4() == true
646                {
647                    return ProxyV2AddrType::AfInet;
648                }
649                else
650                {
651                    return ProxyV2AddrType::AfInet6;
652                }
653            }
654            ProxyV2Addr::Unix{ .. } => 
655                return ProxyV2AddrType::AfUnix
656        }
657    }
658
659    /// Reads the address section of the HaProxy. The address family should be 
660    /// obtained from the same packet before. The `cur` must point to the beginning
661    /// of the address block.
662    /// 
663    /// # Returns
664    /// 
665    /// The [Result] is returned. The [Option::None] will be returned only if the
666    /// `addr_fam` is [ProxyV2AddrType::AfUnspec].
667    pub 
668    fn read(addr_fam: ProxyV2AddrType, cur: &mut Cursor<&[u8]>) -> HaProxRes<Option<Self>>
669    {
670        match addr_fam
671        {
672            ProxyV2AddrType::AfUnspec => Ok(None),
673            ProxyV2AddrType::AfInet => 
674            {
675                let src = IpAddr::from(Ipv4Addr::from_bits(cur.read_u32::<BigEndian>().map_err(common::map_io_err)?));
676                let dst = IpAddr::from(Ipv4Addr::from_bits(cur.read_u32::<BigEndian>().map_err(common::map_io_err)?));
677                let src_port = cur.read_u16::<BigEndian>().map_err(common::map_io_err)?;
678                let dst_port = cur.read_u16::<BigEndian>().map_err(common::map_io_err)?;
679
680                return Ok(Some(Self::try_from((src, src_port, dst, dst_port))?));
681            },
682            ProxyV2AddrType::AfInet6 => 
683            {
684                let src = IpAddr::from(Ipv6Addr::from_bits(cur.read_u128::<BigEndian>().map_err(common::map_io_err)?));
685                let dst = IpAddr::from(Ipv6Addr::from_bits(cur.read_u128::<BigEndian>().map_err(common::map_io_err)?));
686                let src_port = cur.read_u16::<BigEndian>().map_err(common::map_io_err)?;
687                let dst_port = cur.read_u16::<BigEndian>().map_err(common::map_io_err)?;
688
689                return Ok(Some(Self::try_from((src, src_port, dst, dst_port))?));
690            },
691            ProxyV2AddrType::AfUnix => 
692            {
693                let mut n_src: [u8; HEADER_UNIX_ADDR_LEN] = [0_u8; HEADER_UNIX_ADDR_LEN];
694                cur.read(&mut n_src).map_err(common::map_io_err)?;
695
696                let mut n_dst: [u8; HEADER_UNIX_ADDR_LEN] = [0_u8; HEADER_UNIX_ADDR_LEN];
697                cur.read(&mut n_dst).map_err(common::map_io_err)?;
698
699                let src_s = 
700                    net::SocketAddr::from_pathname(
701                        CStr::from_bytes_until_nul(&n_src)
702                            .map_err(|e| 
703                                map_error!(MalformedData, "cannot read unix path, error: {}", e)
704                            )?
705                            .to_str()
706                            .map_err(|e|
707                                map_error!(MalformedData, "cannot read unix path, error: {}", e)
708                            )?
709                    )
710                    .map_err(|e|
711                        map_error!(MalformedData, "cannot read unix path, error: {}", e)
712                    )?;
713
714                let dst_s = 
715                    net::SocketAddr::from_pathname(
716                        CStr::from_bytes_until_nul(&n_dst)
717                            .map_err(|e| 
718                                map_error!(MalformedData, "cannot read unix path, error: {}", e)
719                            )?
720                            .to_str()
721                            .map_err(|e|
722                                map_error!(MalformedData, "cannot read unix path, error: {}", e)
723                            )?
724                    )
725                    .map_err(|e|
726                        map_error!(MalformedData, "cannot read unix path, error: {}", e)
727                    )?;
728
729                return Ok(Some(Self::try_from((src_s, dst_s))?));
730            },
731        }
732    }
733
734    /// Writes the content of the current instance to packet in format of 
735    /// the HaProxy address. The `cur` [Cursor] should point to the
736    /// beginning of the address block.
737    pub  
738    fn write(&self, cur: &mut Cursor<Vec<u8>>) -> HaProxRes<()>
739    {
740        match self
741        {
742            ProxyV2Addr::Ip{ src, dst } => 
743            {
744                match src.ip()
745                {
746                    IpAddr::V4(ipv4_addr) => 
747                        cur.write_u32::<BigEndian>(ipv4_addr.to_bits()).map_err(common::map_io_err)?,
748                    IpAddr::V6(ipv6_addr) => 
749                        cur.write_u128::<BigEndian>(ipv6_addr.to_bits()).map_err(common::map_io_err)?,
750                }
751
752                match dst.ip()
753                {
754                    IpAddr::V4(ipv4_addr) => 
755                        cur.write_u32::<BigEndian>(ipv4_addr.to_bits()).map_err(common::map_io_err)?,
756                    IpAddr::V6(ipv6_addr) => 
757                        cur.write_u128::<BigEndian>(ipv6_addr.to_bits()).map_err(common::map_io_err)?,
758                }
759
760                cur.write_u16::<BigEndian>(src.port()).map_err(common::map_io_err)?;
761                cur.write_u16::<BigEndian>(dst.port()).map_err(common::map_io_err)?;
762            },
763            ProxyV2Addr::Unix { src, dst } => 
764            {
765                let src_p = 
766                    src.as_pathname().ok_or_else(|| map_error!(ArgumentEinval, "UNIX src socket addr is not path"))?;
767                let dst_p = 
768                    dst.as_pathname().ok_or_else(|| map_error!(ArgumentEinval, "UNIX src socket addr is not path"))?;
769
770                let src_b = src_p.as_os_str().as_bytes();
771                let dst_b = dst_p.as_os_str().as_bytes();
772
773                if src_b.len() > HEADER_UNIX_ADDR_LEN
774                {
775                    return_error!(ArgumentEinval, "socket path: '{}' longer than: '{}'", 
776                        src_p.display(), HEADER_UNIX_ADDR_LEN);
777                }
778                else if dst_b.len() > HEADER_UNIX_ADDR_LEN
779                {
780                    return_error!(ArgumentEinval, "socket path: '{}' longer than: '{}'", 
781                        dst_p.display(), HEADER_UNIX_ADDR_LEN);
782                }
783
784                
785                let mut n_src: [u8; HEADER_UNIX_ADDR_LEN] = [0_u8; HEADER_UNIX_ADDR_LEN];
786                n_src[0..src_b.len()].copy_from_slice(src_b);
787
788                cur.write_all(&n_src).map_err(common::map_io_err)?;
789
790                let mut n_dst: [u8; HEADER_UNIX_ADDR_LEN] = [0_u8; HEADER_UNIX_ADDR_LEN];
791                n_dst[0..dst_b.len()].copy_from_slice(dst_b);
792
793                cur.write_all(&n_dst).map_err(common::map_io_err)?;
794            }
795        }
796
797        return Ok(());
798    }
799}
800
801/// A transport family.
802/// > Other values are unspecified and must not be emitted in version 2 of this
803/// > protocol and must be rejected as invalid by receivers.`
804#[repr(u8)]
805#[derive(Clone, Debug, PartialEq, Eq)]
806pub enum ProxyTransportFam
807{
808    /// > the connection is forwarded for an unknown, unspecified
809    /// > or unsupported protocol. The sender should use this family when sending
810    /// > LOCAL commands or when dealing with unsupported protocol families. The
811    /// > receiver is free to accept the connection anyway and use the real endpoint
812    /// > addresses or to reject it. The receiver should ignore address information.
813    UNSPEC = 0x00,
814
815    /// > the forwarded connection uses a SOCK_STREAM protocol (eg:
816    /// > TCP or UNIX_STREAM). When used with AF_INET/AF_INET6 (TCP), the addresses
817    /// > are followed by the source and destination ports represented on 2 bytes
818    /// > each in network byte order.
819    STREAM,
820
821    /// > the forwarded connection uses a SOCK_DGRAM protocol (eg:
822    /// > UDP or UNIX_DGRAM). When used with AF_INET/AF_INET6 (UDP), the addresses
823    /// > are followed by the source and destination ports represented on 2 bytes
824    /// > each in network byte order.
825    DGRAM,
826}
827
828impl fmt::Display for ProxyTransportFam
829{
830    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
831    {
832        match self
833        {
834            Self::UNSPEC => write!(f, "UNSPEC"),
835            Self::STREAM => write!(f, "STREAM"),
836            Self::DGRAM => write!(f, "DGRAM"),
837        }
838    }
839}
840
841impl From<ProxyTransportFam> for u8
842{
843    fn from(value: ProxyTransportFam) -> Self 
844    {
845        return value as u8;
846    }
847}
848
849impl From<&ProxyTransportFam> for u8
850{
851    fn from(value: &ProxyTransportFam) -> Self 
852    {
853        return unsafe { *<*const _>::from(value).cast::<Self>() };
854    }
855}
856
857impl ProxyTransportFam
858{
859    pub(crate) 
860    fn decode(value: u8) -> HaProxRes<Self>
861    {
862        match value & protocol_raw::ProxyHdrV2::TRANSPT_MASK
863        {
864            v if ProxyTransportFam::UNSPEC as u8 == v => 
865                return Ok(Self::UNSPEC),
866            v if ProxyTransportFam::STREAM as u8 == v => 
867                return Ok(Self::STREAM),
868            v if ProxyTransportFam::DGRAM as u8 == v => 
869                return Ok(Self::DGRAM),
870            _ => 
871                return_error!(ProtocolUnknownData, "unknown transport {:02X}", value)
872        }
873    }
874}
875
876#[cfg(test)]
877mod tests
878{
879    use core::fmt;
880    use std::{slice, time::Instant};
881
882    use crate::protocol::{protocol::{PP2TlvClient, ProxyTransportFam, ProxyV2Addr}, protocol_composer::{HdrV2OpLocal, HdrV2OpProxy, ProxyHdrV2}, protocol_raw::{self, HEADER_MAGIC_V2, HEADER_MAGINC_LEN}, PP2TlvUniqId};
883    #[test]
884    fn test_hdr1()
885    {
886        
887        for _ in 0..10
888        {
889            let s = Instant::now();
890            let _local = ProxyHdrV2::<HdrV2OpLocal>::new();
891
892            let e = s.elapsed();
893
894            println!("{:?}", e);
895        }
896
897        let buf = ProxyHdrV2::<HdrV2OpLocal>::new();
898
899
900        
901        let mut sign: [u8; HEADER_MAGINC_LEN] = [0_u8; HEADER_MAGINC_LEN];
902        sign.copy_from_slice(HEADER_MAGIC_V2);
903        let ctrl =
904            vec![
905                protocol_raw::ProxyHdrV2
906                {
907                    signature: sign,
908                    ver_cmd: 0x20,
909                    fam: 0,
910                    len: 0,
911                    address: [],
912                }
913            ];
914
915            println!("{} {}", buf.len(), size_of::<protocol_raw::ProxyHdrV2>());
916        let ctrl_buf = unsafe { slice::from_raw_parts(ctrl.as_ptr() as *const _ as *const u8, size_of::<protocol_raw::ProxyHdrV2>()) };
917
918        assert_eq!(buf.as_slice(), ctrl_buf);
919    }
920
921    #[test]
922    fn test_proxy_compose()
923    {
924        struct UniqIdHolder;
925        impl UniqIdHolder
926        {
927            const ID: &'static [u8] = b"ABCD12345678901234567890";
928        }
929        impl fmt::Display for UniqIdHolder
930        {
931            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result 
932            {
933                write!(f, "")
934            }
935        }
936        impl PP2TlvUniqId for UniqIdHolder
937        {
938            fn into_bytes(&self) -> Vec<u8> 
939            {
940                Self::ID.to_vec()
941            }
942        
943            fn get_len(&self) -> u16 
944            {
945                Self::ID.len() as u16
946            }
947        }
948        for _ in 0..10
949        {
950            let addr: ProxyV2Addr = ProxyV2Addr::try_from(("127.0.0.1:4567", "127.0.0.1:443")).unwrap();
951            let id = UniqIdHolder;
952
953            let s = Instant::now();
954            let mut proxy = 
955                ProxyHdrV2::<HdrV2OpProxy>::new(ProxyTransportFam::STREAM, addr).unwrap();
956
957            let mut plts = proxy.set_plts();
958            plts.add_crc32().unwrap();
959            plts.add_authority("www.example.com").unwrap();
960            plts.add_uniq_id(id).unwrap();
961            drop(plts);
962
963            let e = s.elapsed();
964
965            println!("prep: {:?}", e);
966        
967            let s = Instant::now();
968            let _buf: Vec<u8> = proxy.try_into().unwrap();
969            let e = s.elapsed();
970
971            println!("{:?}", e);
972        }
973
974       // assert_eq!(buf.as_slice(), ctrl_buf);
975       return;
976    }
977
978    #[test]
979    fn test_hdr2()
980    {
981        let addr: ProxyV2Addr = ProxyV2Addr::try_from(("127.0.0.1:39754", "127.0.0.67:11883")).unwrap();
982
983        let s = Instant::now();
984        let mut proxy = 
985            ProxyHdrV2::<HdrV2OpProxy>::new(ProxyTransportFam::STREAM, addr).unwrap();
986      
987        let plts = proxy.set_plts();
988
989        let mut sub_ssl = plts.add_ssl(PP2TlvClient::PP2_CLIENT_SSL, 0).unwrap();
990
991        sub_ssl.add_ssl_sub_version("TLSv1.2").unwrap();
992
993        sub_ssl.done().unwrap();
994
995
996        let e = s.elapsed();
997
998        println!("prep: {:?}", e);
999
1000        let s = Instant::now();
1001        let buf: Vec<u8> = proxy.try_into().unwrap();
1002        let e = s.elapsed();
1003
1004        println!("{:?}", e);
1005        
1006        
1007        let reference = 
1008            b"\x0d\x0a\x0d\x0a\x00\x0d\x0a\x51\x55\x49\x54\x0a\x21\x11\x00\x1e\
1009            \x7f\x00\x00\x01\x7f\x00\x00\x43\x9b\x4a\x2e\x6b\x20\x00\x0f\x01\
1010            \x00\x00\x00\x00\x21\x00\x07\x54\x4c\x53\x76\x31\x2e\x32";
1011
1012        //println!("{:02X?}\n{:02X?}", buf.as_slice(), reference.as_slice());
1013
1014        assert_eq!(buf.as_slice(), reference.as_slice());
1015    }
1016}