1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
10use std::str;
11
12use crate::crc32c::Crc32c;
13use crate::proxy::{ProxyError, ProxyFacts, ProxyVersions};
14
15const V1_PREFIX: &[u8] = b"PROXY ";
16const V1_MAX: usize = 107;
17const V2_SIGNATURE: [u8; 12] = [
18 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A,
19];
20const V2_FIXED: usize = 16;
21
22const TLV_ALPN: u8 = 0x01;
23const TLV_AUTHORITY: u8 = 0x02;
24const TLV_CRC32C: u8 = 0x03;
25const TLV_NOOP: u8 = 0x04;
26const TLV_UNIQUE_ID: u8 = 0x05;
27const TLV_SSL: u8 = 0x20;
28const SSL_VERSION: u8 = 0x21;
29const SSL_CN: u8 = 0x22;
30const SSL_CIPHER: u8 = 0x23;
31const SSL_SIG_ALG: u8 = 0x24;
32const SSL_KEY_ALG: u8 = 0x25;
33const TLV_NETNS: u8 = 0x30;
34const UNIQUE_ID_MAX: usize = 128;
35
36#[derive(Clone, Copy, Debug, PartialEq, Eq)]
38enum Kind {
39 Undecided,
40 V1,
41 V2,
42}
43
44#[derive(Clone, Debug)]
62pub struct ProxyParser {
63 versions: ProxyVersions,
64 v2_body_max: u16,
65 kind: Kind,
66 scanned: usize,
68}
69
70#[derive(Debug)]
72pub enum ProxyProgress<'a> {
73 NeedMore {
75 at_least: usize,
77 },
78 Done {
80 header: ProxyHeader<'a>,
82 consumed: usize,
84 },
85}
86
87#[non_exhaustive]
89#[derive(Clone, Copy, Debug)]
90pub struct ProxyHeader<'a> {
91 pub version: u8,
93 pub command: ProxyCommand,
96 pub transport: ProxyTransport,
98 pub source: Option<ProxyAddress<'a>>,
100 pub destination: Option<ProxyAddress<'a>>,
102 pub tlvs: Tlvs<'a>,
104 crc_checked: bool,
105}
106
107#[non_exhaustive]
109#[derive(Clone, Copy, Debug, PartialEq, Eq)]
110pub enum ProxyCommand {
111 Proxy,
113 Local,
115}
116
117#[non_exhaustive]
119#[derive(Clone, Copy, Debug, PartialEq, Eq)]
120pub enum ProxyTransport {
121 Stream,
123 Datagram,
125 Unspecified,
127}
128
129#[non_exhaustive]
131#[derive(Clone, Copy, Debug, PartialEq, Eq)]
132pub enum ProxyAddress<'a> {
133 Ip(SocketAddr),
135 Unix(&'a [u8]),
137}
138
139impl ProxyAddress<'_> {
140 #[must_use]
142 pub fn socket_addr(&self) -> Option<SocketAddr> {
143 match self {
144 ProxyAddress::Ip(a) => Some(*a),
145 ProxyAddress::Unix(_) => None,
146 }
147 }
148}
149
150impl std::fmt::Display for ProxyAddress<'_> {
151 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152 match self {
153 ProxyAddress::Ip(a) => write!(f, "{a}"),
154 ProxyAddress::Unix(p) => write!(f, "{}", String::from_utf8_lossy(p)),
155 }
156 }
157}
158
159#[derive(Clone, Copy, Debug, PartialEq, Eq)]
161pub struct Tlv<'a> {
162 pub kind: u8,
164 pub value: &'a [u8],
166}
167
168#[derive(Clone, Copy, Debug)]
170pub struct Tlvs<'a> {
171 rest: &'a [u8],
172}
173
174impl<'a> Iterator for Tlvs<'a> {
175 type Item = Tlv<'a>;
176
177 fn next(&mut self) -> Option<Tlv<'a>> {
178 loop {
179 let (tlv, rest) = split_tlv(self.rest)?;
180 self.rest = rest;
181 if tlv.kind != TLV_NOOP {
182 return Some(tlv);
183 }
184 }
185 }
186}
187
188#[non_exhaustive]
190#[derive(Clone, Copy, Debug)]
191pub struct ProxySsl<'a> {
192 pub client: u8,
195 pub verified: bool,
197 pub version: Option<&'a str>,
199 pub common_name: Option<&'a str>,
201 pub cipher: Option<&'a str>,
203 pub signature_algorithm: Option<&'a str>,
205 pub key_algorithm: Option<&'a str>,
207}
208
209impl<'a> ProxyHeader<'a> {
210 fn find(&self, kind: u8) -> Option<&'a [u8]> {
211 let mut tlvs = self.tlvs;
212 tlvs.find(|t| t.kind == kind).map(|t| t.value)
213 }
214
215 #[must_use]
217 pub fn alpn(&self) -> Option<&'a [u8]> {
218 self.find(TLV_ALPN)
219 }
220
221 #[must_use]
223 pub fn authority(&self) -> Option<&'a str> {
224 self.find(TLV_AUTHORITY)
225 .and_then(|v| str::from_utf8(v).ok())
226 }
227
228 #[must_use]
230 pub fn unique_id(&self) -> Option<&'a [u8]> {
231 self.find(TLV_UNIQUE_ID)
232 }
233
234 #[must_use]
236 pub fn ssl(&self) -> Option<ProxySsl<'a>> {
237 let v = self.find(TLV_SSL)?;
238 let client = v[0];
239 let verify = u32::from_be_bytes([v[1], v[2], v[3], v[4]]);
240 let mut ssl = ProxySsl {
241 client,
242 verified: verify == 0,
243 version: None,
244 common_name: None,
245 cipher: None,
246 signature_algorithm: None,
247 key_algorithm: None,
248 };
249 let mut rest = &v[5..];
250 while let Some((sub, more)) = split_tlv(rest) {
251 let text = str::from_utf8(sub.value).ok();
252 match sub.kind {
253 SSL_VERSION => ssl.version = text,
254 SSL_CN => ssl.common_name = text,
255 SSL_CIPHER => ssl.cipher = text,
256 SSL_SIG_ALG => ssl.signature_algorithm = text,
257 SSL_KEY_ALG => ssl.key_algorithm = text,
258 _ => {}
259 }
260 rest = more;
261 }
262 Some(ssl)
263 }
264
265 #[must_use]
267 pub fn network_namespace(&self) -> Option<&'a [u8]> {
268 self.find(TLV_NETNS)
269 }
270
271 #[must_use]
273 pub fn crc_checked(&self) -> bool {
274 self.crc_checked
275 }
276
277 #[must_use]
280 pub fn to_facts(&self) -> ProxyFacts {
281 ProxyFacts::from_parts(
282 self.alpn(),
283 self.authority(),
284 self.unique_id(),
285 self.ssl().map(|s| s.client),
286 )
287 }
288}
289
290impl ProxyParser {
291 #[must_use]
294 pub fn new(versions: ProxyVersions, v2_body_max: u16) -> ProxyParser {
295 ProxyParser {
296 versions,
297 v2_body_max,
298 kind: Kind::Undecided,
299 scanned: 0,
300 }
301 }
302
303 pub fn feed<'a>(&mut self, input: &'a [u8]) -> Result<ProxyProgress<'a>, ProxyError> {
309 if self.kind == Kind::Undecided {
310 let Some(&first) = input.first() else {
311 return Ok(ProxyProgress::NeedMore { at_least: 1 });
312 };
313 let v1 = matches!(self.versions, ProxyVersions::V1 | ProxyVersions::Both);
314 let v2 = matches!(self.versions, ProxyVersions::V2 | ProxyVersions::Both);
315 self.kind = match first {
316 b'P' if v1 => Kind::V1,
317 0x0D if v2 => Kind::V2,
318 _ => return Err(ProxyError::NotProxy),
319 };
320 }
321 match self.kind {
322 Kind::V1 => self.feed_v1(input),
323 _ => self.feed_v2(input),
324 }
325 }
326
327 fn feed_v1<'a>(&mut self, input: &'a [u8]) -> Result<ProxyProgress<'a>, ProxyError> {
328 let n = input.len().min(V1_PREFIX.len());
329 if input[..n] != V1_PREFIX[..n] {
330 return Err(ProxyError::NotProxy);
331 }
332 let limit = input.len().min(V1_MAX);
333 let start = self.scanned.min(limit);
334 let Some(lf) = input[start..limit].iter().position(|&b| b == b'\n') else {
335 if input.len() >= V1_MAX {
336 return Err(ProxyError::V1TooLong);
337 }
338 self.scanned = limit;
339 return Ok(ProxyProgress::NeedMore { at_least: 1 });
340 };
341 let lf = start + lf;
342 if lf == 0 || input[lf - 1] != b'\r' {
343 return Err(ProxyError::V1Syntax { at: offset(lf) });
344 }
345 let header = parse_v1_line(&input[..lf - 1])?;
346 Ok(ProxyProgress::Done {
347 header,
348 consumed: lf + 1,
349 })
350 }
351
352 fn feed_v2<'a>(&mut self, input: &'a [u8]) -> Result<ProxyProgress<'a>, ProxyError> {
353 let n = input.len().min(V2_SIGNATURE.len());
354 if input[..n] != V2_SIGNATURE[..n] {
355 return Err(ProxyError::NotProxy);
356 }
357 if input.len() < V2_FIXED {
358 return Ok(ProxyProgress::NeedMore {
359 at_least: V2_FIXED - input.len(),
360 });
361 }
362 let version = input[12] >> 4;
363 if version != 2 {
364 return Err(ProxyError::V2BadVersion);
365 }
366 let command = match input[12] & 0x0F {
367 0x0 => ProxyCommand::Local,
368 0x1 => ProxyCommand::Proxy,
369 _ => return Err(ProxyError::V2BadCommand),
370 };
371 let family = input[13];
372 let (address_len, transport) = match family {
373 0x00 => (0, ProxyTransport::Unspecified),
374 0x11 => (12, ProxyTransport::Stream),
375 0x12 => (12, ProxyTransport::Datagram),
376 0x21 => (36, ProxyTransport::Stream),
377 0x22 => (36, ProxyTransport::Datagram),
378 0x31 => (216, ProxyTransport::Stream),
379 0x32 => (216, ProxyTransport::Datagram),
380 _ => return Err(ProxyError::V2BadFamily),
381 };
382 let declared = u16::from_be_bytes([input[14], input[15]]);
383 if declared > self.v2_body_max {
384 return Err(ProxyError::V2LengthTooLarge {
385 declared,
386 max: self.v2_body_max,
387 });
388 }
389 let total = V2_FIXED + usize::from(declared);
390 if input.len() < total {
391 return Ok(ProxyProgress::NeedMore {
392 at_least: total - input.len(),
393 });
394 }
395 let header = &input[..total];
396 let body = &header[V2_FIXED..];
397 if body.len() < address_len {
398 return Err(ProxyError::V2AddressTooShort);
399 }
400 let (source, destination) = if command == ProxyCommand::Proxy {
401 v2_addresses(family >> 4, &body[..address_len])
402 } else {
403 (None, None)
404 };
405 let tlv_bytes = &body[address_len..];
406 let crc_checked = check_tlvs(header, V2_FIXED + address_len)?;
407 Ok(ProxyProgress::Done {
408 header: ProxyHeader {
409 version: 2,
410 command,
411 transport,
412 source,
413 destination,
414 tlvs: Tlvs { rest: tlv_bytes },
415 crc_checked,
416 },
417 consumed: total,
418 })
419 }
420}
421
422fn offset(at: usize) -> u8 {
424 u8::try_from(at).unwrap_or(u8::MAX)
425}
426
427fn split_tlv(bytes: &[u8]) -> Option<(Tlv<'_>, &[u8])> {
429 if bytes.len() < 3 {
430 return None;
431 }
432 let len = usize::from(u16::from_be_bytes([bytes[1], bytes[2]]));
433 let value = bytes.get(3..3 + len)?;
434 Some((
435 Tlv {
436 kind: bytes[0],
437 value,
438 },
439 &bytes[3 + len..],
440 ))
441}
442
443fn check_tlvs(header: &[u8], start: usize) -> Result<bool, ProxyError> {
447 let mut pos = start;
448 let mut crc_checked = false;
449 while pos < header.len() {
450 let rest = &header[pos..];
451 let Some((tlv, _)) = split_tlv(rest) else {
452 return Err(ProxyError::V2TlvOverrun);
453 };
454 let value_at = pos + 3;
455 match tlv.kind {
456 TLV_CRC32C => {
457 if tlv.value.len() != 4 {
458 return Err(ProxyError::V2CrcMismatch);
459 }
460 let expected =
461 u32::from_be_bytes([tlv.value[0], tlv.value[1], tlv.value[2], tlv.value[3]]);
462 let mut c = Crc32c::new();
463 c.update(&header[..value_at]);
464 c.update(&[0; 4]);
465 c.update(&header[value_at + 4..]);
466 if c.finish() != expected {
467 return Err(ProxyError::V2CrcMismatch);
468 }
469 crc_checked = true;
470 }
471 TLV_UNIQUE_ID if tlv.value.len() > UNIQUE_ID_MAX => {
472 return Err(ProxyError::V2UniqueIdTooLong);
473 }
474 TLV_SSL => check_ssl(tlv.value)?,
475 _ => {}
476 }
477 pos = value_at + tlv.value.len();
478 }
479 Ok(crc_checked)
480}
481
482fn check_ssl(value: &[u8]) -> Result<(), ProxyError> {
483 if value.len() < 5 {
484 return Err(ProxyError::V2SslMalformed);
485 }
486 let mut rest = &value[5..];
487 while !rest.is_empty() {
488 match split_tlv(rest) {
489 Some((_, more)) => rest = more,
490 None => return Err(ProxyError::V2SslMalformed),
491 }
492 }
493 Ok(())
494}
495
496fn v2_addresses(family: u8, block: &[u8]) -> (Option<ProxyAddress<'_>>, Option<ProxyAddress<'_>>) {
497 let port = |b: &[u8]| u16::from_be_bytes([b[0], b[1]]);
498 match family {
499 0x1 => {
500 let src = Ipv4Addr::new(block[0], block[1], block[2], block[3]);
501 let dst = Ipv4Addr::new(block[4], block[5], block[6], block[7]);
502 (
503 Some(ProxyAddress::Ip(SocketAddr::new(
504 IpAddr::V4(src),
505 port(&block[8..]),
506 ))),
507 Some(ProxyAddress::Ip(SocketAddr::new(
508 IpAddr::V4(dst),
509 port(&block[10..]),
510 ))),
511 )
512 }
513 0x2 => {
514 let mut s = [0u8; 16];
515 let mut d = [0u8; 16];
516 s.copy_from_slice(&block[..16]);
517 d.copy_from_slice(&block[16..32]);
518 (
519 Some(ProxyAddress::Ip(SocketAddr::new(
520 IpAddr::V6(Ipv6Addr::from(s)),
521 port(&block[32..]),
522 ))),
523 Some(ProxyAddress::Ip(SocketAddr::new(
524 IpAddr::V6(Ipv6Addr::from(d)),
525 port(&block[34..]),
526 ))),
527 )
528 }
529 0x3 => (
530 Some(ProxyAddress::Unix(trim_zeros(&block[..108]))),
531 Some(ProxyAddress::Unix(trim_zeros(&block[108..216]))),
532 ),
533 _ => (None, None),
534 }
535}
536
537fn trim_zeros(path: &[u8]) -> &[u8] {
538 let end = path.iter().rposition(|&b| b != 0).map_or(0, |i| i + 1);
539 &path[..end]
540}
541
542fn parse_v1_line(line: &[u8]) -> Result<ProxyHeader<'static>, ProxyError> {
544 let rest = &line[V1_PREFIX.len()..];
545 let base = V1_PREFIX.len();
546 let empty = Tlvs { rest: &[] };
547 if let Some(after) = rest.strip_prefix(b"UNKNOWN") {
548 if after.is_empty() || after[0] == b' ' {
550 return Ok(ProxyHeader {
551 version: 1,
552 command: ProxyCommand::Proxy,
553 transport: ProxyTransport::Unspecified,
554 source: None,
555 destination: None,
556 tlvs: empty,
557 crc_checked: false,
558 });
559 }
560 return Err(ProxyError::V1Syntax {
561 at: offset(base + 7),
562 });
563 }
564 let mut fields = [&[][..]; 5];
565 let mut count = 0;
566 let mut at = base;
567 for field in rest.split(|&b| b == b' ') {
568 if field.is_empty() || count == 5 {
569 return Err(ProxyError::V1Syntax { at: offset(at) });
570 }
571 fields[count] = field;
572 count += 1;
573 at += field.len() + 1;
574 }
575 if count != 5 {
576 return Err(ProxyError::V1Syntax {
577 at: offset(line.len()),
578 });
579 }
580 let v6 = match fields[0] {
581 b"TCP4" => false,
582 b"TCP6" => true,
583 _ => return Err(ProxyError::V1Syntax { at: offset(base) }),
584 };
585 let address = |text: &[u8]| -> Result<IpAddr, ProxyError> {
586 let mine = if v6 {
587 parse_ipv6(text).map(IpAddr::V6)
588 } else {
589 parse_ipv4(text).map(IpAddr::V4)
590 };
591 if let Some(ip) = mine {
592 return Ok(ip);
593 }
594 let other = if v6 {
596 parse_ipv4(text).is_some()
597 } else {
598 parse_ipv6(text).is_some()
599 };
600 Err(if other {
601 ProxyError::FamilyMismatch
602 } else {
603 ProxyError::V1BadAddress
604 })
605 };
606 let src = address(fields[1])?;
607 let dst = address(fields[2])?;
608 let sport = parse_port(fields[3]).ok_or(ProxyError::V1BadPort)?;
609 let dport = parse_port(fields[4]).ok_or(ProxyError::V1BadPort)?;
610 Ok(ProxyHeader {
611 version: 1,
612 command: ProxyCommand::Proxy,
613 transport: ProxyTransport::Stream,
614 source: Some(ProxyAddress::Ip(SocketAddr::new(src, sport))),
615 destination: Some(ProxyAddress::Ip(SocketAddr::new(dst, dport))),
616 tlvs: empty,
617 crc_checked: false,
618 })
619}
620
621fn parse_port(text: &[u8]) -> Option<u16> {
623 decimal(text, 5).and_then(|v| u16::try_from(v).ok())
624}
625
626fn decimal(text: &[u8], max_digits: usize) -> Option<u32> {
628 if text.is_empty() || text.len() > max_digits || (text.len() > 1 && text[0] == b'0') {
629 return None;
630 }
631 text.iter().try_fold(0u32, |acc, &b| {
632 b.is_ascii_digit().then(|| acc * 10 + u32::from(b - b'0'))
633 })
634}
635
636fn parse_ipv4(text: &[u8]) -> Option<Ipv4Addr> {
638 let mut octets = [0u8; 4];
639 let mut n = 0;
640 for part in text.split(|&b| b == b'.') {
641 if n == 4 {
642 return None;
643 }
644 octets[n] = u8::try_from(decimal(part, 3)?).ok()?;
645 n += 1;
646 }
647 (n == 4).then(|| Ipv4Addr::from(octets))
648}
649
650fn parse_ipv6(text: &[u8]) -> Option<Ipv6Addr> {
654 let (head, tail, compressed) = match find_double_colon(text) {
655 Some(i) => (&text[..i], &text[i + 2..], true),
656 None => (text, &[][..], false),
657 };
658 if compressed && find_double_colon(tail).is_some() {
659 return None;
660 }
661 let mut groups = [0u16; 8];
662 let front = groups_into(head, &mut groups, 0, !compressed)?;
664 if !compressed {
665 return (front == 8).then(|| Ipv6Addr::from(groups));
666 }
667 let mut back = [0u16; 8];
668 let n_back = groups_into(tail, &mut back, 0, true)?;
669 if front + n_back > 7 {
670 return None;
671 }
672 groups[8 - n_back..].copy_from_slice(&back[..n_back]);
673 Some(Ipv6Addr::from(groups))
674}
675
676fn find_double_colon(text: &[u8]) -> Option<usize> {
677 text.windows(2).position(|w| w == b"::")
678}
679
680fn groups_into(text: &[u8], out: &mut [u16; 8], mut at: usize, last: bool) -> Option<usize> {
684 if text.is_empty() {
685 return Some(at);
686 }
687 let mut parts = text.split(|&b| b == b':').peekable();
688 while let Some(part) = parts.next() {
689 let is_last = parts.peek().is_none();
690 if is_last && last && part.contains(&b'.') {
691 let v4 = parse_ipv4(part)?.octets();
692 if at + 2 > 8 {
693 return None;
694 }
695 out[at] = u16::from_be_bytes([v4[0], v4[1]]);
696 out[at + 1] = u16::from_be_bytes([v4[2], v4[3]]);
697 at += 2;
698 continue;
699 }
700 if part.is_empty() || part.len() > 4 || at >= 8 {
701 return None;
702 }
703 let mut v = 0u16;
704 for &b in part {
705 let d = (b as char).to_digit(16)?;
706 v = (v << 4) | u16::try_from(d).ok()?;
707 }
708 out[at] = v;
709 at += 1;
710 }
711 Some(at)
712}
713
714pub fn encode_v1(
732 source: SocketAddr,
733 destination: SocketAddr,
734 out: &mut [u8],
735) -> Result<usize, ProxyError> {
736 let family = match (source, destination) {
737 (SocketAddr::V4(_), SocketAddr::V4(_)) => "TCP4",
738 (SocketAddr::V6(_), SocketAddr::V6(_)) => "TCP6",
739 _ => return Err(ProxyError::FamilyMismatch),
740 };
741 let line = format!(
742 "PROXY {family} {} {} {} {}\r\n",
743 source.ip(),
744 destination.ip(),
745 source.port(),
746 destination.port()
747 );
748 let need = line.len();
749 let target = out
750 .get_mut(..need)
751 .ok_or(ProxyError::OutputTooSmall { need })?;
752 target.copy_from_slice(line.as_bytes());
753 Ok(need)
754}
755
756pub fn encode_v2(
778 command: ProxyCommand,
779 source: Option<SocketAddr>,
780 destination: Option<SocketAddr>,
781 tlvs: &[Tlv<'_>],
782 with_crc: bool,
783 out: &mut [u8],
784) -> Result<usize, ProxyError> {
785 const STREAM: u8 = 1;
786 let (family, address_len) = match (source, destination) {
787 (Some(SocketAddr::V4(_)), Some(SocketAddr::V4(_))) => (0x10 | STREAM, 12),
788 (Some(SocketAddr::V6(_)), Some(SocketAddr::V6(_))) => (0x20 | STREAM, 36),
789 (None, None) => (0, 0),
790 _ => return Err(ProxyError::FamilyMismatch),
791 };
792 let tlv_len: usize = tlvs.iter().map(|t| 3 + t.value.len()).sum();
793 let crc_len = if with_crc { 7 } else { 0 };
794 let body = address_len + tlv_len + crc_len;
795 let declared = u16::try_from(body).map_err(|_| ProxyError::V2LengthTooLarge {
796 declared: u16::MAX,
797 max: u16::MAX,
798 })?;
799 let need = V2_FIXED + body;
800 let frame = out
801 .get_mut(..need)
802 .ok_or(ProxyError::OutputTooSmall { need })?;
803 frame[..12].copy_from_slice(&V2_SIGNATURE);
804 frame[12] = match command {
805 ProxyCommand::Proxy => 0x21,
806 ProxyCommand::Local => 0x20,
807 };
808 frame[13] = family;
809 frame[14..16].copy_from_slice(&declared.to_be_bytes());
810 let mut at = V2_FIXED;
811 match (source, destination) {
812 (Some(SocketAddr::V4(s)), Some(SocketAddr::V4(d))) => {
813 frame[at..at + 4].copy_from_slice(&s.ip().octets());
814 frame[at + 4..at + 8].copy_from_slice(&d.ip().octets());
815 frame[at + 8..at + 10].copy_from_slice(&s.port().to_be_bytes());
816 frame[at + 10..at + 12].copy_from_slice(&d.port().to_be_bytes());
817 at += 12;
818 }
819 (Some(SocketAddr::V6(s)), Some(SocketAddr::V6(d))) => {
820 frame[at..at + 16].copy_from_slice(&s.ip().octets());
821 frame[at + 16..at + 32].copy_from_slice(&d.ip().octets());
822 frame[at + 32..at + 34].copy_from_slice(&s.port().to_be_bytes());
823 frame[at + 34..at + 36].copy_from_slice(&d.port().to_be_bytes());
824 at += 36;
825 }
826 _ => {}
827 }
828 for t in tlvs {
829 let len = t.value.len() as u16;
830 frame[at] = t.kind;
831 frame[at + 1..at + 3].copy_from_slice(&len.to_be_bytes());
832 frame[at + 3..at + 3 + t.value.len()].copy_from_slice(t.value);
833 at += 3 + t.value.len();
834 }
835 if with_crc {
836 frame[at] = TLV_CRC32C;
837 frame[at + 1..at + 3].copy_from_slice(&4u16.to_be_bytes());
838 frame[at + 3..at + 7].fill(0);
839 let mut crc = Crc32c::new();
840 crc.update(frame);
841 let value = crc.finish().to_be_bytes();
842 frame[at + 3..at + 7].copy_from_slice(&value);
843 }
844 Ok(need)
845}
846
847#[cfg(test)]
848mod tests {
849 use super::*;
850
851 fn done(p: &mut ProxyParser, bytes: &[u8]) -> (ProxyHeader<'static>, usize) {
852 let bytes: &'static [u8] = Box::leak(bytes.to_vec().into_boxed_slice());
853 match p.feed(bytes).unwrap() {
854 ProxyProgress::Done { header, consumed } => (header, consumed),
855 ProxyProgress::NeedMore { at_least } => panic!("need {at_least} more"),
856 }
857 }
858
859 fn v1(line: &str) -> Result<ProxyHeader<'static>, ProxyError> {
860 let bytes: &'static [u8] = Box::leak(line.as_bytes().to_vec().into_boxed_slice());
861 match ProxyParser::new(ProxyVersions::Both, 1024).feed(bytes)? {
862 ProxyProgress::Done { header, .. } => Ok(header),
863 ProxyProgress::NeedMore { .. } => panic!("incomplete: {line:?}"),
864 }
865 }
866
867 fn v2(command: u8, family: u8, block: &[u8], tlvs: &[(u8, &[u8])], crc: bool) -> Vec<u8> {
869 let mut body = block.to_vec();
870 for (kind, value) in tlvs {
871 body.push(*kind);
872 body.extend_from_slice(&u16::try_from(value.len()).unwrap().to_be_bytes());
873 body.extend_from_slice(value);
874 }
875 let crc_at = if crc {
876 body.extend_from_slice(&[TLV_CRC32C, 0, 4, 0, 0, 0, 0]);
877 Some(V2_FIXED + body.len() - 4)
878 } else {
879 None
880 };
881 let mut h = V2_SIGNATURE.to_vec();
882 h.push(0x20 | command);
883 h.push(family);
884 h.extend_from_slice(&u16::try_from(body.len()).unwrap().to_be_bytes());
885 h.extend_from_slice(&body);
886 if let Some(at) = crc_at {
887 let sum = crate::crc32c::crc32c(&h);
888 h[at..at + 4].copy_from_slice(&sum.to_be_bytes());
889 }
890 h
891 }
892
893 fn ipv4_block() -> Vec<u8> {
894 let mut b = vec![192, 0, 2, 1, 198, 51, 100, 2];
895 b.extend_from_slice(&51000u16.to_be_bytes());
896 b.extend_from_slice(&443u16.to_be_bytes());
897 b
898 }
899
900 #[test]
901 fn test_v1_tcp4_and_rest_is_data() {
902 let mut p = ProxyParser::new(ProxyVersions::Both, 1024);
903 let (h, consumed) = done(
904 &mut p,
905 b"PROXY TCP4 192.0.2.1 198.51.100.2 51000 443\r\nGET",
906 );
907 assert_eq!(h.version, 1);
908 assert_eq!(
909 h.source,
910 Some(ProxyAddress::Ip("192.0.2.1:51000".parse().unwrap()))
911 );
912 assert_eq!(
913 h.destination,
914 Some(ProxyAddress::Ip("198.51.100.2:443".parse().unwrap()))
915 );
916 assert_eq!(consumed, 45);
917 }
918
919 #[test]
920 fn test_v1_tcp6_unknown_and_mapped() {
921 let h = v1("PROXY TCP6 2001:db8::1 ::ffff:192.0.2.1 1 65535\r\n").unwrap();
922 assert_eq!(h.source.unwrap().to_string(), "[2001:db8::1]:1");
923 let h = v1("PROXY UNKNOWN\r\n").unwrap();
924 assert!(h.source.is_none());
925 let h = v1("PROXY UNKNOWN anything at all 1 2\r\n").unwrap();
926 assert_eq!(h.transport, ProxyTransport::Unspecified);
927 }
928
929 #[test]
930 fn test_v1_strict_grammar() {
931 use ProxyError::*;
932 let bad = [
933 ("PROXY TCP4 192.0.2.1 198.51.100.2 1 2\r\n", "double space"),
934 (
935 "PROXY TCP4 192.0.2.1 198.51.100.2 1 2 \r\n",
936 "trailing space",
937 ),
938 ("PROXY TCP4 192.0.2.1 198.51.100.2 1\r\n", "missing port"),
939 ("PROXY TCP5 192.0.2.1 198.51.100.2 1 2\r\n", "protocol"),
940 ("PROXY UNKNOWNX\r\n", "unknown suffix"),
941 ];
942 for (line, why) in bad {
943 assert!(
944 matches!(v1(line), Err(V1Syntax { .. })),
945 "{why}: {:?}",
946 v1(line)
947 );
948 }
949 assert_eq!(
950 v1("PROXY TCP4 192.0.2.01 198.51.100.2 1 2\r\n").unwrap_err(),
951 V1BadAddress
952 );
953 assert_eq!(
954 v1("PROXY TCP4 256.0.2.1 198.51.100.2 1 2\r\n").unwrap_err(),
955 V1BadAddress
956 );
957 assert_eq!(
958 v1("PROXY TCP4 192.0.2.1 198.51.100.2 01 2\r\n").unwrap_err(),
959 V1BadPort
960 );
961 assert_eq!(
962 v1("PROXY TCP4 192.0.2.1 198.51.100.2 +1 2\r\n").unwrap_err(),
963 V1BadPort
964 );
965 assert_eq!(
966 v1("PROXY TCP4 192.0.2.1 198.51.100.2 65536 2\r\n").unwrap_err(),
967 V1BadPort
968 );
969 assert_eq!(
970 v1("PROXY TCP4 2001:db8::1 198.51.100.2 1 2\r\n").unwrap_err(),
971 FamilyMismatch
972 );
973 assert_eq!(
974 v1("PROXY TCP6 192.0.2.1 ::1 1 2\r\n").unwrap_err(),
975 FamilyMismatch
976 );
977 assert!(matches!(
978 ProxyParser::new(ProxyVersions::Both, 1024).feed(b"PROXY TCP4 1.2.3.4 1.2.3.4 1 2\n"),
979 Err(V1Syntax { .. })
980 ));
981 }
982
983 #[test]
985 fn test_v1_too_long() {
986 let mut line = b"PROXY UNKNOWN ".to_vec();
987 line.resize(107, b'x');
988 let r = ProxyParser::new(ProxyVersions::V1, 1024).feed(&line);
989 assert_eq!(r.unwrap_err(), ProxyError::V1TooLong);
990 let mut ok = b"PROXY UNKNOWN ".to_vec();
991 ok.resize(105, b'x');
992 ok.extend_from_slice(b"\r\n");
993 assert!(matches!(
994 ProxyParser::new(ProxyVersions::V1, 1024).feed(&ok),
995 Ok(ProxyProgress::Done { consumed: 107, .. })
996 ));
997 }
998
999 #[test]
1000 fn test_not_proxy_and_version_filters() {
1001 let mut p = ProxyParser::new(ProxyVersions::Both, 1024);
1002 assert_eq!(p.feed(b"GET / HTTP/1.1").unwrap_err(), ProxyError::NotProxy);
1003 assert_eq!(
1004 ProxyParser::new(ProxyVersions::Both, 1024)
1005 .feed(b"PROXX")
1006 .unwrap_err(),
1007 ProxyError::NotProxy
1008 );
1009 let v2h = v2(1, 0x11, &ipv4_block(), &[], false);
1010 assert_eq!(
1011 ProxyParser::new(ProxyVersions::V1, 1024)
1012 .feed(&v2h)
1013 .unwrap_err(),
1014 ProxyError::NotProxy
1015 );
1016 assert_eq!(
1017 ProxyParser::new(ProxyVersions::V2, 1024)
1018 .feed(b"PROXY TCP4")
1019 .unwrap_err(),
1020 ProxyError::NotProxy
1021 );
1022 }
1023
1024 #[test]
1025 fn test_v2_ipv4_tlvs_and_crc() {
1026 let h = v2(
1027 1,
1028 0x11,
1029 &ipv4_block(),
1030 &[
1031 (TLV_ALPN, b"h2"),
1032 (TLV_NOOP, b"pad"),
1033 (TLV_AUTHORITY, b"example.com"),
1034 (TLV_UNIQUE_ID, b"id-1"),
1035 (
1036 TLV_SSL,
1037 &[
1038 0x07,
1039 0,
1040 0,
1041 0,
1042 0,
1043 SSL_VERSION,
1044 0,
1045 7,
1046 b'T',
1047 b'L',
1048 b'S',
1049 b'v',
1050 b'1',
1051 b'.',
1052 b'3',
1053 SSL_CN,
1054 0,
1055 3,
1056 b'b',
1057 b'o',
1058 b'b',
1059 ],
1060 ),
1061 (0xE0, b"custom"),
1062 ],
1063 true,
1064 );
1065 let mut p = ProxyParser::new(ProxyVersions::Both, 1024);
1066 let (header, consumed) = done(&mut p, &h);
1067 assert_eq!(consumed, h.len());
1068 assert_eq!(header.command, ProxyCommand::Proxy);
1069 assert_eq!(header.source.unwrap().to_string(), "192.0.2.1:51000");
1070 assert_eq!(header.alpn(), Some(&b"h2"[..]));
1071 assert_eq!(header.authority(), Some("example.com"));
1072 assert_eq!(header.unique_id(), Some(&b"id-1"[..]));
1073 assert!(header.crc_checked());
1074 let ssl = header.ssl().unwrap();
1075 assert_eq!(
1076 (ssl.client, ssl.verified, ssl.version, ssl.common_name),
1077 (7, true, Some("TLSv1.3"), Some("bob"))
1078 );
1079 assert!({ header.tlvs }.all(|t| t.kind != TLV_NOOP), "NOOP skipped");
1080 assert!({ header.tlvs }.any(|t| t.kind == 0xE0 && t.value == b"custom"));
1081 let facts = header.to_facts();
1082 assert_eq!(facts.alpn(), Some(&b"h2"[..]));
1083 assert_eq!(facts.authority(), Some("example.com"));
1084 assert_eq!(facts.ssl_client(), Some(7));
1085 }
1086
1087 #[test]
1088 fn test_v2_ipv6_unix_local_unspec() {
1089 let mut block = vec![0u8; 36];
1090 block[15] = 1;
1091 block[31] = 2;
1092 block[32..34].copy_from_slice(&80u16.to_be_bytes());
1093 let h = v2(1, 0x21, &block, &[], false);
1094 let (hd, _) = done(&mut ProxyParser::new(ProxyVersions::V2, 1024), &h);
1095 assert_eq!(hd.source.unwrap().to_string(), "[::1]:80");
1096 let mut unix = vec![0u8; 216];
1097 unix[..9].copy_from_slice(b"/run/a.sk");
1098 let h = v2(1, 0x31, &unix, &[], false);
1099 let (hd, _) = done(&mut ProxyParser::new(ProxyVersions::V2, 1024), &h);
1100 assert_eq!(hd.source, Some(ProxyAddress::Unix(b"/run/a.sk")));
1101 let h = v2(0, 0x11, &ipv4_block(), &[], false);
1102 let (hd, _) = done(&mut ProxyParser::new(ProxyVersions::V2, 1024), &h);
1103 assert_eq!((hd.command, hd.source), (ProxyCommand::Local, None));
1104 let h = v2(1, 0x00, &[], &[], false);
1105 let (hd, _) = done(&mut ProxyParser::new(ProxyVersions::V2, 1024), &h);
1106 assert_eq!(
1107 (hd.transport, hd.source),
1108 (ProxyTransport::Unspecified, None)
1109 );
1110 }
1111
1112 #[test]
1113 fn test_v2_errors() {
1114 use ProxyError::*;
1115 let feed = |h: &[u8]| ProxyParser::new(ProxyVersions::V2, 64).feed(h).map(|_| ());
1116 let mut h = v2(1, 0x11, &ipv4_block(), &[], false);
1117 h[12] = 0x11;
1118 assert_eq!(feed(&h).unwrap_err(), V2BadVersion);
1119 let mut h = v2(1, 0x11, &ipv4_block(), &[], false);
1120 h[12] = 0x22;
1121 assert_eq!(feed(&h).unwrap_err(), V2BadCommand);
1122 let mut h = v2(1, 0x11, &ipv4_block(), &[], false);
1123 h[13] = 0x13;
1124 assert_eq!(feed(&h).unwrap_err(), V2BadFamily);
1125 let big = v2(1, 0x11, &ipv4_block(), &[(0xE0, &[0u8; 100])], false);
1126 assert_eq!(
1127 feed(&big).unwrap_err(),
1128 V2LengthTooLarge {
1129 declared: 115,
1130 max: 64
1131 }
1132 );
1133 let short = v2(1, 0x21, &[0u8; 20], &[], false);
1134 assert_eq!(feed(&short).unwrap_err(), V2AddressTooShort);
1135 let mut over = v2(1, 0x11, &ipv4_block(), &[(0xE0, b"abc")], false);
1136 let n = over.len();
1137 over[n - 4] = 9; assert_eq!(feed(&over).unwrap_err(), V2TlvOverrun);
1139 let mut crc = v2(1, 0x11, &ipv4_block(), &[(TLV_ALPN, b"h2")], true);
1140 let n = crc.len();
1141 crc[n - 1] ^= 1;
1142 assert_eq!(feed(&crc).unwrap_err(), V2CrcMismatch);
1143 let long_id = vec![b'i'; 129];
1144 let h = v2(1, 0x11, &ipv4_block(), &[(TLV_UNIQUE_ID, &long_id)], false);
1145 assert_eq!(
1146 ProxyParser::new(ProxyVersions::V2, 1024)
1147 .feed(&h)
1148 .map(|_| ())
1149 .unwrap_err(),
1150 V2UniqueIdTooLong
1151 );
1152 let h = v2(1, 0x11, &ipv4_block(), &[(TLV_SSL, &[1, 0, 0])], false);
1153 assert_eq!(feed(&h).unwrap_err(), V2SslMalformed);
1154 }
1155
1156 #[test]
1158 fn test_v2_split_into_segments_waits_then_succeeds() {
1159 let mut h = v2(
1160 1,
1161 0x11,
1162 &ipv4_block(),
1163 &[(TLV_AUTHORITY, b"a.example")],
1164 true,
1165 );
1166 h.extend_from_slice(b"DATA");
1167 let total = h.len() - 4;
1168 let mut p = ProxyParser::new(ProxyVersions::Both, 1024);
1169 let step = h.len().div_ceil(12);
1170 let mut have = 0;
1171 loop {
1172 have = (have + step).min(h.len());
1173 match p.feed(&h[..have]).unwrap() {
1174 ProxyProgress::NeedMore { at_least } => assert!(at_least > 0 && have < h.len()),
1175 ProxyProgress::Done { consumed, .. } => {
1176 assert_eq!(consumed, total);
1177 break;
1178 }
1179 }
1180 }
1181 }
1182
1183 #[test]
1186 fn test_second_header_is_data() {
1187 let two = b"PROXY UNKNOWN\r\nPROXY UNKNOWN\r\n";
1188 let mut p = ProxyParser::new(ProxyVersions::V1, 1024);
1189 let (_, consumed) = done(&mut p, two);
1190 assert_eq!(&two[consumed..], b"PROXY UNKNOWN\r\n");
1191 }
1192
1193 #[test]
1195 fn prop_every_split_point_agrees() {
1196 let headers: Vec<Vec<u8>> = vec![
1197 b"PROXY TCP6 2001:db8:0:0:1:0:0:1 ::ffff:10.0.0.1 1024 8080\r\n".to_vec(),
1198 v2(
1199 1,
1200 0x11,
1201 &ipv4_block(),
1202 &[(TLV_ALPN, b"http/1.1"), (TLV_UNIQUE_ID, b"u")],
1203 true,
1204 ),
1205 ];
1206 for h in headers {
1207 for split in 0..h.len() {
1208 let mut p = ProxyParser::new(ProxyVersions::Both, 1024);
1209 if split > 0 {
1210 assert!(
1211 matches!(p.feed(&h[..split]).unwrap(), ProxyProgress::NeedMore { .. }),
1212 "split {split}"
1213 );
1214 }
1215 match p.feed(&h).unwrap() {
1216 ProxyProgress::Done { consumed, .. } => assert_eq!(consumed, h.len()),
1217 ProxyProgress::NeedMore { .. } => {
1218 panic!("whole header incomplete at split {split}")
1219 }
1220 }
1221 }
1222 }
1223 }
1224
1225 #[test]
1227 fn prop_random_input_never_panics() {
1228 use crate::testing::Gen;
1229 let mut g = Gen::new(0x9F0C_7E11);
1230 for _ in 0..if cfg!(miri) { 200 } else { 50_000 } {
1231 let len = g.below(300) as usize;
1232 let mut bytes: Vec<u8> = (0..len).map(|_| g.next_u64() as u8).collect();
1233 match g.below(3) {
1234 0 if len >= 12 => bytes[..12].copy_from_slice(&V2_SIGNATURE),
1235 1 if len >= 6 => bytes[..6].copy_from_slice(V1_PREFIX),
1236 _ => {}
1237 }
1238 let mut p = ProxyParser::new(ProxyVersions::Both, u16::MAX);
1239 if let Ok(ProxyProgress::Done { consumed, header }) = p.feed(&bytes) {
1240 assert!(consumed <= bytes.len());
1241 let _ = (header.alpn(), header.ssl(), header.tlvs.count());
1242 }
1243 }
1244 }
1245
1246 #[test]
1249 fn prop_ipv6_grammar_matches_std() {
1250 use crate::testing::Gen;
1251 let mut g = Gen::new(0x1FE6_0001);
1252 let alphabet = b"0123456789abcdefABCDEF:.";
1253 for _ in 0..if cfg!(miri) { 200 } else { 100_000 } {
1254 let len = 1 + g.below(40) as usize;
1255 let text: Vec<u8> = (0..len)
1256 .map(|_| alphabet[g.below(alphabet.len() as u64) as usize])
1257 .collect();
1258 if let Some(ours) = parse_ipv6(&text) {
1259 let s = str::from_utf8(&text).unwrap();
1260 assert_eq!(s.parse::<Ipv6Addr>().ok(), Some(ours), "{s}");
1261 }
1262 }
1263 for _ in 0..if cfg!(miri) { 200 } else { 20_000 } {
1264 let mut b = [0u8; 16];
1265 for x in &mut b {
1266 *x = if g.chance(2) { 0 } else { g.next_u64() as u8 };
1268 }
1269 let a = Ipv6Addr::from(b);
1270 assert_eq!(parse_ipv6(a.to_string().as_bytes()), Some(a), "{a}");
1271 }
1272 for (s, ok) in [
1273 ("::", true),
1274 ("::1", true),
1275 ("1::", true),
1276 ("1:2:3:4:5:6:7:8", true),
1277 ("1:2:3:4:5:6:7::", true),
1278 ("1:2:3:4:5:6:1.2.3.4", true),
1279 (":1", false),
1280 ("1:", false),
1281 ("1:::2", false),
1282 ("1::2::3", false),
1283 ("1:2:3:4:5:6:7:8:9", false),
1284 ("12345::", false),
1285 ("::1.2.3", false),
1286 ("fe80::1%eth0", false),
1287 ] {
1288 assert_eq!(parse_ipv6(s.as_bytes()).is_some(), ok, "{s}");
1289 }
1290 }
1291
1292 #[test]
1293 fn test_ipv4_grammar() {
1294 for (s, ok) in [
1295 ("0.0.0.0", true),
1296 ("255.255.255.255", true),
1297 ("1.2.3.04", false),
1298 ("1.2.3", false),
1299 ("1.2.3.4.5", false),
1300 ("1.2.3.256", false),
1301 ("1..3.4", false),
1302 (" 1.2.3.4", false),
1303 ] {
1304 assert_eq!(parse_ipv4(s.as_bytes()).is_some(), ok, "{s}");
1305 }
1306 }
1307
1308 #[test]
1309 fn test_encoders_round_trip_through_the_parser() {
1310 let s: SocketAddr = "[2001:db8::1]:5000".parse().unwrap();
1311 let d: SocketAddr = "[2001:db8::2]:443".parse().unwrap();
1312 let mut out = [0u8; 256];
1313 let n = encode_v1(s, d, &mut out).unwrap();
1314 let mut p = ProxyParser::new(ProxyVersions::Both, 1024);
1315 match p.feed(&out[..n]).unwrap() {
1316 ProxyProgress::Done { header, consumed } => {
1317 assert_eq!(consumed, n);
1318 assert_eq!(header.source.and_then(|a| a.socket_addr()), Some(s));
1319 }
1320 other => panic!("{other:?}"),
1321 }
1322 let tlv = Tlv {
1323 kind: 0x02,
1324 value: b"example.com",
1325 };
1326 let n = encode_v2(
1327 ProxyCommand::Proxy,
1328 Some(s),
1329 Some(d),
1330 &[tlv],
1331 true,
1332 &mut out,
1333 )
1334 .unwrap();
1335 let mut p = ProxyParser::new(ProxyVersions::Both, 1024);
1336 match p.feed(&out[..n]).unwrap() {
1337 ProxyProgress::Done { header, consumed } => {
1338 assert_eq!(consumed, n);
1339 assert_eq!(header.source.and_then(|a| a.socket_addr()), Some(s));
1340 assert!(header.crc_checked());
1341 }
1342 other => panic!("{other:?}"),
1343 }
1344 }
1345
1346 #[test]
1347 fn test_encoders_refuse_what_they_cannot_write() {
1348 let v4: SocketAddr = "192.0.2.1:1".parse().unwrap();
1349 let v6: SocketAddr = "[::1]:1".parse().unwrap();
1350 let mut small = [0u8; 8];
1351 assert_eq!(
1352 encode_v1(v4, v6, &mut small),
1353 Err(ProxyError::FamilyMismatch)
1354 );
1355 assert!(matches!(
1356 encode_v1(v4, v4, &mut small),
1357 Err(ProxyError::OutputTooSmall { .. })
1358 ));
1359 assert!(matches!(
1360 encode_v2(ProxyCommand::Local, None, None, &[], false, &mut small),
1361 Err(ProxyError::OutputTooSmall { need: 16 })
1362 ));
1363 let mut out = [0u8; 16];
1364 assert_eq!(
1365 encode_v2(ProxyCommand::Local, None, None, &[], false, &mut out),
1366 Ok(16)
1367 );
1368 }
1369}