Builds a PROXY protocol v2 header for TCP connections # Arguments `client_addr` - The original client's socket address `server_addr` - The server's socket address (destination) # Returns A byte vector containing the complete PROXY v2 header
(client_addr: &SocketAddr, server_addr: &SocketAddr)
| 33 | /// # Returns |
| 34 | /// A byte vector containing the complete PROXY v2 header |
| 35 | pub fn build_proxy_v2_header(client_addr: &SocketAddr, server_addr: &SocketAddr) -> Vec<u8> { |
| 36 | let mut header = Vec::with_capacity(52); // Max size for IPv6 |
| 37 | |
| 38 | // 1. Signature (12 bytes) |
| 39 | header.extend_from_slice(&PROXY_V2_SIGNATURE); |
| 40 | |
| 41 | // Determine address family and protocol |
| 42 | let (af_proto, addr_len, addr_data) = match (client_addr.ip(), server_addr.ip()) { |
| 43 | (IpAddr::V4(src_ip), IpAddr::V4(dst_ip)) => { |
| 44 | // IPv4 + TCP |
| 45 | let af_proto = AF_INET | STREAM; |
| 46 | let mut data = Vec::with_capacity(12); |
| 47 | data.extend_from_slice(&src_ip.octets()); // 4 bytes src addr |
| 48 | data.extend_from_slice(&dst_ip.octets()); // 4 bytes dst addr |
| 49 | data.extend_from_slice(&client_addr.port().to_be_bytes()); // 2 bytes src port |
| 50 | data.extend_from_slice(&server_addr.port().to_be_bytes()); // 2 bytes dst port |
| 51 | (af_proto, 12u16, data) |
| 52 | } |
| 53 | (IpAddr::V6(src_ip), IpAddr::V6(dst_ip)) => { |
| 54 | // IPv6 + TCP |
| 55 | let af_proto = AF_INET6 | STREAM; |
| 56 | let mut data = Vec::with_capacity(36); |
| 57 | data.extend_from_slice(&src_ip.octets()); // 16 bytes src addr |
| 58 | data.extend_from_slice(&dst_ip.octets()); // 16 bytes dst addr |
| 59 | data.extend_from_slice(&client_addr.port().to_be_bytes()); // 2 bytes src port |
| 60 | data.extend_from_slice(&server_addr.port().to_be_bytes()); // 2 bytes dst port |
| 61 | (af_proto, 36u16, data) |
| 62 | } |
| 63 | (IpAddr::V4(src_ip), IpAddr::V6(_)) => { |
| 64 | // Mixed: convert IPv4 to IPv6-mapped address |
| 65 | let src_v6 = src_ip.to_ipv6_mapped(); |
| 66 | let dst_v6 = match server_addr.ip() { |
| 67 | IpAddr::V6(ip) => ip, |
| 68 | _ => unreachable!(), |
| 69 | }; |
| 70 | let af_proto = AF_INET6 | STREAM; |
| 71 | let mut data = Vec::with_capacity(36); |
| 72 | data.extend_from_slice(&src_v6.octets()); |
| 73 | data.extend_from_slice(&dst_v6.octets()); |
| 74 | data.extend_from_slice(&client_addr.port().to_be_bytes()); |
| 75 | data.extend_from_slice(&server_addr.port().to_be_bytes()); |
| 76 | (af_proto, 36u16, data) |
| 77 | } |
| 78 | (IpAddr::V6(_), IpAddr::V4(dst_ip)) => { |
| 79 | // Mixed: convert IPv4 to IPv6-mapped address |
| 80 | let src_v6 = match client_addr.ip() { |
| 81 | IpAddr::V6(ip) => ip, |
| 82 | _ => unreachable!(), |
| 83 | }; |
| 84 | let dst_v6 = dst_ip.to_ipv6_mapped(); |
| 85 | let af_proto = AF_INET6 | STREAM; |
| 86 | let mut data = Vec::with_capacity(36); |
| 87 | data.extend_from_slice(&src_v6.octets()); |
| 88 | data.extend_from_slice(&dst_v6.octets()); |
| 89 | data.extend_from_slice(&client_addr.port().to_be_bytes()); |
| 90 | data.extend_from_slice(&server_addr.port().to_be_bytes()); |
| 91 | (af_proto, 36u16, data) |
| 92 | } |