diff --git a/rust/relay/ebpf-turn-router/src/error.rs b/rust/relay/ebpf-turn-router/src/error.rs index 9de2cd50e..a1a633311 100644 --- a/rust/relay/ebpf-turn-router/src/error.rs +++ b/rust/relay/ebpf-turn-router/src/error.rs @@ -1,36 +1,34 @@ use core::num::NonZeroUsize; -use aya_ebpf::bindings::xdp_action; - #[derive(Debug, Clone, Copy)] pub enum Error { PacketTooShort, + NotUdp, + NotTurn, + NotIp, Ipv4PacketWithOptions, NotAChannelDataMessage, BadChannelDataLength, NoChannelBinding, -} - -impl Error { - pub fn xdp_action(&self) -> xdp_action::Type { - match self { - Error::PacketTooShort => xdp_action::XDP_PASS, - Error::Ipv4PacketWithOptions => xdp_action::XDP_PASS, - Error::BadChannelDataLength => xdp_action::XDP_DROP, - Error::NotAChannelDataMessage => xdp_action::XDP_PASS, - Error::NoChannelBinding => xdp_action::XDP_PASS, - } - } + XdpLoadBytesFailed, + XdpAdjustHeadFailed, + XdpStoreBytesFailed, } impl aya_log_ebpf::WriteToBuf for Error { fn write(self, buf: &mut [u8]) -> Option { let msg = match self { Error::PacketTooShort => "Packet is too short", + Error::NotUdp => "Not a UDP packet", + Error::NotTurn => "Not TURN traffic", + Error::NotIp => "Not an IP packet", Error::Ipv4PacketWithOptions => "IPv4 packet has options", Error::NotAChannelDataMessage => "Not a channel data message", Error::BadChannelDataLength => "Channel data length does not match packet length", Error::NoChannelBinding => "No channel binding", + Error::XdpLoadBytesFailed => "Failed to load bytes", + Error::XdpAdjustHeadFailed => "Failed to adjust head", + Error::XdpStoreBytesFailed => "Failed to store bytes", }; msg.write(buf) diff --git a/rust/relay/ebpf-turn-router/src/main.rs b/rust/relay/ebpf-turn-router/src/main.rs index 21be07f98..9f934477e 100644 --- a/rust/relay/ebpf-turn-router/src/main.rs +++ b/rust/relay/ebpf-turn-router/src/main.rs @@ -56,12 +56,28 @@ static UDP_TO_CHAN_66: HashMap = #[xdp] pub fn handle_turn(ctx: XdpContext) -> u32 { - try_handle_turn(&ctx).unwrap_or_else(|e| { - let action = e.xdp_action(); + try_handle_turn(&ctx).unwrap_or_else(|e| match e { + Error::NotUdp + | Error::NotTurn + | Error::NotIp + | Error::NotAChannelDataMessage + | Error::Ipv4PacketWithOptions => xdp_action::XDP_PASS, - debug!(&ctx, "Failed to handle packet {}; action = {}", e, action); + Error::XdpStoreBytesFailed + | Error::XdpAdjustHeadFailed + | Error::XdpLoadBytesFailed + | Error::PacketTooShort + | Error::NoChannelBinding => { + debug!(&ctx, "Failed to handle packet: {}", e); - action + xdp_action::XDP_PASS + } + + Error::BadChannelDataLength => { + debug!(&ctx, "Failed to handle packet: {}; dropping", e); + + xdp_action::XDP_DROP + } }) } @@ -69,27 +85,24 @@ pub fn handle_turn(ctx: XdpContext) -> u32 { fn try_handle_turn(ctx: &XdpContext) -> Result { let eth = Eth::parse(ctx)?; - let action = match eth.ether_type() { + match eth.ether_type() { EtherType::Ipv4 => try_handle_turn_ipv4(ctx)?, EtherType::Ipv6 => try_handle_turn_ipv6(ctx)?, - _ => return Ok(xdp_action::XDP_PASS), + _ => return Err(Error::NotIp), }; - // If we send the packet back out, swap the source and destination MAC addresses. - // We will have adjusted the packet pointers so we need to reparse the packet. - if action == xdp_action::XDP_TX { - Eth::parse(ctx)?.swap_src_and_dst(); - } + // If we get to here, we modified the packet and need to send it back out again. + Eth::parse(ctx)?.swap_src_and_dst(); - Ok(action) + Ok(xdp_action::XDP_TX) } #[inline(always)] -fn try_handle_turn_ipv4(ctx: &XdpContext) -> Result { +fn try_handle_turn_ipv4(ctx: &XdpContext) -> Result<(), Error> { let ipv4 = Ip4::parse(ctx)?; if ipv4.protocol() != IpProto::Udp { - return Ok(xdp_action::XDP_PASS); + return Err(Error::NotUdp); } let udp = Udp::parse(ctx, Ipv4Hdr::LEN)?; // TODO: Change the API so we parse the UDP header _from_ the ipv4 struct? @@ -106,28 +119,24 @@ fn try_handle_turn_ipv4(ctx: &XdpContext) -> Result { ); if config::allocation_range().contains(&udp.dst()) { - let action = try_handle_ipv4_udp_to_channel_data(ctx, ipv4, udp)?; + try_handle_ipv4_udp_to_channel_data(ctx, ipv4, udp)?; stats::emit_data_relayed(ctx, udp_payload_len); - return Ok(action); + return Ok(()); } if udp.dst() == 3478 { - let action = try_handle_ipv4_channel_data_to_udp(ctx, ipv4, udp)?; + try_handle_ipv4_channel_data_to_udp(ctx, ipv4, udp)?; stats::emit_data_relayed(ctx, udp_payload_len - CdHdr::LEN as u16); - return Ok(action); + return Ok(()); } - Ok(xdp_action::XDP_PASS) + Err(Error::NotTurn) } #[inline(always)] -fn try_handle_ipv4_channel_data_to_udp( - ctx: &XdpContext, - ipv4: Ip4, - udp: Udp, -) -> Result { +fn try_handle_ipv4_channel_data_to_udp(ctx: &XdpContext, ipv4: Ip4, udp: Udp) -> Result<(), Error> { let cd = ChannelData::parse(ctx, Ipv4Hdr::LEN)?; // SAFETY: ??? @@ -147,17 +156,13 @@ fn try_handle_ipv4_channel_data_to_udp( new_udp_len, ); - remove_channel_data_header_ipv4(ctx); + remove_channel_data_header_ipv4(ctx)?; - Ok(xdp_action::XDP_TX) + Ok(()) } #[inline(always)] -fn try_handle_ipv4_udp_to_channel_data( - ctx: &XdpContext, - ipv4: Ip4, - udp: Udp, -) -> Result { +fn try_handle_ipv4_udp_to_channel_data(ctx: &XdpContext, ipv4: Ip4, udp: Udp) -> Result<(), Error> { let client_and_channel = unsafe { UDP_TO_CHAN_44.get(&PortAndPeerV4::new(ipv4.src(), udp.dst(), udp.src())) } .ok_or(Error::NoChannelBinding)?; @@ -180,17 +185,17 @@ fn try_handle_ipv4_udp_to_channel_data( let channel_data_header = [cd_num[0], cd_num[1], cd_len[0], cd_len[1]]; - add_channel_data_header_ipv4(ctx, channel_data_header); + add_channel_data_header_ipv4(ctx, channel_data_header)?; - Ok(xdp_action::XDP_TX) + Ok(()) } #[inline(always)] -fn try_handle_turn_ipv6(ctx: &XdpContext) -> Result { +fn try_handle_turn_ipv6(ctx: &XdpContext) -> Result<(), Error> { let ipv6 = Ip6::parse(ctx)?; if ipv6.protocol() != IpProto::Udp { - return Ok(xdp_action::XDP_PASS); + return Err(Error::NotUdp); } let udp = Udp::parse(ctx, Ipv6Hdr::LEN)?; // TODO: Change the API so we parse the UDP header _from_ the ipv6 struct? @@ -207,27 +212,23 @@ fn try_handle_turn_ipv6(ctx: &XdpContext) -> Result { ); if config::allocation_range().contains(&udp.dst()) { - let action = try_handle_ipv6_udp_to_channel_data(ctx, ipv6, udp)?; + try_handle_ipv6_udp_to_channel_data(ctx, ipv6, udp)?; stats::emit_data_relayed(ctx, udp_payload_len); - return Ok(action); + return Ok(()); } if udp.dst() == 3478 { - let action = try_handle_ipv6_channel_data_to_udp(ctx, ipv6, udp)?; + try_handle_ipv6_channel_data_to_udp(ctx, ipv6, udp)?; stats::emit_data_relayed(ctx, udp_payload_len - CdHdr::LEN as u16); - return Ok(action); + return Ok(()); } - Ok(xdp_action::XDP_PASS) + Err(Error::NotTurn) } -fn try_handle_ipv6_udp_to_channel_data( - ctx: &XdpContext, - ipv6: Ip6, - udp: Udp, -) -> Result { +fn try_handle_ipv6_udp_to_channel_data(ctx: &XdpContext, ipv6: Ip6, udp: Udp) -> Result<(), Error> { let client_and_channel = unsafe { UDP_TO_CHAN_66.get(&PortAndPeerV6::new(ipv6.src(), udp.dst(), udp.src())) } .ok_or(Error::NoChannelBinding)?; @@ -250,16 +251,12 @@ fn try_handle_ipv6_udp_to_channel_data( let channel_data_header = [cd_num[0], cd_num[1], cd_len[0], cd_len[1]]; - add_channel_data_header_ipv6(ctx, channel_data_header); + add_channel_data_header_ipv6(ctx, channel_data_header)?; - Ok(xdp_action::XDP_TX) + Ok(()) } -fn try_handle_ipv6_channel_data_to_udp( - ctx: &XdpContext, - ipv6: Ip6, - udp: Udp, -) -> Result { +fn try_handle_ipv6_channel_data_to_udp(ctx: &XdpContext, ipv6: Ip6, udp: Udp) -> Result<(), Error> { let cd = ChannelData::parse(ctx, Ipv6Hdr::LEN)?; // SAFETY: ??? @@ -279,9 +276,9 @@ fn try_handle_ipv6_channel_data_to_udp( new_udp_len, ); - remove_channel_data_header_ipv6(ctx); + remove_channel_data_header_ipv6(ctx)?; - Ok(xdp_action::XDP_TX) + Ok(()) } /// Defines our panic handler. diff --git a/rust/relay/ebpf-turn-router/src/move_headers.rs b/rust/relay/ebpf-turn-router/src/move_headers.rs index 924e71755..6810c7a52 100644 --- a/rust/relay/ebpf-turn-router/src/move_headers.rs +++ b/rust/relay/ebpf-turn-router/src/move_headers.rs @@ -9,42 +9,52 @@ use network_types::{ udp::UdpHdr, }; -use crate::channel_data::CdHdr; +use crate::{channel_data::CdHdr, error::Error}; #[inline(always)] -pub fn remove_channel_data_header_ipv4(ctx: &XdpContext) { +pub fn remove_channel_data_header_ipv4(ctx: &XdpContext) -> Result<(), Error> { move_headers::<{ CdHdr::LEN as i32 }, { Ipv4Hdr::LEN }>(ctx) } #[inline(always)] -pub fn add_channel_data_header_ipv4(ctx: &XdpContext, mut header: [u8; 4]) { - move_headers::<{ -(CdHdr::LEN as i32) }, { Ipv4Hdr::LEN }>(ctx); +pub fn add_channel_data_header_ipv4(ctx: &XdpContext, mut header: [u8; 4]) -> Result<(), Error> { + move_headers::<{ -(CdHdr::LEN as i32) }, { Ipv4Hdr::LEN }>(ctx)?; let offset = (EthHdr::LEN + Ipv4Hdr::LEN + UdpHdr::LEN) as u32; let header_ptr = &mut header as *mut _ as *mut c_void; let header_len = CdHdr::LEN as u32; - unsafe { bpf_xdp_store_bytes(ctx.ctx, offset, header_ptr, header_len) }; + if unsafe { bpf_xdp_store_bytes(ctx.ctx, offset, header_ptr, header_len) } < 0 { + return Err(Error::XdpStoreBytesFailed); + } + + Ok(()) } #[inline(always)] -pub fn remove_channel_data_header_ipv6(ctx: &XdpContext) { +pub fn remove_channel_data_header_ipv6(ctx: &XdpContext) -> Result<(), Error> { move_headers::<{ CdHdr::LEN as i32 }, { Ipv6Hdr::LEN }>(ctx) } #[inline(always)] -pub fn add_channel_data_header_ipv6(ctx: &XdpContext, mut header: [u8; 4]) { - move_headers::<{ -(CdHdr::LEN as i32) }, { Ipv6Hdr::LEN }>(ctx); +pub fn add_channel_data_header_ipv6(ctx: &XdpContext, mut header: [u8; 4]) -> Result<(), Error> { + move_headers::<{ -(CdHdr::LEN as i32) }, { Ipv6Hdr::LEN }>(ctx)?; let offset = (EthHdr::LEN + Ipv6Hdr::LEN + UdpHdr::LEN) as u32; let header_ptr = &mut header as *mut _ as *mut c_void; let header_len = CdHdr::LEN as u32; - unsafe { bpf_xdp_store_bytes(ctx.ctx, offset, header_ptr, header_len) }; + if unsafe { bpf_xdp_store_bytes(ctx.ctx, offset, header_ptr, header_len) } < 0 { + return Err(Error::XdpStoreBytesFailed); + } + + Ok(()) } #[inline(always)] -fn move_headers(ctx: &XdpContext) { +fn move_headers( + ctx: &XdpContext, +) -> Result<(), Error> { // Scratch space for our headers. // IPv6 headers are always 40 bytes long. // IPv4 headers are between 20 and 60 bytes long. @@ -58,11 +68,18 @@ fn move_headers(ctx: &XdpContext) let headers_len = (EthHdr::LEN + IP_HEADER_LEN + UdpHdr::LEN) as u32; // Copy headers into buffer. - unsafe { bpf_xdp_load_bytes(ctx.ctx, 0, headers_ptr, headers_len) }; + if unsafe { bpf_xdp_load_bytes(ctx.ctx, 0, headers_ptr, headers_len) } < 0 { + return Err(Error::XdpLoadBytesFailed); + } - // Move the head for the packet by `DELTA`. - unsafe { bpf_xdp_adjust_head(ctx.ctx, DELTA) }; + if unsafe { bpf_xdp_adjust_head(ctx.ctx, DELTA) } < 0 { + return Err(Error::XdpAdjustHeadFailed); + } // Copy the headers back. - unsafe { bpf_xdp_store_bytes(ctx.ctx, 0, headers_ptr, headers_len) }; + if unsafe { bpf_xdp_store_bytes(ctx.ctx, 0, headers_ptr, headers_len) } < 0 { + return Err(Error::XdpStoreBytesFailed); + } + + Ok(()) }