diff --git a/network/src/backend.rs b/network/src/backend.rs index e1239bc..f849d96 100644 --- a/network/src/backend.rs +++ b/network/src/backend.rs @@ -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 => {} } diff --git a/network/src/lib.rs b/network/src/lib.rs index e30caa3..c346758 100644 --- a/network/src/lib.rs +++ b/network/src/lib.rs @@ -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; diff --git a/network/src/nat.rs b/network/src/nat.rs index fb39ca4..ebc8aa3 100644 --- a/network/src/nat.rs +++ b/network/src/nat.rs @@ -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> { + 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> { + 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> { + 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> { + 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> { + 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> { + 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, + })) + } } diff --git a/network/src/pkt.rs b/network/src/pkt.rs new file mode 100644 index 0000000..91dbfed --- /dev/null +++ b/network/src/pkt.rs @@ -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>, +} + +impl RecvPacket<'_> { + pub fn new<'a>(raw: &'a [u8], slice: &'a SlicedPacket<'a>) -> Result> { + 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) + } +}