1
protomask/src/nat/packet.rs

132 lines
3.9 KiB
Rust

use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
// // use etherparse::{IpHeader, Ipv4Header, Ipv4Extensions};
use pnet_packet::{
ethernet::EtherTypes::Ipv6,
ipv4::{checksum, Ipv4, Ipv4Packet, MutableIpv4Packet},
ipv6::{Ipv6, Ipv6Packet, MutableIpv6Packet},
Packet,
};
/// A protocol-agnostic packet type
#[derive(Debug)]
pub enum IpPacket<'a> {
/// IPv4 packet
V4(Ipv4Packet<'a>),
/// IPv6 packet
V6(Ipv6Packet<'a>),
}
impl IpPacket<'_> {
/// Creates a new packet from a byte slice
pub fn new<'a>(bytes: &'a [u8]) -> Option<IpPacket<'a>> {
match bytes[0] >> 4 {
4 => Some(IpPacket::V4(Ipv4Packet::new(bytes)?)),
6 => Some(IpPacket::V6(Ipv6Packet::new(bytes)?)),
_ => None,
}
}
/// Returns the source address
pub fn get_source(&self) -> IpAddr {
match self {
IpPacket::V4(packet) => IpAddr::V4(packet.get_source()),
IpPacket::V6(packet) => IpAddr::V6(packet.get_source()),
}
}
/// Returns the destination address
pub fn get_destination(&self) -> IpAddr {
match self {
IpPacket::V4(packet) => IpAddr::V4(packet.get_destination()),
IpPacket::V6(packet) => IpAddr::V6(packet.get_destination()),
}
}
/// Returns the packet header
pub fn get_header(&self) -> &[u8] {
match self {
IpPacket::V4(packet) => packet.packet()[..20].as_ref(),
IpPacket::V6(packet) => packet.packet()[..40].as_ref(),
}
}
/// Returns the packet payload
pub fn get_payload(&self) -> &[u8] {
match self {
IpPacket::V4(packet) => packet.payload(),
IpPacket::V6(packet) => packet.payload(),
}
}
/// Converts the packet to a byte vector
pub fn to_bytes(&self) -> Vec<u8> {
match self {
IpPacket::V4(packet) => packet.packet().to_vec(),
IpPacket::V6(packet) => packet.packet().to_vec(),
}
}
/// Returns the packet length
pub fn len(&self) -> usize {
match self {
IpPacket::V4(packet) => packet.packet().len(),
IpPacket::V6(packet) => packet.packet().len(),
}
}
}
pub fn xlat_v6_to_v4(
ipv6_packet: &Ipv6Packet,
new_source: Ipv4Addr,
new_dest: Ipv4Addr,
) -> Vec<u8> {
let data = Ipv4 {
version: 4,
header_length: 20,
dscp: 0,
ecn: 0,
total_length: 20 + ipv6_packet.payload().len() as u16,
identification: 0,
flags: 0,
fragment_offset: 0,
ttl: ipv6_packet.get_hop_limit(),
next_level_protocol: ipv6_packet.get_next_header(),
checksum: 0,
source: new_source,
destination: new_dest,
options: vec![],
payload: ipv6_packet.payload().to_vec(),
};
let mut buffer = vec![0; 20 + ipv6_packet.payload().len()];
let mut packet = MutableIpv4Packet::new(buffer.as_mut()).unwrap();
packet.populate(&data);
packet.set_checksum(checksum(&packet.to_immutable()));
let mut output = packet.to_immutable().packet().to_vec();
// TODO: There is a bug here.. for now, force write header size
output[0] = 0x45;
output
}
pub fn xlat_v4_to_v6(
ipv4_packet: &Ipv4Packet,
new_source: Ipv6Addr,
new_dest: Ipv6Addr,
) -> Vec<u8> {
let data = Ipv6 {
version: 6,
traffic_class: 0,
flow_label: 0,
payload_length: 40 + ipv4_packet.payload().len() as u16,
next_header: ipv4_packet.get_next_level_protocol(),
hop_limit: ipv4_packet.get_ttl(),
source: new_source,
destination: new_dest,
payload: ipv4_packet.payload().to_vec(),
};
let mut buffer = vec![0; 40 + ipv4_packet.payload().len()];
let mut packet = MutableIpv6Packet::new(buffer.as_mut()).unwrap();
packet.populate(&data);
packet.to_immutable().packet().to_vec()
}