use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use crate::protocol::constants::*; #[derive(Clone, Copy)] pub(crate) enum IpMaterial { V4([u8; 4]), V6([u8; 16]), } pub(crate) fn extract_ip_material(addr: SocketAddr) -> IpMaterial { match addr.ip() { IpAddr::V4(v4) => IpMaterial::V4(v4.octets()), IpAddr::V6(v6) => { if let Some(v4) = v6.to_ipv4_mapped() { IpMaterial::V4(v4.octets()) } else { IpMaterial::V6(v6.octets()) } } } } fn ipv4_to_mapped_v6_c_compat(ip: Ipv4Addr) -> [u8; 16] { let mut buf = [0u8; 16]; // Matches tl_store_long(0) + tl_store_int(-0x10000). buf[8..12].copy_from_slice(&(-0x10000i32).to_le_bytes()); // Matches tl_store_int(htonl(remote_ip_host_order)). let host_order = u32::from_ne_bytes(ip.octets()); let network_order = host_order.to_be(); buf[12..16].copy_from_slice(&network_order.to_le_bytes()); buf } fn append_mapped_addr_and_port(buf: &mut Vec, addr: SocketAddr) { match addr.ip() { IpAddr::V4(v4) => buf.extend_from_slice(&ipv4_to_mapped_v6_c_compat(v4)), IpAddr::V6(v6) => buf.extend_from_slice(&v6.octets()), } buf.extend_from_slice(&(addr.port() as u32).to_le_bytes()); } pub(crate) fn build_proxy_req_payload( conn_id: u64, client_addr: SocketAddr, our_addr: SocketAddr, data: &[u8], proxy_tag: Option<&[u8]>, proto_flags: u32, ) -> Vec { let mut b = Vec::with_capacity(128 + data.len()); b.extend_from_slice(&RPC_PROXY_REQ_U32.to_le_bytes()); b.extend_from_slice(&proto_flags.to_le_bytes()); b.extend_from_slice(&conn_id.to_le_bytes()); append_mapped_addr_and_port(&mut b, client_addr); append_mapped_addr_and_port(&mut b, our_addr); if proto_flags & 12 != 0 { let extra_start = b.len(); b.extend_from_slice(&0u32.to_le_bytes()); if let Some(tag) = proxy_tag { b.extend_from_slice(&TL_PROXY_TAG_U32.to_le_bytes()); if tag.len() < 254 { b.push(tag.len() as u8); b.extend_from_slice(tag); let pad = (4 - ((1 + tag.len()) % 4)) % 4; b.extend(std::iter::repeat_n(0u8, pad)); } else { b.push(0xfe); let len_bytes = (tag.len() as u32).to_le_bytes(); b.extend_from_slice(&len_bytes[..3]); b.extend_from_slice(tag); let pad = (4 - (tag.len() % 4)) % 4; b.extend(std::iter::repeat_n(0u8, pad)); } } let extra_bytes = (b.len() - extra_start - 4) as u32; b[extra_start..extra_start + 4].copy_from_slice(&extra_bytes.to_le_bytes()); } b.extend_from_slice(data); b } pub fn proto_flags_for_tag(tag: crate::protocol::constants::ProtoTag, has_proxy_tag: bool) -> u32 { use crate::protocol::constants::ProtoTag; let mut flags = RPC_FLAG_MAGIC | RPC_FLAG_EXTMODE2; if has_proxy_tag { flags |= RPC_FLAG_HAS_AD_TAG; } match tag { ProtoTag::Abridged => flags | RPC_FLAG_ABRIDGED, ProtoTag::Intermediate => flags | RPC_FLAG_INTERMEDIATE, ProtoTag::Secure => flags | RPC_FLAG_PAD | RPC_FLAG_INTERMEDIATE, } }