icmp translation
This commit is contained in:
parent
6cd9bdb6d6
commit
fc567c63ff
171
src/nat/icmp.rs
Normal file
171
src/nat/icmp.rs
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
//! ICMP packets require their own translation system
|
||||||
|
|
||||||
|
use colored::Colorize;
|
||||||
|
use pnet_packet::{
|
||||||
|
icmp::{self, Icmp, IcmpCode, IcmpPacket, IcmpType, MutableIcmpPacket},
|
||||||
|
icmpv6::Icmpv6Packet,
|
||||||
|
Packet,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn icmpv6_to_icmp<'a>(input: &'a Icmpv6Packet<'a>) -> Option<IcmpPacket<'a>> {
|
||||||
|
let data = match input.get_icmpv6_type().0 {
|
||||||
|
// Destination Unreachable
|
||||||
|
1 => Icmp {
|
||||||
|
icmp_type: IcmpType(3),
|
||||||
|
// A best guess translation of ICMP codes. Feel free to open a PR to improve this :)
|
||||||
|
icmp_code: IcmpCode(match input.get_icmpv6_code().0 {
|
||||||
|
// No route to destination -> Destination network unreachable
|
||||||
|
0 => 0,
|
||||||
|
// Communication with destination administratively prohibited -> Communication administratively prohibited
|
||||||
|
1 => 13,
|
||||||
|
// Beyond scope of source address -> Destination network unreachable
|
||||||
|
2 => 0,
|
||||||
|
// Address unreachable -> Destination host unreachable
|
||||||
|
3 => 1,
|
||||||
|
// Port unreachable -> Destination port unreachable
|
||||||
|
4 => 3,
|
||||||
|
// Source address failed ingress/egress policy -> Source route failed
|
||||||
|
5 => 5,
|
||||||
|
// Reject route to destination -> Destination network unreachable
|
||||||
|
6 => 0,
|
||||||
|
// Error in Source Routing Header -> Destination network unreachable
|
||||||
|
7 => 0,
|
||||||
|
// All others -> Destination network unreachable
|
||||||
|
_ => 0,
|
||||||
|
}),
|
||||||
|
checksum: 0,
|
||||||
|
payload: input.payload().to_vec(),
|
||||||
|
},
|
||||||
|
// Time Exceeded
|
||||||
|
3 => Icmp {
|
||||||
|
icmp_type: IcmpType(11),
|
||||||
|
icmp_code: IcmpCode(input.get_icmpv6_code().0),
|
||||||
|
checksum: 0,
|
||||||
|
payload: input.payload().to_vec(),
|
||||||
|
},
|
||||||
|
// Echo Request
|
||||||
|
128 => Icmp {
|
||||||
|
icmp_type: IcmpType(8),
|
||||||
|
icmp_code: IcmpCode(0),
|
||||||
|
checksum: 0,
|
||||||
|
payload: input.payload().to_vec(),
|
||||||
|
},
|
||||||
|
// Echo Reply
|
||||||
|
129 => Icmp {
|
||||||
|
icmp_type: IcmpType(0),
|
||||||
|
icmp_code: IcmpCode(0),
|
||||||
|
checksum: 0,
|
||||||
|
payload: input.payload().to_vec(),
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
log::warn!("ICMPv6 type {} not supported", input.get_icmpv6_type().0);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Debug logging
|
||||||
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
|
{
|
||||||
|
log::debug!("> Input ICMP Type: {}", input.get_icmpv6_type().0.to_string().bright_cyan());
|
||||||
|
log::debug!("> Input ICMP Code: {}", input.get_icmpv6_code().0.to_string().bright_cyan());
|
||||||
|
log::debug!("> Output ICMP Type: {}", data.icmp_type.0.to_string().bright_cyan());
|
||||||
|
log::debug!("> Output ICMP Code: {}", data.icmp_code.0.to_string().bright_cyan());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new ICMP packet
|
||||||
|
let mut output = MutableIcmpPacket::owned(vec![0u8; IcmpPacket::packet_size(&data)]).unwrap();
|
||||||
|
output.populate(&data);
|
||||||
|
output.set_checksum(icmp::checksum(&output.to_immutable()));
|
||||||
|
|
||||||
|
IcmpPacket::owned(output.to_immutable().packet().to_vec())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn icmp_to_icmpv6<'a>(input: &'a IcmpPacket<'a>) -> Option<Icmpv6Packet<'a>> {
|
||||||
|
let data = match input.get_icmp_type().0 {
|
||||||
|
// Destination Unreachable
|
||||||
|
3 => Icmp {
|
||||||
|
icmp_type: IcmpType(1),
|
||||||
|
// A best guess translation of ICMP codes. Feel free to open a PR to improve this :)
|
||||||
|
icmp_code: IcmpCode(match input.get_icmp_code().0 {
|
||||||
|
// Destination network unreachable -> No route to destination
|
||||||
|
0 => 0,
|
||||||
|
// Destination host unreachable -> Address unreachable
|
||||||
|
1 => 3,
|
||||||
|
// Destination protocol unreachable -> No route to destination
|
||||||
|
2 => 0,
|
||||||
|
// Destination port unreachable -> Port unreachable
|
||||||
|
3 => 4,
|
||||||
|
// Fragmentation required, and DF flag set -> Packet too big
|
||||||
|
4 => 2,
|
||||||
|
// Source route failed -> Source address failed ingress/egress policy
|
||||||
|
5 => 5,
|
||||||
|
// Destination network unknown -> No route to destination
|
||||||
|
6 => 0,
|
||||||
|
// Destination host unknown -> Address unreachable
|
||||||
|
7 => 3,
|
||||||
|
// Source host isolated -> No route to destination
|
||||||
|
8 => 0,
|
||||||
|
// Network administratively prohibited -> Communication with destination administratively prohibited
|
||||||
|
9 => 1,
|
||||||
|
// Host administratively prohibited -> Communication with destination administratively prohibited
|
||||||
|
10 => 1,
|
||||||
|
// Network unreachable for ToS -> No route to destination
|
||||||
|
11 => 0,
|
||||||
|
// Host unreachable for ToS -> Address unreachable
|
||||||
|
12 => 3,
|
||||||
|
// Communication administratively prohibited -> Communication with destination administratively prohibited
|
||||||
|
13 => 1,
|
||||||
|
// Host Precedence Violation -> Communication with destination administratively prohibited
|
||||||
|
14 => 1,
|
||||||
|
// Precedence cutoff in effect -> Communication with destination administratively prohibited
|
||||||
|
15 => 1,
|
||||||
|
// All others -> No route to destination
|
||||||
|
_ => 0,
|
||||||
|
}),
|
||||||
|
checksum: 0,
|
||||||
|
payload: input.payload().to_vec(),
|
||||||
|
},
|
||||||
|
// Time Exceeded
|
||||||
|
11 => Icmp {
|
||||||
|
icmp_type: IcmpType(3),
|
||||||
|
icmp_code: IcmpCode(input.get_icmp_code().0),
|
||||||
|
checksum: 0,
|
||||||
|
payload: input.payload().to_vec(),
|
||||||
|
},
|
||||||
|
// Echo Request
|
||||||
|
8 => Icmp {
|
||||||
|
icmp_type: IcmpType(128),
|
||||||
|
icmp_code: IcmpCode(0),
|
||||||
|
checksum: 0,
|
||||||
|
payload: input.payload().to_vec(),
|
||||||
|
},
|
||||||
|
|
||||||
|
// Echo Reply
|
||||||
|
0 => Icmp {
|
||||||
|
icmp_type: IcmpType(129),
|
||||||
|
icmp_code: IcmpCode(0),
|
||||||
|
checksum: 0,
|
||||||
|
payload: input.payload().to_vec(),
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
log::warn!("ICMP type {} not supported", input.get_icmp_type().0);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Debug logging
|
||||||
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
|
{
|
||||||
|
log::debug!("> Input ICMP Type: {}", input.get_icmp_type().0.to_string().bright_cyan());
|
||||||
|
log::debug!("> Input ICMP Code: {}", input.get_icmp_code().0.to_string().bright_cyan());
|
||||||
|
log::debug!("> Output ICMP Type: {}", data.icmp_type.0.to_string().bright_cyan());
|
||||||
|
log::debug!("> Output ICMP Code: {}", data.icmp_code.0.to_string().bright_cyan());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new ICMP packet
|
||||||
|
let mut output = MutableIcmpPacket::owned(vec![0u8; IcmpPacket::packet_size(&data)]).unwrap();
|
||||||
|
output.populate(&data);
|
||||||
|
output.set_checksum(icmp::checksum(&output.to_immutable()));
|
||||||
|
|
||||||
|
Icmpv6Packet::owned(output.to_immutable().packet().to_vec())
|
||||||
|
}
|
128
src/nat/mod.rs
128
src/nat/mod.rs
@ -2,19 +2,22 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
|||||||
|
|
||||||
use bimap::BiMap;
|
use bimap::BiMap;
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use ipnet::{IpAdd, Ipv4Net, Ipv6Net};
|
use ipnet::{Ipv4Net, Ipv6Net};
|
||||||
|
use pnet_packet::{
|
||||||
|
icmpv6::Icmpv6Packet,
|
||||||
|
ip::IpNextHeaderProtocols,
|
||||||
|
ipv6::{Ipv6Packet, MutableIpv6Packet},
|
||||||
|
Packet, ipv4::{Ipv4Packet, MutableIpv4Packet}, icmp::IcmpPacket,
|
||||||
|
};
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use tun_tap::{Iface, Mode};
|
use tun_tap::{Iface, Mode};
|
||||||
|
|
||||||
use crate::nat::{
|
use crate::nat::packet::{xlat_v6_to_v4, IpPacket};
|
||||||
packet::{xlat_v6_to_v4, IpPacket},
|
|
||||||
utils::bytes_to_hex_str,
|
|
||||||
};
|
|
||||||
|
|
||||||
use self::packet::xlat_v4_to_v6;
|
use self::packet::xlat_v4_to_v6;
|
||||||
|
|
||||||
|
mod icmp;
|
||||||
mod packet;
|
mod packet;
|
||||||
mod utils;
|
|
||||||
|
|
||||||
/// A cleaner way to execute a CLI command
|
/// A cleaner way to execute a CLI command
|
||||||
macro_rules! command {
|
macro_rules! command {
|
||||||
@ -25,8 +28,17 @@ macro_rules! command {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts bytes to a hex string for debugging
|
||||||
|
fn bytes_to_hex_str(bytes: &[u8]) -> String {
|
||||||
|
bytes
|
||||||
|
.iter()
|
||||||
|
.map(|val| format!("{:02x}", val))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(" ")
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Nat64 {
|
pub struct Nat64 {
|
||||||
/// Handle for the TUN interface
|
/// Handle for the Tun interface
|
||||||
interface: Iface,
|
interface: Iface,
|
||||||
/// Instance IPv4 address
|
/// Instance IPv4 address
|
||||||
instance_v4: Ipv4Addr,
|
instance_v4: Ipv4Addr,
|
||||||
@ -89,7 +101,15 @@ impl Nat64 {
|
|||||||
// Add every IPv4 prefix to the routing table
|
// Add every IPv4 prefix to the routing table
|
||||||
for prefix in ipv4_pool.iter() {
|
for prefix in ipv4_pool.iter() {
|
||||||
log::debug!("Adding route {} via {}", prefix, interface_name);
|
log::debug!("Adding route {} via {}", prefix, interface_name);
|
||||||
command!("ip", "route", "add", prefix.to_string(), "dev", interface_name).await?;
|
command!(
|
||||||
|
"ip",
|
||||||
|
"route",
|
||||||
|
"add",
|
||||||
|
prefix.to_string(),
|
||||||
|
"dev",
|
||||||
|
interface_name
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a reservation list
|
// Build a reservation list
|
||||||
@ -232,6 +252,7 @@ impl Nat64 {
|
|||||||
log::debug!("> IP Header: {}", bytes_to_hex_str(input_packet.get_header()).bright_cyan());
|
log::debug!("> IP Header: {}", bytes_to_hex_str(input_packet.get_header()).bright_cyan());
|
||||||
log::debug!("> Source: {}", input_packet.get_source().to_string().bright_cyan());
|
log::debug!("> Source: {}", input_packet.get_source().to_string().bright_cyan());
|
||||||
log::debug!("> Destination: {}", input_packet.get_destination().to_string().bright_cyan());
|
log::debug!("> Destination: {}", input_packet.get_destination().to_string().bright_cyan());
|
||||||
|
log::debug!("> Next Header: {}", input_packet.get_next_header().to_string().bright_cyan());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore packets that aren't destined for the NAT instance
|
// Ignore packets that aren't destined for the NAT instance
|
||||||
@ -240,6 +261,12 @@ impl Nat64 {
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drop packets with 0 TTL
|
||||||
|
if input_packet.get_ttl() == 0 {
|
||||||
|
log::debug!("{}", "Ignoring packet. TTL is 0".yellow());
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
// Handle packet translation
|
// Handle packet translation
|
||||||
let output_packet = match input_packet {
|
let output_packet = match input_packet {
|
||||||
IpPacket::V4(packet) => {
|
IpPacket::V4(packet) => {
|
||||||
@ -254,17 +281,42 @@ impl Nat64 {
|
|||||||
log::debug!("> Mapped IPv6 Destination: {}", new_dest.to_string().bright_cyan());
|
log::debug!("> Mapped IPv6 Destination: {}", new_dest.to_string().bright_cyan());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translate the packet
|
// Handle inner packet conversion for protocols that don't support both v4 and v6
|
||||||
let data = xlat_v4_to_v6(&packet, new_source, new_dest);
|
if let Some(packet) = Ipv4Packet::owned(match packet.get_next_level_protocol() {
|
||||||
|
// ICMP must be translated to ICMPv6
|
||||||
|
IpNextHeaderProtocols::Icmp => {
|
||||||
|
if let Some(new_payload) =
|
||||||
|
icmp::icmp_to_icmpv6(&IcmpPacket::new(packet.payload()).unwrap())
|
||||||
|
{
|
||||||
|
// Mutate the input packet
|
||||||
|
let mut packet =
|
||||||
|
MutableIpv4Packet::owned(packet.packet().to_vec()).unwrap();
|
||||||
|
packet.set_next_level_protocol(IpNextHeaderProtocols::Icmpv6);
|
||||||
|
packet.set_payload(&new_payload.packet().to_vec());
|
||||||
|
packet.packet().to_vec()
|
||||||
|
} else {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Log the translated packet header
|
// By default, packets can be directly fed to the next function
|
||||||
log::debug!(
|
_ => packet.packet().to_vec(),
|
||||||
"> Translated Header: {}",
|
}) {
|
||||||
bytes_to_hex_str(&data[0..40]).bright_cyan()
|
// Translate the packet
|
||||||
);
|
let translated = xlat_v4_to_v6(&packet, new_source, new_dest, true);
|
||||||
|
|
||||||
|
// Log the translated packet header
|
||||||
|
log::debug!(
|
||||||
|
"> Translated Header: {}",
|
||||||
|
bytes_to_hex_str(&translated[0..40]).bright_cyan()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Return the translated packet
|
||||||
|
translated
|
||||||
|
} else {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
// Return the translated packet
|
|
||||||
data
|
|
||||||
} else {
|
} else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
@ -281,17 +333,41 @@ impl Nat64 {
|
|||||||
log::debug!("> Mapped IPv4 Destination: {}", new_dest.to_string().bright_cyan());
|
log::debug!("> Mapped IPv4 Destination: {}", new_dest.to_string().bright_cyan());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translate the packet
|
// Handle inner packet conversion for protocols that don't support both v4 and v6
|
||||||
let data = xlat_v6_to_v4(&packet, new_source, new_dest);
|
if let Some(packet) = Ipv6Packet::owned(match packet.get_next_header() {
|
||||||
|
// ICMPv6 must be translated to ICMP
|
||||||
|
IpNextHeaderProtocols::Icmpv6 => {
|
||||||
|
if let Some(new_payload) =
|
||||||
|
icmp::icmpv6_to_icmp(&Icmpv6Packet::new(packet.payload()).unwrap())
|
||||||
|
{
|
||||||
|
// Mutate the input packet
|
||||||
|
let mut packet =
|
||||||
|
MutableIpv6Packet::owned(packet.packet().to_vec()).unwrap();
|
||||||
|
packet.set_next_header(IpNextHeaderProtocols::Icmp);
|
||||||
|
packet.set_payload(&new_payload.packet().to_vec());
|
||||||
|
packet.packet().to_vec()
|
||||||
|
} else {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Log the translated packet header
|
// By default, packets can be directly fed to the next function
|
||||||
log::debug!(
|
_ => packet.packet().to_vec(),
|
||||||
"> Translated Header: {}",
|
}) {
|
||||||
bytes_to_hex_str(&data[0..20]).bright_cyan()
|
// Translate the packet
|
||||||
);
|
let translated = xlat_v6_to_v4(&packet, new_source, new_dest, true);
|
||||||
|
|
||||||
// Return the translated packet
|
// Log the translated packet header
|
||||||
data
|
log::debug!(
|
||||||
|
"> Translated Header: {}",
|
||||||
|
bytes_to_hex_str(&translated[0..20]).bright_cyan()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Return the translated packet
|
||||||
|
translated
|
||||||
|
} else {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||||
|
|
||||||
// // use etherparse::{IpHeader, Ipv4Header, Ipv4Extensions};
|
|
||||||
use pnet_packet::{
|
use pnet_packet::{
|
||||||
ethernet::EtherTypes::Ipv6,
|
ip::IpNextHeaderProtocol,
|
||||||
ipv4::{checksum, Ipv4, Ipv4Packet, MutableIpv4Packet},
|
ipv4::{checksum, Ipv4, Ipv4Packet, MutableIpv4Packet},
|
||||||
ipv6::{Ipv6, Ipv6Packet, MutableIpv6Packet},
|
ipv6::{Ipv6, Ipv6Packet, MutableIpv6Packet},
|
||||||
Packet,
|
Packet,
|
||||||
@ -74,12 +73,29 @@ impl IpPacket<'_> {
|
|||||||
IpPacket::V6(packet) => packet.packet().len(),
|
IpPacket::V6(packet) => packet.packet().len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the next header
|
||||||
|
pub fn get_next_header(&self) -> IpNextHeaderProtocol {
|
||||||
|
match self {
|
||||||
|
IpPacket::V4(packet) => packet.get_next_level_protocol(),
|
||||||
|
IpPacket::V6(packet) => packet.get_next_header(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the TTL
|
||||||
|
pub fn get_ttl(&self) -> u8 {
|
||||||
|
match self {
|
||||||
|
IpPacket::V4(packet) => packet.get_ttl(),
|
||||||
|
IpPacket::V6(packet) => packet.get_hop_limit(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn xlat_v6_to_v4(
|
pub fn xlat_v6_to_v4(
|
||||||
ipv6_packet: &Ipv6Packet,
|
ipv6_packet: &Ipv6Packet,
|
||||||
new_source: Ipv4Addr,
|
new_source: Ipv4Addr,
|
||||||
new_dest: Ipv4Addr,
|
new_dest: Ipv4Addr,
|
||||||
|
decr_ttl: bool,
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
let data = Ipv4 {
|
let data = Ipv4 {
|
||||||
version: 4,
|
version: 4,
|
||||||
@ -98,10 +114,15 @@ pub fn xlat_v6_to_v4(
|
|||||||
options: vec![],
|
options: vec![],
|
||||||
payload: ipv6_packet.payload().to_vec(),
|
payload: ipv6_packet.payload().to_vec(),
|
||||||
};
|
};
|
||||||
let mut buffer = vec![0; 20 + ipv6_packet.payload().len()];
|
let mut packet = MutableIpv4Packet::owned(vec![0; 20 + ipv6_packet.payload().len()]).unwrap();
|
||||||
let mut packet = MutableIpv4Packet::new(buffer.as_mut()).unwrap();
|
|
||||||
packet.populate(&data);
|
packet.populate(&data);
|
||||||
packet.set_checksum(checksum(&packet.to_immutable()));
|
packet.set_checksum(checksum(&packet.to_immutable()));
|
||||||
|
|
||||||
|
// Decrement the TTL if needed
|
||||||
|
if decr_ttl {
|
||||||
|
packet.set_ttl(packet.get_ttl() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
let mut output = packet.to_immutable().packet().to_vec();
|
let mut output = packet.to_immutable().packet().to_vec();
|
||||||
// TODO: There is a bug here.. for now, force write header size
|
// TODO: There is a bug here.. for now, force write header size
|
||||||
output[0] = 0x45;
|
output[0] = 0x45;
|
||||||
@ -112,6 +133,7 @@ pub fn xlat_v4_to_v6(
|
|||||||
ipv4_packet: &Ipv4Packet,
|
ipv4_packet: &Ipv4Packet,
|
||||||
new_source: Ipv6Addr,
|
new_source: Ipv6Addr,
|
||||||
new_dest: Ipv6Addr,
|
new_dest: Ipv6Addr,
|
||||||
|
decr_ttl: bool,
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
let data = Ipv6 {
|
let data = Ipv6 {
|
||||||
version: 6,
|
version: 6,
|
||||||
@ -124,8 +146,13 @@ pub fn xlat_v4_to_v6(
|
|||||||
destination: new_dest,
|
destination: new_dest,
|
||||||
payload: ipv4_packet.payload().to_vec(),
|
payload: ipv4_packet.payload().to_vec(),
|
||||||
};
|
};
|
||||||
let mut buffer = vec![0; 40 + ipv4_packet.payload().len()];
|
let mut packet = MutableIpv6Packet::owned(vec![0; 40 + ipv4_packet.payload().len()]).unwrap();
|
||||||
let mut packet = MutableIpv6Packet::new(buffer.as_mut()).unwrap();
|
|
||||||
packet.populate(&data);
|
packet.populate(&data);
|
||||||
|
|
||||||
|
// Decrement the TTL if needed
|
||||||
|
if decr_ttl {
|
||||||
|
packet.set_hop_limit(packet.get_hop_limit() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
packet.to_immutable().packet().to_vec()
|
packet.to_immutable().packet().to_vec()
|
||||||
}
|
}
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
|
||||||
|
|
||||||
use ipnet::Ipv6Net;
|
|
||||||
|
|
||||||
/// Calculates the checksum value for an IPv4 header
|
|
||||||
pub fn ipv4_header_checksum(header: &[u8]) -> u16 {
|
|
||||||
let mut sum = 0u32;
|
|
||||||
|
|
||||||
// Iterate over the header in 16-bit chunks
|
|
||||||
for i in (0..header.len()).step_by(2) {
|
|
||||||
// Combine the two bytes into a 16-bit integer
|
|
||||||
let word = ((header[i] as u16) << 8) | (header[i + 1] as u16);
|
|
||||||
|
|
||||||
// Add to the sum
|
|
||||||
sum = sum.wrapping_add(word as u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fold the carry bits
|
|
||||||
while sum >> 16 != 0 {
|
|
||||||
sum = (sum & 0xffff) + (sum >> 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the checksum
|
|
||||||
!(sum as u16)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert bytes to an IPv6 address
|
|
||||||
pub fn bytes_to_ipv6_addr(bytes: &[u8]) -> Ipv6Addr {
|
|
||||||
assert!(bytes.len() == 16);
|
|
||||||
let mut octets = [0u8; 16];
|
|
||||||
octets.copy_from_slice(bytes);
|
|
||||||
Ipv6Addr::from(octets)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert bytes to an IPv4 address
|
|
||||||
pub fn bytes_to_ipv4_addr(bytes: &[u8]) -> Ipv4Addr {
|
|
||||||
assert!(bytes.len() == 4);
|
|
||||||
let mut octets = [0u8; 4];
|
|
||||||
octets.copy_from_slice(bytes);
|
|
||||||
Ipv4Addr::from(octets)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts bytes to a hex string for debugging
|
|
||||||
pub fn bytes_to_hex_str(bytes: &[u8]) -> String {
|
|
||||||
bytes
|
|
||||||
.iter()
|
|
||||||
.map(|val| format!("{:02x}", val))
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join(" ")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate the appropriate IPv6 address that maps to an IPv4 address
|
|
||||||
pub fn ipv4_to_ipv6(v4: &Ipv4Addr, prefix: &Ipv6Net) -> Ipv6Addr {
|
|
||||||
let net_addr_bytes = prefix.network().octets();
|
|
||||||
let v4_bytes = v4.octets();
|
|
||||||
return Ipv6Addr::new(
|
|
||||||
u16::from_be_bytes([net_addr_bytes[0], net_addr_bytes[1]]),
|
|
||||||
u16::from_be_bytes([net_addr_bytes[2], net_addr_bytes[3]]),
|
|
||||||
u16::from_be_bytes([net_addr_bytes[4], net_addr_bytes[5]]),
|
|
||||||
u16::from_be_bytes([net_addr_bytes[6], net_addr_bytes[7]]),
|
|
||||||
u16::from_be_bytes([net_addr_bytes[8], net_addr_bytes[9]]),
|
|
||||||
u16::from_be_bytes([net_addr_bytes[10], net_addr_bytes[11]]),
|
|
||||||
u16::from_be_bytes([v4_bytes[0], v4_bytes[1]]),
|
|
||||||
u16::from_be_bytes([v4_bytes[2], v4_bytes[3]]),
|
|
||||||
);
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user