//! 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()) }