diff --git a/Cargo.lock b/Cargo.lock index 1d7babd..15588f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,7 +117,7 @@ checksum = "d18bc4e506fbb85ab7392ed993a7db4d1a452c71b75a246af4a80ab8c9d2dd50" dependencies = [ "assert_matches", "aya-obj", - "bitflags 2.9.2", + "bitflags 2.9.3", "bytes", "libc", "log", @@ -169,9 +169,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.2" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" +checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" [[package]] name = "block-buffer" @@ -217,9 +217,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.33" +version = "1.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee0f8803222ba5a7e2777dd72ca451868909b1ac410621b676adf07280e9b5f" +checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" dependencies = [ "shlex", ] @@ -372,7 +372,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "crossterm_winapi", "mio", "parking_lot", @@ -388,7 +388,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "crossterm_winapi", "derive_more", "document-features", @@ -770,9 +770,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indexmap" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" dependencies = [ "equivalent", "hashbrown", @@ -915,7 +915,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "libc", ] @@ -925,7 +925,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51a1679740111eb63b7b4cb3c97b1d5d9f82e142292a25edcfdb4120a48b3880" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", ] [[package]] @@ -1041,8 +1041,7 @@ dependencies = [ [[package]] name = "network-types" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f06f1863cb5565864300c6bfb012312969908878d2ca5881eaf0bbdb8b519c23" +source = "git+https://github.com/vadorovsky/network-types?rev=b78424c#b78424c582951ac0af4392bce595d0cb236280e8" dependencies = [ "memoffset", ] @@ -1053,7 +1052,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "cfg-if", "cfg_aliases", "libc", @@ -1174,6 +1173,7 @@ dependencies = [ "regex", "serde", "serde_json", + "strum 0.27.2", "tui-big-text", "tui-input", "uuid", @@ -1370,7 +1370,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "cassowary", "compact_str 0.8.1", "crossterm 0.28.1", @@ -1405,7 +1405,7 @@ version = "0.1.0-alpha.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f836b2eac888da74162b680a8facdbe784ae73df3b0f711eef74bb90a7477f78" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "compact_str 0.9.0", "hashbrown", "indoc", @@ -1456,7 +1456,7 @@ version = "0.3.0-alpha.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388428527811be6da3e23157d951308d9eae4ce1b4d1d545a55673bbcdfb7326" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "hashbrown", "indoc", "instability", @@ -1475,7 +1475,7 @@ version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", ] [[package]] @@ -1491,9 +1491,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" dependencies = [ "aho-corasick", "memchr", @@ -1503,9 +1503,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", @@ -1514,9 +1514,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "rustix" @@ -1524,7 +1524,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "errno", "libc", "linux-raw-sys 0.4.15", @@ -1537,7 +1537,7 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", "errno", "libc", "linux-raw-sys 0.9.4", @@ -1759,7 +1759,7 @@ checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" dependencies = [ "anyhow", "base64", - "bitflags 2.9.2", + "bitflags 2.9.3", "fancy-regex", "filedescriptor", "finl_unicode", @@ -2347,7 +2347,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.2", + "bitflags 2.9.3", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 197ee95..19f75e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ repository = "https://github.com/pythops/oryx" homepage = "https://github.com/pythops/oryx" [workspace.dependencies] -network-types = "0.1.0" +network-types = { git = "https://github.com/vadorovsky/network-types", rev = "b78424c" } [profile.release] lto = "fat" diff --git a/oryx-common/src/lib.rs b/oryx-common/src/lib.rs index f2ab08c..2c36e08 100644 --- a/oryx-common/src/lib.rs +++ b/oryx-common/src/lib.rs @@ -4,7 +4,7 @@ use core::mem; use network_types::{ - arp::ArpHdr, eth::EthHdr, icmp::IcmpHdr, ip::IpHdr, sctp::SctpHdr, tcp::TcpHdr, udp::UdpHdr, + arp::ArpHdr, eth::EthHdr, icmp::Icmp, ip::IpHdr, sctp::SctpHdr, tcp::TcpHdr, udp::UdpHdr, }; pub mod protocols; @@ -64,5 +64,5 @@ pub enum ProtoHdr { Tcp(TcpHdr), Udp(UdpHdr), Sctp(SctpHdr), - Icmp(IcmpHdr), + Icmp(Icmp), } diff --git a/oryx-common/src/protocols.rs b/oryx-common/src/protocols.rs index 46308a6..c89b8ec 100644 --- a/oryx-common/src/protocols.rs +++ b/oryx-common/src/protocols.rs @@ -40,7 +40,7 @@ impl TransportProtocol { // Network Protocols -pub const NB_NETWORK_PROTOCOL: u16 = 3; +pub const NB_NETWORK_PROTOCOL: u16 = 4; #[derive(Debug, Copy, Clone, PartialEq, AsRefStr, Display, EnumString)] #[repr(C)] @@ -52,15 +52,19 @@ pub enum NetworkProtocol { Ipv6 = 1, #[strum(ascii_case_insensitive)] - Icmp = 2, + Icmpv4 = 2, + + #[strum(ascii_case_insensitive)] + Icmpv6 = 3, } impl NetworkProtocol { - pub fn all() -> [NetworkProtocol; 3] { + pub fn all() -> [NetworkProtocol; 4] { [ NetworkProtocol::Ipv4, NetworkProtocol::Ipv6, - NetworkProtocol::Icmp, + NetworkProtocol::Icmpv4, + NetworkProtocol::Icmpv6, ] } } diff --git a/oryx-ebpf/Cargo.lock b/oryx-ebpf/Cargo.lock index 70b3774..61f3ec3 100644 --- a/oryx-ebpf/Cargo.lock +++ b/oryx-ebpf/Cargo.lock @@ -65,8 +65,7 @@ dependencies = [ [[package]] name = "network-types" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f06f1863cb5565864300c6bfb012312969908878d2ca5881eaf0bbdb8b519c23" +source = "git+https://github.com/vadorovsky/network-types?rev=b78424c#b78424c582951ac0af4392bce595d0cb236280e8" dependencies = [ "memoffset", ] diff --git a/oryx-ebpf/Cargo.toml b/oryx-ebpf/Cargo.toml index 6a1db42..304c0c9 100644 --- a/oryx-ebpf/Cargo.toml +++ b/oryx-ebpf/Cargo.toml @@ -10,7 +10,7 @@ homepage = "https://github.com/pythops/oryx" [dependencies] aya-ebpf = "0.1.1" oryx-common = { path = "../oryx-common" } -network-types = "0.1.0" +network-types = { git = "https://github.com/vadorovsky/network-types", rev = "b78424c" } [[bin]] name = "oryx" diff --git a/oryx-ebpf/src/main.rs b/oryx-ebpf/src/main.rs index dad4953..86390f2 100644 --- a/oryx-ebpf/src/main.rs +++ b/oryx-ebpf/src/main.rs @@ -12,7 +12,7 @@ use core::mem; use network_types::{ arp::ArpHdr, eth::{EthHdr, EtherType}, - icmp::IcmpHdr, + icmp::{Icmp, IcmpHdr, IcmpV6Hdr}, ip::{IpHdr, IpProto, Ipv4Hdr, Ipv6Hdr}, sctp::SctpHdr, tcp::TcpHdr, @@ -285,7 +285,7 @@ fn process(ctx: TcContext) -> Result { } } IpProto::Icmp => { - if filter_packet(Protocol::Network(NetworkProtocol::Icmp)) { + if filter_packet(Protocol::Network(NetworkProtocol::Icmpv4)) { return Ok(TC_ACT_PIPE); } let icmp_header: *const IcmpHdr = ptr_at(&ctx, EthHdr::LEN + Ipv4Hdr::LEN)?; @@ -296,7 +296,7 @@ fn process(ctx: TcContext) -> Result { header: *eth_header, payload: RawPacket::Ip( IpHdr::V4(*ipv4_header), - ProtoHdr::Icmp(*icmp_header), + ProtoHdr::Icmp(Icmp::V4(*icmp_header)), ), }, pid, @@ -421,11 +421,11 @@ fn process(ctx: TcContext) -> Result { }); } } - IpProto::Icmp => { - if filter_packet(Protocol::Network(NetworkProtocol::Icmp)) { + IpProto::Ipv6Icmp => { + if filter_packet(Protocol::Network(NetworkProtocol::Icmpv6)) { return Ok(TC_ACT_PIPE); } - let icmp_header: *const IcmpHdr = ptr_at(&ctx, EthHdr::LEN + Ipv6Hdr::LEN)?; + let icmp_header: *const IcmpV6Hdr = ptr_at(&ctx, EthHdr::LEN + Ipv6Hdr::LEN)?; unsafe { submit(RawData { @@ -433,7 +433,7 @@ fn process(ctx: TcContext) -> Result { header: *eth_header, payload: RawPacket::Ip( IpHdr::V6(*ipv6_header), - ProtoHdr::Icmp(*icmp_header), + ProtoHdr::Icmp(Icmp::V6(*icmp_header)), ), }, pid, diff --git a/oryx-tui/Cargo.toml b/oryx-tui/Cargo.toml index a450dd9..a476312 100644 --- a/oryx-tui/Cargo.toml +++ b/oryx-tui/Cargo.toml @@ -30,6 +30,7 @@ serde_json = "1" serde = { version = "1", features = ["derive"] } regex = "1" chrono = "0.4" +strum = { version = "0.27", features = ["derive"] } [[bin]] name = "oryx" diff --git a/oryx-tui/src/export.rs b/oryx-tui/src/export.rs index cff3652..136b9f8 100644 --- a/oryx-tui/src/export.rs +++ b/oryx-tui/src/export.rs @@ -10,7 +10,7 @@ use crate::{ app::AppResult, packet::{ AppPacket, NetworkPacket, - network::{IpPacket, IpProto}, + network::{IpPacket, ip::IpProto}, }, }; @@ -112,7 +112,7 @@ pub fn export(packets: &[AppPacket]) -> AppResult<()> { writeln!( file, "{:39} {:^11} {:39} {:^11} {:10} {:10} {:10}", - ipv4_packet.src_ip, "-", ipv4_packet.dst_ip, "-", "ICMP", pid, date + ipv4_packet.src_ip, "-", ipv4_packet.dst_ip, "-", "ICMPv4", pid, date )?; } }, @@ -160,7 +160,7 @@ pub fn export(packets: &[AppPacket]) -> AppResult<()> { writeln!( file, "{:39} {:^11} {:39} {:^11} {:10} {:10} {:10}", - ipv6_packet.src_ip, "-", ipv6_packet.dst_ip, "-", "ICMP", pid, date + ipv6_packet.src_ip, "-", ipv6_packet.dst_ip, "-", "ICMPv6", pid, date )?; } }, diff --git a/oryx-tui/src/filter/network.rs b/oryx-tui/src/filter/network.rs index 3f434d9..9cffdfa 100644 --- a/oryx-tui/src/filter/network.rs +++ b/oryx-tui/src/filter/network.rs @@ -28,7 +28,8 @@ impl NetworkFilter { let protocol = match i { 0 => NetworkProtocol::Ipv4, 1 => NetworkProtocol::Ipv6, - _ => NetworkProtocol::Icmp, + 2 => NetworkProtocol::Icmpv4, + _ => NetworkProtocol::Icmpv6, }; if self.selected_protocols.contains(&protocol) { @@ -131,13 +132,23 @@ impl NetworkFilter { ]), Row::new(vec![ { - if self.selected_protocols.contains(&NetworkProtocol::Icmp) { + if self.selected_protocols.contains(&NetworkProtocol::Icmpv4) { " " } else { "" } }, - "ICMP", + "ICMPv4", + ]), + Row::new(vec![ + { + if self.selected_protocols.contains(&NetworkProtocol::Icmpv6) { + " " + } else { + "" + } + }, + "ICMPv6", ]), ]; diff --git a/oryx-tui/src/packet.rs b/oryx-tui/src/packet.rs index 631806b..d684f80 100644 --- a/oryx-tui/src/packet.rs +++ b/oryx-tui/src/packet.rs @@ -9,11 +9,16 @@ use std::{fmt::Display, mem, net::Ipv4Addr}; use chrono::{DateTime, Utc}; use direction::TrafficDirection; use link::{ArpPacket, ArpType, MacAddr}; -use network::{IcmpPacket, IcmpType, IpPacket, IpProto, Ipv4Packet, Ipv6Packet}; -use network_types::{eth::EthHdr, ip::IpHdr}; +use network::{IpPacket, icmp::IcmpPacket, icmp::icmpv4, icmp::icmpv6, ip::IpProto}; +use network_types::{eth::EthHdr, icmp::Icmp, ip::IpHdr}; use oryx_common::{ProtoHdr, RawFrame, RawPacket}; use transport::{SctpPacket, TcpPacket, UdpPacket}; +use crate::packet::network::{ + icmp::icmpv4::Icmpv4Packet, icmp::icmpv6::Icmpv6Packet, ip::ipv4::Ipv4Packet, + ip::ipv6::Ipv6Packet, +}; + #[derive(Debug, Copy, Clone)] pub struct AppPacket { pub frame: EthFrame, @@ -86,28 +91,14 @@ impl From for EthFrame { verification_tag: u32::from_be_bytes(sctp_header.verification_tag), checksum: u32::from_be_bytes(sctp_header.checksum), }), - ProtoHdr::Icmp(icmp_header) => { - let icmp_type = match u8::from_be(icmp_header.type_) { - 0 => IcmpType::EchoReply, - 3 => IcmpType::DestinationUnreachable, - 5 => IcmpType::RedirectMessage, - 8 => IcmpType::EchoRequest, - 9 => IcmpType::RouterAdvertisement, - 10 => IcmpType::RouterSolicitation, - 11 => IcmpType::TimeExceeded, - 12 => IcmpType::BadIPheader, - 13 => IcmpType::Timestamp, - 14 => IcmpType::TimestampReply, - 42 => IcmpType::ExtendedEchoRequest, - 43 => IcmpType::ExtendedEchoReply, - _ => IcmpType::Deprecated, - }; - IpProto::Icmp(IcmpPacket { - icmp_type, + ProtoHdr::Icmp(Icmp::V4(icmp_header)) => { + IpProto::Icmp(IcmpPacket::V4(Icmpv4Packet { + icmp_type: icmpv4::IcmpType::from(u8::from_be(icmp_header.type_)), code: u8::from_be(icmp_header.code), checksum: u16::from_be_bytes(icmp_header.check), - }) + })) } + _ => unreachable!(), }; EthFrame { @@ -161,28 +152,14 @@ impl From for EthFrame { verification_tag: u32::from_be_bytes(sctp_header.verification_tag), checksum: u32::from_be_bytes(sctp_header.checksum), }), - ProtoHdr::Icmp(icmp_header) => { - let icmp_type = match u8::from_be(icmp_header.type_) { - 0 => IcmpType::EchoReply, - 3 => IcmpType::DestinationUnreachable, - 5 => IcmpType::RedirectMessage, - 8 => IcmpType::EchoRequest, - 9 => IcmpType::RouterAdvertisement, - 10 => IcmpType::RouterSolicitation, - 11 => IcmpType::TimeExceeded, - 12 => IcmpType::BadIPheader, - 13 => IcmpType::Timestamp, - 14 => IcmpType::TimestampReply, - 42 => IcmpType::ExtendedEchoRequest, - 43 => IcmpType::ExtendedEchoReply, - _ => IcmpType::Deprecated, - }; - IpProto::Icmp(IcmpPacket { - icmp_type, + ProtoHdr::Icmp(Icmp::V6(icmp_header)) => { + IpProto::Icmp(IcmpPacket::V6(Icmpv6Packet { + icmp_type: icmpv6::IcmpType::from(u8::from_be(icmp_header.type_)), code: u8::from_be(icmp_header.code), checksum: u16::from_be_bytes(icmp_header.check), - }) + })) } + _ => unreachable!(), }; EthFrame { diff --git a/oryx-tui/src/packet/network.rs b/oryx-tui/src/packet/network.rs index a4eecce..9fe1d3c 100644 --- a/oryx-tui/src/packet/network.rs +++ b/oryx-tui/src/packet/network.rs @@ -1,16 +1,15 @@ -use core::{ - fmt::Display, - net::{Ipv4Addr, Ipv6Addr}, -}; +pub mod icmp; +pub mod ip; + +use core::fmt::Display; use ratatui::{ Frame, layout::{Constraint, Direction, Layout, Rect}, - style::{Style, Stylize}, - text::Span, - widgets::{Block, Borders, Padding, Paragraph, Row, Table}, }; -use super::transport::{SctpPacket, TcpPacket, UdpPacket}; +use ip::{ipv4::Ipv4Packet, ipv6::Ipv6Packet}; + +use crate::packet::network::{icmp::IcmpPacket, ip::IpProto}; #[derive(Debug, Copy, Clone)] pub enum IpPacket { @@ -65,7 +64,7 @@ impl IpPacket { ip_packet.render(network_block, frame); sctp_packet.render(transport_block, frame); } - IpProto::Icmp(icmp_packet) => { + IpProto::Icmp(IcmpPacket::V4(icmp_packet)) => { let (transport_block, network_block) = { let chunks = Layout::default() .direction(Direction::Vertical) @@ -79,6 +78,7 @@ impl IpPacket { ip_packet.render(network_block, frame); icmp_packet.render(transport_block, frame); } + _ => unreachable!(), }, IpPacket::V6(ip_packet) => match ip_packet.proto { IpProto::Tcp(tcp_packet) => { @@ -124,7 +124,7 @@ impl IpPacket { ip_packet.render(network_block, frame); sctp_packet.render(transport_block, frame); } - IpProto::Icmp(icmp_packet) => { + IpProto::Icmp(IcmpPacket::V6(icmp_packet)) => { let (transport_block, network_block) = { let chunks = Layout::default() .direction(Direction::Vertical) @@ -138,309 +138,12 @@ impl IpPacket { ip_packet.render(network_block, frame); icmp_packet.render(transport_block, frame); } + _ => unreachable!(), }, } } } -#[derive(Debug, Copy, Clone)] -pub struct Ipv4Packet { - pub src_ip: Ipv4Addr, - pub dst_ip: Ipv4Addr, - pub ihl: u8, - pub tos: u8, - pub total_length: u16, - pub id: u16, - pub fragment_offset: u16, - pub ttl: u8, - pub proto: IpProto, - pub checksum: u16, -} - -impl Ipv4Packet { - pub fn render(self, block: Rect, frame: &mut Frame) { - let (title_block, data_block) = { - let chunks = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Length(10), Constraint::Fill(1)]) - .margin(2) - .split(block); - - (chunks[0], chunks[1]) - }; - // Title - let title = Paragraph::new("IPv4") - .bold() - .block(Block::new().padding(Padding::top({ - if title_block.height.is_multiple_of(2) { - (title_block.height / 2).saturating_sub(1) - } else { - title_block.height / 2 - } - }))); - - // IP - let widths = [Constraint::Length(23), Constraint::Fill(1)]; - let infos = [ - Row::new(vec![ - Span::styled("Source IP", Style::new().bold()), - Span::from(self.src_ip.to_string()), - ]), - Row::new(vec![ - Span::styled("Destination IP", Style::new().bold()), - Span::from(self.dst_ip.to_string()), - ]), - Row::new(vec![ - Span::styled("Internet Header Length", Style::new().bold()), - Span::from(format!("{} bytes", self.ihl * 4)), - ]), - Row::new(vec![ - Span::styled("Type Of Service", Style::new().bold()), - Span::from(self.tos.to_string()), - ]), - Row::new(vec![ - Span::styled("Total Length", Style::new().bold()), - Span::from(format!("{} bytes", self.total_length)), - ]), - Row::new(vec![ - Span::styled("ID", Style::new().bold()), - Span::from(self.id.to_string()), - ]), - Row::new(vec![ - Span::styled("Fragment Offset", Style::new().bold()), - Span::from(self.fragment_offset.to_string()), - ]), - Row::new(vec![ - Span::styled("TTL", Style::new().bold()), - Span::from(self.ttl.to_string()), - ]), - Row::new(vec![ - Span::styled("Checksum", Style::new().bold()), - Span::from(format!("{:#0x}", self.checksum)), - ]), - ]; - - let table = Table::new(infos, widths).column_spacing(2).block( - Block::default() - .borders(Borders::LEFT) - .border_style(Style::new().bold().magenta()) - .border_type(ratatui::widgets::BorderType::Thick) - .style(Style::default()), - ); - - frame.render_widget(table, data_block); - frame.render_widget(title, title_block); - } -} - -#[derive(Debug, Copy, Clone)] -pub struct Ipv6Packet { - pub ds: u8, - pub ecn: u8, - pub flow_label: u32, - pub payload_length: u16, - pub hop_limit: u8, - pub src_ip: Ipv6Addr, - pub dst_ip: Ipv6Addr, - pub proto: IpProto, -} - -impl Ipv6Packet { - pub fn render(self, block: Rect, frame: &mut Frame) { - let (title_block, data_block) = { - let chunks = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Length(10), Constraint::Fill(1)]) - .margin(2) - .split(block); - - (chunks[0], chunks[1]) - }; - // Title - let title = Paragraph::new("IPv6") - .bold() - .block(Block::new().padding(Padding::top({ - if title_block.height.is_multiple_of(2) { - (title_block.height / 2).saturating_sub(1) - } else { - title_block.height / 2 - } - }))); - - // IP - let widths = [Constraint::Length(23), Constraint::Fill(1)]; - let infos = [ - Row::new(vec![ - Span::styled("Source IP", Style::new().bold()), - Span::from(self.src_ip.to_string()), - ]), - Row::new(vec![ - Span::styled("Destination IP", Style::new().bold()), - Span::from(self.dst_ip.to_string()), - ]), - Row::new(vec![ - Span::styled("Differentiated services ", Style::new().bold()), - Span::from(self.ds.to_string()), - ]), - Row::new(vec![ - Span::styled("ECN", Style::new().bold()), - Span::from(self.ecn.to_string()), - ]), - Row::new(vec![ - Span::styled("Flow Label", Style::new().bold()), - Span::from(format!("{:#0x}", self.flow_label)), - ]), - Row::new(vec![ - Span::styled("Payload Length", Style::new().bold()), - Span::from(self.payload_length.to_string()), - ]), - Row::new(vec![ - Span::styled("Hop Limit", Style::new().bold()), - Span::from(self.hop_limit.to_string()), - ]), - ]; - - let table = Table::new(infos, widths).column_spacing(2).block( - Block::default() - .borders(Borders::LEFT) - .border_style(Style::new().bold().magenta()) - .border_type(ratatui::widgets::BorderType::Thick) - .style(Style::default()), - ); - - frame.render_widget(table, data_block); - frame.render_widget(title, title_block); - } -} - -#[derive(Debug, Copy, Clone)] -pub enum IpProto { - Tcp(TcpPacket), - Udp(UdpPacket), - Sctp(SctpPacket), - Icmp(IcmpPacket), -} - -#[derive(Debug, Copy, Clone)] -pub struct IcmpPacket { - pub icmp_type: IcmpType, - pub code: u8, - pub checksum: u16, -} - -impl IcmpPacket { - pub fn render(self, block: Rect, frame: &mut Frame) { - let (title_block, data_block) = { - let chunks = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Length(10), Constraint::Fill(1)]) - .margin(2) - .split(block); - - (chunks[0], chunks[1]) - }; - let title = Paragraph::new("ICMP") - .bold() - .block(Block::new().padding(Padding::top({ - if title_block.height.is_multiple_of(2) { - (title_block.height / 2).saturating_sub(1) - } else { - title_block.height / 2 - } - }))); - - let widths = [Constraint::Length(23), Constraint::Fill(1)]; - let infos = [ - Row::new(vec![ - Span::styled("Type", Style::new().bold()), - Span::from(self.icmp_type.to_string()), - ]), - Row::new(vec![ - Span::styled("Code", Style::new().bold()), - Span::from(self.code.to_string()), - ]), - Row::new(vec![ - Span::styled("Checksum", Style::new().bold()), - Span::from(format!("{:#0x}", self.checksum)), - ]), - ]; - - let table = Table::new(infos, widths).column_spacing(2).block( - Block::default() - .borders(Borders::LEFT) - .border_style(Style::new().bold().yellow()) - .border_type(ratatui::widgets::BorderType::Thick) - .style(Style::default()), - ); - - frame.render_widget(table, data_block); - frame.render_widget(title, title_block); - } -} - -#[derive(Debug, Copy, Clone)] -pub enum IcmpType { - EchoRequest, - EchoReply, - DestinationUnreachable, - RedirectMessage, - RouterAdvertisement, - RouterSolicitation, - TimeExceeded, - BadIPheader, - Timestamp, - TimestampReply, - ExtendedEchoRequest, - ExtendedEchoReply, - Deprecated, -} - -impl Display for IcmpType { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - IcmpType::EchoReply => { - write!(f, "Echo Reply") - } - IcmpType::EchoRequest => { - write!(f, "Echo Request") - } - IcmpType::DestinationUnreachable => { - write!(f, "Destination Unreachable") - } - IcmpType::RedirectMessage => { - write!(f, "Redirect Message") - } - IcmpType::RouterAdvertisement => { - write!(f, "Router Advertisement") - } - IcmpType::RouterSolicitation => { - write!(f, "Router Solicitation") - } - IcmpType::TimeExceeded => { - write!(f, "Time Exceeded") - } - IcmpType::BadIPheader => { - write!(f, "Bad IP header") - } - IcmpType::Timestamp => { - write!(f, "Timestamp") - } - IcmpType::TimestampReply => { - write!(f, "Timestamp Reply") - } - IcmpType::ExtendedEchoRequest => { - write!(f, "Extended Echo Request") - } - IcmpType::ExtendedEchoReply => { - write!(f, "Extended Echo Reply") - } - IcmpType::Deprecated => { - write!(f, "Deprecated") - } - } - } -} - impl Display for IpPacket { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { diff --git a/oryx-tui/src/packet/network/icmp.rs b/oryx-tui/src/packet/network/icmp.rs new file mode 100644 index 0000000..82342d2 --- /dev/null +++ b/oryx-tui/src/packet/network/icmp.rs @@ -0,0 +1,11 @@ +pub mod icmpv4; +pub mod icmpv6; + +use icmpv4::Icmpv4Packet; +use icmpv6::Icmpv6Packet; + +#[derive(Debug, Copy, Clone)] +pub enum IcmpPacket { + V4(Icmpv4Packet), + V6(Icmpv6Packet), +} diff --git a/oryx-tui/src/packet/network/icmp/icmpv4.rs b/oryx-tui/src/packet/network/icmp/icmpv4.rs new file mode 100644 index 0000000..5103db5 --- /dev/null +++ b/oryx-tui/src/packet/network/icmp/icmpv4.rs @@ -0,0 +1,148 @@ +use core::fmt::Display; +use ratatui::{ + Frame, + layout::{Constraint, Direction, Layout, Rect}, + style::{Style, Stylize}, + text::Span, + widgets::{Block, Borders, Padding, Paragraph, Row, Table}, +}; + +#[derive(Debug, Copy, Clone)] +pub struct Icmpv4Packet { + pub icmp_type: IcmpType, + pub code: u8, + pub checksum: u16, +} + +impl Icmpv4Packet { + pub fn render(self, block: Rect, frame: &mut Frame) { + let (title_block, data_block) = { + let chunks = Layout::default() + .direction(Direction::Horizontal) + .constraints([Constraint::Length(10), Constraint::Fill(1)]) + .margin(2) + .split(block); + + (chunks[0], chunks[1]) + }; + let title = Paragraph::new("ICMP") + .bold() + .block(Block::new().padding(Padding::top({ + if title_block.height.is_multiple_of(2) { + (title_block.height / 2).saturating_sub(1) + } else { + title_block.height / 2 + } + }))); + + let widths = [Constraint::Length(23), Constraint::Fill(1)]; + let infos = [ + Row::new(vec![ + Span::styled("Type", Style::new().bold()), + Span::from(self.icmp_type.to_string()), + ]), + Row::new(vec![ + Span::styled("Code", Style::new().bold()), + Span::from(self.code.to_string()), + ]), + Row::new(vec![ + Span::styled("Checksum", Style::new().bold()), + Span::from(format!("{:#0x}", self.checksum)), + ]), + ]; + + let table = Table::new(infos, widths).column_spacing(2).block( + Block::default() + .borders(Borders::LEFT) + .border_style(Style::new().bold().yellow()) + .border_type(ratatui::widgets::BorderType::Thick) + .style(Style::default()), + ); + + frame.render_widget(table, data_block); + frame.render_widget(title, title_block); + } +} + +#[derive(Debug, Copy, Clone)] +pub enum IcmpType { + EchoReply, + EchoRequest, + DestinationUnreachable, + RedirectMessage, + RouterAdvertisement, + RouterSolicitation, + TimeExceeded, + BadIPheader, + Timestamp, + TimestampReply, + ExtendedEchoRequest, + ExtendedEchoReply, + Deprecated, +} + +impl From for IcmpType { + fn from(value: u8) -> Self { + match value { + 0 => IcmpType::EchoReply, + 3 => IcmpType::DestinationUnreachable, + 5 => IcmpType::RedirectMessage, + 8 => IcmpType::EchoRequest, + 9 => IcmpType::RouterAdvertisement, + 10 => IcmpType::RouterSolicitation, + 11 => IcmpType::TimeExceeded, + 12 => IcmpType::BadIPheader, + 13 => IcmpType::Timestamp, + 14 => IcmpType::TimestampReply, + 42 => IcmpType::ExtendedEchoRequest, + 43 => IcmpType::ExtendedEchoReply, + _ => IcmpType::Deprecated, + } + } +} + +impl Display for IcmpType { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + IcmpType::EchoReply => { + write!(f, "Echo Reply") + } + IcmpType::EchoRequest => { + write!(f, "Echo Request") + } + IcmpType::DestinationUnreachable => { + write!(f, "Destination Unreachable") + } + IcmpType::RedirectMessage => { + write!(f, "Redirect Message") + } + IcmpType::RouterAdvertisement => { + write!(f, "Router Advertisement") + } + IcmpType::RouterSolicitation => { + write!(f, "Router Solicitation") + } + IcmpType::TimeExceeded => { + write!(f, "Time Exceeded") + } + IcmpType::BadIPheader => { + write!(f, "Bad IP header") + } + IcmpType::Timestamp => { + write!(f, "Timestamp") + } + IcmpType::TimestampReply => { + write!(f, "Timestamp Reply") + } + IcmpType::ExtendedEchoRequest => { + write!(f, "Extended Echo Request") + } + IcmpType::ExtendedEchoReply => { + write!(f, "Extended Echo Reply") + } + IcmpType::Deprecated => { + write!(f, "Deprecated") + } + } + } +} diff --git a/oryx-tui/src/packet/network/icmp/icmpv6.rs b/oryx-tui/src/packet/network/icmp/icmpv6.rs new file mode 100644 index 0000000..a59502b --- /dev/null +++ b/oryx-tui/src/packet/network/icmp/icmpv6.rs @@ -0,0 +1,159 @@ +use ratatui::{ + Frame, + layout::{Constraint, Direction, Layout, Rect}, + style::{Style, Stylize}, + text::Span, + widgets::{Block, Borders, Padding, Paragraph, Row, Table}, +}; + +#[derive(Debug, Copy, Clone)] +pub struct Icmpv6Packet { + pub icmp_type: IcmpType, + pub code: u8, + pub checksum: u16, +} + +impl Icmpv6Packet { + pub fn render(self, block: Rect, frame: &mut Frame) { + let (title_block, data_block) = { + let chunks = Layout::default() + .direction(Direction::Horizontal) + .constraints([Constraint::Length(10), Constraint::Fill(1)]) + .margin(2) + .split(block); + + (chunks[0], chunks[1]) + }; + let title = Paragraph::new("ICMP") + .bold() + .block(Block::new().padding(Padding::top({ + if title_block.height.is_multiple_of(2) { + (title_block.height / 2).saturating_sub(1) + } else { + title_block.height / 2 + } + }))); + + let widths = [Constraint::Length(23), Constraint::Fill(1)]; + let infos = [ + Row::new(vec![ + Span::styled("Type", Style::new().bold()), + Span::from(self.icmp_type.to_string()), + ]), + Row::new(vec![ + Span::styled("Code", Style::new().bold()), + Span::from(self.code.to_string()), + ]), + Row::new(vec![ + Span::styled("Checksum", Style::new().bold()), + Span::from(format!("{:#0x}", self.checksum)), + ]), + ]; + + let table = Table::new(infos, widths).column_spacing(2).block( + Block::default() + .borders(Borders::LEFT) + .border_style(Style::new().bold().yellow()) + .border_type(ratatui::widgets::BorderType::Thick) + .style(Style::default()), + ); + + frame.render_widget(table, data_block); + frame.render_widget(title, title_block); + } +} + +#[derive(Debug, Copy, Clone, strum::Display)] +pub enum IcmpType { + #[strum(to_string = "Reserved")] + Reserved, + #[strum(to_string = "Destination Unreachable")] + DestinationUnreachable = 1, + #[strum(to_string = "Packet Too Big")] + PacketTooBig = 2, + #[strum(to_string = "Time Exceeded")] + TimeExceeded = 3, + #[strum(to_string = "Parameter Problem")] + ParameterProblem = 4, + #[strum(to_string = "Echo Request")] + EchoRequest = 128, + #[strum(to_string = "Echo Reply")] + EchoReply = 129, + #[strum(to_string = "Multicast Listener Query")] + MulticastListenerQuery = 130, + #[strum(to_string = "Multicast Listener Report")] + MulticastListenerReport = 131, + #[strum(to_string = "Multicast Listener Done")] + MulticastListenerDone = 132, + #[strum(to_string = "Router Solicitation")] + RouterSolicitation = 133, + #[strum(to_string = "Router Advertisement")] + RouterAdvertisement = 134, + #[strum(to_string = "Neighbor Solicitation")] + NeighborSolicitation = 135, + #[strum(to_string = "Neighbor Advertisement")] + NeighborAdvertisement = 136, + #[strum(to_string = "Redirect Message")] + RedirectMessage = 137, + #[strum(to_string = "Router Renumbering")] + RouterRenumbering = 138, + #[strum(to_string = "ICMP Node Information Query")] + ICMPNodeInformationQuery = 139, + #[strum(to_string = "ICMP Node Information Response")] + ICMPNodeInformationResponse = 140, + #[strum(to_string = "Inverse Neighbor Discovery Solicitation Message")] + InverseNeighborDiscoverySolicitation = 141, + #[strum(to_string = "Inverse Neighbor Discovery Advertisement Message")] + InverseNeighborDiscoveryAdvertisement = 142, + #[strum(to_string = "Home Agent Address Discovery Request Message")] + HomeAgentAddressDiscoveryRequest = 144, + #[strum(to_string = "Home Agent Address Discovery Reply Message")] + HomeAgentAddressDiscoveryReply = 145, + #[strum(to_string = "Mobile Prefix Solicitation")] + MobilePrefixSolicitation = 146, + #[strum(to_string = "Mobile Prefix Advertisement")] + MobilePrefixAdvertisement = 147, + #[strum(to_string = "Duplicate Address Request")] + DuplicateAddressRequest = 157, + #[strum(to_string = "Duplicate Address Confirmation")] + DuplicateAddressConfirmation = 158, + #[strum(to_string = "Extended Echo Request")] + ExtendedEchoRequest = 160, + #[strum(to_string = "Extended Echo Reply")] + ExtendedEchoReply = 161, +} + +impl From for IcmpType { + fn from(value: u8) -> Self { + match value { + 1 => Self::DestinationUnreachable, + 2 => Self::PacketTooBig, + 3 => Self::TimeExceeded, + 4 => Self::ParameterProblem, + 128 => Self::EchoRequest, + 129 => Self::EchoReply, + 130 => Self::MulticastListenerQuery, + 131 => Self::MulticastListenerReport, + 132 => Self::MulticastListenerDone, + 133 => Self::RouterSolicitation, + 134 => Self::RouterAdvertisement, + 135 => Self::NeighborSolicitation, + 136 => Self::NeighborAdvertisement, + 137 => Self::RedirectMessage, + 138 => Self::RouterRenumbering, + 139 => Self::ICMPNodeInformationQuery, + 140 => Self::ICMPNodeInformationResponse, + 141 => Self::InverseNeighborDiscoverySolicitation, + 142 => Self::InverseNeighborDiscoveryAdvertisement, + 144 => Self::HomeAgentAddressDiscoveryRequest, + 145 => Self::HomeAgentAddressDiscoveryReply, + 146 => Self::MobilePrefixSolicitation, + 147 => Self::MobilePrefixAdvertisement, + 157 => Self::DuplicateAddressRequest, + 158 => Self::DuplicateAddressConfirmation, + 160 => Self::ExtendedEchoRequest, + 161 => Self::ExtendedEchoReply, + _ => Self::Reserved, + } + } +} diff --git a/oryx-tui/src/packet/network/ip.rs b/oryx-tui/src/packet/network/ip.rs new file mode 100644 index 0000000..ee2306c --- /dev/null +++ b/oryx-tui/src/packet/network/ip.rs @@ -0,0 +1,15 @@ +pub mod ipv4; +pub mod ipv6; + +use crate::packet::{ + network::icmp::IcmpPacket, + transport::{SctpPacket, TcpPacket, UdpPacket}, +}; + +#[derive(Debug, Copy, Clone)] +pub enum IpProto { + Tcp(TcpPacket), + Udp(UdpPacket), + Sctp(SctpPacket), + Icmp(IcmpPacket), +} diff --git a/oryx-tui/src/packet/network/ip/ipv4.rs b/oryx-tui/src/packet/network/ip/ipv4.rs new file mode 100644 index 0000000..d280cb5 --- /dev/null +++ b/oryx-tui/src/packet/network/ip/ipv4.rs @@ -0,0 +1,100 @@ +use core::net::Ipv4Addr; +use ratatui::{ + Frame, + layout::{Constraint, Direction, Layout, Rect}, + style::{Style, Stylize}, + text::Span, + widgets::{Block, Borders, Padding, Paragraph, Row, Table}, +}; + +use crate::packet::network::ip::IpProto; + +#[derive(Debug, Copy, Clone)] +pub struct Ipv4Packet { + pub src_ip: Ipv4Addr, + pub dst_ip: Ipv4Addr, + pub ihl: u8, + pub tos: u8, + pub total_length: u16, + pub id: u16, + pub fragment_offset: u16, + pub ttl: u8, + pub proto: IpProto, + pub checksum: u16, +} + +impl Ipv4Packet { + pub fn render(self, block: Rect, frame: &mut Frame) { + let (title_block, data_block) = { + let chunks = Layout::default() + .direction(Direction::Horizontal) + .constraints([Constraint::Length(10), Constraint::Fill(1)]) + .margin(2) + .split(block); + + (chunks[0], chunks[1]) + }; + // Title + let title = Paragraph::new("IPv4") + .bold() + .block(Block::new().padding(Padding::top({ + if title_block.height.is_multiple_of(2) { + (title_block.height / 2).saturating_sub(1) + } else { + title_block.height / 2 + } + }))); + + // IP + let widths = [Constraint::Length(23), Constraint::Fill(1)]; + let infos = [ + Row::new(vec![ + Span::styled("Source IP", Style::new().bold()), + Span::from(self.src_ip.to_string()), + ]), + Row::new(vec![ + Span::styled("Destination IP", Style::new().bold()), + Span::from(self.dst_ip.to_string()), + ]), + Row::new(vec![ + Span::styled("Internet Header Length", Style::new().bold()), + Span::from(format!("{} bytes", self.ihl * 4)), + ]), + Row::new(vec![ + Span::styled("Type Of Service", Style::new().bold()), + Span::from(self.tos.to_string()), + ]), + Row::new(vec![ + Span::styled("Total Length", Style::new().bold()), + Span::from(format!("{} bytes", self.total_length)), + ]), + Row::new(vec![ + Span::styled("ID", Style::new().bold()), + Span::from(self.id.to_string()), + ]), + Row::new(vec![ + Span::styled("Fragment Offset", Style::new().bold()), + Span::from(self.fragment_offset.to_string()), + ]), + Row::new(vec![ + Span::styled("TTL", Style::new().bold()), + Span::from(self.ttl.to_string()), + ]), + Row::new(vec![ + Span::styled("Checksum", Style::new().bold()), + Span::from(format!("{:#0x}", self.checksum)), + ]), + ]; + + let table = Table::new(infos, widths).column_spacing(2).block( + Block::default() + .borders(Borders::LEFT) + .border_style(Style::new().bold().magenta()) + .border_type(ratatui::widgets::BorderType::Thick) + .style(Style::default()), + ); + + frame.render_widget(table, data_block); + frame.render_widget(title, title_block); + } +} diff --git a/oryx-tui/src/packet/network/ip/ipv6.rs b/oryx-tui/src/packet/network/ip/ipv6.rs new file mode 100644 index 0000000..113c197 --- /dev/null +++ b/oryx-tui/src/packet/network/ip/ipv6.rs @@ -0,0 +1,90 @@ +use core::net::Ipv6Addr; +use ratatui::{ + Frame, + layout::{Constraint, Direction, Layout, Rect}, + style::{Style, Stylize}, + text::Span, + widgets::{Block, Borders, Padding, Paragraph, Row, Table}, +}; + +use crate::packet::network::ip::IpProto; + +#[derive(Debug, Copy, Clone)] +pub struct Ipv6Packet { + pub ds: u8, + pub ecn: u8, + pub flow_label: u32, + pub payload_length: u16, + pub hop_limit: u8, + pub src_ip: Ipv6Addr, + pub dst_ip: Ipv6Addr, + pub proto: IpProto, +} + +impl Ipv6Packet { + pub fn render(self, block: Rect, frame: &mut Frame) { + let (title_block, data_block) = { + let chunks = Layout::default() + .direction(Direction::Horizontal) + .constraints([Constraint::Length(10), Constraint::Fill(1)]) + .margin(2) + .split(block); + + (chunks[0], chunks[1]) + }; + // Title + let title = Paragraph::new("IPv6") + .bold() + .block(Block::new().padding(Padding::top({ + if title_block.height.is_multiple_of(2) { + (title_block.height / 2).saturating_sub(1) + } else { + title_block.height / 2 + } + }))); + + // IP + let widths = [Constraint::Length(23), Constraint::Fill(1)]; + let infos = [ + Row::new(vec![ + Span::styled("Source IP", Style::new().bold()), + Span::from(self.src_ip.to_string()), + ]), + Row::new(vec![ + Span::styled("Destination IP", Style::new().bold()), + Span::from(self.dst_ip.to_string()), + ]), + Row::new(vec![ + Span::styled("Differentiated services ", Style::new().bold()), + Span::from(self.ds.to_string()), + ]), + Row::new(vec![ + Span::styled("ECN", Style::new().bold()), + Span::from(self.ecn.to_string()), + ]), + Row::new(vec![ + Span::styled("Flow Label", Style::new().bold()), + Span::from(format!("{:#0x}", self.flow_label)), + ]), + Row::new(vec![ + Span::styled("Payload Length", Style::new().bold()), + Span::from(self.payload_length.to_string()), + ]), + Row::new(vec![ + Span::styled("Hop Limit", Style::new().bold()), + Span::from(self.hop_limit.to_string()), + ]), + ]; + + let table = Table::new(infos, widths).column_spacing(2).block( + Block::default() + .borders(Borders::LEFT) + .border_style(Style::new().bold().magenta()) + .border_type(ratatui::widgets::BorderType::Thick) + .style(Style::default()), + ); + + frame.render_widget(table, data_block); + frame.render_widget(title, title_block); + } +} diff --git a/oryx-tui/src/section/alert/syn_flood.rs b/oryx-tui/src/section/alert/syn_flood.rs index 4070832..7ebb476 100644 --- a/oryx-tui/src/section/alert/syn_flood.rs +++ b/oryx-tui/src/section/alert/syn_flood.rs @@ -17,7 +17,7 @@ use ratatui::{ use crate::packet::{ AppPacket, NetworkPacket, direction::TrafficDirection, - network::{IpPacket, IpProto}, + network::{IpPacket, ip::IpProto}, }; const WIN_SIZE: usize = 100_000; diff --git a/oryx-tui/src/section/inspection.rs b/oryx-tui/src/section/inspection.rs index fcb26e5..7e463b0 100644 --- a/oryx-tui/src/section/inspection.rs +++ b/oryx-tui/src/section/inspection.rs @@ -21,7 +21,7 @@ use crate::{ packet::{ AppPacket, NetworkPacket, eth_frame::EthFrameHeader, - network::{IpPacket, IpProto}, + network::{IpPacket, ip::IpProto}, }, }; @@ -388,7 +388,7 @@ impl Inspection { fuzzy::highlight(pattern, ipv4_packet.dst_ip.to_string()) .blue(), Cell::from(Line::from("-").centered()).yellow(), - fuzzy::highlight(pattern, "ICMP".to_string()).cyan(), + fuzzy::highlight(pattern, "ICMPv4".to_string()).cyan(), pid, ]), }, @@ -430,7 +430,7 @@ impl Inspection { fuzzy::highlight(pattern, ipv6_packet.dst_ip.to_string()) .blue(), Cell::from(Line::from("-").centered()).yellow(), - fuzzy::highlight(pattern, "ICMP".to_string()).cyan(), + fuzzy::highlight(pattern, "ICMPv6".to_string()).cyan(), pid, ]), }, @@ -519,7 +519,7 @@ impl Inspection { .into_centered_line() .blue(), Span::from("-").into_centered_line().yellow(), - Span::from("ICMP".to_string()).into_centered_line().cyan(), + Span::from("ICMPv4".to_string()).into_centered_line().cyan(), pid, ]), }, @@ -581,7 +581,7 @@ impl Inspection { .into_centered_line() .blue(), Span::from("-").into_centered_line().yellow(), - Span::from("ICMP".to_string()).into_centered_line().cyan(), + Span::from("ICMPv6".to_string()).into_centered_line().cyan(), pid, ]), }, diff --git a/oryx-tui/src/section/metrics.rs b/oryx-tui/src/section/metrics.rs index 7a70d64..94f3d09 100644 --- a/oryx-tui/src/section/metrics.rs +++ b/oryx-tui/src/section/metrics.rs @@ -26,7 +26,7 @@ use crate::{ packet::{ AppPacket, NetworkPacket, direction::TrafficDirection, - network::{IpPacket, IpProto}, + network::{IpPacket, ip::IpProto}, }, }; diff --git a/oryx-tui/src/section/stats.rs b/oryx-tui/src/section/stats.rs index f5758b4..54e5680 100644 --- a/oryx-tui/src/section/stats.rs +++ b/oryx-tui/src/section/stats.rs @@ -20,7 +20,7 @@ use crate::{ packet::{ AppPacket, NetworkPacket, direction::TrafficDirection, - network::{IpPacket, IpProto}, + network::{IpPacket, ip::IpProto}, }, }; @@ -99,7 +99,7 @@ impl Stats { packet_stats.transport.sctp += 1; } IpProto::Icmp(_) => { - packet_stats.network.icmp += 1; + packet_stats.network.icmpv4 += 1; } } } @@ -137,7 +137,7 @@ impl Stats { packet_stats.transport.sctp += 1; } IpProto::Icmp(_) => { - packet_stats.network.icmp += 1; + packet_stats.network.icmpv6 += 1; } } } @@ -183,7 +183,7 @@ impl Stats { [ Constraint::Max(60), Constraint::Length(12), - Constraint::Length(24), + Constraint::Length(38), Constraint::Length(10), ] .as_ref(), @@ -219,7 +219,7 @@ impl Stats { .max(100); let transport_chart = BarChart::default() - .bar_width(4) + .bar_width(6) .bar_gap(1) .data( BarGroup::default().bars(&[ @@ -269,16 +269,36 @@ impl Stats { 0 }), Bar::default() - .label("ICMP".into()) + .label("ICMPv4".into()) + .style(Style::new().fg(Color::LightCyan)) + .value_style(Style::new().fg(Color::Black).bg(Color::LightCyan)) + .text_value(if packet_stats.total != 0 { + format!( + "{}%", + packet_stats.network.icmpv4 * 100 / packet_stats.total + ) + } else { + "0%".to_string() + }) + .value(if packet_stats.total != 0 { + (packet_stats.network.icmpv4 * 100 / packet_stats.total) as u64 + } else { + 0 + }), + Bar::default() + .label("ICMPv6".into()) .style(Style::new().fg(Color::LightCyan)) .value_style(Style::new().fg(Color::Black).bg(Color::LightCyan)) .text_value(if packet_stats.total != 0 { - format!("{}%", packet_stats.network.icmp * 100 / packet_stats.total) + format!( + "{}%", + packet_stats.network.icmpv6 * 100 / packet_stats.total + ) } else { "0%".to_string() }) .value(if packet_stats.total != 0 { - (packet_stats.network.icmp * 100 / packet_stats.total) as u64 + (packet_stats.network.icmpv6 * 100 / packet_stats.total) as u64 } else { 0 }), @@ -368,7 +388,8 @@ pub struct NetworkStats { pub total: usize, pub ipv4: usize, pub ipv6: usize, - pub icmp: usize, + pub icmpv4: usize, + pub icmpv6: usize, } #[derive(Debug, Default)]