mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-03 05:10:55 +00:00
network: parse received packet before NAT
This commit is contained in:
parent
982536513a
commit
31c4c0fe72
@ -1,9 +1,11 @@
|
||||
use crate::chandev::ChannelDevice;
|
||||
use crate::nat::NatRouter;
|
||||
use crate::pkt::RecvPacket;
|
||||
use crate::proxynat::ProxyNatHandlerFactory;
|
||||
use crate::raw_socket::{AsyncRawSocket, RawSocketProtocol};
|
||||
use advmac::MacAddr6;
|
||||
use anyhow::{anyhow, Result};
|
||||
use etherparse::SlicedPacket;
|
||||
use futures::TryStreamExt;
|
||||
use log::debug;
|
||||
use smoltcp::iface::{Config, Interface, SocketSet};
|
||||
@ -41,30 +43,32 @@ struct NetworkStack<'a> {
|
||||
}
|
||||
|
||||
impl NetworkStack<'_> {
|
||||
async fn poll(&mut self, receive_buffer: &mut [u8]) -> Result<()> {
|
||||
async fn poll(&mut self, buffer: &mut [u8]) -> Result<()> {
|
||||
let what = select! {
|
||||
x = self.kdev.read(buffer) => NetworkStackSelect::Receive(&buffer[0..x?]),
|
||||
x = self.tx.recv() => NetworkStackSelect::Send(x),
|
||||
x = self.kdev.read(receive_buffer) => NetworkStackSelect::Receive(&receive_buffer[0..x?]),
|
||||
_ = self.router.process_reclaim() => NetworkStackSelect::Reclaim,
|
||||
};
|
||||
|
||||
match what {
|
||||
NetworkStackSelect::Receive(packet) => {
|
||||
let slice = SlicedPacket::from_ethernet(packet)?;
|
||||
let packet = RecvPacket::new(packet, &slice)?;
|
||||
if let Err(error) = self.router.process(&packet).await {
|
||||
debug!("router failed to process packet: {}", error);
|
||||
}
|
||||
|
||||
self.udev.rx = Some(packet.raw.to_vec());
|
||||
self.interface
|
||||
.poll(Instant::now(), &mut self.udev, &mut self.sockets);
|
||||
}
|
||||
|
||||
NetworkStackSelect::Send(packet) => {
|
||||
if let Some(packet) = packet {
|
||||
self.kdev.write_all(&packet).await?
|
||||
}
|
||||
}
|
||||
|
||||
NetworkStackSelect::Receive(packet) => {
|
||||
if let Err(error) = self.router.process(packet).await {
|
||||
debug!("router failed to process packet: {}", error);
|
||||
}
|
||||
|
||||
self.udev.rx = Some(packet.to_vec());
|
||||
self.interface
|
||||
.poll(Instant::now(), &mut self.udev, &mut self.sockets);
|
||||
}
|
||||
|
||||
NetworkStackSelect::Reclaim => {}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ pub mod backend;
|
||||
pub mod chandev;
|
||||
pub mod icmp;
|
||||
pub mod nat;
|
||||
pub mod pkt;
|
||||
pub mod proxynat;
|
||||
pub mod raw_socket;
|
||||
|
||||
|
@ -1,17 +1,15 @@
|
||||
use crate::pkt::RecvPacket;
|
||||
use crate::pkt::RecvPacketIp;
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use etherparse::Ethernet2Slice;
|
||||
use etherparse::Icmpv4Header;
|
||||
use etherparse::Icmpv4Type;
|
||||
use etherparse::Icmpv6Header;
|
||||
use etherparse::Icmpv6Type;
|
||||
use etherparse::IpNumber;
|
||||
use etherparse::LaxIpPayloadSlice;
|
||||
use etherparse::LaxIpv4Slice;
|
||||
use etherparse::LaxIpv6Slice;
|
||||
use etherparse::LaxNetSlice;
|
||||
use etherparse::LaxSlicedPacket;
|
||||
use etherparse::LinkSlice;
|
||||
use etherparse::IpPayloadSlice;
|
||||
use etherparse::Ipv4Slice;
|
||||
use etherparse::Ipv6Slice;
|
||||
use etherparse::TcpHeaderSlice;
|
||||
use etherparse::UdpHeaderSlice;
|
||||
use log::{debug, trace};
|
||||
@ -145,13 +143,8 @@ impl NatRouter {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn process(&mut self, data: &[u8]) -> Result<()> {
|
||||
let packet = LaxSlicedPacket::from_ethernet(data)?;
|
||||
let Some(ref link) = packet.link else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let LinkSlice::Ethernet2(ref ether) = link else {
|
||||
pub async fn process<'a>(&mut self, packet: &RecvPacket<'a>) -> Result<()> {
|
||||
let Some(ether) = packet.ether else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
@ -165,173 +158,16 @@ impl NatRouter {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let Some(ref net) = packet.net else {
|
||||
let key = match packet.ip {
|
||||
Some(RecvPacketIp::Ipv4(ipv4)) => self.extract_key_ipv4(packet, ipv4)?,
|
||||
Some(RecvPacketIp::Ipv6(ipv6)) => self.extract_key_ipv6(packet, ipv6)?,
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let Some(key) = key else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
match net {
|
||||
LaxNetSlice::Ipv4(ipv4) => self.process_ipv4(data, ether, ipv4).await?,
|
||||
LaxNetSlice::Ipv6(ipv6) => self.process_ipv6(data, ether, ipv6).await?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn process_ipv4<'a>(
|
||||
&mut self,
|
||||
data: &[u8],
|
||||
ether: &Ethernet2Slice<'a>,
|
||||
ipv4: &LaxIpv4Slice<'a>,
|
||||
) -> Result<()> {
|
||||
let source_addr = IpAddress::Ipv4(ipv4.header().source_addr().into());
|
||||
let dest_addr = IpAddress::Ipv4(ipv4.header().destination_addr().into());
|
||||
match ipv4.header().protocol() {
|
||||
IpNumber::TCP => {
|
||||
self.process_tcp(data, ether, source_addr, dest_addr, ipv4.payload())
|
||||
.await?;
|
||||
}
|
||||
|
||||
IpNumber::UDP => {
|
||||
self.process_udp(data, ether, source_addr, dest_addr, ipv4.payload())
|
||||
.await?;
|
||||
}
|
||||
|
||||
IpNumber::ICMP => {
|
||||
self.process_icmpv4(data, ether, source_addr, dest_addr, ipv4.payload())
|
||||
.await?;
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn process_ipv6<'a>(
|
||||
&mut self,
|
||||
data: &[u8],
|
||||
ether: &Ethernet2Slice<'a>,
|
||||
ipv6: &LaxIpv6Slice<'a>,
|
||||
) -> Result<()> {
|
||||
let source_addr = IpAddress::Ipv6(ipv6.header().source_addr().into());
|
||||
let dest_addr = IpAddress::Ipv6(ipv6.header().destination_addr().into());
|
||||
match ipv6.header().next_header() {
|
||||
IpNumber::TCP => {
|
||||
self.process_tcp(data, ether, source_addr, dest_addr, ipv6.payload())
|
||||
.await?;
|
||||
}
|
||||
|
||||
IpNumber::UDP => {
|
||||
self.process_udp(data, ether, source_addr, dest_addr, ipv6.payload())
|
||||
.await?;
|
||||
}
|
||||
|
||||
IpNumber::IPV6_ICMP => {
|
||||
self.process_icmpv6(data, ether, source_addr, dest_addr, ipv6.payload())
|
||||
.await?;
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn process_tcp<'a>(
|
||||
&mut self,
|
||||
data: &'a [u8],
|
||||
ether: &Ethernet2Slice<'a>,
|
||||
source_addr: IpAddress,
|
||||
dest_addr: IpAddress,
|
||||
payload: &LaxIpPayloadSlice<'a>,
|
||||
) -> Result<()> {
|
||||
let header = TcpHeaderSlice::from_slice(payload.payload)?;
|
||||
let source = IpEndpoint::new(source_addr, header.source_port());
|
||||
let dest = IpEndpoint::new(dest_addr, header.destination_port());
|
||||
let key = NatKey {
|
||||
protocol: NatKeyProtocol::Tcp,
|
||||
client_mac: EthernetAddress(ether.source()),
|
||||
local_mac: EthernetAddress(ether.destination()),
|
||||
client_ip: source,
|
||||
external_ip: dest,
|
||||
};
|
||||
self.process_nat(data, key).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn process_udp<'a>(
|
||||
&mut self,
|
||||
data: &'a [u8],
|
||||
ether: &Ethernet2Slice<'a>,
|
||||
source_addr: IpAddress,
|
||||
dest_addr: IpAddress,
|
||||
payload: &LaxIpPayloadSlice<'a>,
|
||||
) -> Result<()> {
|
||||
let header = UdpHeaderSlice::from_slice(payload.payload)?;
|
||||
let source = IpEndpoint::new(source_addr, header.source_port());
|
||||
let dest = IpEndpoint::new(dest_addr, header.destination_port());
|
||||
let key = NatKey {
|
||||
protocol: NatKeyProtocol::Udp,
|
||||
client_mac: EthernetAddress(ether.source()),
|
||||
local_mac: EthernetAddress(ether.destination()),
|
||||
client_ip: source,
|
||||
external_ip: dest,
|
||||
};
|
||||
self.process_nat(data, key).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn process_icmpv4<'a>(
|
||||
&mut self,
|
||||
data: &'a [u8],
|
||||
ether: &Ethernet2Slice<'a>,
|
||||
source_addr: IpAddress,
|
||||
dest_addr: IpAddress,
|
||||
payload: &LaxIpPayloadSlice<'a>,
|
||||
) -> Result<()> {
|
||||
let (header, _) = Icmpv4Header::from_slice(payload.payload)?;
|
||||
let Icmpv4Type::EchoRequest(_) = header.icmp_type else {
|
||||
return Ok(());
|
||||
};
|
||||
let source = IpEndpoint::new(source_addr, 0);
|
||||
let dest = IpEndpoint::new(dest_addr, 0);
|
||||
let key = NatKey {
|
||||
protocol: NatKeyProtocol::Icmp,
|
||||
client_mac: EthernetAddress(ether.source()),
|
||||
local_mac: EthernetAddress(ether.destination()),
|
||||
client_ip: source,
|
||||
external_ip: dest,
|
||||
};
|
||||
self.process_nat(data, key).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn process_icmpv6<'a>(
|
||||
&mut self,
|
||||
data: &'a [u8],
|
||||
ether: &Ethernet2Slice<'a>,
|
||||
source_addr: IpAddress,
|
||||
dest_addr: IpAddress,
|
||||
payload: &LaxIpPayloadSlice<'a>,
|
||||
) -> Result<()> {
|
||||
let (header, _) = Icmpv6Header::from_slice(payload.payload)?;
|
||||
let Icmpv6Type::EchoRequest(_) = header.icmp_type else {
|
||||
return Ok(());
|
||||
};
|
||||
let source = IpEndpoint::new(source_addr, 0);
|
||||
let dest = IpEndpoint::new(dest_addr, 0);
|
||||
let key = NatKey {
|
||||
protocol: NatKeyProtocol::Icmp,
|
||||
client_mac: EthernetAddress(ether.source()),
|
||||
local_mac: EthernetAddress(ether.destination()),
|
||||
client_ip: source,
|
||||
external_ip: dest,
|
||||
};
|
||||
self.process_nat(data, key).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn process_nat(&mut self, data: &[u8], key: NatKey) -> Result<()> {
|
||||
for cidr in &self.local_cidrs {
|
||||
if cidr.contains_addr(&key.external_ip.addr) {
|
||||
return Ok(());
|
||||
@ -357,10 +193,152 @@ impl NatRouter {
|
||||
};
|
||||
|
||||
if let Some(handler) = handler {
|
||||
if !handler.receive(data).await? {
|
||||
if !handler.receive(packet.raw).await? {
|
||||
self.reclaim_sender.try_send(key)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn extract_key_ipv4<'a>(
|
||||
&mut self,
|
||||
packet: &RecvPacket<'a>,
|
||||
ipv4: &Ipv4Slice<'a>,
|
||||
) -> Result<Option<NatKey>> {
|
||||
let source_addr = IpAddress::Ipv4(ipv4.header().source_addr().into());
|
||||
let dest_addr = IpAddress::Ipv4(ipv4.header().destination_addr().into());
|
||||
Ok(match ipv4.header().protocol() {
|
||||
IpNumber::TCP => {
|
||||
self.extract_key_tcp(packet, source_addr, dest_addr, ipv4.payload())?
|
||||
}
|
||||
|
||||
IpNumber::UDP => {
|
||||
self.extract_key_udp(packet, source_addr, dest_addr, ipv4.payload())?
|
||||
}
|
||||
|
||||
IpNumber::ICMP => {
|
||||
self.extract_key_icmpv4(packet, source_addr, dest_addr, ipv4.payload())?
|
||||
}
|
||||
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn extract_key_ipv6<'a>(
|
||||
&mut self,
|
||||
packet: &RecvPacket<'a>,
|
||||
ipv6: &Ipv6Slice<'a>,
|
||||
) -> Result<Option<NatKey>> {
|
||||
let source_addr = IpAddress::Ipv6(ipv6.header().source_addr().into());
|
||||
let dest_addr = IpAddress::Ipv6(ipv6.header().destination_addr().into());
|
||||
Ok(match ipv6.header().next_header() {
|
||||
IpNumber::TCP => {
|
||||
self.extract_key_tcp(packet, source_addr, dest_addr, ipv6.payload())?
|
||||
}
|
||||
|
||||
IpNumber::UDP => {
|
||||
self.extract_key_udp(packet, source_addr, dest_addr, ipv6.payload())?
|
||||
}
|
||||
|
||||
IpNumber::IPV6_ICMP => {
|
||||
self.extract_key_icmpv6(packet, source_addr, dest_addr, ipv6.payload())?
|
||||
}
|
||||
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn extract_key_tcp<'a>(
|
||||
&mut self,
|
||||
packet: &RecvPacket<'a>,
|
||||
source_addr: IpAddress,
|
||||
dest_addr: IpAddress,
|
||||
payload: &IpPayloadSlice<'a>,
|
||||
) -> Result<Option<NatKey>> {
|
||||
let Some(ether) = packet.ether else {
|
||||
return Ok(None);
|
||||
};
|
||||
let header = TcpHeaderSlice::from_slice(payload.payload)?;
|
||||
let source = IpEndpoint::new(source_addr, header.source_port());
|
||||
let dest = IpEndpoint::new(dest_addr, header.destination_port());
|
||||
Ok(Some(NatKey {
|
||||
protocol: NatKeyProtocol::Tcp,
|
||||
client_mac: EthernetAddress(ether.source()),
|
||||
local_mac: EthernetAddress(ether.destination()),
|
||||
client_ip: source,
|
||||
external_ip: dest,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn extract_key_udp<'a>(
|
||||
&mut self,
|
||||
packet: &RecvPacket<'a>,
|
||||
source_addr: IpAddress,
|
||||
dest_addr: IpAddress,
|
||||
payload: &IpPayloadSlice<'a>,
|
||||
) -> Result<Option<NatKey>> {
|
||||
let Some(ether) = packet.ether else {
|
||||
return Ok(None);
|
||||
};
|
||||
let header = UdpHeaderSlice::from_slice(payload.payload)?;
|
||||
let source = IpEndpoint::new(source_addr, header.source_port());
|
||||
let dest = IpEndpoint::new(dest_addr, header.destination_port());
|
||||
Ok(Some(NatKey {
|
||||
protocol: NatKeyProtocol::Udp,
|
||||
client_mac: EthernetAddress(ether.source()),
|
||||
local_mac: EthernetAddress(ether.destination()),
|
||||
client_ip: source,
|
||||
external_ip: dest,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn extract_key_icmpv4<'a>(
|
||||
&mut self,
|
||||
packet: &RecvPacket<'a>,
|
||||
source_addr: IpAddress,
|
||||
dest_addr: IpAddress,
|
||||
payload: &IpPayloadSlice<'a>,
|
||||
) -> Result<Option<NatKey>> {
|
||||
let Some(ether) = packet.ether else {
|
||||
return Ok(None);
|
||||
};
|
||||
let (header, _) = Icmpv4Header::from_slice(payload.payload)?;
|
||||
let Icmpv4Type::EchoRequest(_) = header.icmp_type else {
|
||||
return Ok(None);
|
||||
};
|
||||
let source = IpEndpoint::new(source_addr, 0);
|
||||
let dest = IpEndpoint::new(dest_addr, 0);
|
||||
Ok(Some(NatKey {
|
||||
protocol: NatKeyProtocol::Icmp,
|
||||
client_mac: EthernetAddress(ether.source()),
|
||||
local_mac: EthernetAddress(ether.destination()),
|
||||
client_ip: source,
|
||||
external_ip: dest,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn extract_key_icmpv6<'a>(
|
||||
&mut self,
|
||||
packet: &RecvPacket<'a>,
|
||||
source_addr: IpAddress,
|
||||
dest_addr: IpAddress,
|
||||
payload: &IpPayloadSlice<'a>,
|
||||
) -> Result<Option<NatKey>> {
|
||||
let Some(ether) = packet.ether else {
|
||||
return Ok(None);
|
||||
};
|
||||
let (header, _) = Icmpv6Header::from_slice(payload.payload)?;
|
||||
let Icmpv6Type::EchoRequest(_) = header.icmp_type else {
|
||||
return Ok(None);
|
||||
};
|
||||
let source = IpEndpoint::new(source_addr, 0);
|
||||
let dest = IpEndpoint::new(dest_addr, 0);
|
||||
Ok(Some(NatKey {
|
||||
protocol: NatKeyProtocol::Icmp,
|
||||
client_mac: EthernetAddress(ether.source()),
|
||||
local_mac: EthernetAddress(ether.destination()),
|
||||
client_ip: source,
|
||||
external_ip: dest,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
37
network/src/pkt.rs
Normal file
37
network/src/pkt.rs
Normal file
@ -0,0 +1,37 @@
|
||||
use anyhow::Result;
|
||||
use etherparse::{Ethernet2Slice, Ipv4Slice, Ipv6Slice, LinkSlice, NetSlice, SlicedPacket};
|
||||
|
||||
pub enum RecvPacketIp<'a> {
|
||||
Ipv4(&'a Ipv4Slice<'a>),
|
||||
Ipv6(&'a Ipv6Slice<'a>),
|
||||
}
|
||||
|
||||
pub struct RecvPacket<'a> {
|
||||
pub raw: &'a [u8],
|
||||
pub slice: &'a SlicedPacket<'a>,
|
||||
pub ether: Option<&'a Ethernet2Slice<'a>>,
|
||||
pub ip: Option<RecvPacketIp<'a>>,
|
||||
}
|
||||
|
||||
impl RecvPacket<'_> {
|
||||
pub fn new<'a>(raw: &'a [u8], slice: &'a SlicedPacket<'a>) -> Result<RecvPacket<'a>> {
|
||||
let ether = match slice.link {
|
||||
Some(LinkSlice::Ethernet2(ref ether)) => Some(ether),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let ip = match slice.net {
|
||||
Some(NetSlice::Ipv4(ref ipv4)) => Some(RecvPacketIp::Ipv4(ipv4)),
|
||||
Some(NetSlice::Ipv6(ref ipv6)) => Some(RecvPacketIp::Ipv6(ipv6)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let packet = RecvPacket {
|
||||
raw,
|
||||
slice,
|
||||
ether,
|
||||
ip,
|
||||
};
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user