1#![forbid(unsafe_code)]
10#![warn(rust_2018_idioms)]
11#![warn(clippy::all)]
12
13pub mod version1;
14pub mod version2;
15
16use bytes::{Buf, BytesMut};
17use snafu::{ensure, ResultExt as _, Snafu};
18
19#[derive(Debug, Snafu)]
20#[cfg_attr(not(feature = "always_exhaustive"), non_exhaustive)] #[cfg_attr(test, derive(PartialEq, Eq))]
22pub enum ParseError {
23 #[snafu(display("the given data is not a PROXY header"))]
25 NotProxyHeader,
26
27 #[snafu(display("the version {} is invalid", version))]
29 InvalidVersion { version: u32 },
30
31 #[snafu(display("there was an error while parsing the v1 header: {}", source))]
33 Version1 { source: version1::ParseError },
34
35 #[snafu(display("there was an error while parsing the v2 header: {}", source))]
37 Version2 { source: version2::ParseError },
38}
39
40#[derive(Debug, Snafu)]
41#[cfg_attr(not(feature = "always_exhaustive"), non_exhaustive)] pub enum EncodeError {
43 #[snafu(display("there was an error while encoding the v1 header: {}", source))]
45 WriteVersion1 { source: version1::EncodeError },
46}
47
48#[derive(Debug, Clone, PartialEq, Eq)]
50#[cfg_attr(not(feature = "always_exhaustive"), non_exhaustive)] pub enum ProxyHeader {
52 Version1 {
56 addresses: version1::ProxyAddresses,
58 },
59
60 Version2 {
65 command: version2::ProxyCommand,
67
68 transport_protocol: version2::ProxyTransportProtocol,
70
71 addresses: version2::ProxyAddresses,
73 },
74}
75
76fn parse_version(buf: &mut impl Buf) -> Result<u32, ParseError> {
77 ensure!(buf.remaining() >= 6, NotProxyHeader);
79
80 if buf.chunk()[..6] == [b'P', b'R', b'O', b'X', b'Y', b' '] {
85 buf.advance(6);
86 return Ok(1);
87 }
88
89 ensure!(buf.remaining() >= 13, NotProxyHeader);
91 ensure!(
92 buf.chunk()[..12]
93 == [0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A],
94 NotProxyHeader
95 );
96 buf.advance(12);
97
98 let version = buf.chunk()[0];
104
105 let version = version >> 4;
113
114 if version == 1 {
116 return InvalidVersion { version: 1u32 }.fail();
117 }
118
119 Ok(version as u32)
120}
121
122pub fn parse(buf: &mut impl Buf) -> Result<ProxyHeader, ParseError> {
128 let version = match parse_version(buf) {
129 Ok(ver) => ver,
130 Err(e) => return Err(e),
131 };
132
133 Ok(match version {
134 1 => self::version1::parse(buf).context(Version1)?,
135 2 => self::version2::parse(buf).context(Version2)?,
136 _ => return InvalidVersion { version }.fail(),
137 })
138}
139
140pub fn encode(header: ProxyHeader) -> Result<BytesMut, EncodeError> {
145 Ok(match header {
146 ProxyHeader::Version1 { addresses, .. } => {
147 version1::encode(addresses).context(WriteVersion1)?
148 }
149 ProxyHeader::Version2 {
150 command,
151 transport_protocol,
152 addresses,
153 } => version2::encode(command, transport_protocol, addresses),
154
155 #[allow(unreachable_patterns)] _ => unimplemented!("Unimplemented version?"),
157 })
158}
159
160#[cfg(test)]
161mod parse_tests {
162 use super::*;
163 use crate::ProxyHeader;
164 use bytes::Bytes;
165 use pretty_assertions::assert_eq;
166 use rand::prelude::*;
167 use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
168
169 #[test]
170 fn test_version1() {
171 let unknown = Ok(ProxyHeader::Version1 {
172 addresses: version1::ProxyAddresses::Unknown,
173 });
174 assert_eq!(parse(&mut &b"PROXY UNKNOWN\r\n"[..]), unknown);
175 assert_eq!(
176 parse(&mut &b"PROXY UNKNOWN this is bogus data!\r\r\r\n"[..]),
177 unknown,
178 );
179 assert_eq!(
180 parse(&mut &b"PROXY UNKNOWN 192.168.0.1 192.168.1.1 123 321\r\n"[..]),
181 unknown,
182 );
183
184 let mut random = [0u8; 128];
185 rand::thread_rng().fill_bytes(&mut random);
186 let mut header = b"PROXY UNKNOWN ".to_vec();
187 header.extend(&random[..]);
188 header.extend(b"\r\n");
189 let mut buf = Bytes::from(header);
190 assert_eq!(parse(&mut buf), unknown);
191 assert!(!buf.has_remaining()); fn valid_v4(
194 (a, b, c, d): (u8, u8, u8, u8),
195 e: u16,
196 (f, g, h, i): (u8, u8, u8, u8),
197 j: u16,
198 ) -> ProxyHeader {
199 ProxyHeader::Version1 {
200 addresses: version1::ProxyAddresses::Ipv4 {
201 source: SocketAddrV4::new(Ipv4Addr::new(a, b, c, d), e),
202 destination: SocketAddrV4::new(Ipv4Addr::new(f, g, h, i), j),
203 },
204 }
205 }
206
207 assert_eq!(
208 parse(&mut &b"PROXY TCP4 192.168.201.102 1.2.3.4 0 65535\r\n"[..]),
209 Ok(valid_v4((192, 168, 201, 102), 0, (1, 2, 3, 4), 65535)),
210 );
211 assert_eq!(
212 parse(&mut &b"PROXY TCP4 0.0.0.0 0.0.0.0 0 0\r\n"[..]),
213 Ok(valid_v4((0, 0, 0, 0), 0, (0, 0, 0, 0), 0)),
214 );
215 assert_eq!(
216 parse(&mut &b"PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"[..]),
217 Ok(valid_v4(
218 (255, 255, 255, 255),
219 65535,
220 (255, 255, 255, 255),
221 65535,
222 )),
223 );
224
225 fn valid_v6(
226 (a, b, c, d, e, f, g, h): (u16, u16, u16, u16, u16, u16, u16, u16),
227 i: u16,
228 (j, k, l, m, n, o, p, q): (u16, u16, u16, u16, u16, u16, u16, u16),
229 r: u16,
230 ) -> ProxyHeader {
231 ProxyHeader::Version1 {
232 addresses: version1::ProxyAddresses::Ipv6 {
233 source: SocketAddrV6::new(Ipv6Addr::new(a, b, c, d, e, f, g, h), i, 0, 0),
234 destination: SocketAddrV6::new(Ipv6Addr::new(j, k, l, m, n, o, p, q), r, 0, 0),
235 },
236 }
237 }
238 assert_eq!(
239 parse(&mut &b"PROXY TCP6 ab:ce:ef:01:23:45:67:89 ::1 0 65535\r\n"[..]),
240 Ok(valid_v6(
241 (0xAB, 0xCE, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89),
242 0,
243 (0, 0, 0, 0, 0, 0, 0, 1),
244 65535,
245 )),
246 );
247 assert_eq!(
248 parse(&mut &b"PROXY TCP6 :: :: 0 0\r\n"[..]),
249 Ok(valid_v6(
250 (0, 0, 0, 0, 0, 0, 0, 0),
251 0,
252 (0, 0, 0, 0, 0, 0, 0, 0),
253 0,
254 )),
255 );
256 assert_eq!(
257 parse(
258 &mut &b"PROXY TCP6 ff:ff:ff:ff:ff:ff:ff:ff ff:ff:ff:ff:ff:ff:ff:ff 65535 65535\r\n"
259 [..],
260 ),
261 Ok(valid_v6(
262 (0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF),
263 65535,
264 (0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF),
265 65535,
266 )),
267 );
268
269 assert_eq!(
270 parse(&mut &b"PROXY UNKNOWN \r"[..]),
271 Err(ParseError::Version1 {
272 source: version1::ParseError::UnexpectedEof,
273 }),
274 );
275 assert_eq!(
276 parse(&mut &b"PROXY UNKNOWN \r\t\t\r"[..]),
277 Err(ParseError::Version1 {
278 source: version1::ParseError::UnexpectedEof,
279 }),
280 );
281 assert_eq!(
282 parse(&mut &b"PROXY UNKNOWN\r\r\r\r\rHello, world!"[..]),
283 Err(ParseError::Version1 {
284 source: version1::ParseError::UnexpectedEof,
285 }),
286 );
287 assert_eq!(
288 parse(&mut &b"PROXY UNKNOWN\nGET /index.html HTTP/1.0"[..]),
289 Err(ParseError::Version1 {
290 source: version1::ParseError::UnexpectedEof,
291 }),
292 );
293 assert_eq!(
294 parse(&mut &b"PROXY UNKNOWN\n"[..]),
295 Err(ParseError::Version1 {
296 source: version1::ParseError::UnexpectedEof,
297 }),
298 );
299 }
300
301 #[test]
302 fn test_version2() {
303 const PREFIX_LOCAL: [u8; 13] = [
304 0x0D,
305 0x0A,
306 0x0D,
307 0x0A,
308 0x00,
309 0x0D,
310 0x0A,
311 0x51,
312 0x55,
313 0x49,
314 0x54,
315 0x0A,
316 (2 << 4) | 0,
317 ];
318 const PREFIX_PROXY: [u8; 13] = [
319 0x0D,
320 0x0A,
321 0x0D,
322 0x0A,
323 0x00,
324 0x0D,
325 0x0A,
326 0x51,
327 0x55,
328 0x49,
329 0x54,
330 0x0A,
331 (2 << 4) | 1,
332 ];
333
334 assert_eq!(
335 parse(&mut [&PREFIX_LOCAL[..], &[0u8; 16][..]].concat().as_slice()),
336 Ok(ProxyHeader::Version2 {
337 command: version2::ProxyCommand::Local,
338 addresses: version2::ProxyAddresses::Unspec,
339 transport_protocol: version2::ProxyTransportProtocol::Unspec,
340 }),
341 );
342 assert_eq!(
343 parse(&mut [&PREFIX_PROXY[..], &[0u8; 16][..]].concat().as_slice()),
344 Ok(ProxyHeader::Version2 {
345 command: version2::ProxyCommand::Proxy,
346 addresses: version2::ProxyAddresses::Unspec,
347 transport_protocol: version2::ProxyTransportProtocol::Unspec,
348 }),
349 );
350
351 assert_eq!(
352 parse(
353 &mut [
354 &PREFIX_PROXY[..],
355 &[
356 (1 << 4) | 1,
358 0,
361 15,
362 127,
364 0,
365 0,
366 1,
367 192,
369 168,
370 0,
371 1,
372 255,
375 255,
376 1,
379 1,
380 69,
382 0,
383 0,
384 ][..]
385 ]
386 .concat()
387 .as_slice(),
388 ),
389 Ok(ProxyHeader::Version2 {
390 command: version2::ProxyCommand::Proxy,
391 transport_protocol: version2::ProxyTransportProtocol::Stream,
392 addresses: version2::ProxyAddresses::Ipv4 {
393 source: SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 65535),
394 destination: SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 257),
395 },
396 })
397 );
398
399 let mut data = Bytes::from(
400 [
401 &PREFIX_LOCAL[..],
402 &[
403 (1 << 4) | 2,
405 0,
407 12,
408 0,
410 0,
411 0,
412 0,
413 255,
415 255,
416 255,
417 255,
418 0,
420 0,
421 255,
423 0,
424 1,
426 2,
427 3,
428 4,
429 ][..],
430 ]
431 .concat(),
432 );
433 assert_eq!(
434 parse(&mut data),
435 Ok(ProxyHeader::Version2 {
436 command: version2::ProxyCommand::Local,
437 transport_protocol: version2::ProxyTransportProtocol::Datagram,
438 addresses: version2::ProxyAddresses::Ipv4 {
439 source: SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0),
440 destination: SocketAddrV4::new(Ipv4Addr::new(255, 255, 255, 255), 255 << 8),
441 },
442 })
443 );
444 assert!(data.remaining() == 4); assert_eq!(
447 parse(
448 &mut [
449 &PREFIX_PROXY[..],
450 &[
451 (2 << 4) | 2,
453 0,
456 39,
457 255,
459 255,
460 255,
461 255,
462 255,
463 255,
464 255,
465 255,
466 255,
467 255,
468 255,
469 255,
470 255,
471 255,
472 255,
473 255,
474 0,
476 0,
477 0,
478 0,
479 0,
480 0,
481 0,
482 0,
483 0,
484 0,
485 0,
486 0,
487 0,
488 0,
489 0,
490 0,
491 255,
494 255,
495 1,
498 1,
499 69,
501 0,
502 0,
503 ][..],
504 ]
505 .concat()
506 .as_slice(),
507 ),
508 Ok(ProxyHeader::Version2 {
509 command: version2::ProxyCommand::Proxy,
510 transport_protocol: version2::ProxyTransportProtocol::Datagram,
511 addresses: version2::ProxyAddresses::Ipv6 {
512 source: SocketAddrV6::new(
513 Ipv6Addr::new(65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535),
514 65535,
515 0,
516 0,
517 ),
518 destination: SocketAddrV6::new(
519 Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0),
520 257,
521 0,
522 0,
523 )
524 },
525 })
526 );
527
528 let mut data = Bytes::from(
529 [
530 &PREFIX_LOCAL[..],
531 &[
532 (2 << 4) | 1,
534 0,
536 36,
537 81,
539 92,
540 0,
541 52,
542 83,
543 12,
544 255,
545 68,
546 19,
547 5,
548 111,
549 200,
550 54,
551 90,
552 55,
553 66,
554 255,
556 255,
557 255,
558 255,
559 0,
560 0,
561 0,
562 0,
563 123,
564 123,
565 69,
566 69,
567 21,
568 21,
569 42,
570 42,
571 123,
573 0,
574 255,
576 255,
577 1,
579 2,
580 3,
581 4,
582 ][..],
583 ]
584 .concat(),
585 );
586 assert_eq!(
587 parse(&mut data),
588 Ok(ProxyHeader::Version2 {
589 command: version2::ProxyCommand::Local,
590 transport_protocol: version2::ProxyTransportProtocol::Stream,
591 addresses: version2::ProxyAddresses::Ipv6 {
592 source: SocketAddrV6::new(
593 Ipv6Addr::new(20828, 52, 21260, 65348, 4869, 28616, 13914, 14146),
594 31488,
595 0,
596 0,
597 ),
598 destination: SocketAddrV6::new(
599 Ipv6Addr::new(65535, 65535, 0, 0, 31611, 17733, 5397, 10794),
600 65535,
601 0,
602 0,
603 ),
604 },
605 })
606 );
607 assert!(data.remaining() == 4); let mut data = [0u8; 200];
610 rand::thread_rng().fill_bytes(&mut data);
611 data[0] = 99; assert!(parse(&mut &data[..]).is_err());
613
614 assert_eq!(
615 parse(&mut &PREFIX_LOCAL[..]),
616 Err(ParseError::Version2 {
617 source: version2::ParseError::UnexpectedEof,
618 }),
619 );
620
621 assert_eq!(
622 parse(
623 &mut [
624 &PREFIX_PROXY[..],
625 &[
626 (1 << 4) | 1,
628 0,
631 3,
632 ][..],
633 ]
634 .concat()
635 .as_slice(),
636 ),
637 Err(ParseError::Version2 {
638 source: version2::ParseError::InsufficientLengthSpecified {
639 given: 3,
640 needs: 4 * 2 + 2 * 2,
641 },
642 }),
643 );
644 }
645
646 #[test]
647 fn test_unknown_version() {
648 assert_eq!(
649 parse_version(
650 &mut &[
651 0x0D,
652 0x0A,
653 0x0D,
654 0x0A,
655 0x00,
656 0x0D,
657 0x0A,
658 0x51,
659 0x55,
660 0x49,
661 0x54,
662 0x0A,
663 1 << 4, ][..],
665 ),
666 Err(ParseError::InvalidVersion { version: 1 }),
667 );
668 }
669
670 #[test]
671 fn test_version_parsing_correct() {
672 assert_eq!(
673 parse_version(&mut &[b'P', b'R', b'O', b'X', b'Y', b' '][..]),
674 Ok(1),
675 );
676 assert_eq!(
677 parse_version(
678 &mut &[
679 0x0D,
680 0x0A,
681 0x0D,
682 0x0A,
683 0x00,
684 0x0D,
685 0x0A,
686 0x51,
687 0x55,
688 0x49,
689 0x54,
690 0x0A,
691 15 << 4, ][..],
693 ),
694 Ok(15),
695 );
696 }
697
698 #[test]
699 fn test_version_parsing_errors() {
700 assert_eq!(
701 parse_version(&mut &b"Proximyst"[..]),
702 Err(ParseError::NotProxyHeader)
703 );
704 }
705}