playit_agent_core/network/
proxy_protocol.rs1use std::{io::Write, net::{Ipv4Addr, Ipv6Addr}};
2
3use byteorder::{BigEndian, ReadBytesExt};
4use playit_agent_proto::udp_proto::UdpFlow;
5use tokio::io::{AsyncWrite, AsyncWriteExt};
6
7use crate::utils::ip_bytes::ReadIpBytesExt;
8
9#[derive(PartialEq, Eq, Debug)]
15pub enum ProxyProtocolHeader {
16 AfInet {
17 client_ip: Ipv4Addr,
18 proxy_ip: Ipv4Addr,
19 client_port: u16,
20 proxy_port: u16,
21 },
22 AfInet6 {
23 client_ip: Ipv6Addr,
24 proxy_ip: Ipv6Addr,
25 client_port: u16,
26 proxy_port: u16,
27 },
28}
29
30impl ProxyProtocolHeader {
31 pub fn from_udp_flow(flow: &UdpFlow) -> Self {
32 match flow {
33 UdpFlow::V4 { src, dst, .. } => {
34 ProxyProtocolHeader::AfInet {
35 client_ip: *src.ip(),
36 proxy_ip: *dst.ip(),
37 client_port: src.port(),
38 proxy_port: dst.port(),
39 }
40 }
41 UdpFlow::V6 { src, dst, .. } => {
42 ProxyProtocolHeader::AfInet6 {
43 client_ip: src.0,
44 proxy_ip: dst.0,
45 client_port: src.1,
46 proxy_port: dst.1,
47 }
48 }
49 }
50 }
51}
52
53impl std::fmt::Display for ProxyProtocolHeader {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 match self {
56 Self::AfInet { client_ip, proxy_ip, client_port, proxy_port } => {
57 write!(f, "PROXY TCP4 {client_ip} {proxy_ip} {client_port} {proxy_port}\r\n")
58 }
59 Self::AfInet6 { client_ip, proxy_ip, client_port, proxy_port } => {
60 write!(f, "PROXY TCP6 {client_ip} {proxy_ip} {client_port} {proxy_port}\r\n")
61 }
62 }
63 }
64}
65
66const PROXY_PROTOCOL_V2_HEADER: &[u8] = &[
67 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A,
68 0x21
69];
70
71pub const UDP_PROXY_PROTOCOL_LEN_V6: usize = 16 + 36;
72pub const UDP_PROXY_PROTOCOL_LEN_V4: usize = 16 + 12;
73pub const UDP_PROXY_PROTOCOL_MAX_LEN: usize = UDP_PROXY_PROTOCOL_LEN_V6;
74
75impl ProxyProtocolHeader {
76 pub async fn write_v1_tcp<W: AsyncWrite + Unpin>(&self, out: &mut W) -> Result<(), std::io::Error> {
77 out.write_all(self.to_string().as_bytes()).await
78 }
79
80 pub async fn write_v2_tcp<W: AsyncWrite + Unpin>(&self, out: &mut W) -> Result<(), std::io::Error> {
81 out.write_all(PROXY_PROTOCOL_V2_HEADER).await?;
82
83 match self {
84 Self::AfInet { client_ip, proxy_ip, client_port, proxy_port } => {
85 out.write_all(&[ 0x11 ]).await?;
86 out.write_all(&12u16.to_be_bytes()).await?;
87 out.write_all(&client_ip.octets()).await?;
88 out.write_all(&proxy_ip.octets()).await?;
89 out.write_all(&client_port.to_be_bytes()).await?;
90 out.write_all(&proxy_port.to_be_bytes()).await?;
91 }
92 Self::AfInet6 { client_ip, proxy_ip, client_port, proxy_port } => {
93 out.write_all(&[ 0x21 ]).await?;
94 out.write_all(&36u16.to_be_bytes()).await?;
95 out.write_all(&client_ip.octets()).await?;
96 out.write_all(&proxy_ip.octets()).await?;
97 out.write_all(&client_port.to_be_bytes()).await?;
98 out.write_all(&proxy_port.to_be_bytes()).await?;
99 }
100 }
101
102 Ok(())
103 }
104
105 pub fn write_v2_udp<W: Write>(&self, out: &mut W) -> Result<(), std::io::Error> {
106 out.write_all(PROXY_PROTOCOL_V2_HEADER)?;
107
108 match self {
109 Self::AfInet { client_ip, proxy_ip, client_port, proxy_port } => {
110 out.write_all(&[ 0x12 ])?;
111 out.write_all(&12u16.to_be_bytes())?;
112 out.write_all(&client_ip.octets())?;
113 out.write_all(&proxy_ip.octets())?;
114 out.write_all(&client_port.to_be_bytes())?;
115 out.write_all(&proxy_port.to_be_bytes())?;
116 }
117 Self::AfInet6 { client_ip, proxy_ip, client_port, proxy_port } => {
118 out.write_all(&[ 0x22 ])?;
119 out.write_all(&36u16.to_be_bytes())?;
120 out.write_all(&client_ip.octets())?;
121 out.write_all(&proxy_ip.octets())?;
122 out.write_all(&client_port.to_be_bytes())?;
123 out.write_all(&proxy_port.to_be_bytes())?;
124 }
125 }
126
127 Ok(())
128 }
129
130 pub fn parse_v2_udp<R: std::io::Read>(buffer: &mut R) -> Option<Self> {
131 let mut header = [0u8; PROXY_PROTOCOL_V2_HEADER.len()];
132 buffer.read_exact(&mut header).ok()?;
133
134 if !header.eq(PROXY_PROTOCOL_V2_HEADER) {
135 return None;
136 }
137
138 let proto_type = buffer.read_u8().ok()?;
139 match proto_type {
140 0x12 => {
142 let mut slab = [0u8; 14];
143 buffer.read_exact(&mut slab).ok()?;
144 let mut reader = &slab[..];
145
146 if reader.read_u16::<BigEndian>().unwrap() != 12 {
148 return None;
149 }
150
151 let client_ip = reader.read_ip4().unwrap();
152 let proxy_ip = reader.read_ip4().unwrap();
153 let client_port = reader.read_u16::<BigEndian>().unwrap();
154 let proxy_port = reader.read_u16::<BigEndian>().unwrap();
155
156 Some(ProxyProtocolHeader::AfInet {
157 client_ip,
158 proxy_ip,
159 client_port,
160 proxy_port,
161 })
162 }
163 0x22 => {
165 let mut slab = [0u8; 38];
166 buffer.read_exact(&mut slab).ok()?;
167 let mut reader = &slab[..];
168
169 if reader.read_u16::<BigEndian>().unwrap() != 36 {
170 return None;
171 }
172
173 let client_ip = reader.read_ip6().unwrap();
174 let proxy_ip = reader.read_ip6().unwrap();
175 let client_port = reader.read_u16::<BigEndian>().unwrap();
176 let proxy_port = reader.read_u16::<BigEndian>().unwrap();
177
178 Some(ProxyProtocolHeader::AfInet6 {
179 client_ip,
180 proxy_ip,
181 client_port,
182 proxy_port,
183 })
184 }
185 _ => None,
186 }
187 }
188}
189
190#[cfg(test)]
191mod test {
192 use super::ProxyProtocolHeader;
193
194 #[test]
195 fn test_parse_header() {
196 let mut buffer = Vec::new();
197 let header = ProxyProtocolHeader::AfInet {
198 client_ip: "123.45.12.34".parse().unwrap(),
199 proxy_ip: "5.6.7.8".parse().unwrap(),
200 client_port: 421,
201 proxy_port: 662
202 };
203
204 header.write_v2_udp(&mut buffer).unwrap();
205
206 let mut reader = &buffer[..];
207 let parsed = ProxyProtocolHeader::parse_v2_udp(&mut reader).unwrap();
208 assert_eq!(header, parsed);
209 }
210}