115 lines
3.7 KiB
Rust
115 lines
3.7 KiB
Rust
#![allow(clippy::doc_markdown)]
|
|
|
|
use std::net::{Ipv4Addr, Ipv6Addr};
|
|
|
|
use pnet_packet::{icmp::IcmpTypes, icmpv6::Icmpv6Types};
|
|
|
|
|
|
use crate::{utils::{profiling::{TimerScope, PacketTimer}, metrics::ICMP_COUNTER}, net::packet::{protocols::{raw::RawBytes, icmpv6::Icmpv6Packet, icmp::IcmpPacket}, error::PacketError}};
|
|
|
|
use super::ip::{translate_ipv4_to_ipv6, translate_ipv6_to_ipv4};
|
|
|
|
mod type_code;
|
|
|
|
/// Translates an ICMP packet to an ICMPv6 packet
|
|
pub fn translate_icmp_to_icmpv6(
|
|
input: IcmpPacket<RawBytes>,
|
|
new_source: Ipv6Addr,
|
|
new_destination: Ipv6Addr,
|
|
timer: &mut PacketTimer
|
|
) -> Result<Icmpv6Packet<RawBytes>, PacketError> {
|
|
ICMP_COUNTER
|
|
.with_label_values(&[
|
|
"icmp",
|
|
&input.icmp_type.0.to_string(),
|
|
&input.icmp_code.0.to_string(),
|
|
])
|
|
.inc();
|
|
timer.start(TimerScope::IcmpToIcmpv6);
|
|
|
|
// Translate the type and code
|
|
let (icmpv6_type, icmpv6_code) =
|
|
type_code::translate_type_and_code_4_to_6(input.icmp_type, input.icmp_code)?;
|
|
|
|
// Some ICMP types require special payload edits
|
|
let payload = match icmpv6_type {
|
|
Icmpv6Types::TimeExceeded => {
|
|
// In this case, the current payload looks like: 4bytes + Ipv4(Data)
|
|
// This needs to be translated to: 4bytes + Ipv6(Data)
|
|
let inner_payload = input.payload.0[4..].to_vec();
|
|
|
|
// Translate
|
|
let inner_payload =
|
|
translate_ipv4_to_ipv6(inner_payload.try_into()?, new_source, new_destination, timer)?;
|
|
let inner_payload: Vec<u8> = inner_payload.into();
|
|
|
|
// Build the new payload
|
|
RawBytes({
|
|
let mut buffer = Vec::with_capacity(4 + inner_payload.len());
|
|
buffer.extend_from_slice(&input.payload.0[..4]);
|
|
buffer.extend_from_slice(&inner_payload);
|
|
buffer
|
|
})
|
|
}
|
|
_ => input.payload,
|
|
};
|
|
|
|
// Build output packet
|
|
timer.end(TimerScope::IcmpToIcmpv6);
|
|
Ok(Icmpv6Packet::new(
|
|
new_source,
|
|
new_destination,
|
|
icmpv6_type,
|
|
icmpv6_code,
|
|
payload,
|
|
))
|
|
}
|
|
|
|
/// Translates an ICMPv6 packet to an ICMP packet
|
|
pub fn translate_icmpv6_to_icmp(
|
|
input: Icmpv6Packet<RawBytes>,
|
|
new_source: Ipv4Addr,
|
|
new_destination: Ipv4Addr,
|
|
timer: &mut PacketTimer
|
|
) -> Result<IcmpPacket<RawBytes>, PacketError> {
|
|
ICMP_COUNTER
|
|
.with_label_values(&[
|
|
"icmpv6",
|
|
&input.icmp_type.0.to_string(),
|
|
&input.icmp_code.0.to_string(),
|
|
])
|
|
.inc();
|
|
timer.start(TimerScope::Icmpv6ToIcmp);
|
|
|
|
// Translate the type and code
|
|
let (icmp_type, icmp_code) =
|
|
type_code::translate_type_and_code_6_to_4(input.icmp_type, input.icmp_code)?;
|
|
|
|
// Some ICMP types require special payload edits
|
|
let payload = match icmp_type {
|
|
IcmpTypes::TimeExceeded => {
|
|
// In this case, the current payload looks like: 4bytes + Ipv6(Data)
|
|
// This needs to be translated to: 4bytes + Ipv4(Data)
|
|
let inner_payload = input.payload.0[4..].to_vec();
|
|
|
|
// Translate
|
|
let inner_payload =
|
|
translate_ipv6_to_ipv4(&inner_payload.try_into()?, new_source, new_destination, timer)?;
|
|
let inner_payload: Vec<u8> = inner_payload.into();
|
|
|
|
// Build the new payload
|
|
RawBytes({
|
|
let mut buffer = Vec::with_capacity(4 + inner_payload.len());
|
|
buffer.extend_from_slice(&input.payload.0[..4]);
|
|
buffer.extend_from_slice(&inner_payload);
|
|
buffer
|
|
})
|
|
}
|
|
_ => input.payload,
|
|
};
|
|
|
|
// Build output packet
|
|
timer.end(TimerScope::Icmpv6ToIcmp);
|
|
Ok(IcmpPacket::new(icmp_type, icmp_code, payload))
|
|
}
|