Skip to main content

sozu_lib/protocol/proxy_protocol/
parser.rs

1//! PROXY-v2 wire parser.
2//!
3//! Decodes the 12-byte PROXY-v2 signature plus the variable address block
4//! defined by the HAProxy PROXY protocol specification. Returns a
5//! `HeaderV2` to the caller (`expect.rs` / `relay.rs`); rejects malformed
6//! framing through `nom::Err` so the session can close cleanly. No I/O.
7
8use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
9
10use nom::{
11    Err, IResult,
12    bytes::streaming::{tag, take},
13    error::{Error, ErrorKind, ParseError},
14    number::streaming::{be_u8, be_u16},
15};
16
17use crate::protocol::proxy_protocol::header::{Command, HeaderV2, ProxyAddr};
18
19const PROTOCOL_SIGNATURE_V2: [u8; 12] = [
20    0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A,
21];
22
23fn parse_command(i: &[u8]) -> IResult<&[u8], Command> {
24    let i2 = i;
25    let (i, cmd) = be_u8(i)?;
26    match cmd {
27        0x20 => Ok((i, Command::Local)),
28        0x21 => Ok((i, Command::Proxy)),
29        _ => Err(Err::Error(Error::from_error_kind(i2, ErrorKind::Switch))),
30    }
31}
32
33pub fn parse_v2_header(i: &[u8]) -> IResult<&[u8], HeaderV2> {
34    let (i, _) = tag(&PROTOCOL_SIGNATURE_V2)(i)?;
35    let (i, command) = parse_command(i)?;
36    let (i, family) = be_u8(i)?;
37    let (i, len) = be_u16(i)?;
38    let (i, data) = take(len)(i)?;
39    let (_, addr) = parse_addr_v2(family)(data)?;
40
41    Ok((
42        i,
43        (HeaderV2 {
44            command,
45            family,
46            addr,
47        }),
48    ))
49}
50
51fn parse_addr_v2(family: u8) -> impl Fn(&[u8]) -> IResult<&[u8], ProxyAddr> {
52    move |i: &[u8]| match (family >> 4) & 0x0f {
53        0x00 => Ok((i, ProxyAddr::AfUnspec)),
54        0x01 => parse_ipv4_on_v2(i),
55        0x02 => parse_ipv6_on_v2(i),
56        _ => Err(Err::Error(Error::from_error_kind(i, ErrorKind::Switch))),
57    }
58}
59
60fn parse_ipv4_on_v2(i: &[u8]) -> IResult<&[u8], ProxyAddr> {
61    let (i, src_ip) = take(4u8)(i)?;
62    let (i, dest_ip) = take(4u8)(i)?;
63    let (i, src_port) = be_u16(i)?;
64    let (i, dest_port) = be_u16(i)?;
65
66    Ok((
67        i,
68        ProxyAddr::Ipv4Addr {
69            src_addr: SocketAddrV4::new(
70                Ipv4Addr::new(src_ip[0], src_ip[1], src_ip[2], src_ip[3]),
71                src_port,
72            ),
73            dst_addr: SocketAddrV4::new(
74                Ipv4Addr::new(dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3]),
75                dest_port,
76            ),
77        },
78    ))
79}
80
81fn parse_ipv6_on_v2(i: &[u8]) -> IResult<&[u8], ProxyAddr> {
82    let (i, src_ip) = take(16u8)(i)?;
83    let (i, dest_ip) = take(16u8)(i)?;
84    let (i, src_port) = be_u16(i)?;
85    let (i, dest_port) = be_u16(i)?;
86
87    Ok((
88        i,
89        ProxyAddr::Ipv6Addr {
90            src_addr: SocketAddrV6::new(slice_to_ipv6(src_ip), src_port, 0, 0),
91            dst_addr: SocketAddrV6::new(slice_to_ipv6(dest_ip), dest_port, 0, 0),
92        },
93    ))
94}
95
96// assumes the slice has 16 bytes
97pub fn slice_to_ipv6(sl: &[u8]) -> Ipv6Addr {
98    let mut arr: [u8; 16] = [0; 16];
99    arr.clone_from_slice(sl);
100    Ipv6Addr::from(arr)
101}
102
103#[cfg(test)]
104mod test {
105
106    use std::net::{IpAddr, SocketAddr};
107
108    use nom::{Err, Needed};
109
110    use super::*;
111
112    #[test]
113    fn test_parse_proxy_protocol_v2_local_ipv4_addr_header() {
114        let input = &[
115            0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54,
116            0x0A, // MAGIC header
117            0x20, // Version 2 and command LOCAL
118            0x11, // family AF_UNIX with IPv4
119            0x00, 0x0C, // address sizes = 12
120            0x7D, 0x19, 0x0A, 0x01, // source address
121            0x0A, 0x04, 0x05, 0x08, // destination address
122            0x1F, 0x90, // source port
123            0x10, 0x68, // destination port
124        ];
125
126        let src_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(125, 25, 10, 1)), 8080);
127        let dst_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 4, 5, 8)), 4200);
128        let expected = HeaderV2::new(Command::Local, src_addr, dst_addr);
129
130        assert_eq!(Ok((&[][..], expected)), parse_v2_header(input));
131    }
132
133    #[test]
134    fn test_parse_proxy_protocol_v2_proxy_ipv4_addr_header() {
135        let input = &[
136            0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54,
137            0x0A, // MAGIC header
138            0x21, // Version 2 and command LOCAL
139            0x11, // family AF_UNIX with IPv4
140            0x00, 0x0C, // address sizes = 12
141            0x7D, 0x19, 0x0A, 0x01, // source address
142            0x0A, 0x04, 0x05, 0x08, // destination address
143            0x1F, 0x90, // source port
144            0x10, 0x68, // destination port
145        ];
146
147        let src_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(125, 25, 10, 1)), 8080);
148        let dst_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 4, 5, 8)), 4200);
149        let expected = HeaderV2::new(Command::Proxy, src_addr, dst_addr);
150
151        assert_eq!(Ok((&[][..], expected)), parse_v2_header(input));
152    }
153
154    #[test]
155    fn it_should_parse_proxy_protocol_v2_ipv6_addr_header() {
156        let input = &[
157            0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54,
158            0x0A, // MAGIC header
159            0x20, // Version 2 and command LOCAL
160            0x21, // family AF_UNIX with IPv6
161            0x00, 0x24, // address sizes = 36
162            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
163            0x00, 0x01, // source address
164            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165            0x00, 0x02, // destination address
166            0x1F, 0x90, // source port
167            0x10, 0x68, // destination port
168        ];
169
170        let src_addr = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 8080);
171        let dst_addr = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 2)), 4200);
172        let expected = HeaderV2::new(Command::Local, src_addr, dst_addr);
173
174        assert_eq!(Ok((&[][..], expected)), parse_v2_header(input));
175    }
176
177    #[test]
178    fn it_should_parse_proxy_protocol_v2_afunspec_header() {
179        let input = &[
180            0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54,
181            0x0A, // MAGIC header
182            0x20, // Version 2 and command LOCAL
183            0x00, // family AF_UNSPEC and transport protocol unknown
184            0x00, 0x00, // address sizes = 0
185        ];
186
187        let expected = HeaderV2 {
188            command: Command::Local,
189            family: 0,
190            addr: ProxyAddr::AfUnspec,
191        };
192
193        assert_eq!(Ok((&[][..], expected)), parse_v2_header(input));
194    }
195
196    #[test]
197    fn it_should_not_parse_proxy_protocol_v2_with_unknown_version() {
198        let unknow_version = 0x30;
199
200        let input = &[
201            0x0D,
202            0x0A,
203            0x0D,
204            0x0A,
205            0x00,
206            0x0D,
207            0x0A,
208            0x51,
209            0x55,
210            0x49,
211            0x54,
212            0x0A,           // MAGIC header
213            unknow_version, // invalid version
214        ];
215
216        assert!(parse_v2_header(input).is_err());
217    }
218
219    #[test]
220    fn it_should_not_parse_proxy_protocol_v2_with_unknown_command() {
221        let unknow_command = 0x23;
222
223        let input = &[
224            0x0D,
225            0x0A,
226            0x0D,
227            0x0A,
228            0x00,
229            0x0D,
230            0x0A,
231            0x51,
232            0x55,
233            0x49,
234            0x54,
235            0x0A,           // MAGIC header
236            unknow_command, // Version 2 and invalid command
237        ];
238
239        assert!(parse_v2_header(input).is_err());
240    }
241
242    #[test]
243    fn it_should_not_parse_proxy_protocol_with_unknown_family() {
244        let unknow_family = 0x30;
245
246        let input = &[
247            0x0D,
248            0x0A,
249            0x0D,
250            0x0A,
251            0x00,
252            0x0D,
253            0x0A,
254            0x51,
255            0x55,
256            0x49,
257            0x54,
258            0x0A,          // MAGIC header
259            0x20,          // Version 2 and command LOCAL
260            unknow_family, // family
261            0x00,
262            0x00, // address sizes = 0
263        ];
264
265        assert!(parse_v2_header(input).is_err());
266    }
267
268    #[test]
269    fn it_should_not_parse_request_without_magic_header() {
270        let input = &[
271            0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D,
272            0x0D, // INCORRECT MAGIC header
273        ];
274
275        assert!(parse_v2_header(input).is_err());
276    }
277
278    #[test]
279    fn it_should_not_parse_proxy_protocol_v2_ipv4_addr_header_with_missing_data() {
280        let input = &[
281            0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54,
282            0x0A, // MAGIC header
283            0x20, // Version 2 and command LOCAL
284            0x11, // family AF_UNIX with IPv4
285        ];
286
287        assert_eq!(Err(Err::Incomplete(Needed::new(2))), parse_v2_header(input));
288    }
289
290    #[test]
291    fn it_should_not_parse_proxy_protocol_v2_with_invalid_length() {
292        let input = &[
293            0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54,
294            0x0A, // MAGIC header
295            0x20, // Version 2 and command LOCAL
296            0x21, // family AF_UNIX with IPv6
297            0x00, 0x10, // address sizes = 36
298            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299            0x00, 0x01, // source address
300            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301            0x00, 0x02, // destination address
302            0x1F, 0x90, // source port
303            0x10, 0x68, // destination port
304        ];
305
306        assert_eq!(
307            Err(Err::Incomplete(Needed::new(16))),
308            parse_v2_header(input)
309        );
310    }
311}