sozu_lib/protocol/proxy_protocol/
parser.rs

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