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#[test]
171fn ttt()
172{
173    let bi: u8 = 7;
174
175    println!("{} {:?}", PP2TlvClient::all().bits(), PP2TlvClient::from_bits(bi));
176}
177
178#[derive(Clone, Debug, PartialEq, Eq)]
179pub struct PP2TlvsTypeSsl
180{
181    /// client came with something
182    pub(crate) client: PP2TlvClient, 
183                
184    /// field will be zero if the client presented a certificate
185    /// and it was successfully verified, and non-zero otherwise.
186    pub(crate) verify: u32, 
187
188    /// included sub TLVs
189    pub(crate) sub_tlv: Vec<PP2Tlvs>
190}
191
192impl fmt::Display for PP2TlvsTypeSsl
193{
194    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
195    {
196        write!(f, "CLIENT: {:?}, VERIFY: {}, TLVs: {}", 
197            self.client, self.verify, 
198            self.sub_tlv.iter().map(|t| t.to_string()).collect::<Vec<String>>().join(", "))
199    }
200}
201
202/*
203impl From<PP2TlvsTypeSsl> for PP2Tlvs
204{
205    fn from(value: PP2TlvsTypeSsl) -> Self where Self: PP2TlvDump
206    {
207        return Self::TypeSsl(value);
208    }
209}*/
210
211/// Can be used for testing.
212#[repr(u8)]
213#[derive(Clone, Debug, PartialEq, Eq)]
214pub enum PP2Tlvs
215{
216    /// Application-Layer Protocol Negotiation (ALPN).
217    TypeAlpn(Vec<Vec<u8>>) = Self::TYPE_ALPN,
218
219    /// "SNI" i.e the "server_name" extension as defined by RFC3546
220    /// UTF8-encoded string
221    TypeAuthority(String) = Self::TYPE_AUTHORITY,
222
223    /// 32-bit number storing the CRC32c checksum of the PROXY protocol header
224    TypeCrc32c(u32) = Self::TYPE_CRC32C,
225
226    /// The TLV of this type should be ignored when parsed. The value is zero or more
227    /// bytes. Can be used for data padding or alignment. Note that it can be used
228    /// to align only by 3 or more bytes because a TLV can not be smaller than that.
229    TypeNoop = Self::TYPE_NOOP,
230
231    /// opaque byte sequence of up to 128 bytes generated by the upstream proxy 
232    /// that uniquely identifies the connection.
233    TypeUniqId(Vec<u8>) = Self::TYPE_UNIQID,
234
235    /// SSL properties
236    TypeSsl
237    {
238        client: PP2TlvClient,
239        verify: u32,
240    } = Self::TYPE_SSL,
241
242    /// US-ASCII string representation of the TLS version (format?)
243    TypeSubtypeSslVersion(Cow<'static, str>) = Self::TYPE_SUBTYPE_SSL_VERSION,
244
245    /// In all cases, the string representation (in UTF8) of the Common Name field
246    /// (OID: 2.5.4.3) of the client certificate's Distinguished Name, is appended
247    /// using the TLV format and the type PP2_SUBTYPE_SSL_CN. E.g. "example.com".
248    TypeSubtypeSslCn(Cow<'static, str>) = Self::TYPE_SUBTYPE_SSL_CN,
249    
250    /// US-ASCII string name of the used cipher, for example "ECDHE-RSA-AES128-GCM-SHA256".
251    TypeSubtypeSslCipher(Cow<'static, str>) = Self::TYPE_SUBTYPE_SSL_CIPHER,
252
253    /// US-ASCII string name of the algorithm used to sign the certificate presented by the 
254    /// frontend when the incoming connection was made over an SSL/TLS transport layer, for example
255    /// "SHA256".
256    TypeSubtypeSslSigAlg(Cow<'static, str>) = Self::TYPE_SUBTYPE_SSL_SIGALG,
257
258    /// US-ASCII string name of the algorithm used to generate the key of the certificate 
259    /// presented by the frontend when the incoming connection was made over an SSL/TLS 
260    /// transport layer, for example "RSA2048".
261    TypeSubtypeSslKeyAlg(Cow<'static, str>) = Self::TYPE_SUBTYPE_SSL_KEYALG,
262
263    /// US-ASCII string representation of the namespace's name
264    TypeNetNs(String) = Self::TYPE_NETNS,
265}
266
267impl fmt::Display for PP2Tlvs
268{
269    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
270    {
271        let id : u8= self.into();
272
273        match self
274        {
275            PP2Tlvs::TypeAlpn(alpns) => 
276            {
277                let alpns_dec = 
278                    alpns
279                        .iter()
280                        .map(
281                            |a| 
282                            std
283                                ::str
284                                ::from_utf8(a)
285                                    .map_err(|e| map_error!(MalformedData, "{}", e))
286                        )
287                        .collect::<HaProxRes<Vec<&str>>>()
288                        .map_err(|_e| fmt::Error)?
289                        .join(",");
290
291                write!(f, "ALPNS({:02X}): {}", id, alpns_dec)
292            },
293            PP2Tlvs::TypeAuthority(sni) => 
294                write!(f, "SNI({:02X}): {}", id, sni),
295            PP2Tlvs::TypeCrc32c(crc) => 
296                write!(f, "CRC({:02X}): {}", id, crc),
297            PP2Tlvs::TypeNoop => 
298                write!(f, "NOOP({:02X})", id),
299            PP2Tlvs::TypeUniqId(items) => 
300                write!(f, "UNIQID({:02X}): {:02X?}", id, items),
301            PP2Tlvs::TypeSsl{client, verify} => 
302                write!(f, "SSL({:02X}): client: {:?}, verify: {}", id, client, verify),
303            PP2Tlvs::TypeSubtypeSslVersion(ver) => 
304                write!(f, "SSL VERSION({:02X}): {}", id, ver),
305            PP2Tlvs::TypeSubtypeSslCn(cn) => 
306                write!(f, "SSL CN({:02X}): {}", id, cn),
307            PP2Tlvs::TypeSubtypeSslCipher(c) => 
308                write!(f, "SSL CIPHER({:02X}): {}", id, c),
309            PP2Tlvs::TypeSubtypeSslSigAlg(sa) => 
310                write!(f, "SSL SIGALG({:02X}): {}", id, sa),
311            PP2Tlvs::TypeSubtypeSslKeyAlg(ka) => 
312                write!(f, "SSL KEYALG({:02X}): {}", id, ka),
313            PP2Tlvs::TypeNetNs(ns) => 
314                write!(f, "NETNS({:02X}): {}", id, ns),
315        }
316    }
317}
318
319impl From<PP2Tlvs> for u8
320{
321    fn from(value: PP2Tlvs) -> Self 
322    {
323        return (&value).into();
324    }
325}
326
327impl From<&PP2Tlvs> for u8
328{
329    fn from(value: &PP2Tlvs) -> Self 
330    {
331        return unsafe { *<*const _>::from(value).cast::<Self>() };
332    }
333}
334
335
336
337impl PP2Tlvs
338{
339    /// A constraints by range of all types.
340    pub const TLV_TYPE_MAIN_RANGES: &'static [RangeInclusive<u8>] = 
341        &[
342            Self::TYPE_ALPN..=Self::TYPE_SSL,  
343            Self::TYPE_NETNS ..= Self::TYPE_NETNS
344        ];
345
346    /// A constraints for the SSL subtypes.
347    pub const TLV_TYPE_SSL_SUB_RANGE: &'static [RangeInclusive<u8>] = 
348        &[Self::TYPE_SUBTYPE_SSL_VERSION ..= Self::TYPE_SUBTYPE_SSL_KEYALG];
349
350    pub const TYPE_ALPN: u8 = 0x01;
351
352    pub const TYPE_AUTHORITY: u8 = 0x02;
353
354    pub const TYPE_CRC32C: u8 = 0x03;
355
356    pub const TYPE_NOOP: u8 = 0x04;
357
358    pub const TYPE_UNIQID: u8 = 0x05;
359
360    pub const TYPE_SSL: u8 = 0x20;
361
362    pub const TYPE_SUBTYPE_SSL_VERSION: u8 = 0x21;
363
364    pub const TYPE_SUBTYPE_SSL_CN: u8 = 0x22;
365    
366    pub const TYPE_SUBTYPE_SSL_CIPHER: u8 = 0x23;
367
368    pub const TYPE_SUBTYPE_SSL_SIGALG: u8 = 0x24;
369
370    pub const TYPE_SUBTYPE_SSL_KEYALG: u8 = 0x25;
371
372    pub const TYPE_NETNS: u8 = 0x30;
373
374    pub 
375    fn contains_subtype(&self) -> bool
376    {
377        let Self::TypeSsl{ .. } = self else { return false };
378
379        return true;
380    }
381
382    pub 
383    fn conntains_subtype_discr(discr: u8) -> bool
384    {
385        return discr == Self::TYPE_SSL;
386    }
387}
388
389/// A quote from protocol descr:
390/// > other values are unspecified and must not be emitted in version 2 of this
391/// > protocol and must be rejected as invalid by receivers.
392#[repr(u8)]
393#[derive(Clone, Copy, Debug, PartialEq, Eq)]
394pub enum ProxyV2AddrType
395{
396    /// A quote from protocol descr:
397    /// > the connection is forwarded for an unknown, unspecified
398    /// > or unsupported protocol. The sender should use this family when sending
399    /// > LOCAL commands or when dealing with unsupported protocol families. The
400    /// > receiver is free to accept the connection anyway and use the real endpoint
401    /// > addresses or to reject it. The receiver should ignore address information.
402    AfUnspec = 0x00,
403
404    /// A quote from protocol descr:
405    /// > the forwarded connection uses the AF_INET address family
406    /// > (IPv4). The addresses are exactly 4 bytes each in network byte order,
407    /// > followed by transport protocol information (typically ports).
408    AfInet = 0x01,
409
410    /// A quote from protocol descr:
411    /// > the forwarded connection uses the AF_INET6 address family
412    /// > (IPv6). The addresses are exactly 16 bytes each in network byte order,
413    /// > followed by transport protocol information (typically ports).
414    AfInet6 = 0x02,
415
416    /// A quote from protocol descr:
417    /// > the forwarded connection uses the AF_UNIX address family
418    /// > (UNIX). The addresses are exactly 108 bytes each.
419    AfUnix = 0x03,
420}
421
422impl From<ProxyV2AddrType> for u8
423{
424    fn from(value: ProxyV2AddrType) -> Self 
425    {
426        return value as u8;
427    }
428}
429
430impl ProxyV2AddrType
431{
432    pub const DEF_IPV4_ADDR_LEN: u16 = 12;
433    pub const DEF_IPV6_ADDR_LEN: u16 = 36;
434    pub const DEF_UNIX_ADDR_LEN: u16 = 216;
435
436    pub(crate) 
437    fn decode(raw: u8) -> HaProxRes<Self>
438    {
439        match raw >> 4
440        {
441            r if r == ProxyV2AddrType::AfUnspec.into() => 
442                return Ok(Self::AfUnspec),
443            r if r == ProxyV2AddrType::AfInet.into() => 
444                return Ok(Self::AfInet),
445            r if r == ProxyV2AddrType::AfInet6.into() => 
446                return Ok(Self::AfInet6),
447            r if r == ProxyV2AddrType::AfUnix.into() => 
448                return Ok(Self::AfUnix),
449            r => 
450                return_error!(ProtocolUnknownData, "can not decode address type: '{:02X}'", r),
451        }
452    }
453
454    pub 
455    fn get_size_by_addr_family(&self) -> Option<u16>
456    {
457        match self
458        {
459            Self::AfUnspec => 
460                return None,
461            Self::AfInet => 
462                return Some(Self::DEF_IPV4_ADDR_LEN),
463            Self::AfInet6 => 
464                return Some(Self::DEF_IPV6_ADDR_LEN),
465            Self::AfUnix => 
466                return Some(Self::DEF_UNIX_ADDR_LEN),
467        }
468    }
469}
470
471
472/// An address re-representation. Can be initialized using `TryFrom` 
473/// implementations.
474/// 
475/// TryFrom("ip:port", "ip:port")
476/// TryFrom(IpAddr, u16, IpAddr, u16)
477/// TryFrom(net::SocketAddr, net::SocketAddr)
478/// TryFrom(SocketAddr, SocketAddr)
479/// 
480/// The type will be determined automatically.
481#[derive(Clone, Debug)]
482pub enum ProxyV2Addr
483{
484    /// AF_INET, AF_INET6
485    Ip
486    {
487        src: SocketAddr,
488        dst: SocketAddr,
489    },
490
491    /// AF_UNIX
492    Unix
493    {
494        src: net::SocketAddr,
495        dst: net::SocketAddr,
496    }
497}
498
499impl Eq for ProxyV2Addr {}
500
501impl PartialEq for ProxyV2Addr
502{
503    fn eq(&self, other: &Self) -> bool 
504    {
505        match (self, other) 
506        {
507            (
508                Self::Ip { src: l_src, dst: l_dst }, 
509                Self::Ip { src: r_src, dst: r_dst }
510            ) => 
511                l_src == r_src && l_dst == r_dst,
512
513            (
514                Self::Unix { src: l_src, dst: l_dst }, 
515                Self::Unix { src: r_src, dst: r_dst }
516            ) => 
517                l_src.as_pathname() == r_src.as_pathname() && l_dst.as_pathname() == r_dst.as_pathname(),
518            _ => false,
519        }
520    }
521}
522
523impl fmt::Display for ProxyV2Addr
524{
525    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
526    {
527        match self
528        {
529            ProxyV2Addr::Ip{ src, dst } => 
530                write!(f, "SRC: {}, DST: {}", src, dst),
531            ProxyV2Addr::Unix{ src, dst } => 
532                write!(f, "SRC: {:?}, DST: {:?}", src, dst)
533        }
534    }
535}
536
537impl TryFrom<(IpAddr, u16, IpAddr, u16)> for ProxyV2Addr
538{
539    type Error = HaProxErr;
540
541    /// # Arguments
542    /// 
543    /// * `value.0` - source IP address [IpAddr]
544    /// 
545    /// * `value.1` - source port [u16]
546    /// 
547    /// * `value.2` - destination IP address [IpAddr]
548    /// 
549    /// * `value.3` - destination port [u16]
550    fn try_from(value: (IpAddr, u16, IpAddr, u16)) -> Result<Self, Self::Error> 
551    {
552        let src = SocketAddr::new(value.0, value.1);
553        let dst = SocketAddr::new(value.2, value.3);
554
555        return Ok(Self::Ip{ src: src, dst: dst });
556    }
557}
558
559impl TryFrom<(SocketAddr, SocketAddr)> for ProxyV2Addr
560{
561    type Error = HaProxErr;
562
563    /// # Arguments
564    /// 
565    /// * `value.0` - source address [SocketAddr]
566    /// 
567    /// * `value.1` - destination address [SocketAddr]
568    fn try_from(value: (SocketAddr, SocketAddr)) -> Result<Self, Self::Error> 
569    {
570        return Ok(Self::Ip{ src: value.0, dst: value.1 });
571    }
572}
573
574impl TryFrom<(net::SocketAddr, net::SocketAddr)> for ProxyV2Addr
575{
576    type Error = HaProxErr;
577
578    /// # Arguments
579    /// 
580    /// * `value.0` - source address [net::SocketAddr]
581    /// 
582    /// * `value.1` - destination address [net::SocketAddr]
583    fn try_from(value: (net::SocketAddr, net::SocketAddr)) -> Result<Self, Self::Error> 
584    {
585        return Ok(Self::Unix{ src: value.0, dst: value.1 });
586    }
587}
588
589
590impl TryFrom<(&str, &str)> for ProxyV2Addr
591{
592    type Error = HaProxErr;
593
594    /// # Arguments
595    /// 
596    /// * `value.0` - source address [str]
597    /// 
598    /// * `value.1` - destination address [str]
599    fn try_from(value: (&str, &str)) -> Result<Self, Self::Error> 
600    {
601        if let Ok(src) = SocketAddr::from_str(value.0)
602        {
603            let Ok(dst) = SocketAddr::from_str(value.1)
604            else 
605            {
606                return_error!(ArgumentEinval, "can not convert '{}' to SocketAddr", 
607                    common::sanitize_str_unicode(value.1));
608            };
609
610            return Ok(Self::Ip{ src: src, dst: dst });
611        }
612        else if let Ok(src) = net::SocketAddr::from_pathname(value.0)
613        {
614            let Ok(dst) = net::SocketAddr::from_pathname(value.1)
615            else 
616            {
617                return_error!(ArgumentEinval, "can not convert '{}' to net::SocketAddr", 
618                    common::sanitize_str_unicode(value.1));
619            };
620
621            return Ok(Self::Unix{ src: src, dst: dst });
622        }
623        else
624        {
625            return_error!(ArgumentEinval, "can not convert '{}' to either SocketAddr or net::SocketAddr", 
626                common::sanitize_str_unicode(value.0));
627        }
628    }
629}
630
631impl ProxyV2Addr
632{
633    #[inline]
634    pub 
635    fn get_len(&self) -> u16
636    {
637        return self.as_addr_family().get_size_by_addr_family().unwrap();
638    }
639
640    /// Returns the address type.
641    #[inline]
642    pub 
643    fn as_addr_family(&self) -> ProxyV2AddrType
644    {
645        match self
646        {
647            ProxyV2Addr::Ip{ src, .. } => 
648            {
649                if src.is_ipv4() == true
650                {
651                    return ProxyV2AddrType::AfInet;
652                }
653                else
654                {
655                    return ProxyV2AddrType::AfInet6;
656                }
657            }
658            ProxyV2Addr::Unix{ .. } => 
659                return ProxyV2AddrType::AfUnix
660        }
661    }
662
663    /// Reads the address section of the HaProxy. The address family should be 
664    /// obtained from the same packet before. The `cur` must point to the beginning
665    /// of the address block.
666    /// 
667    /// # Returns
668    /// 
669    /// The [Result] is returned. The [Option::None] will be returned only if the
670    /// `addr_fam` is [ProxyV2AddrType::AfUnspec].
671    pub 
672    fn read(addr_fam: ProxyV2AddrType, cur: &mut Cursor<&[u8]>) -> HaProxRes<Option<Self>>
673    {
674        match addr_fam
675        {
676            ProxyV2AddrType::AfUnspec => Ok(None),
677            ProxyV2AddrType::AfInet => 
678            {
679                let src = IpAddr::from(Ipv4Addr::from_bits(cur.read_u32::<BigEndian>().map_err(common::map_io_err)?));
680                let dst = IpAddr::from(Ipv4Addr::from_bits(cur.read_u32::<BigEndian>().map_err(common::map_io_err)?));
681                let src_port = cur.read_u16::<BigEndian>().map_err(common::map_io_err)?;
682                let dst_port = cur.read_u16::<BigEndian>().map_err(common::map_io_err)?;
683
684                return Ok(Some(Self::try_from((src, src_port, dst, dst_port))?));
685            },
686            ProxyV2AddrType::AfInet6 => 
687            {
688                let src = IpAddr::from(Ipv6Addr::from_bits(cur.read_u128::<BigEndian>().map_err(common::map_io_err)?));
689                let dst = IpAddr::from(Ipv6Addr::from_bits(cur.read_u128::<BigEndian>().map_err(common::map_io_err)?));
690                let src_port = cur.read_u16::<BigEndian>().map_err(common::map_io_err)?;
691                let dst_port = cur.read_u16::<BigEndian>().map_err(common::map_io_err)?;
692
693                return Ok(Some(Self::try_from((src, src_port, dst, dst_port))?));
694            },
695            ProxyV2AddrType::AfUnix => 
696            {
697                let mut n_src: [u8; HEADER_UNIX_ADDR_LEN] = [0_u8; HEADER_UNIX_ADDR_LEN];
698                cur.read(&mut n_src).map_err(common::map_io_err)?;
699
700                let mut n_dst: [u8; HEADER_UNIX_ADDR_LEN] = [0_u8; HEADER_UNIX_ADDR_LEN];
701                cur.read(&mut n_dst).map_err(common::map_io_err)?;
702
703                let src_s = 
704                    net::SocketAddr::from_pathname(
705                        CStr::from_bytes_until_nul(&n_src)
706                            .map_err(|e| 
707                                map_error!(MalformedData, "cannot read unix path, error: {}", e)
708                            )?
709                            .to_str()
710                            .map_err(|e|
711                                map_error!(MalformedData, "cannot read unix path, error: {}", e)
712                            )?
713                    )
714                    .map_err(|e|
715                        map_error!(MalformedData, "cannot read unix path, error: {}", e)
716                    )?;
717
718                let dst_s = 
719                    net::SocketAddr::from_pathname(
720                        CStr::from_bytes_until_nul(&n_dst)
721                            .map_err(|e| 
722                                map_error!(MalformedData, "cannot read unix path, error: {}", e)
723                            )?
724                            .to_str()
725                            .map_err(|e|
726                                map_error!(MalformedData, "cannot read unix path, error: {}", e)
727                            )?
728                    )
729                    .map_err(|e|
730                        map_error!(MalformedData, "cannot read unix path, error: {}", e)
731                    )?;
732
733                return Ok(Some(Self::try_from((src_s, dst_s))?));
734            },
735        }
736    }
737
738    /// Writes the content of the current instance to packet in format of 
739    /// the HaProxy address. The `cur` [Cursor] should point to the
740    /// beginning of the address block.
741    pub  
742    fn write(&self, cur: &mut Cursor<Vec<u8>>) -> HaProxRes<()>
743    {
744        match self
745        {
746            ProxyV2Addr::Ip{ src, dst } => 
747            {
748                match src.ip()
749                {
750                    IpAddr::V4(ipv4_addr) => 
751                        cur.write_u32::<BigEndian>(ipv4_addr.to_bits()).map_err(common::map_io_err)?,
752                    IpAddr::V6(ipv6_addr) => 
753                        cur.write_u128::<BigEndian>(ipv6_addr.to_bits()).map_err(common::map_io_err)?,
754                }
755
756                match dst.ip()
757                {
758                    IpAddr::V4(ipv4_addr) => 
759                        cur.write_u32::<BigEndian>(ipv4_addr.to_bits()).map_err(common::map_io_err)?,
760                    IpAddr::V6(ipv6_addr) => 
761                        cur.write_u128::<BigEndian>(ipv6_addr.to_bits()).map_err(common::map_io_err)?,
762                }
763
764                cur.write_u16::<BigEndian>(src.port()).map_err(common::map_io_err)?;
765                cur.write_u16::<BigEndian>(dst.port()).map_err(common::map_io_err)?;
766            },
767            ProxyV2Addr::Unix { src, dst } => 
768            {
769                let src_p = 
770                    src.as_pathname().ok_or_else(|| map_error!(ArgumentEinval, "UNIX src socket addr is not path"))?;
771                let dst_p = 
772                    dst.as_pathname().ok_or_else(|| map_error!(ArgumentEinval, "UNIX src socket addr is not path"))?;
773
774                let src_b = src_p.as_os_str().as_bytes();
775                let dst_b = dst_p.as_os_str().as_bytes();
776
777                if src_b.len() > HEADER_UNIX_ADDR_LEN
778                {
779                    return_error!(ArgumentEinval, "socket path: '{}' longer than: '{}'", 
780                        src_p.display(), HEADER_UNIX_ADDR_LEN);
781                }
782                else if dst_b.len() > HEADER_UNIX_ADDR_LEN
783                {
784                    return_error!(ArgumentEinval, "socket path: '{}' longer than: '{}'", 
785                        dst_p.display(), HEADER_UNIX_ADDR_LEN);
786                }
787
788                
789                let mut n_src: [u8; HEADER_UNIX_ADDR_LEN] = [0_u8; HEADER_UNIX_ADDR_LEN];
790                n_src[0..src_b.len()].copy_from_slice(src_b);
791
792                cur.write_all(&n_src).map_err(common::map_io_err)?;
793
794                let mut n_dst: [u8; HEADER_UNIX_ADDR_LEN] = [0_u8; HEADER_UNIX_ADDR_LEN];
795                n_dst[0..dst_b.len()].copy_from_slice(dst_b);
796
797                cur.write_all(&n_dst).map_err(common::map_io_err)?;
798            }
799        }
800
801        return Ok(());
802    }
803}
804
805/// A transport family.
806/// > Other values are unspecified and must not be emitted in version 2 of this
807/// > protocol and must be rejected as invalid by receivers.`
808#[repr(u8)]
809#[derive(Clone, Debug, PartialEq, Eq)]
810pub enum ProxyTransportFam
811{
812    /// > the connection is forwarded for an unknown, unspecified
813    /// > or unsupported protocol. The sender should use this family when sending
814    /// > LOCAL commands or when dealing with unsupported protocol families. The
815    /// > receiver is free to accept the connection anyway and use the real endpoint
816    /// > addresses or to reject it. The receiver should ignore address information.
817    UNSPEC = 0x00,
818
819    /// > the forwarded connection uses a SOCK_STREAM protocol (eg:
820    /// > TCP or UNIX_STREAM). When used with AF_INET/AF_INET6 (TCP), the addresses
821    /// > are followed by the source and destination ports represented on 2 bytes
822    /// > each in network byte order.
823    STREAM,
824
825    /// > the forwarded connection uses a SOCK_DGRAM protocol (eg:
826    /// > UDP or UNIX_DGRAM). When used with AF_INET/AF_INET6 (UDP), the addresses
827    /// > are followed by the source and destination ports represented on 2 bytes
828    /// > each in network byte order.
829    DGRAM,
830}
831
832impl fmt::Display for ProxyTransportFam
833{
834    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
835    {
836        match self
837        {
838            Self::UNSPEC => write!(f, "UNSPEC"),
839            Self::STREAM => write!(f, "STREAM"),
840            Self::DGRAM => write!(f, "DGRAM"),
841        }
842    }
843}
844
845impl From<ProxyTransportFam> for u8
846{
847    fn from(value: ProxyTransportFam) -> Self 
848    {
849        return value as u8;
850    }
851}
852
853impl From<&ProxyTransportFam> for u8
854{
855    fn from(value: &ProxyTransportFam) -> Self 
856    {
857        return unsafe { *<*const _>::from(value).cast::<Self>() };
858    }
859}
860
861impl ProxyTransportFam
862{
863    pub(crate) 
864    fn decode(value: u8) -> HaProxRes<Self>
865    {
866        match value & protocol_raw::ProxyHdrV2::TRANSPT_MASK
867        {
868            v if ProxyTransportFam::UNSPEC as u8 == v => return Ok(Self::UNSPEC),
869            v if ProxyTransportFam::STREAM as u8 == v => return Ok(Self::STREAM),
870            v if ProxyTransportFam::DGRAM as u8 == v => return Ok(Self::DGRAM),
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}