use std::net::SocketAddr;
const PP2_SIGNATURE: [u8; 12] = [
0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A,
];
const PP2_VER_CMD_PROXY: u8 = 0x21;
const PP2_FAM_INET_DGRAM: u8 = 0x12;
const PP2_FAM_INET6_DGRAM: u8 = 0x22;
pub fn dgram_header(client: SocketAddr, backend: SocketAddr) -> Vec<u8> {
match (client, backend) {
(SocketAddr::V4(src), SocketAddr::V4(dst)) => {
let mut h = Vec::with_capacity(16 + 12);
h.extend_from_slice(&PP2_SIGNATURE);
h.push(PP2_VER_CMD_PROXY);
h.push(PP2_FAM_INET_DGRAM);
h.extend_from_slice(&12u16.to_be_bytes());
h.extend_from_slice(&src.ip().octets());
h.extend_from_slice(&dst.ip().octets());
h.extend_from_slice(&src.port().to_be_bytes());
h.extend_from_slice(&dst.port().to_be_bytes());
h
}
(SocketAddr::V6(src), SocketAddr::V6(dst)) => {
let mut h = Vec::with_capacity(16 + 36);
h.extend_from_slice(&PP2_SIGNATURE);
h.push(PP2_VER_CMD_PROXY);
h.push(PP2_FAM_INET6_DGRAM);
h.extend_from_slice(&36u16.to_be_bytes());
h.extend_from_slice(&src.ip().octets());
h.extend_from_slice(&dst.ip().octets());
h.extend_from_slice(&src.port().to_be_bytes());
h.extend_from_slice(&dst.port().to_be_bytes());
h
}
_ => {
let mut h = Vec::with_capacity(16);
h.extend_from_slice(&PP2_SIGNATURE);
h.push(PP2_VER_CMD_PROXY);
h.push(0x00); h.extend_from_slice(&0u16.to_be_bytes());
h
}
}
}
pub fn prepend_dgram_header(
payload: &mut Vec<u8>,
client: SocketAddr,
backend: SocketAddr,
) -> usize {
let header = dgram_header(client, backend);
let header_len = header.len();
let mut prefixed = Vec::with_capacity(header_len + payload.len());
prefixed.extend_from_slice(&header);
prefixed.append(payload);
*payload = prefixed;
header_len
}
#[cfg(test)]
mod tests {
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use super::*;
#[test]
fn dgram_header_ipv4_exact_bytes() {
let client = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(125, 25, 10, 1)), 8080);
let backend = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 4, 5, 8)), 4200);
let header = dgram_header(client, backend);
let expected: [u8; 28] = [
0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54,
0x0A, 0x21, 0x12, 0x00, 0x0C, 0x7D, 0x19, 0x0A, 0x01, 0x0A, 0x04, 0x05, 0x08, 0x1F, 0x90, 0x10, 0x68, ];
assert_eq!(&expected[..], &header[..]);
assert_eq!(header.len(), 28);
}
#[test]
fn dgram_header_ipv6_exact_bytes() {
let client = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 8080);
let backend = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 4200);
let header = dgram_header(client, backend);
let expected: [u8; 52] = [
0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54,
0x0A, 0x21, 0x22, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x1F, 0x90, 0x10, 0x68, ];
assert_eq!(&expected[..], &header[..]);
assert_eq!(header.len(), 52);
}
#[test]
fn prepend_shifts_payload() {
let client = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4)), 1234);
let backend = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(5, 6, 7, 8)), 5678);
let mut payload = b"DNSQUERY".to_vec();
let n = prepend_dgram_header(&mut payload, client, backend);
assert_eq!(n, 28);
assert_eq!(&payload[..12], &PP2_SIGNATURE);
assert_eq!(payload[12], PP2_VER_CMD_PROXY);
assert_eq!(payload[13], PP2_FAM_INET_DGRAM);
assert_eq!(&payload[28..], b"DNSQUERY");
}
#[test]
fn mixed_family_emits_unspec() {
let client = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4)), 1);
let backend = SocketAddr::new(IpAddr::V6(Ipv6Addr::LOCALHOST), 2);
let header = dgram_header(client, backend);
assert_eq!(header.len(), 16);
assert_eq!(header[12], PP2_VER_CMD_PROXY);
assert_eq!(header[13], 0x00); assert_eq!(&header[14..16], &[0x00, 0x00]); }
}