From f653ee8e9c705c97bf28e8266bf23327d2a1cc7b Mon Sep 17 00:00:00 2001 From: Alexandra Clifford Date: Tue, 29 Apr 2025 19:23:52 -0400 Subject: [PATCH 1/3] Add frame information to packet info popup --- oryx-common/src/lib.rs | 29 +++++++-- oryx-ebpf/src/main.rs | 79 ++++++++++++++--------- oryx-tui/src/app.rs | 18 +++--- oryx-tui/src/ebpf/egress.rs | 8 +-- oryx-tui/src/ebpf/ingress.rs | 8 +-- oryx-tui/src/filter.rs | 4 +- oryx-tui/src/packet.rs | 92 +++++++++++++++----------- oryx-tui/src/packet/eth_frame.rs | 100 +++++++++++++++++++++++++++++ oryx-tui/src/packet/link.rs | 14 ++-- oryx-tui/src/section/inspection.rs | 46 ++++++++++++- xtask/src/build.rs | 3 +- 11 files changed, 297 insertions(+), 104 deletions(-) create mode 100644 oryx-tui/src/packet/eth_frame.rs diff --git a/oryx-common/src/lib.rs b/oryx-common/src/lib.rs index 6dbcd2c..9ab45a1 100644 --- a/oryx-common/src/lib.rs +++ b/oryx-common/src/lib.rs @@ -2,19 +2,42 @@ use core::mem; -use network_types::{arp::ArpHdr, icmp::IcmpHdr, ip::IpHdr, tcp::TcpHdr, udp::UdpHdr}; +use network_types::{arp::ArpHdr, eth::EthHdr, icmp::IcmpHdr, ip::IpHdr, tcp::TcpHdr, udp::UdpHdr}; pub mod protocols; pub const MAX_FIREWALL_RULES: u32 = 32; pub const MAX_RULES_PORT: usize = 32; +#[repr(C)] +#[derive(Clone)] +pub struct RawFrame { + pub header: EthHdr, + pub payload: RawPacket, +} + +impl RawFrame { + pub const LEN: usize = mem::size_of::(); +} + #[repr(C)] pub enum RawPacket { Ip(IpHdr, ProtoHdr), Arp(ArpHdr), } +impl Clone for RawPacket { + fn clone(&self) -> Self { + match self { + Self::Ip(ip_hdr, proto_hdr) => match ip_hdr { + IpHdr::V4(ipv4_hdr) => Self::Ip(IpHdr::V4(*ipv4_hdr), *proto_hdr), + IpHdr::V6(ipv6_hdr) => Self::Ip(IpHdr::V6(*ipv6_hdr), *proto_hdr), + }, + Self::Arp(arp_hdr) => Self::Arp(*arp_hdr), + } + } +} + #[repr(C)] #[derive(Copy, Clone)] pub enum ProtoHdr { @@ -22,7 +45,3 @@ pub enum ProtoHdr { Udp(UdpHdr), Icmp(IcmpHdr), } - -impl RawPacket { - pub const LEN: usize = mem::size_of::(); -} diff --git a/oryx-ebpf/src/main.rs b/oryx-ebpf/src/main.rs index 051681d..8139b6f 100644 --- a/oryx-ebpf/src/main.rs +++ b/oryx-ebpf/src/main.rs @@ -18,11 +18,11 @@ use network_types::{ }; use oryx_common::{ protocols::{LinkProtocol, NetworkProtocol, Protocol, TransportProtocol}, - ProtoHdr, RawPacket, MAX_FIREWALL_RULES, MAX_RULES_PORT, + ProtoHdr, RawFrame, RawPacket, MAX_FIREWALL_RULES, MAX_RULES_PORT, }; #[map] -static DATA: RingBuf = RingBuf::with_byte_size(4096 * RawPacket::LEN as u32, 0); +static DATA: RingBuf = RingBuf::with_byte_size(4096 * RawFrame::LEN as u32, 0); #[map] static NETWORK_FILTERS: Array = Array::with_max_entries(8, 0); @@ -56,8 +56,8 @@ pub fn oryx(ctx: TcContext) -> i32 { } #[inline] -fn submit(packet: RawPacket) { - if let Some(mut buf) = DATA.reserve::(0) { +fn submit(packet: RawFrame) { + if let Some(mut buf) = DATA.reserve::(0) { unsafe { (*buf.as_mut_ptr()) = packet }; buf.submit(0); } @@ -183,10 +183,13 @@ fn process(ctx: TcContext) -> Result { return Ok(TC_ACT_PIPE); } - submit(RawPacket::Ip( - IpHdr::V4(header), - ProtoHdr::Tcp(unsafe { *tcphdr }), - )); + submit(RawFrame { + header: ethhdr, + payload: RawPacket::Ip( + IpHdr::V4(header), + ProtoHdr::Tcp(unsafe { *tcphdr }), + ), + }); } IpProto::Udp => { let udphdr: *const UdpHdr = ptr_at(&ctx, EthHdr::LEN + Ipv4Hdr::LEN)?; @@ -207,20 +210,26 @@ fn process(ctx: TcContext) -> Result { return Ok(TC_ACT_PIPE); } - submit(RawPacket::Ip( - IpHdr::V4(header), - ProtoHdr::Udp(unsafe { *udphdr }), - )); + submit(RawFrame { + header: ethhdr, + payload: RawPacket::Ip( + IpHdr::V4(header), + ProtoHdr::Udp(unsafe { *udphdr }), + ), + }); } IpProto::Icmp => { if filter_packet(Protocol::Network(NetworkProtocol::Icmp)) { return Ok(TC_ACT_PIPE); } let icmphdr: *const IcmpHdr = ptr_at(&ctx, EthHdr::LEN + Ipv4Hdr::LEN)?; - submit(RawPacket::Ip( - IpHdr::V4(header), - ProtoHdr::Icmp(unsafe { *icmphdr }), - )); + submit(RawFrame { + header: ethhdr, + payload: RawPacket::Ip( + IpHdr::V4(header), + ProtoHdr::Icmp(unsafe { *icmphdr }), + ), + }); } _ => {} } @@ -252,10 +261,13 @@ fn process(ctx: TcContext) -> Result { { return Ok(TC_ACT_PIPE); } - submit(RawPacket::Ip( - IpHdr::V6(header), - ProtoHdr::Tcp(unsafe { *tcphdr }), - )); + submit(RawFrame { + header: ethhdr, + payload: RawPacket::Ip( + IpHdr::V6(header), + ProtoHdr::Tcp(unsafe { *tcphdr }), + ), + }); } IpProto::Udp => { let udphdr: *const UdpHdr = ptr_at(&ctx, EthHdr::LEN + Ipv6Hdr::LEN)?; @@ -275,20 +287,26 @@ fn process(ctx: TcContext) -> Result { { return Ok(TC_ACT_PIPE); } - submit(RawPacket::Ip( - IpHdr::V6(header), - ProtoHdr::Udp(unsafe { *udphdr }), - )); + submit(RawFrame { + header: ethhdr, + payload: RawPacket::Ip( + IpHdr::V6(header), + ProtoHdr::Udp(unsafe { *udphdr }), + ), + }); } IpProto::Icmp => { if filter_packet(Protocol::Network(NetworkProtocol::Icmp)) { return Ok(TC_ACT_PIPE); } let icmphdr: *const IcmpHdr = ptr_at(&ctx, EthHdr::LEN + Ipv6Hdr::LEN)?; - submit(RawPacket::Ip( - IpHdr::V6(header), - ProtoHdr::Icmp(unsafe { *icmphdr }), - )); + submit(RawFrame { + header: ethhdr, + payload: RawPacket::Ip( + IpHdr::V6(header), + ProtoHdr::Icmp(unsafe { *icmphdr }), + ), + }); } _ => {} } @@ -298,7 +316,10 @@ fn process(ctx: TcContext) -> Result { return Ok(TC_ACT_PIPE); } let header: ArpHdr = ctx.load(EthHdr::LEN).map_err(|_| ())?; - submit(RawPacket::Arp(header)); + submit(RawFrame { + header: ethhdr, + payload: RawPacket::Arp(header), + }); } _ => {} }; diff --git a/oryx-tui/src/app.rs b/oryx-tui/src/app.rs index 1f55f82..f4b8c55 100644 --- a/oryx-tui/src/app.rs +++ b/oryx-tui/src/app.rs @@ -2,7 +2,7 @@ use clap::ArgMatches; use itertools::Itertools; use oryx_common::{ protocols::{LinkProtocol, NetworkProtocol, TransportProtocol}, - RawPacket, + RawFrame, }; use ratatui::{ layout::{Constraint, Direction, Layout}, @@ -19,7 +19,7 @@ use std::{ use crate::{ filter::Filter, help::Help, - packet::{direction::TrafficDirection, NetworkPacket}, + packet::{direction::TrafficDirection, EthFrame}, }; use crate::{filter::IoChannels, notification::Notification}; use crate::{packet::AppPacket, section::Section}; @@ -39,7 +39,7 @@ pub enum ActivePopup { #[derive(Debug)] pub struct DataEventHandler { - pub sender: kanal::Sender<[u8; RawPacket::LEN]>, + pub sender: kanal::Sender<[u8; RawFrame::LEN]>, pub handler: thread::JoinHandle<()>, } @@ -52,7 +52,7 @@ pub struct App { pub packets: Arc>>, pub notifications: Vec, pub section: Section, - pub data_channel_sender: kanal::Sender<([u8; RawPacket::LEN], TrafficDirection)>, + pub data_channel_sender: kanal::Sender<([u8; RawFrame::LEN], TrafficDirection)>, pub is_editing: bool, pub active_popup: Option, pub start_from_cli: bool, @@ -60,9 +60,7 @@ pub struct App { impl App { pub fn new(cli_args: &ArgMatches) -> Self { - let packets = Arc::new(RwLock::new(Vec::with_capacity( - RawPacket::LEN * 1024 * 1024, - ))); + let packets = Arc::new(RwLock::new(Vec::with_capacity(RawFrame::LEN * 1024 * 1024))); let (sender, receiver) = kanal::unbounded(); @@ -71,13 +69,15 @@ impl App { thread::spawn({ let packets = packets.clone(); move || loop { - if let Ok((raw_packet, direction)) = receiver.recv() { - let network_packet = NetworkPacket::from(raw_packet); + if let Ok((raw_frame, direction)) = receiver.recv() { + let eth_frame = EthFrame::from(raw_frame); + let network_packet = eth_frame.payload; let mut packets = packets.write().unwrap(); if packets.len() == packets.capacity() { packets.reserve(1024 * 1024); } let app_packet = AppPacket { + eth_header: eth_frame.header, packet: network_packet, direction, }; diff --git a/oryx-tui/src/ebpf/egress.rs b/oryx-tui/src/ebpf/egress.rs index d15c356..9dbfb25 100644 --- a/oryx-tui/src/ebpf/egress.rs +++ b/oryx-tui/src/ebpf/egress.rs @@ -13,7 +13,7 @@ use aya::{ EbpfLoader, }; use log::error; -use oryx_common::{protocols::Protocol, RawPacket, MAX_RULES_PORT}; +use oryx_common::{protocols::Protocol, RawFrame, MAX_RULES_PORT}; use crate::{ event::Event, @@ -32,7 +32,7 @@ use super::{ pub fn load_egress( iface: String, notification_sender: kanal::Sender, - data_sender: kanal::Sender<([u8; RawPacket::LEN], TrafficDirection)>, + data_sender: kanal::Sender<([u8; RawFrame::LEN], TrafficDirection)>, filter_channel_receiver: kanal::Receiver, firewall_egress_receiver: kanal::Receiver, terminate: Arc, @@ -219,8 +219,8 @@ pub fn load_egress( if terminate.load(std::sync::atomic::Ordering::Relaxed) { break; } - let packet: [u8; RawPacket::LEN] = item.to_owned().try_into().unwrap(); - data_sender.send((packet, TrafficDirection::Egress)).ok(); + let frame: [u8; RawFrame::LEN] = item.to_owned().try_into().unwrap(); + data_sender.send((frame, TrafficDirection::Egress)).ok(); } } } diff --git a/oryx-tui/src/ebpf/ingress.rs b/oryx-tui/src/ebpf/ingress.rs index 6057095..5e5c051 100644 --- a/oryx-tui/src/ebpf/ingress.rs +++ b/oryx-tui/src/ebpf/ingress.rs @@ -13,7 +13,7 @@ use aya::{ EbpfLoader, }; use log::error; -use oryx_common::{protocols::Protocol, RawPacket, MAX_RULES_PORT}; +use oryx_common::{protocols::Protocol, RawFrame, MAX_RULES_PORT}; use crate::{ event::Event, @@ -32,7 +32,7 @@ use super::{ pub fn load_ingress( iface: String, notification_sender: kanal::Sender, - data_sender: kanal::Sender<([u8; RawPacket::LEN], TrafficDirection)>, + data_sender: kanal::Sender<([u8; RawFrame::LEN], TrafficDirection)>, filter_channel_receiver: kanal::Receiver, firewall_ingress_receiver: kanal::Receiver, terminate: Arc, @@ -223,8 +223,8 @@ pub fn load_ingress( if terminate.load(std::sync::atomic::Ordering::Relaxed) { break; } - let packet: [u8; RawPacket::LEN] = item.to_owned().try_into().unwrap(); - data_sender.send((packet, TrafficDirection::Ingress)).ok(); + let frame: [u8; RawFrame::LEN] = item.to_owned().try_into().unwrap(); + data_sender.send((frame, TrafficDirection::Ingress)).ok(); } } } diff --git a/oryx-tui/src/filter.rs b/oryx-tui/src/filter.rs index 4fe6f0e..28559f1 100644 --- a/oryx-tui/src/filter.rs +++ b/oryx-tui/src/filter.rs @@ -13,7 +13,7 @@ use oryx_common::{ LinkProtocol, NetworkProtocol, Protocol, TransportProtocol, NB_LINK_PROTOCOL, NB_NETWORK_PROTOCOL, NB_TRANSPORT_PROTOCOL, }, - RawPacket, + RawFrame, }; use ratatui::{ layout::{Alignment, Constraint, Direction, Flex, Layout, Margin, Rect}, @@ -159,7 +159,7 @@ impl Filter { pub fn start( &mut self, notification_sender: kanal::Sender, - data_sender: kanal::Sender<([u8; RawPacket::LEN], TrafficDirection)>, + data_sender: kanal::Sender<([u8; RawFrame::LEN], TrafficDirection)>, ) -> AppResult<()> { let iface = self.interface.selected_interface.name.clone(); diff --git a/oryx-tui/src/packet.rs b/oryx-tui/src/packet.rs index 2fd7bc6..b1acf79 100644 --- a/oryx-tui/src/packet.rs +++ b/oryx-tui/src/packet.rs @@ -1,4 +1,5 @@ pub mod direction; +pub mod eth_frame; pub mod link; pub mod network; pub mod transport; @@ -8,12 +9,13 @@ use std::{fmt::Display, mem, net::Ipv4Addr}; use direction::TrafficDirection; use link::{ArpPacket, ArpType, MacAddr}; use network::{IcmpPacket, IcmpType, IpPacket, IpProto, Ipv4Packet, Ipv6Packet}; -use network_types::ip::IpHdr; -use oryx_common::{ProtoHdr, RawPacket}; +use network_types::{eth::EthHdr, ip::IpHdr}; +use oryx_common::{ProtoHdr, RawFrame, RawPacket}; use transport::{TcpPacket, UdpPacket}; #[derive(Debug, Copy, Clone)] pub struct AppPacket { + pub eth_header: EthHdr, pub packet: NetworkPacket, pub direction: TrafficDirection, } @@ -37,10 +39,15 @@ impl Display for NetworkPacket { } } -impl From<[u8; RawPacket::LEN]> for NetworkPacket { - fn from(value: [u8; RawPacket::LEN]) -> Self { - let raw_packet = value.as_ptr() as *const RawPacket; - match unsafe { &*raw_packet } { +pub struct EthFrame { + pub header: EthHdr, + pub payload: NetworkPacket, +} + +impl From<[u8; RawFrame::LEN]> for EthFrame { + fn from(value: [u8; RawFrame::LEN]) -> Self { + let raw_packet = value.as_ptr() as *const RawFrame; + match unsafe { &(*raw_packet).payload } { RawPacket::Ip(packet, proto) => match packet { IpHdr::V4(ipv4_packet) => { let src_ip = Ipv4Addr::from(u32::from_be(ipv4_packet.src_addr)); @@ -95,18 +102,21 @@ impl From<[u8; RawPacket::LEN]> for NetworkPacket { } }; - NetworkPacket::Ip(IpPacket::V4(Ipv4Packet { - src_ip, - dst_ip, - ihl: u8::from_be(ipv4_packet.ihl()), - tos: u8::from_be(ipv4_packet.tos), - total_length: u16::from_be(ipv4_packet.tot_len), - id: u16::from_be(ipv4_packet.id), - fragment_offset: u16::from_be(ipv4_packet.frag_off), - ttl: u8::from_be(ipv4_packet.ttl), - checksum: u16::from_be(ipv4_packet.check), - proto, - })) + EthFrame { + header: unsafe { (*raw_packet).header }, + payload: NetworkPacket::Ip(IpPacket::V4(Ipv4Packet { + src_ip, + dst_ip, + ihl: u8::from_be(ipv4_packet.ihl()), + tos: u8::from_be(ipv4_packet.tos), + total_length: u16::from_be(ipv4_packet.tot_len), + id: u16::from_be(ipv4_packet.id), + fragment_offset: u16::from_be(ipv4_packet.frag_off), + ttl: u8::from_be(ipv4_packet.ttl), + checksum: u16::from_be(ipv4_packet.check), + proto, + })), + } } IpHdr::V6(ipv6_packet) => { let src_ip = ipv6_packet.src_addr(); @@ -161,15 +171,18 @@ impl From<[u8; RawPacket::LEN]> for NetworkPacket { } }; - NetworkPacket::Ip(IpPacket::V6(Ipv6Packet { - traffic_class: ipv6_packet.priority(), - flow_label: ipv6_packet.flow_label, - payload_length: u16::from_be(ipv6_packet.payload_len), - hop_limit: u8::from_be(ipv6_packet.hop_limit), - src_ip, - dst_ip, - proto, - })) + EthFrame { + header: unsafe { (*raw_packet).header }, + payload: NetworkPacket::Ip(IpPacket::V6(Ipv6Packet { + traffic_class: ipv6_packet.priority(), + flow_label: ipv6_packet.flow_label, + payload_length: u16::from_be(ipv6_packet.payload_len), + hop_limit: u8::from_be(ipv6_packet.hop_limit), + src_ip, + dst_ip, + proto, + })), + } } }, RawPacket::Arp(packet) => { @@ -179,17 +192,20 @@ impl From<[u8; RawPacket::LEN]> for NetworkPacket { _ => unreachable!(), }; - Self::Arp(ArpPacket { - htype: packet.ptype, - ptype: packet.ptype, - hlen: u8::from_be(packet.hlen), - plen: u8::from_be(packet.plen), - arp_type, - src_mac: MacAddr(packet.sha), - src_ip: Ipv4Addr::from(packet.spa), - dst_mac: MacAddr(packet.tha), - dst_ip: Ipv4Addr::from(packet.tpa), - }) + EthFrame { + header: unsafe { (*raw_packet).header }, + payload: NetworkPacket::Arp(ArpPacket { + htype: packet.ptype, + ptype: packet.ptype, + hlen: u8::from_be(packet.hlen), + plen: u8::from_be(packet.plen), + arp_type, + src_mac: MacAddr(packet.sha), + src_ip: Ipv4Addr::from(packet.spa), + dst_mac: MacAddr(packet.tha), + dst_ip: Ipv4Addr::from(packet.tpa), + }), + } } } } diff --git a/oryx-tui/src/packet/eth_frame.rs b/oryx-tui/src/packet/eth_frame.rs new file mode 100644 index 0000000..1742bbc --- /dev/null +++ b/oryx-tui/src/packet/eth_frame.rs @@ -0,0 +1,100 @@ +use core::fmt::Display; + +use network_types::eth::{EthHdr, EtherType}; +use ratatui::{ + layout::{Constraint, Direction, Layout, Rect}, + style::{Style, Stylize}, + text::Span, + widgets::{Block, Borders, Padding, Paragraph, Row, Table}, + Frame, +}; + +use super::link::MacAddr; + +pub struct EthFrameHeader { + pub src: MacAddr, + pub dst: MacAddr, + pub ether_type: EtherTypeWrapper, +} + +pub struct EtherTypeWrapper(pub EtherType); + +impl From for EthFrameHeader { + fn from(value: EthHdr) -> Self { + Self { + src: MacAddr(value.src_addr), + dst: MacAddr(value.dst_addr), + ether_type: EtherTypeWrapper(value.ether_type), + } + } +} + +impl EthFrameHeader { + pub fn render(self, block: Rect, frame: &mut Frame) { + let (title_block, data_block) = { + let chunks = Layout::default() + .direction(Direction::Horizontal) + .constraints([Constraint::Length(6), Constraint::Fill(1)]) + .margin(2) + .split(block); + + (chunks[0], chunks[1]) + }; + + let title = Paragraph::new("Frame") + .bold() + .block(Block::new().padding(Padding::top({ + if title_block.height % 2 == 0 { + title_block.height / 2 - 1 + } else { + title_block.height / 2 + } + }))); + + let widths = [Constraint::Length(23), Constraint::Fill(1)]; + + let infos = [ + Row::new(vec![ + Span::styled("Dest. MAC Address", Style::new().bold()), + Span::from(self.dst.to_string()), + ]), + Row::new(vec![ + Span::styled("Source MAC Address", Style::new().bold()), + Span::from(self.src.to_string()), + ]), + ]; + let table = Table::new(infos, widths).column_spacing(2).block( + Block::default() + .borders(Borders::LEFT) + .border_style(Style::new().bold().light_blue()) + .border_type(ratatui::widgets::BorderType::Thick) + .style(Style::default()), + ); + frame.render_widget(table, data_block); + frame.render_widget(title, title_block); + } +} + +impl Display for EthFrameHeader { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "{} {} {} EthFrameHeader", + self.src, self.dst, self.ether_type + ) + } +} + +impl Display for EtherTypeWrapper { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.0 { + EtherType::Loop => write!(f, "Loop"), + EtherType::Ipv4 => write!(f, "Ipv4"), + EtherType::Arp => write!(f, "Arp"), + EtherType::Ipv6 => write!(f, "Ipv6"), + EtherType::FibreChannel => write!(f, "FibreChannel"), + EtherType::Infiniband => write!(f, "Infiniband"), + EtherType::LoopbackIeee8023 => write!(f, "LoopbackIeee8023"), + } + } +} diff --git a/oryx-tui/src/packet/link.rs b/oryx-tui/src/packet/link.rs index 189cb44..761c65f 100644 --- a/oryx-tui/src/packet/link.rs +++ b/oryx-tui/src/packet/link.rs @@ -26,20 +26,16 @@ impl ArpPacket { pub fn render(self, block: Rect, frame: &mut Frame) { let block = Layout::default() .direction(Direction::Vertical) - .constraints([ - Constraint::Fill(1), - Constraint::Length(13), - Constraint::Fill(1), - ]) - .flex(ratatui::layout::Flex::SpaceBetween) + .constraints([Constraint::Length(11), Constraint::Fill(1)]) + .flex(ratatui::layout::Flex::SpaceAround) .margin(1) - .split(block)[1]; + .split(block)[0]; let (title_block, data_block) = { let chunks = Layout::default() .direction(Direction::Horizontal) .constraints([Constraint::Length(6), Constraint::Fill(1)]) - .margin(2) + .margin(1) .split(block); (chunks[0], chunks[1]) @@ -94,7 +90,7 @@ impl ArpPacket { Span::from(self.dst_ip.to_string()), ]), ]; - let table = Table::new(infos, widths).column_spacing(3).block( + let table = Table::new(infos, widths).column_spacing(2).block( Block::default() .borders(Borders::LEFT) .border_style(Style::new().bold().yellow()) diff --git a/oryx-tui/src/section/inspection.rs b/oryx-tui/src/section/inspection.rs index 7cf9829..2ec97b6 100644 --- a/oryx-tui/src/section/inspection.rs +++ b/oryx-tui/src/section/inspection.rs @@ -19,6 +19,7 @@ use crate::{ filter::fuzzy::{self, Fuzzy}, notification::{Notification, NotificationLevel}, packet::{ + eth_frame::EthFrameHeader, network::{IpPacket, IpProto}, AppPacket, NetworkPacket, }, @@ -657,9 +658,50 @@ impl Inspection { .border_type(BorderType::Thick), block, ); + match app_packet.packet { - NetworkPacket::Ip(ip_packet) => ip_packet.render(block, frame), - NetworkPacket::Arp(arp_packet) => arp_packet.render(block, frame), + NetworkPacket::Ip(ip_packet) => { + let (network_packet_block, eth_frame_block) = { + let chunks = Layout::default() + .direction(Direction::Vertical) + .constraints(Constraint::from_percentages([70, 30])) + .flex(ratatui::layout::Flex::SpaceAround) + .margin(2) + .split(block); + + (chunks[0], chunks[1]) + }; + + // split to apply extra margin to line up with network packet rendering + let eth_frame_block = Layout::default() + .direction(Direction::Horizontal) + .constraints(Constraint::from_percentages([95, 5])) + .margin(2) + .split(eth_frame_block)[0]; + + EthFrameHeader::from(app_packet.eth_header).render(eth_frame_block, frame); + ip_packet.render(network_packet_block, frame) + } + NetworkPacket::Arp(arp_packet) => { + let (arp_block, eth_frame_block) = { + let chunks = Layout::default() + .direction(Direction::Vertical) + .constraints([ + Constraint::Fill(1), + Constraint::Percentage(50), + Constraint::Length(6), + Constraint::Fill(1), + ]) + .flex(ratatui::layout::Flex::Center) + .margin(2) + .split(block); + + (chunks[1], chunks[2]) + }; + + arp_packet.render(arp_block, frame); + EthFrameHeader::from(app_packet.eth_header).render(eth_frame_block, frame); + } }; } } diff --git a/xtask/src/build.rs b/xtask/src/build.rs index c33755a..e1faa22 100644 --- a/xtask/src/build.rs +++ b/xtask/src/build.rs @@ -53,7 +53,6 @@ pub fn build(opts: Options) -> Result<(), anyhow::Error> { Ok(()) } - /// Run linter on the project with ORYX_BIN_DIR env var set pub fn lint() -> Result<(), anyhow::Error> { set_ebpf_build_base_dir("debug"); @@ -71,4 +70,4 @@ pub fn lint() -> Result<(), anyhow::Error> { assert!(status.success()); Ok(()) -} \ No newline at end of file +} From 5a79a1f4b86d7c45da06e1685ca8003b582756ee Mon Sep 17 00:00:00 2001 From: Alexandra Clifford Date: Tue, 29 Apr 2025 19:51:20 -0400 Subject: [PATCH 2/3] silence some clippy warnings --- oryx-tui/src/filter.rs | 16 ++++++++-------- oryx-tui/src/filter/link.rs | 8 +------- oryx-tui/src/filter/network.rs | 8 +------- oryx-tui/src/filter/transport.rs | 8 +------- oryx-tui/src/help.rs | 8 +------- oryx-tui/src/interface.rs | 8 +------- oryx-tui/src/packet.rs | 4 ++-- oryx-tui/src/section/firewall.rs | 10 ++-------- 8 files changed, 17 insertions(+), 53 deletions(-) diff --git a/oryx-tui/src/filter.rs b/oryx-tui/src/filter.rs index 28559f1..5db4344 100644 --- a/oryx-tui/src/filter.rs +++ b/oryx-tui/src/filter.rs @@ -645,12 +645,12 @@ impl Filter { .map(|filter| { if self.transport.applied_protocols.contains(filter) { Span::styled( - format!(" {} ", filter), + format!(" {filter} "), Style::default().light_green(), ) } else { Span::styled( - format!(" {} ", filter), + format!(" {filter} "), Style::default().light_red(), ) } @@ -666,12 +666,12 @@ impl Filter { .map(|filter| { if self.network.applied_protocols.contains(filter) { Span::styled( - format!(" {} ", filter), + format!(" {filter} "), Style::default().light_green(), ) } else { Span::styled( - format!(" {} ", filter), + format!(" {filter} "), Style::default().light_red(), ) } @@ -687,12 +687,12 @@ impl Filter { .map(|filter| { if self.link.applied_protocols.contains(filter) { Span::styled( - format!(" {} ", filter), + format!(" {filter} "), Style::default().light_green(), ) } else { Span::styled( - format!(" {} ", filter), + format!(" {filter} "), Style::default().light_red(), ) } @@ -708,12 +708,12 @@ impl Filter { .map(|filter| { if self.traffic_direction.applied_direction.contains(filter) { Span::styled( - format!("󰞁 {} ", filter), + format!("󰞁 {filter} "), Style::default().light_green(), ) } else { Span::styled( - format!("󰿝 {} ", filter), + format!("󰿝 {filter} "), Style::default().light_red(), ) } diff --git a/oryx-tui/src/filter/link.rs b/oryx-tui/src/filter/link.rs index a9a8643..4e64b74 100644 --- a/oryx-tui/src/filter/link.rs +++ b/oryx-tui/src/filter/link.rs @@ -50,13 +50,7 @@ impl LinkFilter { pub fn scroll_up(&mut self) { let i = match self.state.selected() { - Some(i) => { - if i > 1 { - i - 1 - } else { - 0 - } - } + Some(i) => i.saturating_sub(1), None => 0, }; diff --git a/oryx-tui/src/filter/network.rs b/oryx-tui/src/filter/network.rs index 475bc96..1195141 100644 --- a/oryx-tui/src/filter/network.rs +++ b/oryx-tui/src/filter/network.rs @@ -55,13 +55,7 @@ impl NetworkFilter { pub fn scroll_up(&mut self) { let i = match self.state.selected() { - Some(i) => { - if i > 1 { - i - 1 - } else { - 0 - } - } + Some(i) => i.saturating_sub(1), None => 0, }; diff --git a/oryx-tui/src/filter/transport.rs b/oryx-tui/src/filter/transport.rs index 1937c09..185b1ce 100644 --- a/oryx-tui/src/filter/transport.rs +++ b/oryx-tui/src/filter/transport.rs @@ -54,13 +54,7 @@ impl TransportFilter { pub fn scroll_up(&mut self) { let i = match self.state.selected() { - Some(i) => { - if i > 1 { - i - 1 - } else { - 0 - } - } + Some(i) => i.saturating_sub(1), None => 0, }; diff --git a/oryx-tui/src/help.rs b/oryx-tui/src/help.rs index 980e170..ebe2fca 100644 --- a/oryx-tui/src/help.rs +++ b/oryx-tui/src/help.rs @@ -83,13 +83,7 @@ impl Help { } pub fn scroll_up(&mut self) { let i = match self.state.selected() { - Some(i) => { - if i > 1 { - i - 1 - } else { - 0 - } - } + Some(i) => i.saturating_sub(1), None => 1, }; *self.state.offset_mut() = i; diff --git a/oryx-tui/src/interface.rs b/oryx-tui/src/interface.rs index b6523c0..58caabf 100644 --- a/oryx-tui/src/interface.rs +++ b/oryx-tui/src/interface.rs @@ -142,13 +142,7 @@ impl Interface { } pub fn scroll_up(&mut self) { let i = match self.state.selected() { - Some(i) => { - if i > 1 { - i - 1 - } else { - 0 - } - } + Some(i) => i.saturating_sub(1), None => 0, }; diff --git a/oryx-tui/src/packet.rs b/oryx-tui/src/packet.rs index b1acf79..da15596 100644 --- a/oryx-tui/src/packet.rs +++ b/oryx-tui/src/packet.rs @@ -33,8 +33,8 @@ pub enum NetworkPacket { impl Display for NetworkPacket { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - Self::Arp(packet) => write!(f, "{}", packet), - Self::Ip(packet) => write!(f, "{}", packet), + Self::Arp(packet) => write!(f, "{packet}"), + Self::Ip(packet) => write!(f, "{packet}"), } } } diff --git a/oryx-tui/src/section/firewall.rs b/oryx-tui/src/section/firewall.rs index c81d85b..222cc2b 100644 --- a/oryx-tui/src/section/firewall.rs +++ b/oryx-tui/src/section/firewall.rs @@ -42,7 +42,7 @@ pub enum BlockedPort { impl Display for BlockedPort { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - BlockedPort::Single(p) => write!(f, "{}", p), + BlockedPort::Single(p) => write!(f, "{p}"), BlockedPort::All => write!(f, "*"), } } @@ -605,13 +605,7 @@ impl Firewall { return Ok(()); } let i = match self.state.selected() { - Some(i) => { - if i > 1 { - i - 1 - } else { - 0 - } - } + Some(i) => i.saturating_sub(1), None => 0, }; From 38f5513d0a737e7aa90eb6dcc16261b626082f9d Mon Sep 17 00:00:00 2001 From: Alexandra Clifford Date: Wed, 30 Apr 2025 19:03:17 -0400 Subject: [PATCH 3/3] fixup! Add frame information to packet info popup --- oryx-ebpf/src/main.rs | 4 ++-- oryx-tui/src/app.rs | 18 +++++++++--------- oryx-tui/src/handler.rs | 2 +- oryx-tui/src/packet/eth_frame.rs | 2 +- oryx-tui/src/section/inspection.rs | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/oryx-ebpf/src/main.rs b/oryx-ebpf/src/main.rs index 8139b6f..de3354b 100644 --- a/oryx-ebpf/src/main.rs +++ b/oryx-ebpf/src/main.rs @@ -56,9 +56,9 @@ pub fn oryx(ctx: TcContext) -> i32 { } #[inline] -fn submit(packet: RawFrame) { +fn submit(frame: RawFrame) { if let Some(mut buf) = DATA.reserve::(0) { - unsafe { (*buf.as_mut_ptr()) = packet }; + unsafe { (*buf.as_mut_ptr()) = frame }; buf.submit(0); } } diff --git a/oryx-tui/src/app.rs b/oryx-tui/src/app.rs index f4b8c55..cf24c9c 100644 --- a/oryx-tui/src/app.rs +++ b/oryx-tui/src/app.rs @@ -49,7 +49,7 @@ pub struct App { pub help: Help, pub filter: Filter, pub start_sniffing: bool, - pub packets: Arc>>, + pub frames: Arc>>, pub notifications: Vec, pub section: Section, pub data_channel_sender: kanal::Sender<([u8; RawFrame::LEN], TrafficDirection)>, @@ -60,28 +60,28 @@ pub struct App { impl App { pub fn new(cli_args: &ArgMatches) -> Self { - let packets = Arc::new(RwLock::new(Vec::with_capacity(RawFrame::LEN * 1024 * 1024))); + let frames = Arc::new(RwLock::new(Vec::with_capacity(RawFrame::LEN * 1024 * 1024))); let (sender, receiver) = kanal::unbounded(); let firewall_channels = IoChannels::new(); thread::spawn({ - let packets = packets.clone(); + let frames = frames.clone(); move || loop { if let Ok((raw_frame, direction)) = receiver.recv() { let eth_frame = EthFrame::from(raw_frame); let network_packet = eth_frame.payload; - let mut packets = packets.write().unwrap(); - if packets.len() == packets.capacity() { - packets.reserve(1024 * 1024); + let mut frames = frames.write().unwrap(); + if frames.len() == frames.capacity() { + frames.reserve(1024 * 1024); } let app_packet = AppPacket { eth_header: eth_frame.header, packet: network_packet, direction, }; - packets.push(app_packet); + frames.push(app_packet); } } }); @@ -186,9 +186,9 @@ impl App { direction, ), start_sniffing: false, - packets: packets.clone(), + frames: frames.clone(), notifications: Vec::new(), - section: Section::new(packets.clone(), firewall_channels.clone()), + section: Section::new(frames.clone(), firewall_channels.clone()), data_channel_sender: sender, is_editing: false, active_popup: None, diff --git a/oryx-tui/src/handler.rs b/oryx-tui/src/handler.rs index e9e0a23..a7f4647 100644 --- a/oryx-tui/src/handler.rs +++ b/oryx-tui/src/handler.rs @@ -21,7 +21,7 @@ pub fn handle_key_events( match key_event.code { KeyCode::Enter => { if app.filter.focused_block == FocusedBlock::Apply { - app.section.stats = Some(Stats::new(app.packets.clone())); + app.section.stats = Some(Stats::new(app.frames.clone())); app.filter .start(event_sender.clone(), app.data_channel_sender.clone())?; diff --git a/oryx-tui/src/packet/eth_frame.rs b/oryx-tui/src/packet/eth_frame.rs index 1742bbc..260e08e 100644 --- a/oryx-tui/src/packet/eth_frame.rs +++ b/oryx-tui/src/packet/eth_frame.rs @@ -55,7 +55,7 @@ impl EthFrameHeader { let infos = [ Row::new(vec![ - Span::styled("Dest. MAC Address", Style::new().bold()), + Span::styled("Dest MAC Address", Style::new().bold()), Span::from(self.dst.to_string()), ]), Row::new(vec![ diff --git a/oryx-tui/src/section/inspection.rs b/oryx-tui/src/section/inspection.rs index 2ec97b6..efac0c7 100644 --- a/oryx-tui/src/section/inspection.rs +++ b/oryx-tui/src/section/inspection.rs @@ -665,7 +665,7 @@ impl Inspection { let chunks = Layout::default() .direction(Direction::Vertical) .constraints(Constraint::from_percentages([70, 30])) - .flex(ratatui::layout::Flex::SpaceAround) + .flex(ratatui::layout::Flex::Center) .margin(2) .split(block);