Skip to main content

sozu_lib/protocol/proxy_protocol/
header.rs

1//! PROXY protocol v1 / v2 header model.
2//!
3//! Owns the `ProxyProtocolHeader` enum, the `into_bytes` serializers for
4//! both wire versions, and the address helpers (`ProxyAddr`,
5//! `ProtocolSupportedV1`, `Command`, `HeaderV1`, `HeaderV2`) shared by the
6//! `expect`, `relay`, and `send` roles. No I/O here; pure data shapes.
7
8use std::{
9    fmt,
10    net::{SocketAddr, SocketAddrV4, SocketAddrV6},
11};
12
13#[derive(PartialEq, Debug)]
14pub enum ProxyProtocolHeader {
15    V1(HeaderV1),
16    V2(HeaderV2),
17}
18
19impl ProxyProtocolHeader {
20    // Use this method to writte the header in the backend socket
21    pub fn into_bytes(&self) -> Vec<u8> {
22        match *self {
23            ProxyProtocolHeader::V1(ref header) => header.into_bytes(),
24            ProxyProtocolHeader::V2(ref header) => header.into_bytes(),
25        }
26    }
27}
28
29/// Indicate the proxied INET protocol and family
30#[derive(Debug, PartialEq, Eq)]
31pub enum ProtocolSupportedV1 {
32    TCP4,    // TCP over IPv4
33    TCP6,    // TCP over IPv6
34    UNKNOWN, // unsupported,or unknown protocols
35}
36
37impl fmt::Display for ProtocolSupportedV1 {
38    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39        match *self {
40            ProtocolSupportedV1::TCP4 => write!(f, "TCP4"),
41            ProtocolSupportedV1::TCP6 => write!(f, "TCP6"),
42            ProtocolSupportedV1::UNKNOWN => write!(f, "UNKNOWN"),
43        }
44    }
45}
46
47/// WARNING: proxy protocol v1 is never used in Sōzu, only v2.
48/// The tests have been commented out, the whole code may be meant for deletion.
49///
50/// Proxy Protocol header for version 1 (text version)
51/// Example:
52/// - TCP/IPv4: `PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n`
53/// - TCP/IPv6: `PROXY TCP6 ffff:f...f:ffff ffff:f...f:ffff 65535 65535\r\n`
54/// - Unknown: `PROXY UNKNOWN\r\n`
55#[derive(Debug, PartialEq, Eq)]
56pub struct HeaderV1 {
57    pub protocol: ProtocolSupportedV1,
58    pub addr_src: SocketAddr,
59    pub addr_dst: SocketAddr,
60}
61
62const PROXY_PROTO_IDENTIFIER: &str = "PROXY";
63
64impl HeaderV1 {
65    pub fn new(addr_src: SocketAddr, addr_dst: SocketAddr) -> Self {
66        let protocol = if addr_dst.is_ipv6() {
67            ProtocolSupportedV1::TCP6
68        } else if addr_dst.is_ipv4() {
69            ProtocolSupportedV1::TCP4
70        } else {
71            ProtocolSupportedV1::UNKNOWN
72        };
73
74        HeaderV1 {
75            protocol,
76            addr_src,
77            addr_dst,
78        }
79    }
80
81    pub fn into_bytes(&self) -> Vec<u8> {
82        if self.protocol.eq(&ProtocolSupportedV1::UNKNOWN) {
83            format!("{} {}\r\n", PROXY_PROTO_IDENTIFIER, self.protocol,).into_bytes()
84        } else {
85            format!(
86                "{} {} {} {} {} {}\r\n",
87                PROXY_PROTO_IDENTIFIER,
88                self.protocol,
89                self.addr_src.ip(),
90                self.addr_dst.ip(),
91                self.addr_src.port(),
92                self.addr_dst.port(),
93            )
94            .into_bytes()
95        }
96    }
97}
98
99/*
100#[cfg(test)]
101mod test {
102
103    use super::*;
104    use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
105
106    #[test]
107    fn it_should_return_a_correct_header_with_ipv4() {
108        let header = HeaderV1::new(
109            SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 80),
110            SocketAddr::new(IpAddr::V4(Ipv4Addr::new(172, 17, 40, 59)), 80),
111        );
112
113        let header_to_cmp = "PROXY TCP4 127.0.0.1 172.17.40.59 80 80\r\n".as_bytes();
114
115        assert_eq!(header_to_cmp, &header.into_bytes()[..]);
116    }
117
118    #[test]
119    fn it_should_return_a_correct_header_with_ipv6() {
120        let header = HeaderV1::new(
121            SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0xffff)), 80),
122            SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x9c, 0x76)), 80),
123        );
124
125        let header_to_cmp = "PROXY TCP6 ::ffff ::9c:76 80 80\r\n".as_bytes();
126
127        assert_eq!(header_to_cmp, &header.into_bytes()[..]);
128    }
129}
130*/
131
132#[derive(Debug, PartialEq, Eq)]
133pub enum Command {
134    Local,
135    Proxy,
136}
137
138#[derive(Debug, PartialEq)]
139pub struct HeaderV2 {
140    pub command: Command,
141    pub family: u8, // protocol family and address
142    pub addr: ProxyAddr,
143}
144
145impl HeaderV2 {
146    pub fn new(command: Command, addr_src: SocketAddr, addr_dst: SocketAddr) -> Self {
147        let addr = ProxyAddr::from(addr_src, addr_dst);
148
149        HeaderV2 {
150            command,
151            family: get_family(&addr),
152            addr,
153        }
154    }
155
156    pub fn into_bytes(&self) -> Vec<u8> {
157        let mut header = Vec::with_capacity(self.len());
158
159        let signature = [
160            0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A,
161        ];
162        header.extend_from_slice(&signature);
163
164        let command = match self.command {
165            Command::Local => 0,
166            Command::Proxy => 1,
167        };
168        let ver_and_cmd = 0x20 | command;
169        header.push(ver_and_cmd);
170
171        header.push(self.family);
172        header.extend_from_slice(&u16_to_array_of_u8(self.addr.len()));
173        self.addr.write_bytes_to(&mut header);
174        header
175    }
176
177    pub fn len(&self) -> usize {
178        // signature + ver_and_cmd + family + len + addr
179        12 + 1 + 1 + 2 + self.addr.len() as usize
180    }
181
182    pub fn is_empty(&self) -> bool {
183        0 == self.len()
184    }
185}
186
187pub enum ProxyAddr {
188    Ipv4Addr {
189        src_addr: SocketAddrV4,
190        dst_addr: SocketAddrV4,
191    },
192    Ipv6Addr {
193        src_addr: SocketAddrV6,
194        dst_addr: SocketAddrV6,
195    },
196    UnixAddr {
197        src_addr: [u8; 108],
198        dst_addr: [u8; 108],
199    },
200    AfUnspec,
201}
202
203impl ProxyAddr {
204    pub fn from(addr_src: SocketAddr, addr_dst: SocketAddr) -> Self {
205        match (addr_src, addr_dst) {
206            (SocketAddr::V4(addr_ipv4_src), SocketAddr::V4(addr_ipv4_dst)) => ProxyAddr::Ipv4Addr {
207                src_addr: addr_ipv4_src,
208                dst_addr: addr_ipv4_dst,
209            },
210            (SocketAddr::V6(addr_ipv6_src), SocketAddr::V6(addr_ipv6_dst)) => ProxyAddr::Ipv6Addr {
211                src_addr: addr_ipv6_src,
212                dst_addr: addr_ipv6_dst,
213            },
214            _ => ProxyAddr::AfUnspec,
215        }
216    }
217
218    fn len(&self) -> u16 {
219        match *self {
220            ProxyAddr::Ipv4Addr { .. } => 12,
221            ProxyAddr::Ipv6Addr { .. } => 36,
222            ProxyAddr::UnixAddr { .. } => 216,
223            ProxyAddr::AfUnspec => 0,
224        }
225    }
226
227    pub fn source(&self) -> Option<SocketAddr> {
228        match self {
229            ProxyAddr::Ipv4Addr { src_addr: src, .. } => Some(SocketAddr::V4(*src)),
230            ProxyAddr::Ipv6Addr { src_addr: src, .. } => Some(SocketAddr::V6(*src)),
231            _ => None,
232        }
233    }
234
235    pub fn destination(&self) -> Option<SocketAddr> {
236        match self {
237            ProxyAddr::Ipv4Addr { dst_addr: dst, .. } => Some(SocketAddr::V4(*dst)),
238            ProxyAddr::Ipv6Addr { dst_addr: dst, .. } => Some(SocketAddr::V6(*dst)),
239            _ => None,
240        }
241    }
242
243    // TODO: rename to a less ambiguous name, like "write bytes to buffer"
244    fn write_bytes_to(&self, buf: &mut Vec<u8>) {
245        match *self {
246            ProxyAddr::Ipv4Addr { src_addr, dst_addr } => {
247                buf.extend_from_slice(&src_addr.ip().octets());
248                buf.extend_from_slice(&dst_addr.ip().octets());
249                buf.extend_from_slice(&u16_to_array_of_u8(src_addr.port()));
250                buf.extend_from_slice(&u16_to_array_of_u8(dst_addr.port()));
251            }
252            ProxyAddr::Ipv6Addr { src_addr, dst_addr } => {
253                buf.extend_from_slice(&src_addr.ip().octets());
254                buf.extend_from_slice(&dst_addr.ip().octets());
255                buf.extend_from_slice(&u16_to_array_of_u8(src_addr.port()));
256                buf.extend_from_slice(&u16_to_array_of_u8(dst_addr.port()));
257            }
258            ProxyAddr::UnixAddr { src_addr, dst_addr } => {
259                buf.extend_from_slice(&src_addr);
260                buf.extend_from_slice(&dst_addr);
261            }
262            ProxyAddr::AfUnspec => {}
263        };
264    }
265}
266
267// Implemented because we don't have the Debug for [u8; 108] (UnixAddr case)
268impl fmt::Debug for ProxyAddr {
269    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
270        match *self {
271            ProxyAddr::Ipv4Addr { src_addr, dst_addr } => {
272                write!(f, "{dst_addr:?} {src_addr:?}")
273            }
274            ProxyAddr::Ipv6Addr { src_addr, dst_addr } => {
275                write!(f, "{dst_addr:?} {src_addr:?}")
276            }
277            ProxyAddr::UnixAddr { src_addr, dst_addr } => {
278                write!(f, "{:?} {:?}", &dst_addr[..], &src_addr[..])
279            }
280            ProxyAddr::AfUnspec => write!(f, "AFUNSPEC"),
281        }
282    }
283}
284
285// Implemented because we don't have the PartialEq for [u8; 108] (UnixAddr case)
286impl PartialEq for ProxyAddr {
287    fn eq(&self, other: &ProxyAddr) -> bool {
288        match *self {
289            ProxyAddr::Ipv4Addr { src_addr, dst_addr } => match other {
290                ProxyAddr::Ipv4Addr {
291                    src_addr: src_other,
292                    dst_addr: dst_other,
293                } => *src_other == src_addr && *dst_other == dst_addr,
294                _ => false,
295            },
296            ProxyAddr::Ipv6Addr { src_addr, dst_addr } => match other {
297                ProxyAddr::Ipv6Addr {
298                    src_addr: src_other,
299                    dst_addr: dst_other,
300                } => *src_other == src_addr && *dst_other == dst_addr,
301                _ => false,
302            },
303            ProxyAddr::UnixAddr { src_addr, dst_addr } => match other {
304                ProxyAddr::UnixAddr {
305                    src_addr: src_other,
306                    dst_addr: dst_other,
307                } => src_other[..] == src_addr[..] && dst_other[..] == dst_addr[..],
308                _ => false,
309            },
310            ProxyAddr::AfUnspec => {
311                if let ProxyAddr::AfUnspec = other {
312                    return true;
313                }
314                false
315            }
316        }
317    }
318}
319
320fn get_family(addr: &ProxyAddr) -> u8 {
321    match *addr {
322        ProxyAddr::Ipv4Addr { .. } => 0x10 | 0x01, // AF_INET  = 1 + STREAM = 1
323        ProxyAddr::Ipv6Addr { .. } => 0x20 | 0x01, // AF_INET6 = 2 + STREAM = 1
324        ProxyAddr::UnixAddr { .. } => 0x30 | 0x01, // AF_UNIX  = 3 + STREAM = 1
325        ProxyAddr::AfUnspec => 0x00,               // AF_UNSPEC + UNSPEC
326    }
327}
328
329fn u16_to_array_of_u8(x: u16) -> [u8; 2] {
330    let b1: u8 = ((x >> 8) & 0xff) as u8;
331    let b2: u8 = (x & 0xff) as u8;
332    [b1, b2]
333}
334
335#[cfg(test)]
336mod test_v2 {
337
338    use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
339
340    use super::*;
341
342    #[test]
343    fn test_u16_to_array_of_u8() {
344        let val_u16: u16 = 65534;
345        let expected = [0xff, 0xfe];
346        assert_eq!(expected, u16_to_array_of_u8(val_u16));
347    }
348
349    #[test]
350    fn test_deserialize_tcp_ipv4_proxy_protocol_header() {
351        let src_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(125, 25, 10, 1)), 8080);
352        let dst_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 4, 5, 8)), 4200);
353
354        let header = HeaderV2::new(Command::Local, src_addr, dst_addr);
355        let expected = &[
356            0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54,
357            0x0A, // MAGIC header
358            0x20, // Version 2 and command LOCAL
359            0x11, // family AF_UNIX with IPv4
360            0x00, 0x0C, // address sizes = 12
361            0x7D, 0x19, 0x0A, 0x01, // source address
362            0x0A, 0x04, 0x05, 0x08, // destination address
363            0x1F, 0x90, // source port
364            0x10, 0x68, // destination port
365        ];
366
367        assert_eq!(expected, &header.into_bytes()[..]);
368    }
369
370    #[test]
371    fn test_deserialize_tcp_ipv6_proxy_protocol_header() {
372        let src_addr = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 8080);
373        let dst_addr = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 4200);
374
375        let header = HeaderV2::new(Command::Proxy, src_addr, dst_addr);
376        let expected = [
377            0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54,
378            0x0A, // MAGIC header
379            0x21, // Version 2 and command PROXY
380            0x21, // family AF_UNIX with IPv6
381            0x00, 0x24, // address sizes = 36
382            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
383            0x00, 0x01, // source address
384            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385            0x00, 0x01, // destination address
386            0x1F, 0x90, // source port
387            0x10, 0x68,
388        ];
389
390        assert_eq!(&expected[..], &header.into_bytes()[..]);
391    }
392}