diff --git a/debug.sh b/debug.sh new file mode 100644 index 0000000..ae42de0 --- /dev/null +++ b/debug.sh @@ -0,0 +1,19 @@ +#! /bin/bash +# A little script to isolate and run protomask for testing +set -ex + +# Set up network namespace +ip netns del protomask || true +ip netns add protomask +ip netns exec protomask ip link set lo up +ip netns exec protomask ip link add test1 type dummy +ip netns exec protomask ip link set test1 up +ip netns exec protomask ip addr add 2001:db8:1::2 dev test1 +ip netns exec protomask ip link add test2 type dummy +ip netns exec protomask ip link set test2 up +ip netns exec protomask ip addr add 172.16.10.2 dev test2 + +# Run protomask +ip netns exec protomask ./target/debug/protomask protomask.toml -v + + diff --git a/src/nat/icmp.rs b/src/nat/icmp.rs index 6864dcf..ab0c2b1 100644 --- a/src/nat/icmp.rs +++ b/src/nat/icmp.rs @@ -1,9 +1,11 @@ //! ICMP packets require their own translation system +use std::net::Ipv6Addr; + use colored::Colorize; use pnet_packet::{ icmp::{self, Icmp, IcmpCode, IcmpPacket, IcmpType, MutableIcmpPacket}, - icmpv6::Icmpv6Packet, + icmpv6::{self, Icmpv6Packet, MutableIcmpv6Packet, Icmpv6, Icmpv6Type, Icmpv6Code}, Packet, }; @@ -80,13 +82,17 @@ pub fn icmpv6_to_icmp<'a>(input: &'a Icmpv6Packet<'a>) -> Option> IcmpPacket::owned(output.to_immutable().packet().to_vec()) } -pub fn icmp_to_icmpv6<'a>(input: &'a IcmpPacket<'a>) -> Option> { +pub fn icmp_to_icmpv6<'a>( + input: &'a IcmpPacket<'a>, + source: &Ipv6Addr, + dest: &Ipv6Addr, +) -> Option> { let data = match input.get_icmp_type().0 { // Destination Unreachable - 3 => Icmp { - icmp_type: IcmpType(1), + 3 => Icmpv6 { + icmpv6_type: Icmpv6Type(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 { + icmpv6_code: Icmpv6Code(match input.get_icmp_code().0 { // Destination network unreachable -> No route to destination 0 => 0, // Destination host unreachable -> Address unreachable @@ -126,24 +132,24 @@ pub fn icmp_to_icmpv6<'a>(input: &'a IcmpPacket<'a>) -> Option> payload: input.payload().to_vec(), }, // Time Exceeded - 11 => Icmp { - icmp_type: IcmpType(3), - icmp_code: IcmpCode(input.get_icmp_code().0), + 11 => Icmpv6 { + icmpv6_type: Icmpv6Type(3), + icmpv6_code: Icmpv6Code(input.get_icmp_code().0), checksum: 0, payload: input.payload().to_vec(), }, // Echo Request - 8 => Icmp { - icmp_type: IcmpType(128), - icmp_code: IcmpCode(0), + 8 => Icmpv6 { + icmpv6_type: Icmpv6Type(128), + icmpv6_code: Icmpv6Code(0), checksum: 0, payload: input.payload().to_vec(), }, // Echo Reply - 0 => Icmp { - icmp_type: IcmpType(129), - icmp_code: IcmpCode(0), + 0 => Icmpv6 { + icmpv6_type: Icmpv6Type(129), + icmpv6_code: Icmpv6Code(0), checksum: 0, payload: input.payload().to_vec(), }, @@ -158,14 +164,14 @@ pub fn icmp_to_icmpv6<'a>(input: &'a IcmpPacket<'a>) -> Option> { 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()); + log::debug!("> Output ICMP Type: {}", data.icmpv6_type.0.to_string().bright_cyan()); + log::debug!("> Output ICMP Code: {}", data.icmpv6_code.0.to_string().bright_cyan()); } // Create new ICMP packet - let mut output = MutableIcmpPacket::owned(vec![0u8; IcmpPacket::packet_size(&data)]).unwrap(); + let mut output = MutableIcmpv6Packet::owned(vec![0u8; Icmpv6Packet::packet_size(&data)]).unwrap(); output.populate(&data); - output.set_checksum(icmp::checksum(&output.to_immutable())); + output.set_checksum(icmpv6::checksum(&output.to_immutable(), source, dest)); Icmpv6Packet::owned(output.to_immutable().packet().to_vec()) } diff --git a/src/nat/mod.rs b/src/nat/mod.rs index c253582..6e6f50b 100644 --- a/src/nat/mod.rs +++ b/src/nat/mod.rs @@ -4,10 +4,12 @@ use bimap::BiMap; use colored::Colorize; use ipnet::{Ipv4Net, Ipv6Net}; use pnet_packet::{ + icmp::IcmpPacket, icmpv6::Icmpv6Packet, ip::IpNextHeaderProtocols, + ipv4::{self, Ipv4Packet, MutableIpv4Packet}, ipv6::{Ipv6Packet, MutableIpv6Packet}, - Packet, ipv4::{Ipv4Packet, MutableIpv4Packet}, icmp::IcmpPacket, + Packet, }; use tokio::process::Command; use tun_tap::{Iface, Mode}; @@ -282,26 +284,31 @@ impl Nat64 { } // Handle inner packet conversion for protocols that don't support both v4 and v6 - 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); + 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(), + &new_source, + &new_dest, + ) { + // 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.set_checksum(ipv4::checksum(&packet.to_immutable())); + packet.packet().to_vec() + } else { + return Ok(None); + } } - } - // By default, packets can be directly fed to the next function - _ => packet.packet().to_vec(), - }) { + // By default, packets can be directly fed to the next function + _ => packet.packet().to_vec(), + }) + { // Translate the packet let translated = xlat_v4_to_v6(&packet, new_source, new_dest, true); @@ -316,7 +323,6 @@ impl Nat64 { } else { return Ok(None); } - } else { return Ok(None); } diff --git a/src/nat/packet.rs b/src/nat/packet.rs index 9a3203e..871896d 100644 --- a/src/nat/packet.rs +++ b/src/nat/packet.rs @@ -139,7 +139,7 @@ pub fn xlat_v4_to_v6( version: 6, traffic_class: 0, flow_label: 0, - payload_length: 40 + ipv4_packet.payload().len() as u16, + payload_length: ipv4_packet.payload().len() as u16, next_header: ipv4_packet.get_next_level_protocol(), hop_limit: ipv4_packet.get_ttl(), source: new_source,