IPR: use passthrough mode for the tun crate (#4196)

* Add Passthrough mode to tun device crate

* Use passthrough mode in ipr

* Only parse dst address for response packets
This commit is contained in:
Jon Häggblad
2023-11-29 15:39:45 +01:00
committed by GitHub
parent dafed3ad58
commit 115cae54a0
2 changed files with 69 additions and 13 deletions
+15 -1
View File
@@ -99,6 +99,9 @@ pub enum RoutingMode {
// This is an alternative to the routing table, where we just match outgoing source IP with
// incoming destination IP.
Nat(NatInner),
// Just forward without checking anything
Passthrough,
}
impl RoutingMode {
@@ -112,6 +115,10 @@ impl RoutingMode {
pub fn new_allowed_ips(peers_by_ip: std::sync::Arc<tokio::sync::Mutex<PeersByIp>>) -> Self {
RoutingMode::AllowedIps(AllowedIpsInner { peers_by_ip })
}
pub fn new_passthrough() -> Self {
RoutingMode::Passthrough
}
}
#[cfg(feature = "wireguard")]
@@ -180,7 +187,6 @@ impl TunDevice {
);
// TODO: expire old entries
#[allow(irrefutable_let_patterns)]
if let RoutingMode::Nat(nat_table) = &mut self.routing_mode {
nat_table.nat_table.insert(src_addr, tag);
}
@@ -228,6 +234,14 @@ impl TunDevice {
.map_err(|err| err.into());
}
}
RoutingMode::Passthrough => {
log::debug!("Forward packet without checking anything");
return self
.tun_task_response_tx
.try_send((0, packet.to_vec()))
.map_err(|err| err.into());
}
}
log::info!("No peer found, packet dropped");
+54 -12
View File
@@ -2,7 +2,7 @@
use std::{
collections::HashMap,
net::{IpAddr, SocketAddr},
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
path::Path,
time::Duration,
};
@@ -155,7 +155,7 @@ impl IpPacketRouterBuilder {
netmask: TUN_DEVICE_NETMASK.parse().unwrap(),
};
let (tun, tun_task_tx, tun_task_response_rx) = nym_tun::tun_device::TunDevice::new(
nym_tun::tun_device::RoutingMode::new_nat(),
nym_tun::tun_device::RoutingMode::new_passthrough(),
config,
);
tun.start();
@@ -382,10 +382,8 @@ impl IpPacketRouter {
}
// TODO: consider changing from Vec<u8> to bytes::Bytes?
// TODO: consider just removing the tag
let tag = 0;
self.tun_task_tx
.try_send((tag, data_request.ip_packet.into()))
.try_send((0, data_request.ip_packet.into()))
.map_err(|err| IpPacketRouterError::FailedToSendPacketToTun { source: err })?;
Ok(None)
@@ -483,13 +481,7 @@ impl IpPacketRouter {
},
packet = self.tun_task_response_rx.recv() => {
if let Some((_tag, packet)) = packet {
// TODO: skip full parsing since we only need dst_addr
let Ok(ParsedPacket {
packet_type: _,
src_addr: _,
dst_addr,
dst: _,
}) = parse_packet(&packet) else {
let Some(dst_addr) = parse_dst_addr(&packet) else {
log::warn!("Failed to parse packet");
continue;
};
@@ -576,6 +568,38 @@ fn parse_packet(packet: &[u8]) -> Result<ParsedPacket, IpPacketRouterError> {
})
}
// Constants for IPv4 and IPv6 headers
const IPV4_DEST_ADDR_START: usize = 16;
const IPV4_DEST_ADDR_LEN: usize = 4;
const IPV6_DEST_ADDR_START: usize = 24;
const IPV6_DEST_ADDR_LEN: usize = 16;
// Only parse the destination address, for when we don't need the other stuff
fn parse_dst_addr(packet: &[u8]) -> Option<IpAddr> {
let version = packet.first().map(|v| v >> 4)?;
match version {
4 => {
// IPv4
let addr_end = IPV4_DEST_ADDR_START + IPV4_DEST_ADDR_LEN;
let addr_array: [u8; IPV4_DEST_ADDR_LEN] = packet
.get(IPV4_DEST_ADDR_START..addr_end)?
.try_into()
.ok()?;
Some(IpAddr::V4(Ipv4Addr::from(addr_array)))
}
6 => {
// IPv6
let addr_end = IPV6_DEST_ADDR_START + IPV6_DEST_ADDR_LEN;
let addr_array: [u8; IPV6_DEST_ADDR_LEN] = packet
.get(IPV6_DEST_ADDR_START..addr_end)?
.try_into()
.ok()?;
Some(IpAddr::V6(Ipv6Addr::from(addr_array)))
}
_ => None, // Unknown IP version
}
}
// Helper function to create the mixnet client.
// This is NOT in the SDK since we don't want to expose any of the client-core config types.
// We could however consider moving it to a crate in common in the future.
@@ -620,3 +644,21 @@ async fn create_mixnet_client(
.await
.map_err(|err| IpPacketRouterError::FailedToConnectToMixnet { source: err })
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_destination_from_ip_packet() {
// Create packet
let builder =
etherparse::PacketBuilder::ipv4([192, 168, 1, 1], [192, 168, 1, 2], 20).udp(21, 1234);
let payload = [1, 2, 3, 4, 5, 6, 7, 8];
let mut packet = Vec::<u8>::with_capacity(builder.size(payload.len()));
builder.write(&mut packet, &payload).unwrap();
let dst_addr = parse_dst_addr(&packet).unwrap();
assert_eq!(dst_addr, IpAddr::V4(Ipv4Addr::new(192, 168, 1, 2)));
}
}