haprox_rs/protocol_v2/
protocol_parser.rs

1/*-
2 * haprox-rs - a HaProxy protocol parser.
3 * 
4 * Copyright 2025 (c) 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. The MIT License (MIT)
11 *                     
12 *   3. EUROPEAN UNION PUBLIC LICENCE v. 1.2 EUPL © the European Union 2007, 2016
13 */
14
15use std::mem::offset_of;
16use std::{fmt, io::Cursor, marker::PhantomData};
17use byteorder::{BigEndian, ReadBytesExt};
18use crc32fast::Hasher;
19
20use crate::common::map_io_err;
21use crate::{error::{HaProxErr, HaProxRes}, map_error, return_error};
22
23use crate::protocol_raw;
24
25use super::
26{
27    protocol::
28    {
29        HdrV2Command, 
30        PP2Tlvs, 
31        ProtocolVersion, 
32        ProxyTransportFam, 
33        ProxyV2Addr, 
34        ProxyV2AddrType
35    }, 
36    PP2TlvRestore
37};
38
39/// Used with [ProxyV2Parser] its `PAR` generic.
40/// 
41/// A parser which copies data from external buffer to PP2Tlvs
42/// and setting the `'static` lifetime to this enum.
43#[derive(Debug)]
44pub struct PPV2ParserCopying();
45
46impl fmt::Display for PPV2ParserCopying
47{
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
49    {
50        write!(f, "copying parser")
51    }
52}
53
54/// Used with [ProxyV2Parser] its `PAR` generic.
55/// 
56/// A parser which borrows the data from external buffer without
57/// copying it. The lifetime is a lifetime of the parser instance.
58#[derive(Debug)]
59pub struct PPV2ParserZeroCopy<'zc>(PhantomData<&'zc ()>);
60
61impl<'zc> fmt::Display for PPV2ParserZeroCopy<'zc>
62{
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
64    {
65        write!(f, "zerocopy parser")
66    }
67}
68
69/// A HaProxy V2 parser main instance.
70/// 
71/// An uppstream code should specify which type of parser is preferable and
72/// set the `EXT` if any additional fields is required to parse. If not the
73/// [ProxyV2Dummy] can be used.
74/// 
75/// There are two types of parsers:
76/// 
77/// * [PPV2ParserCopying] - copies data from source into new location.
78/// 
79/// * [PPV2ParserZeroCopy] - does not copy data, only borrow.
80/// 
81/// # Generics
82/// 
83/// * `PAR` - an internal parser, see above.
84/// 
85/// * `EXT` - an external parser. If it is required to parse some non-std
86///     TLVs in the message, this should be implemented. It is up to you
87///     if it will be copying or borrowing.  
88///     If it is not required, then the [ProxyV2Dummy] can be used.
89#[derive(Debug)]
90pub struct ProxyV2Parser<'t, PAR = PPV2ParserZeroCopy<'t>, EXT = ProxyV2Dummy>
91where 
92    PAR: PP2TlvRestore<'t>,
93    EXT: PP2TlvRestore<'t>,
94{
95    /// A received packed which should contain the proxy pkt.
96    buffer: &'t [u8],
97
98    /// Phantom for the extension for the protocol.
99    _p1: PhantomData<EXT>,
100
101    /// Phantom for the parser type.
102    _p2: PhantomData<PAR>,
103}
104
105impl<'t> ProxyV2Parser<'t>
106{
107    /// Constructs the instance from the temporary reference to the buffer. 
108    pub 
109    fn try_from_slice(value: &'t [u8]) -> HaProxRes<Self>
110    {
111        let pkt_size = Self::new_from(value)?;
112
113        let tmp = 
114            Self
115            { 
116                buffer: &value[0..pkt_size], 
117                _p1: PhantomData,
118                _p2: PhantomData,
119            };
120
121        tmp.post_check()?;
122
123        return Ok(tmp);
124    }
125}
126
127impl<'t, PAR: PP2TlvRestore<'t>, EXT: PP2TlvRestore<'t>> ProxyV2Parser<'t, PAR, EXT>
128{
129    /// Constructs the instance from the temporary reference to the buffer
130    /// with custom extenal TLV parser for custom TLV extensions.
131    pub 
132    fn try_from_slice_custom(value: &'t [u8]) -> HaProxRes<Self>
133    {
134        let pkt_size = Self::new_from(value)?;
135
136        let tmp = 
137            Self
138            { 
139                buffer: &value[0..pkt_size], 
140                _p1: PhantomData,
141                _p2: PhantomData,
142            };
143
144        tmp.post_check()?;
145
146        return Ok(tmp);
147    }
148}
149
150impl<'t, PAR: PP2TlvRestore<'t>, EXT: PP2TlvRestore<'t>> ProxyV2Parser<'t, PAR, EXT>
151{
152    fn post_check(&self) -> HaProxRes<()>
153    {
154        let _ = self.get_address_family()?;
155        let _ = self.get_transport()?;
156
157        return Ok(());
158    }
159
160    /// Internal function.
161    /// 
162    /// Checks the header for the specific pattern to determine if this is a HaProxy
163    /// mesage and if it initial header bits are valid.
164    fn new_from(value: &[u8]) -> HaProxRes<usize>
165    {
166        if value.len() <= protocol_raw::HEADER_MAGIC_V1.len()
167        {
168            return_error!(IncorrectBanner, "protocol with footprint '{:02X?}' unknown", 
169                value);
170        }
171        else if &value[0..protocol_raw::HEADER_MAGIC_V1.len()] == protocol_raw::HEADER_MAGIC_V1
172        {
173            return_error!(ProtocolNotSuported, "V1 protocol is not supported");
174        }
175        else if value.len() < size_of::<protocol_raw::ProxyHdrV2>()
176        {
177            return_error!(ProtocolMsgIncomplete, "protocol with footprint '{:02X?}' unknown", 
178                value);
179        }
180        else if &value[0..protocol_raw::HEADER_MAGIC_V2.len()] != protocol_raw::HEADER_MAGIC_V2
181        {
182            return_error!(IncorrectBanner, "protocol with footprint '{:02X?}' unknown", 
183                value);
184        }
185        else if value[offset_of!(protocol_raw::ProxyHdrV2, ver_cmd)] & protocol_raw::ProxyHdrV2::VERSION_MASK != 
186            protocol_raw::ProxyHdrV2::VERSION_RAW
187        {
188            return_error!(MalformedData, "protocol version '{:02X?}' incorrect", 
189                value[offset_of!(protocol_raw::ProxyHdrV2, ver_cmd)]);
190        }
191
192        let payload_len =  
193            [
194                value[offset_of!(protocol_raw::ProxyHdrV2, len)],
195                value[offset_of!(protocol_raw::ProxyHdrV2, len)+1]
196            ];
197
198        let full_size = u16::from_be_bytes(payload_len) + protocol_raw::ProxyHdrV2::HEADER_LEN as u16;
199
200        if value.len() < full_size as usize
201        {
202            return_error!(ProtocolMsgIncomplete, "fragmented pkt received, declared len + header: {}, received len: {}",
203                full_size, value.len());
204        }
205
206        return Ok(full_size as usize);
207    }
208
209    /// Extracts and decodes the protocol version from the packet.
210    pub 
211    fn get_proto_version(&self) -> ProtocolVersion
212    {
213        return ProtocolVersion::decode(self.buffer[offset_of!(protocol_raw::ProxyHdrV2, ver_cmd)]);
214    }
215
216    /// Extracts and decodes the protocol command code from the packet.
217    pub 
218    fn get_proto_command(&self) -> HdrV2Command
219    {
220        return HdrV2Command::decode(self.buffer[offset_of!(protocol_raw::ProxyHdrV2, ver_cmd)]);
221    }
222
223    /// Extracts and decodes the transport type from the packet.
224    pub 
225    fn get_transport(&self) -> HaProxRes<ProxyTransportFam>
226    {
227        return ProxyTransportFam::decode(self.buffer[offset_of!(protocol_raw::ProxyHdrV2, fam)]);
228    }
229
230    /// Extracts and decodes the address family from the packet. It does not extract address. 
231    pub 
232    fn get_address_family(&self) -> HaProxRes<ProxyV2AddrType>
233    {
234        return ProxyV2AddrType::decode(self.buffer[offset_of!(protocol_raw::ProxyHdrV2, fam)]);
235    }
236
237    /// Returns the size of the packet (without header len).
238    pub 
239    fn get_palyload_len(&self) -> u16
240    {
241        let hi =  
242            [
243                self
244                    .buffer[offset_of!(protocol_raw::ProxyHdrV2, len)],
245                self
246                    .buffer[offset_of!(protocol_raw::ProxyHdrV2, len)+1]
247            ];
248            
249
250        return u16::from_be_bytes(hi);
251    }
252
253    /// Returns the full size of the packet.
254    pub 
255    fn get_full_len(&self) -> u16
256    {
257        let hi =  
258            [
259                self
260                    .buffer[offset_of!(protocol_raw::ProxyHdrV2, len)],
261                self
262                    .buffer[offset_of!(protocol_raw::ProxyHdrV2, len)+1]
263            ];
264            
265
266        return u16::from_be_bytes(hi) + protocol_raw::ProxyHdrV2::HEADER_LEN as u16;
267    }
268
269    /// Extracts the address section from the packet. The address family can be obtained from the 
270    /// returned instance.
271    /// 
272    /// # Returns
273    /// 
274    /// A [HaProxRes] is returned with:
275    /// 
276    /// * [Result::Ok] - the  [Option] with:
277    /// 
278    /// * * [Option::Some] - a parsed address is returned in form of [ProxyV2Addr]
279    /// 
280    /// * * [Option::None] - if address family is unspecified.
281    /// 
282    /// * [Result::Err] - an error description.
283    pub 
284    fn get_address(&self) -> HaProxRes<Option<ProxyV2Addr>>
285    {
286        let addr_fam = self.get_address_family()?;
287
288        let Some(addr_len) = addr_fam.get_size_by_addr_family()
289        else { return Ok(None) };
290
291        let buf_len = self.buffer.len() - size_of::<protocol_raw::ProxyHdrV2>();
292
293        if buf_len < addr_len as usize
294        {
295            return_error!(ProtocolMsgIncomplete, "cannot read address, msg len: '{}', addr len: '{}'", 
296                buf_len, addr_len);
297        }
298
299        let mut cur = Cursor::new(&self.buffer.as_ref()[offset_of!(protocol_raw::ProxyHdrV2, address)..]);
300
301        return ProxyV2Addr::read(addr_fam, &mut cur);
302    }
303
304    /// Creates an iterator over TLVs which could be in the payload of the packer. This is flat iterator i.e if
305    /// TLV contains a subcodes, it will be returned as it is just in a 1D array. You should track
306    /// if item contains a subcode and a subcode is returned.
307    pub 
308    fn get_tlvs_iter(&self) -> Option<ProxyV2TlvIter<'t, PAR, EXT>>
309    {
310        let addr_fam = self.get_address_family().ok()?.get_size_by_addr_family()?;
311
312        if self.get_palyload_len() - addr_fam == 0
313        {
314            return None;
315        }
316
317        let addr_size = self.get_address_family().ok()?.get_size_by_addr_family()? as usize;
318
319        let tlv_offset_start = 
320            offset_of!(protocol_raw::ProxyHdrV2, address) + addr_size;
321
322        let itr = 
323            ProxyV2TlvIter
324            {
325                curs: 
326                    vec![
327                        ProxyV2TlvIterTlv
328                        {
329                            cur: Cursor::new(&self.buffer.as_ref()[tlv_offset_start..]),
330                            parent_tlv_idx: None,
331                        },
332                    ],
333                _p: PhantomData,
334                _p2: PhantomData,
335            };
336
337        return Some(itr);
338    }
339
340    /// Calculates the CRC of message and returns the result.
341    pub 
342    fn check_crc(&self) -> HaProxRes<bool>
343    {
344        /*let PP2Tlvs::TypeCrc32c(crcpkt) = crc 
345            else { return_error!(ArgumentEinval, "PP2Tlvs type is not TypeCrc32c") };*/
346
347        let mut crc32: Option<u32> = None;
348
349        // init hasher
350        let mut hasher = Hasher::new();
351
352        let addr_fam_len = 
353            self
354                .get_address_family()?
355                .get_size_by_addr_family()
356                .ok_or_else(||
357                    map_error!(ArgumentEinval, "unknown address family")
358                )? as usize;
359
360        
361        let full_hdr_len = addr_fam_len + protocol_raw::ProxyHdrV2::HEADER_LEN;
362        
363        // calculate crc header
364        hasher.update(&self.buffer[0..full_hdr_len]);
365
366        let payload_len = self.get_palyload_len() as usize - addr_fam_len;
367
368        let mut cur = Cursor::new(&self.buffer[full_hdr_len..]);
369
370        while cur.position() < payload_len as u64
371        {
372            let s = cur.position() as usize;
373
374            let op = cur.read_u8().map_err(map_io_err)?;
375            let len = cur.read_u16::<BigEndian>().map_err(map_io_err)?;
376
377            if op == PP2Tlvs::TYPE_CRC32C
378            {
379                crc32 = Some(cur.read_u32::<BigEndian>().map_err(map_io_err)?);
380
381                hasher.update(&[op]);
382                hasher.update(len.to_be_bytes().as_slice());
383                hasher.update(&[0]);
384            }
385            else
386            {
387                let last = s+2+len as usize;
388
389                hasher.update(&self.buffer[s..last]);
390                cur.set_position(last as u64);
391            }
392        }
393
394        if let Some(cr) = crc32
395        {
396            return Ok(cr == hasher.finalize());
397        }
398        else
399        {
400            return_error!(ArgumentEinval, "no CRC TLV found!");
401        }
402    }
403}
404
405
406/// A dummy implementation of the TVL protocol extension.
407#[derive(Clone, Debug)]
408pub enum ProxyV2Dummy {}
409
410impl fmt::Display for ProxyV2Dummy
411{
412    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
413    {
414        write!(f, "DUMMY external reader")
415    }
416}
417
418impl<'zc> PP2TlvRestore<'zc> for ProxyV2Dummy
419{
420    type TlvTblRes = PP2Tlvs<'zc>;
421
422    fn is_in_range(_tlv_type: u8, _tlv_parent_type: Option<u8>) -> bool 
423    {
424        return false;
425    }
426
427    fn contains_subtype(_item: &Self::TlvTblRes) -> bool 
428    {
429        return false;
430    }
431
432    fn restore(_tlv_type: u8, _cur: &mut Cursor<&[u8]>) -> HaProxRes<Self::TlvTblRes>
433    {
434        return_error!(ArgumentEinval, "assertion trap, DUMMY external decoder");
435    } 
436}
437
438impl PP2TlvRestore<'static> for PPV2ParserCopying
439{
440    type TlvTblRes = PP2Tlvs<'static>;
441
442    fn contains_subtype(item: &Self::TlvTblRes) -> bool 
443    {
444        return item.contains_subtype();    
445    }
446
447    fn is_in_range(tlv_type: u8, tlv_parent_type: Option<u8>) -> bool 
448    {
449        return PP2Tlvs::<'static>::is_in_range(tlv_type, tlv_parent_type);
450    }
451
452    fn restore(tlv_type: u8, cur: &mut Cursor<&'static [u8]>) -> HaProxRes<Self::TlvTblRes> 
453    {
454        return PP2Tlvs::<'static>::restore_copying(tlv_type, cur);
455    }
456}
457
458impl<'zc> PP2TlvRestore<'zc> for PPV2ParserZeroCopy<'zc>
459{
460    type TlvTblRes = PP2Tlvs<'zc>;
461
462    fn contains_subtype(item: &Self::TlvTblRes) -> bool 
463    {
464        return item.contains_subtype();    
465    }
466
467    fn is_in_range(tlv_type: u8, tlv_parent_type: Option<u8>) -> bool 
468    {
469        return PP2Tlvs::<'zc>::is_in_range(tlv_type, tlv_parent_type);
470    }
471    
472    fn restore(tlv_type: u8, cur: &mut Cursor<&'zc [u8]>) -> HaProxRes<Self::TlvTblRes> 
473    {
474        return PP2Tlvs::<'zc>::restore_zerocopy(tlv_type, cur);
475    }
476}
477
478/// An `enum` which is returned by the TLV iterator. It may contain either parsed TLV or 
479/// error description which occured during parsing. Normally, in case of error, the 
480/// parsing should be stopped and connection dropped.
481#[derive(Debug, Clone, PartialEq, Eq)]
482pub enum ProxyV2TlvSource<'zc, PAR: PP2TlvRestore<'zc>, EXT: PP2TlvRestore<'zc>>
483{
484    /// A base implementation of the protocl.
485    Internal(PAR::TlvTblRes),
486
487    /// A user's extension to the protocol.
488    External(EXT::TlvTblRes),
489    
490    /// Error during parsing.
491    Error(HaProxErr),
492}
493
494impl<'zc, PAR: PP2TlvRestore<'zc>, EXT: PP2TlvRestore<'zc>> ProxyV2TlvSource<'zc, PAR, EXT>
495{
496    fn new_internal(pp2: HaProxRes<PAR::TlvTblRes>) -> Self
497    {
498        return 
499            pp2.map_or_else(|e| Self::Error(e), |f| Self::Internal(f));
500    }
501
502    fn new_external(pp2: HaProxRes<EXT::TlvTblRes>) -> Self
503    {
504        return 
505            pp2
506                .map_or_else(|e| Self::Error(e), |f| Self::External(f));
507    }
508
509    fn new_error(err: HaProxErr) -> Self
510    {
511        return Self::Error(err);
512    }
513
514    fn new_io_error(err: std::io::Error) -> Self
515    {
516        return Self::Error(map_error!(IoError, "while reading TLV, error: {}", err));
517    }
518
519    /// Consumes the instance returning the [PP2Tlvs] build-in TLV through [Option]. 
520    /// If instance os not `Internal` then instance will be lost.
521    pub 
522    fn take_internal(self) -> Option<PAR::TlvTblRes>
523    {
524        let Self::Internal(s) = self else {return None};
525
526        return Some(s);
527    }
528
529    /// Consumes the instance returning the [PP2Tlvs] build-in TLV through [Option]. 
530    /// If instance os not `External` then instance will be lost.
531    pub 
532    fn take_external(self) -> Option<EXT::TlvTblRes>
533    {
534        let Self::External(s) = self else {return None};
535
536        return Some(s);
537    }
538
539    /// Checks if current instance constains the subtype. For `Error` `false` is
540    /// always returned.
541    pub 
542    fn contains_subtype(&self) -> bool
543    {
544        match self
545        {
546            Self::Internal(i) => 
547                return PAR::contains_subtype(i),
548            Self::External(e) => 
549                return EXT::contains_subtype(e),
550            _ => 
551                return false
552        }
553    }
554    
555}
556
557/// TLV iterator instance.
558#[derive(Debug)]
559struct ProxyV2TlvIterTlv<'iter>
560{
561    /// A cursor to the current data.
562    cur: Cursor<&'iter [u8]>,
563
564    /// A parent (previous) TLV's ID.
565    parent_tlv_idx: Option<u8>,
566}
567
568/// A multilayer iterator instance.
569#[derive(Debug)]
570pub struct ProxyV2TlvIter<'iter, PAR: PP2TlvRestore<'iter>, EXT>
571{
572    /// A heap of the cursors. If iterator reaches subtype, the
573    /// previous cursor will be pushed to heap.
574    curs: Vec<ProxyV2TlvIterTlv<'iter>>,
575
576    /// A phantom.
577    _p: PhantomData<EXT>,
578
579    /// A phantom.
580    _p2: PhantomData<PAR>,
581}
582
583impl<'iter, PAR: PP2TlvRestore<'iter>, EXT: PP2TlvRestore<'iter>> ProxyV2TlvIter<'iter, PAR, EXT>
584{
585    fn get_last_cur(&self) -> &Cursor<&'iter [u8]>
586    {
587        return &self.curs.last().unwrap().cur;
588    }
589
590    fn get_last_mut_cur(&mut self) -> &mut Cursor<&'iter [u8]>
591    {
592        return &mut self.curs.last_mut().unwrap().cur;
593    }
594
595    fn get_parent_tlv(&self) -> Option<u8>
596    {
597        return self.curs.last().unwrap().parent_tlv_idx;
598    }
599}
600
601impl<'iter, PAR: PP2TlvRestore<'iter>, EXT: PP2TlvRestore<'iter>> Iterator for ProxyV2TlvIter<'iter, PAR, EXT>
602{
603    type Item = ProxyV2TlvSource<'iter, PAR, EXT>;
604
605    fn next(&mut self) -> Option<Self::Item> 
606    {
607        // check if the end of the section was reached
608        if self.get_last_cur().get_ref().len() <= self.get_last_cur().position() as usize
609        {
610            if self.curs.len() == 1
611            {
612                // nothing left
613                return None;
614            }
615            else
616            {
617                // return back on one level
618                let _ = self.curs.pop();
619
620                return self.next();
621            }
622        }
623
624        // read type of the tlv
625        let tlv_type = 
626            match self.get_last_mut_cur().read_u8()
627            {
628                Ok(r) => r,
629                Err(e) =>
630                    return Some(ProxyV2TlvSource::new_io_error(e)),
631            };
632
633        // read length of the tlv's payload
634        let tlv_len = 
635            match self.get_last_mut_cur().read_u16::<BigEndian>()
636            {
637                Ok(r) => r,
638                Err(e) => 
639                    return Some(ProxyV2TlvSource::new_io_error(e)),
640            };
641
642        let tlv_range = 
643            self.get_last_cur().position() as usize .. (self.get_last_cur().position()+ tlv_len as u64) as usize;
644
645
646        // creating a cursor from slice to prevent parser going out of bounds by the declared size
647        let mut cur = 
648            Cursor::new(&self.get_last_cur().get_ref()[tlv_range]);
649
650        
651        // check in which range it is
652        let next_item = 
653            if PP2Tlvs::is_in_range(tlv_type, self.get_parent_tlv()) == true
654            {
655                ProxyV2TlvSource::new_internal(
656                    PAR::restore(tlv_type, &mut cur)
657                )
658            }
659            else if EXT::is_in_range(tlv_type, self.get_parent_tlv()) == true
660            {
661                ProxyV2TlvSource::new_external(
662                    EXT::restore(tlv_type, &mut cur)
663                )
664            }
665            else
666            {
667                ProxyV2TlvSource::new_error(
668                    map_error!(ProtocolUnknownData, "TLV tpye: '{}' out of int/ext ranges", tlv_type)
669                )
670            };
671
672        // move cursor position forward
673        let new_pos = self.get_last_cur().position()+ tlv_len as u64;
674        self.get_last_mut_cur().set_position(new_pos);
675
676        if next_item.contains_subtype() == true
677        {
678            // push the current cursor
679            self.curs.push(
680                ProxyV2TlvIterTlv
681                {
682                    cur: cur,
683                    parent_tlv_idx: Some(tlv_type),
684                }
685            );
686        }
687
688        return Some(next_item);
689    }
690}
691
692#[cfg(test)]
693mod tests
694{
695    use std::{borrow::Cow, fmt, io::Cursor, mem};
696
697    use byteorder::{BigEndian, ReadBytesExt};
698
699    use crate::{PPV2ParserCopying, PPV2ParserZeroCopy, ProxyV2Dummy, common, error::HaProxRes, protocol_raw, protocol_v2::{PP2TlvDump, PP2TlvRestore, protocol::{HdrV2Command, PP2_TYPE_MIN_CUSTOM, PP2TlvClient, PP2Tlvs, ProtocolVersion, ProxyTransportFam, ProxyV2Addr, ProxyV2AddrType}}, return_error};
700
701    use super::ProxyV2Parser;
702
703    #[test]
704    fn test_0_zerocopy()
705    {
706        let pkt_ssl = 
707b"\x0d\x0a\x0d\x0a\x00\x0d\x0a\x51\x55\x49\x54\x0a\x21\x11\x00\x2a\
708\x7f\x00\x00\x01\x7f\x00\x00\x43\x9d\xd2\x2e\x6b\x20\x00\x1b\x07\
709\x00\x00\x00\x00\x21\x00\x07\x54\x4c\x53\x76\x31\x2e\x32\x22\x00\
710\x09\x6d\x71\x74\x74\x75\x73\x65\x72\x31";
711
712        let dec = ProxyV2Parser::try_from_slice(pkt_ssl.as_slice()).unwrap();
713
714        assert_eq!(dec.get_transport().is_ok(), true);
715        assert_eq!(dec.get_transport().unwrap(), ProxyTransportFam::STREAM);
716
717        assert_eq!(dec.get_proto_version(), ProtocolVersion::V2);
718        assert_eq!(dec.get_proto_command(), HdrV2Command::PROXY);
719
720        assert_eq!(dec.get_address_family().is_ok(), true);
721        assert_eq!(dec.get_address_family().unwrap(), ProxyV2AddrType::AfInet);
722
723        assert_eq!(dec.get_palyload_len() as usize, pkt_ssl.len() - size_of::<protocol_raw::ProxyHdrV2>());
724        
725        let addr = dec.get_address().unwrap();
726
727        assert_eq!(addr.is_some(), true);
728
729        let addr = addr.unwrap();
730        let maddr = ProxyV2Addr::try_from(("127.0.0.1:40402", "127.0.0.67:11883")).unwrap();
731
732        assert_eq!(addr, maddr);
733
734        let tlv_iter = dec.get_tlvs_iter();
735
736        assert_eq!(tlv_iter.is_some(), true);
737
738        let mut tlv_iter = tlv_iter.unwrap();
739
740        let type_ssl = tlv_iter.next().unwrap().take_internal().unwrap();
741
742        assert_eq!(type_ssl.get_type(), PP2Tlvs::TYPE_SSL);
743        let PP2Tlvs::TypeSsl { client, verify } = type_ssl else {panic!("wrong")};
744
745        assert_eq!(client, PP2TlvClient::all());
746        assert_eq!(verify, 0);
747
748        let type_ssl_version = tlv_iter.next().unwrap().take_internal().unwrap();
749
750        assert_eq!(type_ssl_version.get_type(), PP2Tlvs::TYPE_SUBTYPE_SSL_VERSION);
751
752        let PP2Tlvs::TypeSubtypeSslVersion(ssl_version) = type_ssl_version else { panic!("wrong") };
753        
754        assert_eq!(mem::discriminant(&ssl_version), mem::discriminant(&Cow::Borrowed("TLSv1.2")));
755        assert_eq!(ssl_version, "TLSv1.2");
756
757        let type_ssl_cn = tlv_iter.next().unwrap().take_internal().unwrap();
758
759        assert_eq!(type_ssl_cn.get_type(), PP2Tlvs::TYPE_SUBTYPE_SSL_CN);
760
761        let PP2Tlvs::TypeSubtypeSslCn(ssl_cn) = type_ssl_cn else { panic!("wrong") };
762
763        assert_eq!(ssl_cn, "mqttuser1");
764    }
765
766    #[test]
767    fn test_0_copy()
768    {
769        let pkt_ssl = 
770b"\x0d\x0a\x0d\x0a\x00\x0d\x0a\x51\x55\x49\x54\x0a\x21\x11\x00\x2a\
771\x7f\x00\x00\x01\x7f\x00\x00\x43\x9d\xd2\x2e\x6b\x20\x00\x1b\x07\
772\x00\x00\x00\x00\x21\x00\x07\x54\x4c\x53\x76\x31\x2e\x32\x22\x00\
773\x09\x6d\x71\x74\x74\x75\x73\x65\x72\x31";
774
775
776        let dec = 
777            ProxyV2Parser
778                ::<PPV2ParserCopying, ProxyV2Dummy>
779                ::try_from_slice_custom(pkt_ssl.as_slice())
780                    .unwrap();
781
782        assert_eq!(dec.get_transport().is_ok(), true);
783        assert_eq!(dec.get_transport().unwrap(), ProxyTransportFam::STREAM);
784
785        assert_eq!(dec.get_proto_version(), ProtocolVersion::V2);
786        assert_eq!(dec.get_proto_command(), HdrV2Command::PROXY);
787
788        assert_eq!(dec.get_address_family().is_ok(), true);
789        assert_eq!(dec.get_address_family().unwrap(), ProxyV2AddrType::AfInet);
790
791        assert_eq!(dec.get_palyload_len() as usize, pkt_ssl.len() - size_of::<protocol_raw::ProxyHdrV2>());
792        
793        let addr = dec.get_address().unwrap();
794
795        assert_eq!(addr.is_some(), true);
796
797        let addr = addr.unwrap();
798        let maddr = ProxyV2Addr::try_from(("127.0.0.1:40402", "127.0.0.67:11883")).unwrap();
799
800        assert_eq!(addr, maddr);
801
802        let tlv_iter = dec.get_tlvs_iter();
803
804        assert_eq!(tlv_iter.is_some(), true);
805
806        let mut tlv_iter = tlv_iter.unwrap();
807
808        let type_ssl = tlv_iter.next().unwrap().take_internal().unwrap();
809
810        assert_eq!(type_ssl.get_type(), PP2Tlvs::TYPE_SSL);
811        let PP2Tlvs::TypeSsl { client, verify } = type_ssl else {panic!("wrong")};
812
813        assert_eq!(client, PP2TlvClient::all());
814        assert_eq!(verify, 0);
815
816        let type_ssl_version = tlv_iter.next().unwrap().take_internal().unwrap();
817
818        assert_eq!(type_ssl_version.get_type(), PP2Tlvs::TYPE_SUBTYPE_SSL_VERSION);
819
820        let PP2Tlvs::TypeSubtypeSslVersion(ssl_version) = type_ssl_version else { panic!("wrong") };
821
822        assert_eq!(mem::discriminant(&ssl_version), mem::discriminant(&Cow::Owned("TLSv1.2".into())));
823        assert_eq!(ssl_version, "TLSv1.2");
824
825        let type_ssl_cn = tlv_iter.next().unwrap().take_internal().unwrap();
826
827        assert_eq!(type_ssl_cn.get_type(), PP2Tlvs::TYPE_SUBTYPE_SSL_CN);
828
829        let PP2Tlvs::TypeSubtypeSslCn(ssl_cn) = type_ssl_cn else { panic!("wrong") };
830
831        assert_eq!(ssl_cn, "mqttuser1");
832    }
833
834    #[test]
835    fn test_1()
836    {
837
838        #[derive(Clone, Debug)]
839        pub enum ProxyV2Dummy2 
840        {
841            SomeTlvName(u32, u32),
842            OtherTlv,
843        }
844
845        impl fmt::Display for ProxyV2Dummy2
846        {
847            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
848            {
849                write!(f, "DUMMY external reader")
850            }
851        }
852
853        impl PP2TlvRestore<'static> for ProxyV2Dummy2
854        {
855            type TlvTblRes = Self;
856
857            fn restore(tlv_type: u8, cur: &mut Cursor<&[u8]>) -> HaProxRes<Self> where Self: Sized 
858            {
859                match tlv_type
860                {
861                    0xE0 =>
862                    {
863                        let arg0 = cur.read_u32::<BigEndian>().map_err(common::map_io_err)?;
864                        let arg1 = cur.read_u32::<BigEndian>().map_err(common::map_io_err)?;
865
866                        return Ok(Self::SomeTlvName(arg0, arg1));
867                    },
868                    _ => 
869                        return_error!(ProtocolUnknownData, "unknown tlv_type: {}", tlv_type)
870                }
871                
872            }
873            
874            fn is_in_range(tlv_type: u8, _tlv_parent_type: Option<u8>) -> bool 
875            {
876                return tlv_type == PP2_TYPE_MIN_CUSTOM;
877            }
878            
879            fn contains_subtype(_item: &Self::TlvTblRes) -> bool 
880            {
881                return false;
882            }
883        }
884
885        impl PP2TlvDump for ProxyV2Dummy2
886        {
887            fn get_type(&self) -> u8 
888            {
889                let Self::SomeTlvName(..) = self else { panic!("wrong") };
890
891                return 0xE0;
892            }
893
894            fn dump(&self, _cur: &mut Cursor<Vec<u8>>) -> HaProxRes<()> 
895            {
896                todo!()
897            }
898        }
899
900        let pkt_ssl = 
901b"\x0d\x0a\x0d\x0a\x00\x0d\x0a\x51\x55\x49\x54\x0a\x21\x11\x00\x29\
902\x7f\x00\x00\x01\x7f\x00\x00\x43\x9b\x4a\x2e\x6b\x20\x00\x0f\x01\
903\x00\x00\x00\x00\x21\x00\x07\x54\x4c\x53\x76\x31\x2e\x32\xE0\x00\
904\x08\x01\x02\x03\x04\x05\x06\x07\x08";
905
906        let dec = ProxyV2Parser::<PPV2ParserZeroCopy, ProxyV2Dummy2>::try_from_slice_custom(pkt_ssl.as_slice()).unwrap();
907
908        assert_eq!(dec.get_transport().is_ok(), true);
909        assert_eq!(dec.get_transport().unwrap(), ProxyTransportFam::STREAM);
910
911        assert_eq!(dec.get_proto_version(), ProtocolVersion::V2);
912        assert_eq!(dec.get_proto_command(), HdrV2Command::PROXY);
913
914        assert_eq!(dec.get_address_family().is_ok(), true);
915        assert_eq!(dec.get_address_family().unwrap(), ProxyV2AddrType::AfInet);
916        
917        assert_eq!(dec.get_palyload_len() as usize, pkt_ssl.len() - size_of::<protocol_raw::ProxyHdrV2>());
918
919        let addr = dec.get_address().unwrap();
920
921        assert_eq!(addr.is_some(), true);
922
923        let addr = addr.unwrap();
924        let maddr = ProxyV2Addr::try_from(("127.0.0.1:39754", "127.0.0.67:11883")).unwrap();
925
926        assert_eq!(addr, maddr);
927
928        let tlv_iter = dec.get_tlvs_iter();
929
930        assert_eq!(tlv_iter.is_some(), true);
931
932        let mut tlv_iter = tlv_iter.unwrap();
933
934        let type_ssl = tlv_iter.next().unwrap().take_internal().unwrap();
935
936        assert_eq!(type_ssl.get_type(), PP2Tlvs::TYPE_SSL);
937        let PP2Tlvs::TypeSsl { client, verify } = type_ssl else {panic!("wrong")};
938
939        assert_eq!(client, PP2TlvClient::PP2_CLIENT_SSL);
940        assert_eq!(verify, 0);
941
942        // --
943        let type_ssl_version = tlv_iter.next().unwrap().take_internal().unwrap();
944
945        assert_eq!(type_ssl_version.get_type(), PP2Tlvs::TYPE_SUBTYPE_SSL_VERSION);
946
947        let PP2Tlvs::TypeSubtypeSslVersion(ssl_version) = type_ssl_version else { panic!("wrong") };
948
949        assert_eq!(ssl_version, "TLSv1.2");
950
951        // ---
952        let ext_type_e0 = tlv_iter.next().unwrap().take_external().unwrap();
953
954        assert_eq!(ext_type_e0.get_type(), 0xE0);
955
956        let ProxyV2Dummy2::SomeTlvName(arg0, arg1) = ext_type_e0 else {panic!("wrong")};
957
958        assert_eq!(arg0, 0x01020304);
959        assert_eq!(arg1, 0x05060708);
960
961
962    }
963
964    #[test]
965    fn test_3()
966    {
967        let pkt_ssl = 
968b"\x0d\x0a\x0d\x0a\x00\x0d\x0a\x51\x55\x49\x54\x0a\x21\x11\x00\x0c\
969\x7f\x00\x00\x01\x7f\x00\x00\x01\x8c\x76\x00\x50";
970
971
972        let dec = ProxyV2Parser::try_from_slice(pkt_ssl.as_slice()).unwrap();
973
974        assert_eq!(dec.get_transport().is_ok(), true);
975        assert_eq!(dec.get_transport().unwrap(), ProxyTransportFam::STREAM);
976
977        assert_eq!(dec.get_proto_version(), ProtocolVersion::V2);
978        assert_eq!(dec.get_proto_command(), HdrV2Command::PROXY);
979
980        assert_eq!(dec.get_address_family().is_ok(), true);
981        assert_eq!(dec.get_address_family().unwrap(), ProxyV2AddrType::AfInet);
982
983        assert_eq!(dec.get_palyload_len() as usize, pkt_ssl.len() - size_of::<protocol_raw::ProxyHdrV2>());
984        
985        let addr = dec.get_address().unwrap();
986
987        assert_eq!(addr.is_some(), true);
988
989        let addr = addr.unwrap();
990        let maddr = ProxyV2Addr::try_from(("127.0.0.1:35958", "127.0.0.1:80")).unwrap();
991
992        assert_eq!(addr, maddr);
993
994        let tlv_iter = dec.get_tlvs_iter();
995
996        assert_eq!(tlv_iter.is_some(), false);
997
998    }
999
1000}