Skip to main content

net_io/
proxy_parse.rs

1//! The PROXY protocol parser (versions 1 and 2): a sans-IO state machine.
2//!
3//! Give [`ProxyParser::feed`] every byte received so far; it resumes where it
4//! stopped and never reads past the end of the header, so the bytes after
5//! `consumed` stay application data. The grammar follows the HAProxy PROXY
6//! protocol specification; the v1 text is parsed strictly (single spaces, no
7//! leading zeros, addresses parsed by this module's own grammar).
8
9use 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/// Which version the parser is reading.
37#[derive(Clone, Copy, Debug, PartialEq, Eq)]
38enum Kind {
39    Undecided,
40    V1,
41    V2,
42}
43
44/// A sans-IO PROXY header parser for one connection.
45///
46/// # Examples
47///
48/// ```
49/// use net_io::{ProxyParser, ProxyProgress, ProxyVersions};
50/// let mut parser = ProxyParser::new(ProxyVersions::Both, 1024);
51/// let bytes = b"PROXY TCP4 192.0.2.1 198.51.100.2 51000 443\r\nGET / HTTP/1.1\r\n";
52/// match parser.feed(bytes)? {
53///     ProxyProgress::Done { header, consumed } => {
54///         assert_eq!(&bytes[consumed..], b"GET / HTTP/1.1\r\n");
55///         assert_eq!(header.source.unwrap().to_string(), "192.0.2.1:51000");
56///     }
57///     ProxyProgress::NeedMore { .. } => unreachable!(),
58/// }
59/// # Ok::<(), net_io::ProxyError>(())
60/// ```
61#[derive(Clone, Debug)]
62pub struct ProxyParser {
63    versions: ProxyVersions,
64    v2_body_max: u16,
65    kind: Kind,
66    /// v1: bytes already searched for the line end.
67    scanned: usize,
68}
69
70/// What [`ProxyParser::feed`] found.
71#[derive(Debug)]
72pub enum ProxyProgress<'a> {
73    /// The header is incomplete: feed again with at least this many more bytes.
74    NeedMore {
75        /// The fewest additional bytes that can make progress.
76        at_least: usize,
77    },
78    /// A complete header; the bytes from `consumed` on are application data.
79    Done {
80        /// The header, borrowing from the input.
81        header: ProxyHeader<'a>,
82        /// The header's length in bytes.
83        consumed: usize,
84    },
85}
86
87/// A parsed PROXY header, borrowing from the bytes it was parsed from.
88#[non_exhaustive]
89#[derive(Clone, Copy, Debug)]
90pub struct ProxyHeader<'a> {
91    /// 1 or 2.
92    pub version: u8,
93    /// `Proxy`, or `Local` (a connection made by the proxy itself, such as a
94    /// health check: keep the socket's own addresses).
95    pub command: ProxyCommand,
96    /// The transport of the proxied connection.
97    pub transport: ProxyTransport,
98    /// The real client; `None` for `LOCAL`, v1 `UNKNOWN`, and v2 `UNSPEC`.
99    pub source: Option<ProxyAddress<'a>>,
100    /// The address the client connected to; `None` as for `source`.
101    pub destination: Option<ProxyAddress<'a>>,
102    /// The v2 TLVs (empty for v1); `NOOP` entries are skipped.
103    pub tlvs: Tlvs<'a>,
104    crc_checked: bool,
105}
106
107/// The PROXY command.
108#[non_exhaustive]
109#[derive(Clone, Copy, Debug, PartialEq, Eq)]
110pub enum ProxyCommand {
111    /// A proxied connection.
112    Proxy,
113    /// A connection made by the proxy itself.
114    Local,
115}
116
117/// The transport of the proxied connection.
118#[non_exhaustive]
119#[derive(Clone, Copy, Debug, PartialEq, Eq)]
120pub enum ProxyTransport {
121    /// A stream (TCP, or a Unix stream socket).
122    Stream,
123    /// Datagrams.
124    Datagram,
125    /// Not given.
126    Unspecified,
127}
128
129/// An address in a PROXY header.
130#[non_exhaustive]
131#[derive(Clone, Copy, Debug, PartialEq, Eq)]
132pub enum ProxyAddress<'a> {
133    /// An IP address and port.
134    Ip(SocketAddr),
135    /// A Unix socket path (v2 only), with trailing zero bytes removed.
136    Unix(&'a [u8]),
137}
138
139impl ProxyAddress<'_> {
140    /// The IP socket address, if this is one.
141    #[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/// One v2 TLV.
160#[derive(Clone, Copy, Debug, PartialEq, Eq)]
161pub struct Tlv<'a> {
162    /// The type byte.
163    pub kind: u8,
164    /// The value.
165    pub value: &'a [u8],
166}
167
168/// The TLVs of a v2 header, already checked to fit the declared length.
169#[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/// The SSL facts a proxy that terminated TLS reports (v2 TLV `0x20`).
189#[non_exhaustive]
190#[derive(Clone, Copy, Debug)]
191pub struct ProxySsl<'a> {
192    /// The client flags: bit 0 SSL, bit 1 a client certificate on this
193    /// connection, bit 2 one in the session.
194    pub client: u8,
195    /// Whether the client certificate was verified (`verify` field 0).
196    pub verified: bool,
197    /// The TLS version, such as `TLSv1.3`.
198    pub version: Option<&'a str>,
199    /// The client certificate's common name.
200    pub common_name: Option<&'a str>,
201    /// The cipher.
202    pub cipher: Option<&'a str>,
203    /// The certificate's signature algorithm.
204    pub signature_algorithm: Option<&'a str>,
205    /// The certificate's key algorithm.
206    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    /// The ALPN protocol the proxy negotiated with the client (TLV `0x01`).
216    #[must_use]
217    pub fn alpn(&self) -> Option<&'a [u8]> {
218        self.find(TLV_ALPN)
219    }
220
221    /// The authority (host name) the client asked for (TLV `0x02`), if UTF-8.
222    #[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    /// The proxy's unique connection id (TLV `0x05`, at most 128 bytes).
229    #[must_use]
230    pub fn unique_id(&self) -> Option<&'a [u8]> {
231        self.find(TLV_UNIQUE_ID)
232    }
233
234    /// The SSL facts (TLV `0x20`).
235    #[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    /// The network namespace (TLV `0x30`).
266    #[must_use]
267    pub fn network_namespace(&self) -> Option<&'a [u8]> {
268        self.find(TLV_NETNS)
269    }
270
271    /// Whether a CRC32C TLV was present and matched.
272    #[must_use]
273    pub fn crc_checked(&self) -> bool {
274        self.crc_checked
275    }
276
277    /// The facts net-io keeps after the header's bytes are gone (fixed arrays;
278    /// a value longer than its array is left out).
279    #[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    /// A parser accepting `versions`, refusing a v2 header whose body (after the
292    /// 16 fixed bytes) is longer than `v2_body_max`.
293    #[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    /// Parses from `input`, which holds every byte received so far.
304    ///
305    /// # Errors
306    ///
307    /// [`ProxyError`]: the bytes are not an allowed header, or are malformed.
308    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
422/// A byte offset within a v1 line, which is at most 107 bytes.
423fn offset(at: usize) -> u8 {
424    u8::try_from(at).unwrap_or(u8::MAX)
425}
426
427/// One TLV from the front of `bytes`, or `None` when fewer than a whole TLV remain.
428fn 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
443/// Walks every TLV of `header` (starting at `start`) and checks it ends exactly
444/// at the declared length; verifies CRC32C, the unique id, and the SSL TLV.
445/// Returns whether a checksum was verified.
446fn 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
542/// Parses a v1 line without its CRLF.
543fn 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        // The receiver ignores everything after UNKNOWN on the line.
549        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        // Only a failure pays for the other family, to name the error.
595        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
621/// A decimal port, 0 to 65535, no sign and no leading zeros.
622fn parse_port(text: &[u8]) -> Option<u16> {
623    decimal(text, 5).and_then(|v| u16::try_from(v).ok())
624}
625
626/// Decimal digits only, at most `max_digits`, no leading zero unless the value is 0.
627fn 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
636/// A dotted-quad IPv4 address: four decimal octets, no leading zeros.
637fn 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
650/// An IPv6 address in RFC 4291 text form: eight groups of one to four hex
651/// digits, at most one `::`, optionally ending in a dotted-quad IPv4 address.
652/// No zone index.
653fn 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    // Groups before `::` (or all of them, when there is no `::`).
663    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
680/// Parses `:`-separated groups of `text` into `out` from index `at`; an IPv4
681/// tail (two groups) is allowed when `last` says this part ends the address.
682/// Returns the next free index.
683fn 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
714/// Writes a v1 header for a proxied TCP connection; returns its length (at most 107).
715/// For a proxy that speaks PROXY to its backends.
716///
717/// ```
718/// let mut out = [0u8; 107];
719/// let n = net_io::encode_v1(
720///     "192.0.2.1:5000".parse().unwrap(),
721///     "192.0.2.2:80".parse().unwrap(),
722///     &mut out,
723/// )?;
724/// assert_eq!(&out[..n], b"PROXY TCP4 192.0.2.1 192.0.2.2 5000 80\r\n");
725/// # Ok::<(), net_io::ProxyError>(())
726/// ```
727///
728/// # Errors
729///
730/// `FamilyMismatch` when the two addresses differ in family, `OutputTooSmall`.
731pub 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
756/// Writes a v2 header; returns its length. `None` for either address sends `UNSPEC`,
757/// which is what `ProxyCommand::Local` means. `with_crc` adds a CRC32C TLV.
758///
759/// ```
760/// use net_io::{ProxyCommand, ProxyParser, ProxyProgress, ProxyVersions};
761/// let mut out = [0u8; 64];
762/// let n = net_io::encode_v2(
763///     ProxyCommand::Proxy,
764///     Some("192.0.2.1:5000".parse().unwrap()),
765///     Some("192.0.2.2:80".parse().unwrap()),
766///     &[],
767///     true,
768///     &mut out,
769/// )?;
770/// assert!(n > 16);
771/// # Ok::<(), net_io::ProxyError>(())
772/// ```
773///
774/// # Errors
775///
776/// `FamilyMismatch`, `OutputTooSmall`, `V2LengthTooLarge` when it cannot fit 65,535 bytes.
777pub 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    /// Builds a v2 header: command, family, address block, TLVs; optionally a CRC.
868    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    /// Edge case 13: 107 bytes without a line end.
984    #[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; // TLV length runs past the end
1138        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    /// Edge case 14: a v2 header split across 12 segments.
1157    #[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    /// Edge cases 15 and 16: the header and data in one segment, and a second
1184    /// header is application data.
1185    #[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    /// Property: every split of a valid header gives the same result as the whole.
1194    #[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    /// Property: random bytes never panic, and a header is never longer than the input.
1226    #[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    /// Property: the IPv6 grammar accepts only what std accepts, with the same value,
1247    /// and accepts every address std prints.
1248    #[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                // Runs of zeros, so `::` forms appear.
1267                *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}