68 lines
2.6 KiB
Rust
68 lines
2.6 KiB
Rust
use std::net::IpAddr;
|
|
|
|
use pnet_packet::{
|
|
ip::IpNextHeaderProtocols,
|
|
ipv4::{self, Ipv4Packet, MutableIpv4Packet},
|
|
ipv6::{Ipv6Packet, MutableIpv6Packet},
|
|
Packet, tcp::TcpPacket,
|
|
};
|
|
|
|
use crate::nat::packet::IpPacket;
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
pub enum TcpProxyError {
|
|
#[error("Packet too short. Got {0} bytes")]
|
|
PacketTooShort(usize),
|
|
}
|
|
|
|
/// Extracts information from an original packet, and proxies TCP contents via a new source and destination
|
|
pub async fn proxy_tcp_packet<'a>(
|
|
original_packet: IpPacket<'a>,
|
|
new_source: IpAddr,
|
|
new_destination: IpAddr,
|
|
) -> Result<IpPacket, TcpProxyError> {
|
|
// Parse the original packet's payload to extract UDP data
|
|
let tcp_packet = TcpPacket::new(original_packet.get_payload())
|
|
.ok_or_else(|| TcpProxyError::PacketTooShort(original_packet.get_payload().len()))?;
|
|
|
|
// Construct a new output packet
|
|
match (&original_packet, new_source, new_destination) {
|
|
// Translate IPv4(UDP) to IPv6(UDP)
|
|
(IpPacket::V4(_), IpAddr::V6(new_source), IpAddr::V6(new_destination)) => {
|
|
let mut output =
|
|
MutableIpv6Packet::owned(vec![0u8; 40 + tcp_packet.packet().len()]).unwrap();
|
|
output.set_version(6);
|
|
output.set_source(new_source);
|
|
output.set_destination(new_destination);
|
|
output.set_hop_limit(original_packet.get_ttl());
|
|
output.set_next_header(IpNextHeaderProtocols::Udp);
|
|
output.set_payload_length(tcp_packet.packet().len() as u16);
|
|
output.set_payload(tcp_packet.packet());
|
|
Ok(IpPacket::V6(
|
|
Ipv6Packet::owned(output.to_immutable().packet().to_vec()).unwrap(),
|
|
))
|
|
}
|
|
|
|
// Translate IPv6(UDP) to IPv4(UDP)
|
|
(IpPacket::V6(_), IpAddr::V4(new_source), IpAddr::V4(new_destination)) => {
|
|
let mut output =
|
|
MutableIpv4Packet::owned(vec![0u8; 20 + tcp_packet.packet().len()]).unwrap();
|
|
output.set_version(4);
|
|
output.set_source(new_source);
|
|
output.set_destination(new_destination);
|
|
output.set_ttl(original_packet.get_ttl());
|
|
output.set_next_level_protocol(IpNextHeaderProtocols::Udp);
|
|
output.set_header_length(5);
|
|
output.set_total_length(20 + tcp_packet.packet().len() as u16);
|
|
output.set_payload(tcp_packet.packet());
|
|
output.set_checksum(0);
|
|
output.set_checksum(ipv4::checksum(&output.to_immutable()));
|
|
Ok(IpPacket::V4(
|
|
Ipv4Packet::owned(output.to_immutable().packet().to_vec()).unwrap(),
|
|
))
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
}
|
|
}
|