Deal with inner ICMP packets
This commit is contained in:
parent
039a82fd51
commit
de2eb6efed
2
Makefile
2
Makefile
@ -1,5 +1,5 @@
|
||||
SRC=$(wildcard src/*.rs) $(wildcard src/**/*.rs) $(wildcard src/**/**/*.rs) Cargo.toml
|
||||
|
||||
target/debug/protomask: $(SRC)
|
||||
cargo build
|
||||
cross build --target x86_64-unknown-linux-musl
|
||||
sudo setcap cap_net_admin=eip $@
|
@ -72,7 +72,7 @@ macro_rules! ipv6_packet {
|
||||
/// Quickly construct an IPv4 packet with the given parameters
|
||||
#[macro_export]
|
||||
macro_rules! ipv4_packet {
|
||||
($source:expr, $destination:expr, $ttl:expr, $next_level_protocol:expr, $payload:expr) => {
|
||||
($source:expr, $destination:expr, $next_level_protocol:expr, $ttl:expr, $payload:expr) => {
|
||||
ipv4_packet!(
|
||||
$source,
|
||||
$destination,
|
||||
@ -121,3 +121,43 @@ macro_rules! ipv4_packet {
|
||||
pnet_packet::ipv4::Ipv4Packet::owned(output.to_immutable().packet().to_vec()).unwrap()
|
||||
}};
|
||||
}
|
||||
|
||||
/// Quickly construct an ICMPv6 packet with the given parameters
|
||||
#[macro_export]
|
||||
macro_rules! icmpv6_packet {
|
||||
($source:expr, $destination:expr, $message_type:expr, $code:expr) => {
|
||||
icmpv6_packet!($source, $destination, $message_type, $code, &[0u8; 0])
|
||||
};
|
||||
($source:expr, $destination:expr, $message_type:expr, $code:expr, $payload:expr) => {{
|
||||
let mut output =
|
||||
pnet_packet::icmpv6::MutableIcmpv6Packet::owned(vec![0u8; 4 + $payload.len()]).unwrap();
|
||||
output.set_icmpv6_type($message_type);
|
||||
output.set_icmpv6_code($code);
|
||||
output.set_payload($payload);
|
||||
output.set_checksum(0);
|
||||
output.set_checksum(pnet_packet::icmpv6::checksum(
|
||||
&output.to_immutable(),
|
||||
&$source,
|
||||
&$destination,
|
||||
));
|
||||
pnet_packet::icmpv6::Icmpv6Packet::owned(output.to_immutable().packet().to_vec()).unwrap()
|
||||
}};
|
||||
}
|
||||
|
||||
/// Quickly construct an ICMP packet with the given parameters
|
||||
#[macro_export]
|
||||
macro_rules! icmp_packet {
|
||||
($message_type:expr, $code:expr) => {
|
||||
icmp_packet!($message_type, $code, &[0u8; 0])
|
||||
};
|
||||
($message_type:expr, $code:expr, $payload:expr) => {{
|
||||
let mut output =
|
||||
pnet_packet::icmp::MutableIcmpPacket::owned(vec![0u8; 4 + $payload.len()]).unwrap();
|
||||
output.set_icmp_type($message_type);
|
||||
output.set_icmp_code($code);
|
||||
output.set_payload($payload);
|
||||
output.set_checksum(0);
|
||||
output.set_checksum(pnet_packet::icmp::checksum(&output.to_immutable()));
|
||||
pnet_packet::icmp::IcmpPacket::owned(output.to_immutable().packet().to_vec()).unwrap()
|
||||
}};
|
||||
}
|
||||
|
@ -7,7 +7,8 @@ use ipnet::{Ipv4Net, Ipv6Net};
|
||||
use pnet_packet::{ip::IpNextHeaderProtocols, Packet};
|
||||
|
||||
use crate::{
|
||||
into_icmp, into_tcp, into_udp, ipv4_packet, ipv6_packet, nat::xlat::translate_udp_4_to_6, into_icmpv6,
|
||||
into_icmp, into_icmpv6, into_tcp, into_udp, ipv4_packet, ipv6_packet,
|
||||
nat::xlat::translate_udp_4_to_6,
|
||||
};
|
||||
|
||||
use self::{
|
||||
@ -75,10 +76,11 @@ impl Nat64 {
|
||||
match self.interface.recv(&mut buffer) {
|
||||
Ok(packet_len) => {
|
||||
// Parse in to a more friendly format
|
||||
log::debug!("--- NEW PACKET ---");
|
||||
match IpPacket::new(&buffer[..packet_len]) {
|
||||
// Try to process the packet
|
||||
Ok(inbound_packet) => match self.process_packet(inbound_packet).await {
|
||||
Ok(inbound_packet) => match inbound_packet {
|
||||
Ok(outbound_packet) => match outbound_packet {
|
||||
// If data is returned, send it back out the interface
|
||||
Some(outbound_packet) => {
|
||||
let packet_bytes = outbound_packet.to_bytes();
|
||||
@ -168,7 +170,7 @@ impl Nat64 {
|
||||
Some(icmp_packet) => Ok(Some(IpPacket::V6(ipv6_packet!(
|
||||
new_source,
|
||||
new_destination,
|
||||
IpNextHeaderProtocols::Icmp,
|
||||
IpNextHeaderProtocols::Icmpv6,
|
||||
packet.get_ttl(),
|
||||
icmp_packet.packet()
|
||||
)))),
|
||||
@ -221,8 +223,8 @@ impl Nat64 {
|
||||
Some(icmp_packet) => Ok(Some(IpPacket::V4(ipv4_packet!(
|
||||
new_source,
|
||||
new_destination,
|
||||
packet.get_hop_limit(),
|
||||
IpNextHeaderProtocols::Icmp,
|
||||
packet.get_hop_limit(),
|
||||
icmp_packet.packet()
|
||||
)))),
|
||||
None => Ok(None),
|
||||
@ -232,8 +234,8 @@ impl Nat64 {
|
||||
IpNextHeaderProtocols::Udp => Ok(Some(IpPacket::V4(ipv4_packet!(
|
||||
new_source,
|
||||
new_destination,
|
||||
packet.get_hop_limit(),
|
||||
IpNextHeaderProtocols::Udp,
|
||||
packet.get_hop_limit(),
|
||||
xlat::translate_udp_6_to_4(
|
||||
into_udp!(packet.payload().to_vec())?,
|
||||
new_source,
|
||||
@ -246,8 +248,8 @@ impl Nat64 {
|
||||
IpNextHeaderProtocols::Tcp => Ok(Some(IpPacket::V4(ipv4_packet!(
|
||||
new_source,
|
||||
new_destination,
|
||||
packet.get_hop_limit(),
|
||||
IpNextHeaderProtocols::Tcp,
|
||||
packet.get_hop_limit(),
|
||||
xlat::translate_tcp_6_to_4(
|
||||
into_tcp!(packet.payload().to_vec())?,
|
||||
new_source,
|
||||
@ -267,20 +269,5 @@ impl Nat64 {
|
||||
// Honestly, this should probably be `unreachable!()`
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
// match next_header_protocol {
|
||||
// IpNextHeaderProtocols::Icmp | IpNextHeaderProtocols::Icmpv6 => Ok(
|
||||
// xlat::proxy_icmp_packet(packet, new_source, new_destination)?,
|
||||
// ),
|
||||
// IpNextHeaderProtocols::Udp => Ok(Some(
|
||||
// xlat::proxy_udp_packet(packet, new_source, new_destination).await?,
|
||||
// )),
|
||||
// IpNextHeaderProtocols::Tcp => Ok(Some(
|
||||
// xlat::proxy_tcp_packet(packet, new_source, new_destination).await?,
|
||||
// )),
|
||||
// next_header_protocol => {
|
||||
// log::warn!("Unsupported next header protocol: {}", next_header_protocol);
|
||||
// Ok(None)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
@ -1,333 +1,3 @@
|
||||
// //! Translation logic for ICMP and ICMPv6
|
||||
|
||||
// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
|
||||
// use pnet_packet::{
|
||||
// icmp::{self, IcmpCode, IcmpPacket, IcmpType, MutableIcmpPacket},
|
||||
// icmpv6::{self, Icmpv6Code, Icmpv6Packet, Icmpv6Type, MutableIcmpv6Packet},
|
||||
// ip::IpNextHeaderProtocols,
|
||||
// ipv4::{self, Ipv4Packet, MutableIpv4Packet},
|
||||
// ipv6::{Ipv6Packet, MutableIpv6Packet},
|
||||
// Packet,
|
||||
// };
|
||||
|
||||
// use crate::nat::packet::IpPacket;
|
||||
|
||||
// fn remap_values_4to6(
|
||||
// icmp_type: IcmpType,
|
||||
// icmp_code: IcmpCode,
|
||||
// new_source: Ipv6Addr,
|
||||
// new_destination: Ipv6Addr,
|
||||
// payload: Vec<u8>,
|
||||
// ) -> Option<(Icmpv6Type, Icmpv6Code, Vec<u8>)> {
|
||||
// match icmp_type {
|
||||
// // Destination Unreachable
|
||||
// IcmpType(3) => match icmp_code {
|
||||
// IcmpCode(0) => Some((Icmpv6Type(1), Icmpv6Code(0), payload)), // Destination network unreachable -> No route to destination
|
||||
// IcmpCode(1) => Some((Icmpv6Type(1), Icmpv6Code(3), payload)), // Destination host unreachable -> Address unreachable
|
||||
// IcmpCode(2) => Some((Icmpv6Type(1), Icmpv6Code(0), payload)), // Destination protocol unreachable -> No route to destination
|
||||
// IcmpCode(3) => Some((Icmpv6Type(1), Icmpv6Code(4), payload)), // Destination port unreachable -> Port unreachable
|
||||
// IcmpCode(4) => Some((Icmpv6Type(2), Icmpv6Code(0), vec![])), // Fragmentation required, and DF flag set -> Packet too big
|
||||
// IcmpCode(5) => Some((Icmpv6Type(1), Icmpv6Code(5), payload)), // Source route failed -> Source address failed ingress/egress policy
|
||||
// IcmpCode(6) => Some((Icmpv6Type(1), Icmpv6Code(0), payload)), // Destination network unknown -> No route to destination
|
||||
// IcmpCode(7) => Some((Icmpv6Type(1), Icmpv6Code(3), payload)), // Destination host unknown -> Address unreachable
|
||||
// IcmpCode(8) => Some((Icmpv6Type(1), Icmpv6Code(0), payload)), // Source host isolated -> No route to destination
|
||||
// IcmpCode(9) => Some((Icmpv6Type(1), Icmpv6Code(1), payload)), // Network administratively prohibited -> Communication with destination administratively prohibited
|
||||
// IcmpCode(10) => Some((Icmpv6Type(1), Icmpv6Code(1), payload)), // Host administratively prohibited -> Communication with destination administratively prohibited
|
||||
// IcmpCode(11) => Some((Icmpv6Type(1), Icmpv6Code(0), payload)), // Network unreachable for ToS -> No route to destination
|
||||
// IcmpCode(12) => Some((Icmpv6Type(1), Icmpv6Code(3), payload)), // Host unreachable for ToS -> Address unreachable
|
||||
// IcmpCode(13) => Some((Icmpv6Type(1), Icmpv6Code(1), payload)), // Communication administratively prohibited -> Communication with destination administratively prohibited
|
||||
// IcmpCode(14) => Some((Icmpv6Type(1), Icmpv6Code(1), payload)), // Host Precedence Violation -> Communication with destination administratively prohibited
|
||||
// IcmpCode(15) => Some((Icmpv6Type(1), Icmpv6Code(1), payload)), // Precedence cutoff in effect -> Communication with destination administratively prohibited
|
||||
// _ => Some((Icmpv6Type(1), Icmpv6Code(0), payload)),
|
||||
// },
|
||||
|
||||
// // Time Exceeded
|
||||
// IcmpType(11) => Some((Icmpv6Type(3), Icmpv6Code(icmp_code.0), {
|
||||
// // The payload contains an IPv4 header and 8 bytes of data. This must also be translated
|
||||
// let embedded_ipv4_packet = Ipv4Packet::new(&payload[4..]).unwrap();
|
||||
// log::debug!("Embedded payload is: {:?}", embedded_ipv4_packet.payload());
|
||||
// log::debug!(
|
||||
// "Embedded next level protocol is: {}",
|
||||
// embedded_ipv4_packet.get_next_level_protocol().0
|
||||
// );
|
||||
|
||||
// // Build an IPv6 packet out of the IPv4 packet
|
||||
// let mut embedded_ipv6_packet =
|
||||
// MutableIpv6Packet::owned(vec![0u8; 40 + 4 + 8])
|
||||
// .unwrap();
|
||||
// embedded_ipv6_packet.set_version(6);
|
||||
// embedded_ipv6_packet.set_source(new_source);
|
||||
// embedded_ipv6_packet.set_destination(new_destination);
|
||||
// embedded_ipv6_packet.set_hop_limit(embedded_ipv4_packet.get_ttl());
|
||||
// embedded_ipv6_packet.set_next_header(
|
||||
// match embedded_ipv4_packet.get_next_level_protocol() {
|
||||
// IpNextHeaderProtocols::Icmp => IpNextHeaderProtocols::Icmpv6,
|
||||
// proto => proto,
|
||||
// },
|
||||
// );
|
||||
// // embedded_ipv6_packet.set_payload_length(embedded_ipv4_packet.payload().len() as u16);
|
||||
// embedded_ipv6_packet.set_payload_length(8u16);
|
||||
|
||||
// // Handle translating the embedded packet if it's ICMP
|
||||
// match embedded_ipv4_packet.get_next_level_protocol() {
|
||||
// IpNextHeaderProtocols::Icmp => {
|
||||
// let embedded_ipv4_packet_payload_bytes = embedded_ipv4_packet.payload();
|
||||
// let embedded_icmp_type = IcmpType(embedded_ipv4_packet_payload_bytes[0]);
|
||||
// let embedded_icmp_code = IcmpCode(embedded_ipv4_packet_payload_bytes[1]);
|
||||
// let embedded_icmp_payload = &embedded_ipv4_packet_payload_bytes[4..];
|
||||
|
||||
// // Translate from ICMP to ICMPv6
|
||||
// let (embedded_icmpv6_type, embedded_icmpv6_code, embedded_icmpv6_payload) =
|
||||
// remap_values_4to6(
|
||||
// embedded_icmp_type,
|
||||
// embedded_icmp_code,
|
||||
// new_source,
|
||||
// new_destination,
|
||||
// embedded_icmp_payload.to_vec(),
|
||||
// )
|
||||
// .unwrap();
|
||||
|
||||
// // Build an ICMPv6 packet out of the ICMPv6 values
|
||||
// let mut double_embedded_icmpv6_packet = MutableIcmpv6Packet::owned(vec![
|
||||
// 0u8;
|
||||
// Icmpv6Packet::minimum_packet_size()
|
||||
// + embedded_icmpv6_payload.len()
|
||||
// ])
|
||||
// .unwrap();
|
||||
// double_embedded_icmpv6_packet.set_icmpv6_type(embedded_icmpv6_type);
|
||||
// double_embedded_icmpv6_packet.set_icmpv6_code(embedded_icmpv6_code);
|
||||
// double_embedded_icmpv6_packet.set_payload(&embedded_icmpv6_payload);
|
||||
// double_embedded_icmpv6_packet.set_checksum(0);
|
||||
// double_embedded_icmpv6_packet.set_checksum(icmpv6::checksum(
|
||||
// &double_embedded_icmpv6_packet.to_immutable(),
|
||||
// &new_source,
|
||||
// &new_destination,
|
||||
// ));
|
||||
|
||||
// // Return the first 8 bytes of the embedded icmpv6 packet
|
||||
// embedded_ipv6_packet.set_payload(&double_embedded_icmpv6_packet.packet()[..8]);
|
||||
// }
|
||||
// _ => embedded_ipv6_packet.set_payload(embedded_ipv4_packet.payload()),
|
||||
// };
|
||||
|
||||
// // Return the IPv6 packet
|
||||
// embedded_ipv6_packet.packet().to_vec()
|
||||
// })),
|
||||
|
||||
// // Echo Request
|
||||
// IcmpType(8) => Some((Icmpv6Type(128), Icmpv6Code(0), payload)),
|
||||
|
||||
// // Echo Reply
|
||||
// IcmpType(0) => Some((Icmpv6Type(129), Icmpv6Code(0), payload)),
|
||||
|
||||
// icmp_type => {
|
||||
// log::warn!("ICMP type {} not supported", icmp_type.0);
|
||||
// return None;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn remap_values_6to4(
|
||||
// icmp_type: Icmpv6Type,
|
||||
// icmp_code: Icmpv6Code,
|
||||
// new_source: Ipv4Addr,
|
||||
// new_destination: Ipv4Addr,
|
||||
// payload: Vec<u8>,
|
||||
// ) -> Option<(IcmpType, IcmpCode, Vec<u8>)> {
|
||||
// match icmp_type {
|
||||
// // Destination Unreachable
|
||||
// Icmpv6Type(1) => match icmp_code {
|
||||
// Icmpv6Code(0) => Some((IcmpType(3), IcmpCode(0), payload)), // No route to destination -> Destination network unreachable
|
||||
// Icmpv6Code(3) => Some((IcmpType(3), IcmpCode(1), payload)), // Address unreachable -> Destination host unreachable
|
||||
// Icmpv6Code(4) => Some((IcmpType(3), IcmpCode(3), payload)), // Port unreachable -> Destination port unreachable
|
||||
// Icmpv6Code(5) => Some((IcmpType(3), IcmpCode(5), payload)), // Source route failed -> Source address failed ingress/egress policy
|
||||
// Icmpv6Code(1) => Some((IcmpType(3), IcmpCode(13), payload)), // Communication administratively prohibited -> Communication administratively prohibited
|
||||
// _ => Some((IcmpType(3), IcmpCode(0), payload)),
|
||||
// },
|
||||
|
||||
// // Time Exceeded
|
||||
// Icmpv6Type(3) => Some((IcmpType(11), IcmpCode(icmp_code.0), {
|
||||
// // The payload contains an IPv6 header and 8 bytes of data. This must also be translated
|
||||
// let embedded_ipv6_packet = Ipv6Packet::new(&payload).unwrap();
|
||||
// log::debug!("Embedded payload is: {:?}", embedded_ipv6_packet.payload());
|
||||
// log::debug!(
|
||||
// "Embedded next header is: {}",
|
||||
// embedded_ipv6_packet.get_next_header().0
|
||||
// );
|
||||
|
||||
// // Build an IPv4 packet out of the IPv6 packet
|
||||
// let mut embedded_ipv4_packet =
|
||||
// MutableIpv4Packet::owned(vec![0u8; 20 + embedded_ipv6_packet.payload().len()])
|
||||
// .unwrap();
|
||||
// embedded_ipv4_packet.set_version(4);
|
||||
// embedded_ipv4_packet.set_source(new_source);
|
||||
// embedded_ipv4_packet.set_destination(new_destination);
|
||||
// embedded_ipv4_packet.set_ttl(embedded_ipv6_packet.get_hop_limit());
|
||||
// embedded_ipv4_packet.set_next_level_protocol(
|
||||
// match embedded_ipv6_packet.get_next_header() {
|
||||
// IpNextHeaderProtocols::Icmpv6 => IpNextHeaderProtocols::Icmp,
|
||||
// proto => proto,
|
||||
// },
|
||||
// );
|
||||
// embedded_ipv4_packet.set_header_length(5);
|
||||
// embedded_ipv4_packet.set_total_length(20 + embedded_ipv6_packet.payload().len() as u16);
|
||||
// embedded_ipv4_packet.set_payload(embedded_ipv6_packet.payload());
|
||||
// embedded_ipv4_packet.set_checksum(0);
|
||||
// embedded_ipv4_packet.set_checksum(ipv4::checksum(&embedded_ipv4_packet.to_immutable()));
|
||||
|
||||
// // Return the IPv4 packet
|
||||
// embedded_ipv4_packet.packet().to_vec()
|
||||
// })),
|
||||
|
||||
// // Echo Request
|
||||
// Icmpv6Type(128) => Some((IcmpType(8), IcmpCode(0), payload)),
|
||||
|
||||
// // Echo Reply
|
||||
// Icmpv6Type(129) => Some((IcmpType(0), IcmpCode(0), payload)),
|
||||
|
||||
// icmp_type => {
|
||||
// log::warn!("ICMPv6 type {} not supported", icmp_type.0);
|
||||
// return None;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[derive(Debug, thiserror::Error)]
|
||||
// pub enum IcmpProxyError {
|
||||
// #[error("Packet too short. Got {0} bytes")]
|
||||
// PacketTooShort(usize),
|
||||
// }
|
||||
|
||||
// pub fn proxy_icmp_packet<'a>(
|
||||
// original_packet: IpPacket<'a>,
|
||||
// new_source: IpAddr,
|
||||
// new_destination: IpAddr,
|
||||
// ) -> Result<Option<IpPacket>, IcmpProxyError> {
|
||||
// // Parse the original packet's payload to extract ICMP data
|
||||
// let icmp_packet = original_packet.get_payload().to_vec();
|
||||
|
||||
// // Construct a new output packet
|
||||
// match (original_packet, new_source, new_destination) {
|
||||
// // Translate IPv4(ICMP) to IPv6(ICMPv6)
|
||||
// (IpPacket::V4(original_packet), IpAddr::V6(new_source), IpAddr::V6(new_destination)) => {
|
||||
// // Parse the ICMP packet
|
||||
// let icmp_packet = IcmpPacket::new(&icmp_packet)
|
||||
// .ok_or_else(|| IcmpProxyError::PacketTooShort(icmp_packet.len()))?;
|
||||
// log::debug!(
|
||||
// "Incoming packet has ICMP type: {}",
|
||||
// icmp_packet.get_icmp_type().0
|
||||
// );
|
||||
// log::debug!(
|
||||
// "Incoming packet has ICMP code: {}",
|
||||
// icmp_packet.get_icmp_code().0
|
||||
// );
|
||||
|
||||
// // Remap ICMP values to ICMPv6 ones
|
||||
// if let Some((icmpv6_type, icmpv6_code, icmpv6_payload)) = remap_values_4to6(
|
||||
// icmp_packet.get_icmp_type(),
|
||||
// icmp_packet.get_icmp_code(),
|
||||
// new_source,
|
||||
// new_destination,
|
||||
// icmp_packet.payload().to_vec(),
|
||||
// ) {
|
||||
// // Build an actual ICMPv6 packet out of the values
|
||||
// let mut icmpv6_packet = MutableIcmpv6Packet::owned(vec![
|
||||
// 0u8;
|
||||
// Icmpv6Packet::minimum_packet_size()
|
||||
// + icmpv6_payload.len()
|
||||
// ])
|
||||
// .unwrap();
|
||||
// icmpv6_packet.set_icmpv6_type(icmpv6_type);
|
||||
// icmpv6_packet.set_icmpv6_code(icmpv6_code);
|
||||
// icmpv6_packet.set_payload(&icmpv6_payload);
|
||||
// icmpv6_packet.set_checksum(0);
|
||||
// icmpv6_packet.set_checksum(icmpv6::checksum(
|
||||
// &icmpv6_packet.to_immutable(),
|
||||
// &new_source,
|
||||
// &new_destination,
|
||||
// ));
|
||||
|
||||
// // Build an IPv6 packet out of the ICMPv6 packet
|
||||
// let mut output =
|
||||
// MutableIpv6Packet::owned(vec![0u8; 40 + icmpv6_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::Icmpv6);
|
||||
// output.set_payload_length(icmpv6_packet.packet().len() as u16);
|
||||
// output.set_payload(icmpv6_packet.packet());
|
||||
|
||||
// // Return the IPv6 packet
|
||||
// return Ok(Some(IpPacket::V6(
|
||||
// Ipv6Packet::owned(output.to_immutable().packet().to_vec()).unwrap(),
|
||||
// )));
|
||||
// }
|
||||
// return Ok(None);
|
||||
// }
|
||||
|
||||
// // Translate IPv6(ICMPv6) to IPv4(ICMP)
|
||||
// (IpPacket::V6(original_packet), IpAddr::V4(new_source), IpAddr::V4(new_destination)) => {
|
||||
// // Parse the ICMP packet
|
||||
// let icmp_packet = Icmpv6Packet::new(&icmp_packet)
|
||||
// .ok_or_else(|| IcmpProxyError::PacketTooShort(icmp_packet.len()))?;
|
||||
// log::debug!(
|
||||
// "Incoming packet has ICMPv6 type: {}",
|
||||
// icmp_packet.get_icmpv6_type().0
|
||||
// );
|
||||
// log::debug!(
|
||||
// "Incoming packet has ICMPv6 code: {}",
|
||||
// icmp_packet.get_icmpv6_code().0
|
||||
// );
|
||||
|
||||
// // Remap ICMPv6 values to ICMP ones
|
||||
// if let Some((icmp_type, icmp_code, icmp_payload)) = remap_values_6to4(
|
||||
// icmp_packet.get_icmpv6_type(),
|
||||
// icmp_packet.get_icmpv6_code(),
|
||||
// new_source,
|
||||
// new_destination,
|
||||
// icmp_packet.payload().to_vec(),
|
||||
// ) {
|
||||
// // Build an actual ICMP packet out of the values
|
||||
// let mut icmp_packet = MutableIcmpPacket::owned(vec![
|
||||
// 0u8;
|
||||
// IcmpPacket::minimum_packet_size(
|
||||
// ) + icmp_payload.len()
|
||||
// ])
|
||||
// .unwrap();
|
||||
// icmp_packet.set_icmp_type(icmp_type);
|
||||
// icmp_packet.set_icmp_code(icmp_code);
|
||||
// icmp_packet.set_payload(&icmp_payload);
|
||||
// icmp_packet.set_checksum(0);
|
||||
// icmp_packet.set_checksum(icmp::checksum(&icmp_packet.to_immutable()));
|
||||
|
||||
// // Build an IPv4 packet out of the ICMP packet
|
||||
// let mut output =
|
||||
// MutableIpv4Packet::owned(vec![0u8; 20 + icmp_packet.packet().len()]).unwrap();
|
||||
// output.set_version(4);
|
||||
// output.set_source(new_source);
|
||||
// output.set_destination(new_destination);
|
||||
// output.set_ttl(original_packet.get_hop_limit());
|
||||
// output.set_next_level_protocol(IpNextHeaderProtocols::Icmp);
|
||||
// output.set_header_length(5);
|
||||
// output.set_total_length(20 + icmp_packet.packet().len() as u16);
|
||||
// output.set_payload(icmp_packet.packet());
|
||||
// output.set_checksum(0);
|
||||
// output.set_checksum(ipv4::checksum(&output.to_immutable()));
|
||||
|
||||
// // Return the IPv4 packet
|
||||
// return Ok(Some(IpPacket::V4(
|
||||
// Ipv4Packet::owned(output.to_immutable().packet().to_vec()).unwrap(),
|
||||
// )));
|
||||
// }
|
||||
// return Ok(None);
|
||||
// }
|
||||
|
||||
// _ => unreachable!(),
|
||||
// }
|
||||
// }
|
||||
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
|
||||
use pnet_packet::{
|
||||
@ -335,9 +5,14 @@ use pnet_packet::{
|
||||
self, destination_unreachable, IcmpCode, IcmpPacket, IcmpType, IcmpTypes, MutableIcmpPacket,
|
||||
},
|
||||
icmpv6::{self, Icmpv6Code, Icmpv6Packet, Icmpv6Type, Icmpv6Types, MutableIcmpv6Packet},
|
||||
ip::IpNextHeaderProtocols,
|
||||
ipv4::Ipv4Packet,
|
||||
ipv6::Ipv6Packet,
|
||||
Packet,
|
||||
};
|
||||
|
||||
use crate::{icmpv6_packet, ipv4_packet, ipv6_packet, icmp_packet};
|
||||
|
||||
use super::PacketTranslationError;
|
||||
|
||||
/// Best effort translation from an ICMP type and code to an ICMPv6 type and code
|
||||
@ -448,22 +123,66 @@ pub fn translate_icmp_4_to_6(
|
||||
icmp_packet: IcmpPacket,
|
||||
new_source: Ipv6Addr,
|
||||
new_dest: Ipv6Addr,
|
||||
) -> Result<Option<IcmpPacket>, PacketTranslationError> {
|
||||
) -> Result<Option<Icmpv6Packet>, PacketTranslationError> {
|
||||
// Translate the type and code
|
||||
if let Some((icmpv6_type, icmpv6_code)) =
|
||||
translate_type_and_code_4_to_6(icmp_packet.get_icmp_type(), icmp_packet.get_icmp_code())
|
||||
{
|
||||
// Time Exceeded packets require an extra 48 bytes of data
|
||||
let payload_size = match icmpv6_type {
|
||||
Icmpv6Types::TimeExceeded => 48,
|
||||
_ => 0,
|
||||
};
|
||||
// "Time Exceeded" requires an additional payload be embedded in the packet
|
||||
// This payload looks like: 4bytes + IPv6(data)
|
||||
let mut output_payload = vec![];
|
||||
if icmpv6_type == Icmpv6Types::TimeExceeded {
|
||||
// Get access to the original payload
|
||||
let original_payload =
|
||||
Ipv4Packet::new(&icmp_packet.payload()[4..]).ok_or_else(|| {
|
||||
PacketTranslationError::EmbeddedPacketTooShort(icmp_packet.payload().len() - 4)
|
||||
})?;
|
||||
|
||||
// Copy the original payload's payload to a buffer
|
||||
let mut original_payload_inner = vec![0u8; original_payload.payload().len()];
|
||||
original_payload_inner.copy_from_slice(original_payload.payload());
|
||||
|
||||
// if the original payload's next header is ICMP, we need to translated the inner payload's ICMP type
|
||||
if original_payload.get_next_level_protocol() == IpNextHeaderProtocols::Icmp {
|
||||
log::debug!("Time Exceeded packet contains another ICMP packet.. Translating");
|
||||
if let Some((icmpv6_type, icmpv6_code)) = translate_type_and_code_4_to_6(
|
||||
IcmpType(original_payload_inner[0]),
|
||||
IcmpCode(original_payload_inner[1]),
|
||||
) {
|
||||
let inner_icmpv6 = icmpv6_packet!(
|
||||
new_source,
|
||||
new_dest,
|
||||
icmpv6_type,
|
||||
icmpv6_code
|
||||
);
|
||||
original_payload_inner = inner_icmpv6.packet().to_vec();
|
||||
log::debug!("Translated inner ICMPv6 packet: {:?}", original_payload_inner);
|
||||
}
|
||||
}
|
||||
|
||||
// Build a new IPv6 packet out of the embedded IPv4 packet's data
|
||||
let new_payload_packet = ipv6_packet!(
|
||||
new_source,
|
||||
new_dest,
|
||||
match original_payload.get_next_level_protocol() {
|
||||
IpNextHeaderProtocols::Icmp => IpNextHeaderProtocols::Icmpv6,
|
||||
proto => proto,
|
||||
},
|
||||
original_payload.get_ttl(),
|
||||
&original_payload_inner
|
||||
);
|
||||
|
||||
// Set the payload
|
||||
let mut payload = vec![0u8; 4 + new_payload_packet.packet().len()];
|
||||
payload[4..].copy_from_slice(new_payload_packet.packet());
|
||||
output_payload = payload;
|
||||
}
|
||||
|
||||
// Create a new ICMPv6 packet for the translated values to be stored in
|
||||
let mut output = MutableIcmpv6Packet::owned(vec![
|
||||
0u8;
|
||||
Icmpv6Packet::minimum_packet_size()
|
||||
+ payload_size
|
||||
+ output_payload.len()
|
||||
])
|
||||
.unwrap();
|
||||
|
||||
@ -479,11 +198,12 @@ pub fn translate_icmp_4_to_6(
|
||||
&new_dest,
|
||||
));
|
||||
|
||||
//TODO: Add a payload if necessary
|
||||
// Set the payload
|
||||
output.set_payload(&output_payload);
|
||||
|
||||
// Return the translated packet
|
||||
return Ok(Some(
|
||||
IcmpPacket::owned(output.to_immutable().packet().to_vec()).unwrap(),
|
||||
Icmpv6Packet::owned(output.to_immutable().packet().to_vec()).unwrap(),
|
||||
));
|
||||
}
|
||||
|
||||
@ -495,22 +215,82 @@ pub fn translate_icmp_6_to_4(
|
||||
icmpv6_packet: Icmpv6Packet,
|
||||
new_source: Ipv4Addr,
|
||||
new_dest: Ipv4Addr,
|
||||
) -> Result<Option<Icmpv6Packet>, PacketTranslationError> {
|
||||
) -> Result<Option<IcmpPacket>, PacketTranslationError> {
|
||||
// If the incoming packet is a "Parameter Problem", log it
|
||||
if icmpv6_packet.get_icmpv6_type() == Icmpv6Types::ParameterProblem {
|
||||
log::warn!(
|
||||
"ICMPv6 Parameter Problem: {:?}",
|
||||
match icmpv6_packet.get_icmpv6_code().0 {
|
||||
0 => "Erroneous header field encountered",
|
||||
1 => "Unrecognized Next Header type encountered",
|
||||
2 => "Unrecognized IPv6 option encountered",
|
||||
_ => "Unknown",
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Translate the type and code
|
||||
if let Some((icmp_type, icmp_code)) = translate_type_and_code_6_to_4(
|
||||
icmpv6_packet.get_icmpv6_type(),
|
||||
icmpv6_packet.get_icmpv6_code(),
|
||||
) {
|
||||
// Time Exceeded packets require an extra 48 bytes of data
|
||||
let payload_size = match icmp_type {
|
||||
IcmpTypes::TimeExceeded => 48,
|
||||
_ => 0,
|
||||
};
|
||||
// "Time Exceeded" requires an additional payload be embedded in the packet
|
||||
// This payload looks like: 4bytes + IPv6(8bytes)
|
||||
let mut output_payload = vec![];
|
||||
if icmp_type == IcmpTypes::TimeExceeded {
|
||||
// Get access to the original payload
|
||||
let original_payload =
|
||||
Ipv6Packet::new(&icmpv6_packet.payload()[4..]).ok_or_else(|| {
|
||||
PacketTranslationError::EmbeddedPacketTooShort(
|
||||
icmpv6_packet.payload().len() - 4,
|
||||
)
|
||||
})?;
|
||||
|
||||
// Copy the original payload's payload to a buffer
|
||||
let mut original_payload_inner = vec![0u8; original_payload.payload().len()];
|
||||
original_payload_inner.copy_from_slice(original_payload.payload());
|
||||
|
||||
// if the original payload's next header is ICMPv6, we need to translated the inner payload's ICMPv6 type
|
||||
if original_payload.get_next_header() == IpNextHeaderProtocols::Icmpv6 {
|
||||
log::debug!("Time Exceeded packet contains another ICMPv6 packet.. Translating");
|
||||
if let Some((icmp_type, icmp_code)) = translate_type_and_code_6_to_4(
|
||||
Icmpv6Type(original_payload_inner[0]),
|
||||
Icmpv6Code(original_payload_inner[1]),
|
||||
) {
|
||||
let inner_icmp = icmp_packet!(
|
||||
icmp_type,
|
||||
icmp_code
|
||||
);
|
||||
original_payload_inner = inner_icmp.packet().to_vec();
|
||||
log::debug!("Translated inner ICMP packet: {:?}", original_payload_inner);
|
||||
}
|
||||
}
|
||||
|
||||
// Build a new IPv6 packet out of the embedded IPv4 packet's data
|
||||
let new_payload_packet = ipv4_packet!(
|
||||
new_source,
|
||||
new_dest,
|
||||
match original_payload.get_next_header() {
|
||||
IpNextHeaderProtocols::Icmpv6 => IpNextHeaderProtocols::Icmp,
|
||||
proto => proto,
|
||||
},
|
||||
original_payload.get_hop_limit(),
|
||||
&original_payload_inner[..std::cmp::min(8, original_payload_inner.len())]
|
||||
);
|
||||
|
||||
// Set the payload
|
||||
let mut payload = vec![0u8; 4 + new_payload_packet.packet().len()];
|
||||
payload[4..].copy_from_slice(new_payload_packet.packet());
|
||||
output_payload = payload;
|
||||
}
|
||||
|
||||
// Create a new ICMP packet for the translated values to be stored in
|
||||
let mut output =
|
||||
MutableIcmpPacket::owned(vec![0u8; IcmpPacket::minimum_packet_size() + payload_size])
|
||||
.unwrap();
|
||||
let mut output = MutableIcmpPacket::owned(vec![
|
||||
0u8;
|
||||
IcmpPacket::minimum_packet_size()
|
||||
+ output_payload.len()
|
||||
])
|
||||
.unwrap();
|
||||
|
||||
// Set the type and code
|
||||
output.set_icmp_type(icmp_type);
|
||||
@ -520,11 +300,12 @@ pub fn translate_icmp_6_to_4(
|
||||
output.set_checksum(0);
|
||||
output.set_checksum(icmp::checksum(&output.to_immutable()));
|
||||
|
||||
// TODO: Add a payload if necessary
|
||||
// Set the payload
|
||||
output.set_payload(&output_payload);
|
||||
|
||||
// Return the translated packet
|
||||
return Ok(Some(
|
||||
Icmpv6Packet::owned(output.to_immutable().packet().to_vec()).unwrap(),
|
||||
IcmpPacket::owned(output.to_immutable().packet().to_vec()).unwrap(),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -12,4 +12,6 @@ pub use udp::{translate_udp_4_to_6, translate_udp_6_to_4};
|
||||
pub enum PacketTranslationError {
|
||||
#[error("Input packet too short. Got {0} bytes")]
|
||||
InputPacketTooShort(usize),
|
||||
#[error("Embedded packet too short. Got {0} bytes")]
|
||||
EmbeddedPacketTooShort(usize),
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user