1use std::{borrow::Cow, io::{Cursor, Write}, marker::PhantomData, mem::offset_of};
14
15use byteorder::{BigEndian, WriteBytesExt};
16use crc32fast::Hasher;
17
18use crate::{common, error::{HaProxErr, HaProxRes}, return_error};
19
20use super::{protocol::{self, HdrV2Command, PP2TlvClient, PP2Tlvs, ProxyTransportFam, ProxyV2Addr}, protocol_raw, PP2TlvDump, PP2TlvUniqId, ProxyV2OpCode};
21
22
23
24#[derive(Clone, Debug)]
32pub struct HdrV2OpLocal;
33
34#[derive(Clone, Debug)]
39pub struct HdrV2OpProxy;
40
41impl ProxyV2OpCode for HdrV2OpLocal
42{
43 const OPCODE: u8 = HdrV2Command::LOCAL as u8;
45}
46
47impl ProxyV2OpCode for HdrV2OpProxy
48{
49 const OPCODE: u8 = HdrV2Command::PROXY as u8;
51}
52
53#[derive(Debug)]
55pub struct TlvSubTypeSsl<'s>
56{
57 start: u64,
59
60 hdr: TlType<'s>,
62
63 constraints: &'static [std::ops::RangeInclusive<u8>]
65}
66
67impl<'s> TlvSubTypeSsl<'s>
68{
69 fn new(mut main_tp: TlType<'s>, constraints: &'static [std::ops::RangeInclusive<u8>],
70 client: PP2TlvClient, verify: u32) -> HaProxRes<Self>
71 {
72 let start = main_tp.hdr.buffer.position();
73
74 main_tp.add_tlv(PP2Tlvs::TypeSsl{client, verify}, None)?;
75
76 return Ok(
77 Self
78 {
79 start: start,
80 hdr: main_tp,
81 constraints: constraints
82 }
83 );
84 }
85
86 #[inline]
87 fn done_int(&mut self) -> HaProxRes<()>
88 {
89 let cur_pos = self.hdr.hdr.buffer.position();
90
91 self.hdr.hdr.buffer.set_position(self.start + offset_of!(protocol_raw::PP2Tlv, length_hi) as u64);self.hdr.hdr.buffer.write_u16::<BigEndian>((cur_pos - self.start - 3) as u16).map_err(common::map_io_err)?;
94
95 self.hdr.hdr.buffer.set_position(cur_pos);
96
97 return Ok(());
98 }
99
100 #[inline]
108 pub
109 fn done(mut self) -> HaProxRes<TlType<'s>>
110 {
111 self.done_int()?;
112
113
114 return Ok(self.hdr);
115 }
116
117 pub
119 fn add_ssl_sub_version(&mut self, ver: impl Into<String>) -> HaProxRes<()>
120 {
121 return self.hdr.add_tlv(PP2Tlvs::TypeSubtypeSslVersion(Cow::Owned(ver.into())), Some(self.constraints));
122 }
123
124 pub
126 fn add_ssl_sub_cn(&mut self, cn: impl Into<String>) -> HaProxRes<()>
127 {
128 return self.hdr.add_tlv(PP2Tlvs::TypeSubtypeSslCn(Cow::Owned(cn.into())), Some(self.constraints));
129 }
130
131 pub
133 fn add_ssl_sub_cipher(&mut self, ver: impl Into<String>) -> HaProxRes<()>
134 {
135 return self.hdr.add_tlv(PP2Tlvs::TypeSubtypeSslCipher(Cow::Owned(ver.into())), Some(self.constraints));
136 }
137
138 pub
140 fn add_ssl_sub_sigalg(&mut self, ver: impl Into<String>) -> HaProxRes<()>
141 {
142 return self.hdr.add_tlv(PP2Tlvs::TypeSubtypeSslSigAlg(Cow::Owned(ver.into())), Some(self.constraints));
143 }
144
145 pub
147 fn add_ssl_sub_keyalg(&mut self, ver: impl Into<String>) -> HaProxRes<()>
148 {
149 return self.hdr.add_tlv(PP2Tlvs::TypeSubtypeSslKeyAlg(Cow::Owned(ver.into())), Some(self.constraints));
150 }
151
152 pub
154 fn add_ssl_sub_netns(&mut self, ver: impl Into<String>) -> HaProxRes<()>
155 {
156 return self.hdr.add_tlv(PP2Tlvs::TypeNetNs(ver.into()), Some(self.constraints));
157 }
158}
159
160#[derive(Debug)]
162pub struct TlType<'s>
163{
164 hdr: &'s mut ProxyHdrV2<HdrV2OpProxy>,
166
167 constraints: &'static [std::ops::RangeInclusive<u8>]
169}
170
171impl<'s> TlType<'s>
172{
173 fn new(hdr: &'s mut ProxyHdrV2<HdrV2OpProxy>, constraints: &'static [std::ops::RangeInclusive<u8>]) -> Self
174 {
175 return
176 Self
177 {
178 hdr,
179 constraints
180 };
181 }
182
183 pub
185 fn add_alpn<'a>(&mut self, alpns: impl Iterator<Item = &'a [u8]>) -> HaProxRes<()>
186 {
187 return self.add_tlv(PP2Tlvs::TypeAlpn( alpns.map(|v| v.to_vec()).collect()), None);
188 }
189
190 pub
192 fn add_noop(&mut self) -> HaProxRes<()>
193 {
194 return self.add_tlv(PP2Tlvs::TypeNoop, None);
195 }
196
197 pub
199 fn add_netns(&mut self, ns: impl Into<String>) -> HaProxRes<()>
200 {
201 return self.add_tlv(PP2Tlvs::TypeNetNs(ns.into()), None);
202 }
203
204 pub
208 fn add_crc32(&mut self) -> HaProxRes<()>
209 {
210 return self.add_tlv(PP2Tlvs::TypeCrc32c(0), None);
211 }
212
213 pub
215 fn add_uniq_id<ID: PP2TlvUniqId>(&mut self, au: ID) -> HaProxRes<()>
216 {
217 let uniq_id = au.into_bytes();
218
219 return self.add_tlv(PP2Tlvs::TypeUniqId(uniq_id), None);
220 }
221
222 pub
224 fn add_authority(&mut self, authority: impl Into<String>) -> HaProxRes<()>
225 {
226 return self.add_tlv(PP2Tlvs::TypeAuthority(authority.into()), None);
227 }
228
229 pub
233 fn add_ssl(self, client: PP2TlvClient, verify: u32) -> HaProxRes<TlvSubTypeSsl<'s>>
234 {
235 return TlvSubTypeSsl::new(self, PP2Tlvs::TLV_TYPE_SSL_SUB_RANGE, client, verify);
236 }
237
238 pub
240 fn add_tlv<TLV: PP2TlvDump>(&mut self, tlv: TLV,
241 opt_constr: Option<&'static [std::ops::RangeInclusive<u8>]>) -> HaProxRes<()>
242 {
243 let tlv_id: u8 = tlv.get_type();
244
245 let constr = opt_constr.unwrap_or(self.constraints);
246
247 if constr.iter().any(|idr| idr.contains(&tlv_id)) == false
248 {
249 return_error!(ArgumentEinval, "TLV: {} is subtype of other type or type!", tlv);
250 }
251
252 if tlv_id == PP2Tlvs::TypeCrc32c(0).into()
253 {
254 if self.hdr.crc_tlv_offset != 0
255 {
256 return_error!(ArgumentEinval, "diplicate PLT CRC!");
257 }
258
259 self.hdr.crc_tlv_offset = self.hdr.buffer.position();
260 }
261
262 self.hdr.buffer.write_u8(tlv_id).map_err(common::map_io_err)?;
264
265 let size_pos = self.hdr.buffer.position();
267
268 self.hdr.buffer.write_u16::<BigEndian>(0).map_err(common::map_io_err)?;
270
271 tlv.dump(&mut self.hdr.buffer)?;
273
274 let cur_pos = self.hdr.buffer.position();
276 self.hdr.buffer.set_position(size_pos);
277
278 self.hdr.buffer.write_u16::<BigEndian>((cur_pos - size_pos - 2) as u16).map_err(common::map_io_err)?;
280
281 self.hdr.buffer.set_position(cur_pos);
283
284 return Ok(());
285 }
286}
287
288#[derive(Clone, Debug)]
305pub struct ProxyHdrV2<OPC: ProxyV2OpCode>
306{
307 buffer: Cursor<Vec<u8>>,
309
310 crc_tlv_offset: u64,
312
313 _p: PhantomData<OPC>,
315}
316
317impl<OPC: ProxyV2OpCode> ProxyHdrV2<OPC>
318{
319 pub const HDR_MSG_LEN_OFFSET: u64 = offset_of!(protocol_raw::ProxyHdrV2, len) as u64;
321}
322
323impl ProxyHdrV2<HdrV2OpLocal>
325{
326 pub
328 fn new() -> Vec<u8>
329 {
330 return protocol_raw::MSG_HEADER_LOCAL_V2.to_vec();
331 }
332}
333
334impl ProxyHdrV2<HdrV2OpProxy>
336{
337 pub
355 fn new(transport: ProxyTransportFam, address: ProxyV2Addr) -> HaProxRes<Self>
356 {
357 let buf: Vec<u8> =
358 Vec::with_capacity(size_of::<protocol_raw::ProxyHdrV2>());
359
360 let mut cur = Cursor::new(buf);
361 cur.write_all(protocol_raw::HEADER_MAGIC_V2).map_err(common::map_io_err)?;
365
366 cur.write_u8(0x20 | HdrV2OpProxy::OPCODE).map_err(common::map_io_err)?;
368
369 cur.write_u8(((address.as_addr_family() as u8) << 4) | transport as u8).map_err(common::map_io_err)?;
371
372 cur.write_u16::<BigEndian>(address.get_len()).map_err(common::map_io_err)?;
374
375 address.write(&mut cur)?;
377
378 return Ok(
379 Self
380 {
381 buffer: cur,
382 crc_tlv_offset: 0,
383 _p: PhantomData
384 }
385 );
386 }
387
388 pub
390 fn set_plts<'s>(&'s mut self) -> TlType<'s>
391 {
392 return TlType::new(self, PP2Tlvs::TLV_TYPE_MAIN_RANGES);
393 }
394
395 fn finalize(&mut self) -> HaProxRes<()>
396 {
397 let last_off = self.buffer.position();
398
399 self.buffer.set_position(Self::HDR_MSG_LEN_OFFSET);
401
402 let tlv_len = last_off - size_of::<protocol_raw::ProxyHdrV2>() as u64;
403
404 self.buffer.write_u16::<BigEndian>(tlv_len as u16).map_err(common::map_io_err)?;
405
406 if self.crc_tlv_offset > 0
407 {
408 let mut hasher = Hasher::new();
410
411 hasher.update(self.buffer.get_ref());
413
414 self.buffer.set_position(self.crc_tlv_offset + protocol::TLV_HEADER_LEN as u64);
416
417 self.buffer.write_u32::<BigEndian>(hasher.finalize()).map_err(common::map_io_err)?;
419 }
420 return Ok(());
421 }
422
423
424}
425
426impl TryFrom<ProxyHdrV2<HdrV2OpProxy>> for Vec<u8>
429{
430 type Error = HaProxErr;
431
432 fn try_from(mut value: ProxyHdrV2<HdrV2OpProxy>) -> Result<Self, Self::Error>
433 {
434 value.finalize()?;
435
436 return Ok(value.buffer.into_inner());
437 }
438}
439
440impl PP2TlvDump for PP2Tlvs
441{
442 fn get_type(&self) -> u8
443 {
444 return self.into();
445 }
446
447 fn dump(&self, cur: &mut Cursor<Vec<u8>>) -> HaProxRes<()>
448 {
449 match self
450 {
451 PP2Tlvs::TypeAlpn(items) =>
452 {
453 for alpn in items.iter(){
456 cur.write_u16::<BigEndian>(alpn.len() as u16).map_err(common::map_io_err)?;
458
459 cur.write_all(alpn).map_err(common::map_io_err)?;
461 }
462 },
463 PP2Tlvs::TypeAuthority(auth) =>
464 {
465 cur.write_all(auth.as_bytes()).map_err(common::map_io_err)?;
467 },
468 PP2Tlvs::TypeCrc32c(crc) =>
469 {
470 cur.write_u32::<BigEndian>(*crc).map_err(common::map_io_err)?;
471 },
472 PP2Tlvs::TypeNoop =>
473 {
474
475 },
476 PP2Tlvs::TypeUniqId(items) =>
477 {
478 cur.write_all(items.as_slice()).map_err(common::map_io_err)?;
479 },
480 PP2Tlvs::TypeSsl{client, verify} =>
481 {
482 cur.write_u8(client.bits()).map_err(common::map_io_err)?;
484
485 cur.write_u32::<BigEndian>(*verify).map_err(common::map_io_err)?;
487 },
488 PP2Tlvs::TypeSubtypeSslVersion(v) =>
489 {
490 cur.write_all(v.as_bytes()).map_err(common::map_io_err)?;
491 },
492 PP2Tlvs::TypeSubtypeSslCn(cn) =>
493 {
494 cur.write_all(cn.as_bytes()).map_err(common::map_io_err)?;
495 },
496 PP2Tlvs::TypeSubtypeSslCipher(c) =>
497 {
498 cur.write_all(c.as_bytes()).map_err(common::map_io_err)?;
499 },
500 PP2Tlvs::TypeSubtypeSslSigAlg(sa) =>
501 {
502 cur.write_all(sa.as_bytes()).map_err(common::map_io_err)?;
503 },
504 PP2Tlvs::TypeSubtypeSslKeyAlg(ka) =>
505 {
506 cur.write_all(ka.as_bytes()).map_err(common::map_io_err)?;
507 },
508 PP2Tlvs::TypeNetNs(ns) =>
509 {
510 cur.write_all(ns.as_bytes()).map_err(common::map_io_err)?;
511 },
512 }
513
514 return Ok(());
515 }
516}
517
518#[cfg(test)]
519mod tests
520{
521 use std::{fmt, io::Cursor};
522
523 use byteorder::{BigEndian, WriteBytesExt};
524
525 use crate::{common::map_io_err, protocol::{protocol::{PP2TlvClient, PP2Tlvs}, PP2TlvDump}, HaProxRes, ProxyTransportFam, ProxyV2Addr};
526
527 use super::{HdrV2OpProxy, ProxyHdrV2};
528
529 #[test]
530 fn test_comp0()
531 {
532 let addr = ProxyV2Addr::try_from(("127.0.0.1:39754", "127.0.0.67:11883")).unwrap();
533
534 let mut comp =
535 ProxyHdrV2::<HdrV2OpProxy>::new(ProxyTransportFam::STREAM, addr).unwrap();
536
537 let plts = comp.set_plts();
538
539 let mut ssl = plts.add_ssl(PP2TlvClient::PP2_CLIENT_SSL, 0).unwrap();
540
541 ssl.add_ssl_sub_version("TLSv1.2").unwrap();
542
543 ssl.done().unwrap();
544
545 let pkt: Vec<u8> = comp.try_into().unwrap();
546
547 let ctrl =
548b"\x0d\x0a\x0d\x0a\x00\x0d\x0a\x51\x55\x49\x54\x0a\x21\x11\x00\x1e\
549\x7f\x00\x00\x01\x7f\x00\x00\x43\x9b\x4a\x2e\x6b\x20\x00\x0f\x01\
550\x00\x00\x00\x00\x21\x00\x07\x54\x4c\x53\x76\x31\x2e\x32";
551
552 assert_eq!(pkt.as_slice(), ctrl.as_slice());
553 }
554
555 #[test]
556 fn test_comp1()
557 {
558 #[derive(Clone, Debug)]
559 pub enum ProxyV2Dummy2
560 {
561 SomeTlvName(u32, u32),
562 }
563
564 impl fmt::Display for ProxyV2Dummy2
565 {
566 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
567 {
568 write!(f, "DUMMY external reader")
569 }
570 }
571
572 impl PP2TlvDump for ProxyV2Dummy2
573 {
574 fn get_type(&self) -> u8
575 {
576 let Self::SomeTlvName(..) = self else { panic!("wrong") };
577
578 return 0xE0;
579 }
580
581 fn dump(&self, cur: &mut Cursor<Vec<u8>>) -> HaProxRes<()>
582 {
583 match self
584 {
585 Self::SomeTlvName(arg0, arg1) =>
586 {
587 cur.write_u32::<BigEndian>(*arg0).map_err(map_io_err)?;
588 cur.write_u32::<BigEndian>(*arg1).map_err(map_io_err)?;
589 }
590 }
591
592 return Ok(());
593 }
594 }
595
596
597
598 let addr = ProxyV2Addr::try_from(("127.0.0.1:39754", "127.0.0.67:11883")).unwrap();
599
600 let mut comp =
601 ProxyHdrV2::<HdrV2OpProxy>::new(ProxyTransportFam::STREAM, addr).unwrap();
602
603 let plts = comp.set_plts();
604
605 let mut ssl = plts.add_ssl(PP2TlvClient::PP2_CLIENT_SSL, 0).unwrap();
606
607 ssl.add_ssl_sub_version("TLSv1.2").unwrap();
608
609 let mut plts = ssl.done().unwrap();
610
611
612 let cust_plt = ProxyV2Dummy2::SomeTlvName(0x01020304, 0x05060708);
613
614 plts.add_tlv(cust_plt, Some(&[0xE0..=0xE0])).unwrap();
615
616 drop(plts);
617
618 let pkt: Vec<u8> = comp.try_into().unwrap();
619
620 let ctrl =
621b"\x0d\x0a\x0d\x0a\x00\x0d\x0a\x51\x55\x49\x54\x0a\x21\x11\x00\x29\
622\x7f\x00\x00\x01\x7f\x00\x00\x43\x9b\x4a\x2e\x6b\x20\x00\x0f\x01\
623\x00\x00\x00\x00\x21\x00\x07\x54\x4c\x53\x76\x31\x2e\x32\xE0\x00\
624\x08\x01\x02\x03\x04\x05\x06\x07\x08";
625
626 assert_eq!(pkt.as_slice(), ctrl.as_slice());
627 }
628
629 #[test]
630 fn test_alpns()
631 {
632 let mut cur = Cursor::new(Vec::<u8>::with_capacity(64));
633
634 let alpn = PP2Tlvs::TypeAlpn(vec![b"test".as_slice().to_vec()]);
635
636 alpn.dump(&mut cur).unwrap();
637
638 let reference = b"\x00\x04test";
641
642 let generated = cur.into_inner();
643
644 assert_eq!(generated.as_slice(), reference.as_slice());
645 }
646
647 #[test]
648 fn test_authority()
649 {
650 let mut cur = Cursor::new(Vec::<u8>::with_capacity(64));
651
652 let alpn = PP2Tlvs::TypeAuthority("tset".into());
653
654 alpn.dump(&mut cur).unwrap();
655
656 let reference = b"tset";
659
660 let generated = cur.into_inner();
661
662 assert_eq!(generated.as_slice(), reference.as_slice());
663 }
664
665 #[test]
666 fn test_crc32()
667 {
668 let mut cur = Cursor::new(Vec::<u8>::with_capacity(64));
669
670 let alpn = PP2Tlvs::TypeCrc32c(0xABCDEF01);
671
672 alpn.dump(&mut cur).unwrap();
673
674 let reference = b"\xab\xcd\xef\x01";
677
678 let generated = cur.into_inner();
679
680 assert_eq!(generated.as_slice(), reference.as_slice());
681 }
682
683 #[test]
684 fn test_netns()
685 {
686 let mut cur = Cursor::new(Vec::<u8>::with_capacity(64));
687
688 let alpn = PP2Tlvs::TypeNetNs("tstt".into());
689
690 alpn.dump(&mut cur).unwrap();
691
692 let reference = b"tstt";
695
696 let generated = cur.into_inner();
697
698 assert_eq!(generated.as_slice(), reference.as_slice());
699 }
700
701 #[test]
702 fn test_noop()
703 {
704 let mut cur = Cursor::new(Vec::<u8>::with_capacity(64));
705
706 let alpn = PP2Tlvs::TypeNoop;
707
708 alpn.dump(&mut cur).unwrap();
709
710 let reference = b"";
711
712 let generated = cur.into_inner();
713
714 assert_eq!(generated.as_slice(), reference.as_slice());
715 }
716
717 #[test]
718 fn test_ssl()
719 {
720 let mut cur = Cursor::new(Vec::<u8>::with_capacity(64));
721
722 let alpn = PP2Tlvs::TypeSsl{ client: PP2TlvClient::PP2_CLIENT_SSL, verify: 0x00003210};
723
724 alpn.dump(&mut cur).unwrap();
725
726 let reference = b"\x01\x00\x00\x32\x10";
729
730 let generated = cur.into_inner();
731
732 assert_eq!(generated.as_slice(), reference.as_slice());
733 }
734
735 #[test]
736 fn test_uniqid()
737 {
738 const ID: &'static [u8] = b"ABCD12345678901234567890";
739
740 let mut cur = Cursor::new(Vec::<u8>::with_capacity(64));
741
742 let alpn = PP2Tlvs::TypeUniqId(ID.into());
743
744 alpn.dump(&mut cur).unwrap();
745
746 let reference = ID;
747
748 let generated = cur.into_inner();
749
750 assert_eq!(generated.as_slice(), reference);
751 }
752
753 #[test]
754 fn test_ssl_cipher()
755 {
756 let mut cur = Cursor::new(Vec::<u8>::with_capacity(64));
757
758 let ciph = PP2Tlvs::TypeSubtypeSslCipher("ECDHE-RSA-AES128-GCM-SHA256".into());
759
760 ciph.dump(&mut cur).unwrap();
761
762 let reference = b"ECDHE-RSA-AES128-GCM-SHA256";
765
766 let generated = cur.into_inner();
767
768 assert_eq!(generated.as_slice(), reference.as_slice());
769 }
770
771 #[test]
772 fn test_ssl_cn()
773 {
774 let mut cur = Cursor::new(Vec::<u8>::with_capacity(64));
775
776 let cn = PP2Tlvs::TypeSubtypeSslCn("example.com".into());
777
778 cn.dump(&mut cur).unwrap();
779
780 let reference = b"example.com";
783
784 let generated = cur.into_inner();
785
786 assert_eq!(generated.as_slice(), reference.as_slice());
787 }
788
789 #[test]
790 fn test_ssl_keyalg()
791 {
792 let mut cur = Cursor::new(Vec::<u8>::with_capacity(64));
793
794 let keyalg = PP2Tlvs::TypeSubtypeSslKeyAlg("RSA2048".into());
795
796 keyalg.dump(&mut cur).unwrap();
797
798 let reference = b"RSA2048";
801
802 let generated = cur.into_inner();
803
804 assert_eq!(generated.as_slice(), reference.as_slice());
805 }
806
807 #[test]
808 fn test_ssl_sigalg()
809 {
810 let mut cur = Cursor::new(Vec::<u8>::with_capacity(64));
811
812 let sigalg = PP2Tlvs::TypeSubtypeSslSigAlg("SHA256".into());
813
814 sigalg.dump(&mut cur).unwrap();
815
816 let reference = b"SHA256";
819
820 let generated = cur.into_inner();
821
822 assert_eq!(generated.as_slice(), reference.as_slice());
823 }
824
825 #[test]
826 fn test_ssl_version()
827 {
828 let mut cur = Cursor::new(Vec::<u8>::with_capacity(64));
829
830 let vers = PP2Tlvs::TypeSubtypeSslVersion("TLSv1_3".into());
831
832 vers.dump(&mut cur).unwrap();
833
834 let reference = b"TLSv1_3";
837
838 let generated = cur.into_inner();
839
840 assert_eq!(generated.as_slice(), reference.as_slice());
841 }
842}