ICMP NAT!
This commit is contained in:
parent
fc567c63ff
commit
397943bbc4
19
debug.sh
Normal file
19
debug.sh
Normal file
@ -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
|
||||
|
||||
|
@ -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<'a>>
|
||||
IcmpPacket::owned(output.to_immutable().packet().to_vec())
|
||||
}
|
||||
|
||||
pub fn icmp_to_icmpv6<'a>(input: &'a IcmpPacket<'a>) -> Option<Icmpv6Packet<'a>> {
|
||||
pub fn icmp_to_icmpv6<'a>(
|
||||
input: &'a IcmpPacket<'a>,
|
||||
source: &Ipv6Addr,
|
||||
dest: &Ipv6Addr,
|
||||
) -> Option<Icmpv6Packet<'a>> {
|
||||
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<Icmpv6Packet<'a>>
|
||||
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<Icmpv6Packet<'a>>
|
||||
{
|
||||
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())
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user