proxy_protocol/
version2.rs

1use bytes::{Buf, BufMut as _, BytesMut};
2use snafu::{ensure, Snafu};
3use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
4
5#[derive(Debug, Snafu)]
6#[cfg_attr(test, derive(PartialEq, Eq))]
7pub enum ParseError {
8    #[snafu(display("an unexpected eof was hit"))]
9    UnexpectedEof,
10
11    #[snafu(display("invalid command: {}", cmd))]
12    UnknownCommand { cmd: u8 },
13
14    #[snafu(display("invalid address family: {}", family))]
15    UnknownAddressFamily { family: u8 },
16
17    #[snafu(display("invalid transport protocol: {}", protocol))]
18    UnknownTransportProtocol { protocol: u8 },
19
20    #[snafu(display("insufficient length specified: {}, requires minimum {}", given, needs))]
21    InsufficientLengthSpecified { given: usize, needs: usize },
22}
23
24#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
25pub enum ProxyCommand {
26    Local,
27    Proxy,
28}
29
30#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
31pub enum ProxyTransportProtocol {
32    Unspec,
33    Stream,
34    Datagram,
35}
36
37#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
38pub enum ProxyAddresses {
39    Unspec,
40    Ipv4 {
41        source: SocketAddrV4,
42        destination: SocketAddrV4,
43    },
44    Ipv6 {
45        source: SocketAddrV6,
46        destination: SocketAddrV6,
47    },
48    Unix {
49        source: [u8; 108],
50        destination: [u8; 108],
51    },
52}
53
54#[derive(PartialEq, Eq)]
55enum ProxyAddressFamily {
56    Unspec,
57    Inet,
58    Inet6,
59    Unix,
60}
61
62pub(crate) fn parse(buf: &mut impl Buf) -> Result<super::ProxyHeader, ParseError> {
63    // We need to parse the following:
64    //
65    // > struct proxy_hdr_v2 {
66    // >     uint8_t sig[12];  /* hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A */
67    // >     uint8_t ver_cmd;  /* protocol version and command */
68    // >     uint8_t fam;      /* protocol family and address */
69    // >     uint16_t len;     /* number of following bytes part of the header */
70    // > };
71    //
72    // `uint8_t *sig` was parsed in our caller.
73    // We have ver_cmd next up; version is already parsed.
74
75    // No ensure for command byte. We know it must exist.
76    let command = buf.get_u8() << 4 >> 4;
77    let command = match command {
78        0 => ProxyCommand::Local,
79        1 => ProxyCommand::Proxy,
80        cmd => return UnknownCommand { cmd }.fail(),
81    };
82
83    // 4 bits for address family, 4 bits for transport protocol,
84    // then 2 bytes for the length.
85    ensure!(buf.remaining() >= 3, UnexpectedEof);
86
87    let byte = buf.get_u8();
88    let address_family = match byte >> 4 {
89        0 => ProxyAddressFamily::Unspec,
90        1 => ProxyAddressFamily::Inet,
91        2 => ProxyAddressFamily::Inet6,
92        3 => ProxyAddressFamily::Unix,
93        family => return UnknownAddressFamily { family }.fail(),
94    };
95    let transport_protocol = match byte << 4 >> 4 {
96        0 => ProxyTransportProtocol::Unspec,
97        1 => ProxyTransportProtocol::Stream,
98        2 => ProxyTransportProtocol::Datagram,
99        protocol => return UnknownTransportProtocol { protocol }.fail(),
100    };
101
102    let length = buf.get_u16() as usize;
103
104    if address_family == ProxyAddressFamily::Unspec {
105        // We have no information to parse.
106        ensure!(buf.remaining() >= length, UnexpectedEof);
107        buf.advance(length);
108
109        return Ok(super::ProxyHeader::Version2 {
110            command,
111            transport_protocol,
112            addresses: ProxyAddresses::Unspec,
113        });
114    }
115
116    // Time to parse the following:
117    //
118    // > union proxy_addr {
119    // >     struct {        /* for TCP/UDP over IPv4, len = 12 */
120    // >         uint32_t src_addr;
121    // >         uint32_t dst_addr;
122    // >         uint16_t src_port;
123    // >         uint16_t dst_port;
124    // >     } ipv4_addr;
125    // >     struct {        /* for TCP/UDP over IPv6, len = 36 */
126    // >          uint8_t  src_addr[16];
127    // >          uint8_t  dst_addr[16];
128    // >          uint16_t src_port;
129    // >          uint16_t dst_port;
130    // >     } ipv6_addr;
131    // >     struct {        /* for AF_UNIX sockets, len = 216 */
132    // >          uint8_t src_addr[108];
133    // >          uint8_t dst_addr[108];
134    // >     } unix_addr;
135    // > };
136
137    if address_family == ProxyAddressFamily::Unix {
138        ensure!(
139            length >= 108 * 2,
140            InsufficientLengthSpecified {
141                given: length,
142                needs: 108usize * 2,
143            },
144        );
145        ensure!(buf.remaining() >= 108 * 2, UnexpectedEof);
146        let mut source = [0u8; 108];
147        let mut destination = [0u8; 108];
148        buf.copy_to_slice(&mut source[..]);
149        buf.copy_to_slice(&mut destination[..]);
150        // TODO(Mariell Hoversholm): Support TLVs
151        if length > 108 * 2 {
152            buf.advance(length - (108 * 2));
153        }
154
155        return Ok(super::ProxyHeader::Version2 {
156            command,
157            transport_protocol,
158            addresses: ProxyAddresses::Unix {
159                source,
160                destination,
161            },
162        });
163    }
164
165    let port_length = 4;
166    let address_length = match address_family {
167        ProxyAddressFamily::Inet => 8,
168        ProxyAddressFamily::Inet6 => 32,
169        _ => unreachable!(),
170    };
171
172    ensure!(
173        length >= port_length + address_length,
174        InsufficientLengthSpecified {
175            given: length,
176            needs: port_length + address_length,
177        },
178    );
179    ensure!(
180        buf.remaining() >= port_length + address_length,
181        UnexpectedEof,
182    );
183
184    let addresses = if address_family == ProxyAddressFamily::Inet {
185        let mut data = [0u8; 4];
186        buf.copy_to_slice(&mut data[..]);
187        let source = Ipv4Addr::from(data);
188
189        buf.copy_to_slice(&mut data);
190        let destination = Ipv4Addr::from(data);
191
192        let source_port = buf.get_u16();
193        let destination_port = buf.get_u16();
194
195        ProxyAddresses::Ipv4 {
196            source: SocketAddrV4::new(source, source_port),
197            destination: SocketAddrV4::new(destination, destination_port),
198        }
199    } else {
200        let mut data = [0u8; 16];
201        buf.copy_to_slice(&mut data);
202        let source = Ipv6Addr::from(data);
203
204        buf.copy_to_slice(&mut data);
205        let destination = Ipv6Addr::from(data);
206
207        let source_port = buf.get_u16();
208        let destination_port = buf.get_u16();
209
210        ProxyAddresses::Ipv6 {
211            source: SocketAddrV6::new(source, source_port, 0, 0),
212            destination: SocketAddrV6::new(destination, destination_port, 0, 0),
213        }
214    };
215
216    if length > port_length + address_length {
217        // TODO(Mariell Hoversholm): Implement TLVs
218        buf.advance(length - (port_length + address_length));
219    }
220
221    Ok(super::ProxyHeader::Version2 {
222        command,
223        transport_protocol,
224        addresses,
225    })
226}
227
228pub(crate) fn encode(
229    command: ProxyCommand,
230    transport_protocol: ProxyTransportProtocol,
231    addresses: ProxyAddresses,
232) -> BytesMut {
233    // > struct proxy_hdr_v2 {
234    // >     uint8_t sig[12];  /* hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A */
235    // >     uint8_t ver_cmd;  /* protocol version and command */
236    // >     uint8_t fam;      /* protocol family and address */
237    // >     uint16_t len;     /* number of following bytes part of the header */
238    // > };
239    const SIG: [u8; 12] = [
240        0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A,
241    ];
242
243    // > The next byte (the 13th one) is the protocol version and command.
244    // >
245    // > The highest four bits contains the version. As of this specification, it must
246    // > always be sent as \x2 and the receiver must only accept this value.
247    // >
248    // > The lowest four bits represents the command :
249    // >   - \x0 : LOCAL : the connection was established on purpose by the proxy
250    // >     without being relayed. The connection endpoints are the sender and the
251    // >     receiver. Such connections exist when the proxy sends health-checks to the
252    // >     server. The receiver must accept this connection as valid and must use the
253    // >     real connection endpoints and discard the protocol block including the
254    // >     family which is ignored.
255    // >
256    // >   - \x1 : PROXY : the connection was established on behalf of another node,
257    // >     and reflects the original connection endpoints. The receiver must then use
258    // >     the information provided in the protocol block to get original the address.
259    // >
260    // >   - other values are unassigned and must not be emitted by senders. Receivers
261    // >     must drop connections presenting unexpected values here.
262    let ver_cmd = (2 << 4)
263        | match command {
264            ProxyCommand::Local => 0,
265            ProxyCommand::Proxy => 1,
266        };
267
268    // > The 14th byte contains the transport protocol and address family. The highest 4
269    // > bits contain the address family, the lowest 4 bits contain the protocol.
270    // >
271    // > The address family maps to the original socket family without necessarily
272    // > matching the values internally used by the system. It may be one of :
273    // >
274    // >   - 0x0 : AF_UNSPEC : the connection is forwarded for an unknown, unspecified
275    // >     or unsupported protocol. The sender should use this family when sending
276    // >     LOCAL commands or when dealing with unsupported protocol families. The
277    // >     receiver is free to accept the connection anyway and use the real endpoint
278    // >     addresses or to reject it. The receiver should ignore address information.
279    // >
280    // >   - 0x1 : AF_INET : the forwarded connection uses the AF_INET address family
281    // >     (IPv4). The addresses are exactly 4 bytes each in network byte order,
282    // >     followed by transport protocol information (typically ports).
283    // >
284    // >   - 0x2 : AF_INET6 : the forwarded connection uses the AF_INET6 address family
285    // >     (IPv6). The addresses are exactly 16 bytes each in network byte order,
286    // >     followed by transport protocol information (typically ports).
287    // >
288    // >   - 0x3 : AF_UNIX : the forwarded connection uses the AF_UNIX address family
289    // >     (UNIX). The addresses are exactly 108 bytes each.
290    // >
291    // >   - other values are unspecified and must not be emitted in version 2 of this
292    // >     protocol and must be rejected as invalid by receivers.
293    // >
294    // > The transport protocol is specified in the lowest 4 bits of the 14th byte :
295    // >
296    // >   - 0x0 : UNSPEC : the connection is forwarded for an unknown, unspecified
297    // >     or unsupported protocol. The sender should use this family when sending
298    // >     LOCAL commands or when dealing with unsupported protocol families. The
299    // >     receiver is free to accept the connection anyway and use the real endpoint
300    // >     addresses or to reject it. The receiver should ignore address information.
301    // >
302    // >   - 0x1 : STREAM : the forwarded connection uses a SOCK_STREAM protocol (eg:
303    // >     TCP or UNIX_STREAM). When used with AF_INET/AF_INET6 (TCP), the addresses
304    // >     are followed by the source and destination ports represented on 2 bytes
305    // >     each in network byte order.
306    // >
307    // >   - 0x2 : DGRAM : the forwarded connection uses a SOCK_DGRAM protocol (eg:
308    // >     UDP or UNIX_DGRAM). When used with AF_INET/AF_INET6 (UDP), the addresses
309    // >     are followed by the source and destination ports represented on 2 bytes
310    // >     each in network byte order.
311    // >
312    // >   - other values are unspecified and must not be emitted in version 2 of this
313    // >     protocol and must be rejected as invalid by receivers.
314    let fam = (match addresses {
315        ProxyAddresses::Unspec => 0,
316        ProxyAddresses::Ipv4 { .. } => 1,
317        ProxyAddresses::Ipv6 { .. } => 2,
318        ProxyAddresses::Unix { .. } => 3,
319    } << 4)
320        | match transport_protocol {
321            ProxyTransportProtocol::Unspec => 0,
322            ProxyTransportProtocol::Stream => 1,
323            ProxyTransportProtocol::Datagram => 2,
324        };
325
326    // > union proxy_addr {
327    // >     struct {        /* for TCP/UDP over IPv4, len = 12 */
328    // >         uint32_t src_addr;
329    // >         uint32_t dst_addr;
330    // >         uint16_t src_port;
331    // >         uint16_t dst_port;
332    // >     } ipv4_addr;
333    // >     struct {        /* for TCP/UDP over IPv6, len = 36 */
334    // >          uint8_t  src_addr[16];
335    // >          uint8_t  dst_addr[16];
336    // >          uint16_t src_port;
337    // >          uint16_t dst_port;
338    // >     } ipv6_addr;
339    // >     struct {        /* for AF_UNIX sockets, len = 216 */
340    // >          uint8_t src_addr[108];
341    // >          uint8_t dst_addr[108];
342    // >     } unix_addr;
343    // > };
344    let len = match addresses {
345        ProxyAddresses::Unspec => 0,
346        ProxyAddresses::Unix { .. } => {
347            108 + 108
348        }
349        ProxyAddresses::Ipv4 { .. } => {
350            4 + 4 + 2 + 2
351        }
352        ProxyAddresses::Ipv6 { .. } => {
353            16 + 16 + 2 + 2
354        }
355    };
356
357    let mut buf = BytesMut::with_capacity(16 + len);
358    buf.put_slice(&SIG[..]);
359    buf.put_slice(&[ver_cmd, fam][..]);
360    buf.put_u16(len as u16);
361
362    match addresses {
363        ProxyAddresses::Unspec => (),
364        ProxyAddresses::Unix {
365            source,
366            destination,
367        } => {
368            buf.put_slice(&source[..]);
369            buf.put_slice(&destination[..]);
370        }
371        ProxyAddresses::Ipv4 {
372            source,
373            destination,
374        } => {
375            buf.put_slice(&source.ip().octets()[..]);
376            buf.put_slice(&destination.ip().octets()[..]);
377            buf.put_u16(source.port());
378            buf.put_u16(destination.port());
379        }
380        ProxyAddresses::Ipv6 {
381            source,
382            destination,
383        } => {
384            buf.put_slice(&source.ip().octets()[..]);
385            buf.put_slice(&destination.ip().octets()[..]);
386            buf.put_u16(source.port());
387            buf.put_u16(destination.port());
388        }
389    }
390
391    buf
392}
393
394#[cfg(test)]
395mod parse_tests {
396    use super::*;
397    use crate::ProxyHeader;
398    use bytes::{Bytes, BytesMut};
399    use pretty_assertions::assert_eq;
400    use rand::prelude::*;
401    use std::net::{Ipv4Addr, Ipv6Addr};
402
403    #[test]
404    fn test_unspec() {
405        assert_eq!(
406            parse(&mut &[0u8; 16][..]),
407            Ok(ProxyHeader::Version2 {
408                command: ProxyCommand::Local,
409                addresses: ProxyAddresses::Unspec,
410                transport_protocol: ProxyTransportProtocol::Unspec,
411            }),
412        );
413
414        let mut prefix = BytesMut::from(&[1u8][..]);
415        prefix.reserve(16);
416        prefix.extend_from_slice(&[0u8; 16][..]);
417        assert_eq!(
418            parse(&mut prefix),
419            Ok(ProxyHeader::Version2 {
420                command: ProxyCommand::Proxy,
421                addresses: ProxyAddresses::Unspec,
422                transport_protocol: ProxyTransportProtocol::Unspec,
423            }),
424        );
425    }
426
427    #[test]
428    fn test_ipv4() {
429        assert_eq!(
430            parse(
431                &mut &[
432                    // Proxy command
433                    1u8,
434                    // Inet << 4 | Stream
435                    (1 << 4) | 1,
436                    // Length beyond this: 12
437                    // Let's throw in a TLV with no data; 3 bytes.
438                    0,
439                    15,
440                    // Source IP
441                    127,
442                    0,
443                    0,
444                    1,
445                    // Destination IP
446                    192,
447                    168,
448                    0,
449                    1,
450                    // Source port
451                    // 65535 = [255, 255]
452                    255,
453                    255,
454                    // Destination port
455                    // 257 = [1, 1]
456                    1,
457                    1,
458                    // TLV
459                    69,
460                    0,
461                    0,
462                ][..]
463            ),
464            Ok(ProxyHeader::Version2 {
465                command: ProxyCommand::Proxy,
466                transport_protocol: ProxyTransportProtocol::Stream,
467                addresses: ProxyAddresses::Ipv4 {
468                    source: SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 65535),
469                    destination: SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 257),
470                },
471            })
472        );
473
474        let mut data = Bytes::from_static(
475            &[
476                // Local command
477                0u8,
478                // Inet << 4 | Datagram
479                (1 << 4) | 2,
480                // Length beyond this: 12
481                0,
482                12,
483                // Source IP
484                0,
485                0,
486                0,
487                0,
488                // Destination IP
489                255,
490                255,
491                255,
492                255,
493                // Source port
494                0,
495                0,
496                // Destination port
497                255,
498                0,
499                // Extra data
500                1,
501                2,
502                3,
503                4,
504            ][..],
505        );
506        assert_eq!(
507            parse(&mut data),
508            Ok(ProxyHeader::Version2 {
509                command: ProxyCommand::Local,
510                transport_protocol: ProxyTransportProtocol::Datagram,
511                addresses: ProxyAddresses::Ipv4 {
512                    source: SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0),
513                    destination: SocketAddrV4::new(Ipv4Addr::new(255, 255, 255, 255), 255 << 8),
514                },
515            })
516        );
517        assert!(data.remaining() == 4); // Consume the entire header
518    }
519
520    #[test]
521    fn test_ipv6() {
522        assert_eq!(
523            parse(
524                &mut &[
525                    // Proxy command
526                    1u8,
527                    // Inet6 << 4 | Datagram
528                    (2 << 4) | 2,
529                    // Length beyond this: 12
530                    // Let's throw in a TLV with no data; 3 bytes.
531                    0,
532                    39,
533                    // Source IP
534                    255,
535                    255,
536                    255,
537                    255,
538                    255,
539                    255,
540                    255,
541                    255,
542                    255,
543                    255,
544                    255,
545                    255,
546                    255,
547                    255,
548                    255,
549                    255,
550                    // Destination IP
551                    0,
552                    0,
553                    0,
554                    0,
555                    0,
556                    0,
557                    0,
558                    0,
559                    0,
560                    0,
561                    0,
562                    0,
563                    0,
564                    0,
565                    0,
566                    0,
567                    // Source port
568                    // 65535 = [255, 255]
569                    255,
570                    255,
571                    // Destination port
572                    // 257 = [1, 1]
573                    1,
574                    1,
575                    // TLV
576                    69,
577                    0,
578                    0,
579                ][..]
580            ),
581            Ok(ProxyHeader::Version2 {
582                command: ProxyCommand::Proxy,
583                transport_protocol: ProxyTransportProtocol::Datagram,
584                addresses: ProxyAddresses::Ipv6 {
585                    source: SocketAddrV6::new(
586                        Ipv6Addr::new(65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535),
587                        65535,
588                        0,
589                        0,
590                    ),
591                    destination: SocketAddrV6::new(
592                        Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0),
593                        257,
594                        0,
595                        0,
596                    ),
597                },
598            })
599        );
600
601        let mut data = Bytes::from_static(
602            &[
603                // Local command
604                0u8,
605                // Inet6 << 4 | Stream
606                (2 << 4) | 1,
607                // Length beyond this: 12
608                0,
609                36,
610                // Source IP
611                81,
612                92,
613                0,
614                52,
615                83,
616                12,
617                255,
618                68,
619                19,
620                5,
621                111,
622                200,
623                54,
624                90,
625                55,
626                66,
627                // Destination IP
628                255,
629                255,
630                255,
631                255,
632                0,
633                0,
634                0,
635                0,
636                123,
637                123,
638                69,
639                69,
640                21,
641                21,
642                42,
643                42,
644                // Source port
645                123,
646                0,
647                // Destination port
648                255,
649                255,
650                // Extra data
651                1,
652                2,
653                3,
654                4,
655            ][..],
656        );
657        assert_eq!(
658            parse(&mut data),
659            Ok(ProxyHeader::Version2 {
660                command: ProxyCommand::Local,
661                transport_protocol: ProxyTransportProtocol::Stream,
662                addresses: ProxyAddresses::Ipv6 {
663                    source: SocketAddrV6::new(
664                        Ipv6Addr::new(20828, 52, 21260, 65348, 4869, 28616, 13914, 14146),
665                        31488,
666                        0,
667                        0,
668                    ),
669                    destination: SocketAddrV6::new(
670                        Ipv6Addr::new(65535, 65535, 0, 0, 31611, 17733, 5397, 10794),
671                        65535,
672                        0,
673                        0,
674                    ),
675                },
676            })
677        );
678        assert!(data.remaining() == 4); // Consume the entire header
679    }
680
681    #[test]
682    fn test_invalid_data() {
683        let mut data = [0u8; 200];
684        rand::thread_rng().fill_bytes(&mut data);
685        data[0] = 99; // Make 100% sure it's invalid.
686        assert!(parse(&mut &data[..]).is_err());
687
688        assert_eq!(parse(&mut &[0][..]), Err(ParseError::UnexpectedEof));
689
690        assert_eq!(
691            parse(
692                &mut &[
693                    // Proxy command
694                    1u8,
695                    // Inet << 4 | Stream
696                    (1 << 4) | 1,
697                    // Length beyond this: 12
698                    // 3 bytes is clearly too few if we expect 2 IPv4s and ports
699                    0,
700                    3,
701                ][..]
702            ),
703            Err(ParseError::InsufficientLengthSpecified {
704                given: 3,
705                needs: 4 * 2 + 2 * 2,
706            }),
707        );
708    }
709}
710
711#[cfg(test)]
712mod encode_tests {
713    use super::*;
714    use bytes::{Bytes, BytesMut};
715    use pretty_assertions::assert_eq;
716    use std::net::{Ipv4Addr, Ipv6Addr};
717
718    const SIG: [u8; 12] = [
719        0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A,
720    ];
721
722    fn signed(buf: &[u8]) -> Bytes {
723        let mut bytes = BytesMut::from(&SIG[..]);
724        bytes.extend_from_slice(buf);
725        bytes.freeze()
726    }
727
728    #[test]
729    fn test_unspec() {
730        assert_eq!(
731            encode(
732                ProxyCommand::Local,
733                ProxyTransportProtocol::Unspec,
734                ProxyAddresses::Unspec,
735            ),
736            signed(&[(2 << 4) | 0, 0, 0, 0][..]),
737        );
738
739        assert_eq!(
740            encode(
741                ProxyCommand::Proxy,
742                ProxyTransportProtocol::Unspec,
743                ProxyAddresses::Unspec,
744            ),
745            signed(&[(2 << 4) | 1, 0, 0, 0][..]),
746        );
747        assert_eq!(
748            encode(
749                ProxyCommand::Proxy,
750                ProxyTransportProtocol::Unspec,
751                ProxyAddresses::Ipv4 {
752                    source: SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 65535),
753                    destination: SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 9012),
754                },
755            ),
756            signed(
757                &[
758                    (2 << 4) | 1,
759                    (1 << 4) | 0,
760                    0,
761                    12,
762                    1,
763                    2,
764                    3,
765                    4,
766                    192,
767                    168,
768                    0,
769                    1,
770                    255,
771                    255,
772                    (9012u16 >> 8) as u8,
773                    9012u16 as u8,
774                ][..]
775            ),
776        );
777    }
778
779    #[test]
780    fn test_ipv4() {
781        assert_eq!(
782            encode(
783                ProxyCommand::Proxy,
784                ProxyTransportProtocol::Stream,
785                ProxyAddresses::Ipv4 {
786                    source: SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 65535),
787                    destination: SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 9012),
788                },
789            ),
790            signed(
791                &[
792                    (2 << 4) | 1,
793                    (1 << 4) | 1,
794                    0,
795                    12,
796                    1,
797                    2,
798                    3,
799                    4,
800                    192,
801                    168,
802                    0,
803                    1,
804                    255,
805                    255,
806                    (9012u16 >> 8) as u8,
807                    9012u16 as u8,
808                ][..]
809            ),
810        );
811        assert_eq!(
812            encode(
813                ProxyCommand::Local,
814                ProxyTransportProtocol::Datagram,
815                ProxyAddresses::Ipv4 {
816                    source: SocketAddrV4::new(Ipv4Addr::new(255, 255, 255, 255), 324),
817                    destination: SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 2187),
818                },
819            ),
820            signed(
821                &[
822                    (2 << 4) | 0,
823                    (1 << 4) | 2,
824                    0,
825                    12,
826                    255,
827                    255,
828                    255,
829                    255,
830                    192,
831                    168,
832                    0,
833                    1,
834                    (324u16 >> 8) as u8,
835                    324u16 as u8,
836                    (2187 >> 8) as u8,
837                    2187u16 as u8,
838                ][..]
839            ),
840        );
841    }
842
843    #[test]
844    fn test_ipv6() {
845        assert_eq!(
846            encode(
847                ProxyCommand::Local,
848                ProxyTransportProtocol::Datagram,
849                ProxyAddresses::Ipv6 {
850                    source: SocketAddrV6::new(
851                        Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8),
852                        8192,
853                        0,
854                        0,
855                    ),
856                    destination: SocketAddrV6::new(
857                        Ipv6Addr::new(65535, 65535, 32767, 32766, 111, 222, 333, 444),
858                        0,
859                        0,
860                        0,
861                    ),
862                }
863            ),
864            signed(
865                &[
866                    (2 << 4) | 0,
867                    (2 << 4) | 2,
868                    0,
869                    36,
870                    0,
871                    1,
872                    0,
873                    2,
874                    0,
875                    3,
876                    0,
877                    4,
878                    0,
879                    5,
880                    0,
881                    6,
882                    0,
883                    7,
884                    0,
885                    8,
886                    255,
887                    255,
888                    255,
889                    255,
890                    (32767u16 >> 8) as u8,
891                    32767u16 as u8,
892                    (32766u16 >> 8) as u8,
893                    32766u16 as u8,
894                    0,
895                    111,
896                    0,
897                    222,
898                    (333u16 >> 8) as u8,
899                    333u16 as u8,
900                    (444u16 >> 8) as u8,
901                    444u16 as u8,
902                    (8192u16 >> 8) as u8,
903                    8192u16 as u8,
904                    0,
905                    0,
906                ][..]
907            ),
908        );
909    }
910}