Skip to content

Commit

Permalink
WIP - icmpv6 packet dumping
Browse files Browse the repository at this point in the history
  • Loading branch information
Chleba committed Apr 21, 2024
1 parent 52e2095 commit 39520d6
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 34 deletions.
1 change: 1 addition & 0 deletions .config/config.json5
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"<i>": "InputMode",
"<g>": "Graph",
"<p>": "Packets",
"<d>": "Dump",
"<f>": "Interface",
"<s>": "Scan",
"<up>": "Up",
Expand Down
2 changes: 2 additions & 0 deletions src/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub enum Action {
Right,
GraphToggle,
PacketToggle,
DumpToggle,
InterfaceSwitch,
ScanCidr,
ActiveInterface(NetworkInterface),
Expand Down Expand Up @@ -69,6 +70,7 @@ impl<'de> Deserialize<'de> for Action {
"NormalMode" => Ok(Action::ModeChange(Mode::Normal)),
"Graph" => Ok(Action::GraphToggle),
"Packets" => Ok(Action::PacketToggle),
"Dump" => Ok(Action::DumpToggle),
"Interface" => Ok(Action::InterfaceSwitch),
"Scan" => Ok(Action::ScanCidr),
"Up" => Ok(Action::Up),
Expand Down
3 changes: 2 additions & 1 deletion src/components/interfaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ impl Interfaces {
if intf.is_up() && !intf.ips.is_empty() {
for ip in &intf.ips {
// -- set active interface that's not localhost
if ip.is_ipv4() && ip.ip().to_string() != "127.0.0.1" {
// if ip.is_ipv4() && ip.ip().to_string() != "127.0.0.1" {
if ip.ip().to_string() != "127.0.0.1" {
self.active_interfaces.push(intf.clone());
break;
}
Expand Down
102 changes: 100 additions & 2 deletions src/components/packetdump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ use crossterm::event::{KeyCode, KeyEvent};
use crossterm::style::Stylize;
use ipnetwork::Ipv4Network;
use pnet::datalink::{Channel, NetworkInterface};
use pnet::packet::icmpv6::{Icmpv6Type, Icmpv6Types};
use pnet::packet::PrimitiveValues;
use pnet::packet::{
arp::{ArpHardwareTypes, ArpOperations, ArpPacket, MutableArpPacket},
ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket},
icmp::{echo_reply, echo_request, IcmpPacket, IcmpTypes},
icmpv6::Icmpv6Packet,
ip::{IpNextHeaderProtocol, IpNextHeaderProtocols},
ipv4::Ipv4Packet,
tcp::TcpPacket,
Expand All @@ -34,8 +36,8 @@ use crate::{
action::Action,
config::{Config, KeyBindings},
enums::{
ARPPacketInfo, ICMPPacketInfo, PacketTypeEnum, PacketsInfoTypesEnum, TCPPacketInfo,
UDPPacketInfo,
ARPPacketInfo, ICMP6PacketInfo, ICMPPacketInfo, PacketTypeEnum, PacketsInfoTypesEnum,
TCPPacketInfo, UDPPacketInfo,
},
utils::MaxSizeVec,
};
Expand All @@ -58,10 +60,12 @@ pub struct PacketDump {
table_state: TableState,
scrollbar_state: ScrollbarState,
packet_type: PacketTypeEnum,

arp_packets: MaxSizeVec<(DateTime<Local>, PacketsInfoTypesEnum)>,
udp_packets: MaxSizeVec<(DateTime<Local>, PacketsInfoTypesEnum)>,
tcp_packets: MaxSizeVec<(DateTime<Local>, PacketsInfoTypesEnum)>,
icmp_packets: MaxSizeVec<(DateTime<Local>, PacketsInfoTypesEnum)>,
icmp6_packets: MaxSizeVec<(DateTime<Local>, PacketsInfoTypesEnum)>,
all_packets: MaxSizeVec<(DateTime<Local>, PacketsInfoTypesEnum)>,
}

Expand All @@ -86,6 +90,7 @@ impl PacketDump {
udp_packets: MaxSizeVec::new(1000),
tcp_packets: MaxSizeVec::new(1000),
icmp_packets: MaxSizeVec::new(1000),
icmp6_packets: MaxSizeVec::new(1000),
all_packets: MaxSizeVec::new(1000),
}
}
Expand Down Expand Up @@ -175,6 +180,36 @@ impl PacketDump {
}
}

fn handle_icmpv6_packet(
interface_name: &str,
source: IpAddr,
destination: IpAddr,
packet: &[u8],
tx: UnboundedSender<Action>,
) {
let icmpv6_packet = Icmpv6Packet::new(packet);
if let Some(icmpv6_packet) = icmpv6_packet {
tx.send(Action::PacketDump(
Local::now(),
PacketsInfoTypesEnum::Icmp6(ICMP6PacketInfo {
interface_name: interface_name.to_string(),
source,
destination,
icmp_type: icmpv6_packet.get_icmpv6_type(),
}),
PacketTypeEnum::Icmp6,
))
.unwrap();
// println!(
// "[{}]: ICMPv6 packet {} -> {} (type={:?})",
// interface_name,
// source,
// destination,
// icmpv6_packet.get_icmpv6_type()
// )
}
}

fn handle_tcp_packet(
interface_name: &str,
source: IpAddr,
Expand Down Expand Up @@ -218,6 +253,9 @@ impl PacketDump {
IpNextHeaderProtocols::Icmp => {
Self::handle_icmp_packet(interface_name, source, destination, packet, tx)
}
IpNextHeaderProtocols::Icmpv6 => {
Self::handle_icmpv6_packet(interface_name, source, destination, packet, tx)
}
_ => {} // _ => println!(
// "[{}]: Unknown {} packet: {} > {}; protocol: {:?} length: {}",
// interface_name,
Expand Down Expand Up @@ -347,6 +385,17 @@ impl PacketDump {
tx.clone(),
);
continue;
} else if version == 6 {
fake_ethernet_frame.set_destination(MacAddr(0, 0, 0, 0, 0, 0));
fake_ethernet_frame.set_source(MacAddr(0, 0, 0, 0, 0, 0));
fake_ethernet_frame.set_ethertype(EtherTypes::Ipv6);
fake_ethernet_frame.set_payload(&packet[payload_offset..]);
Self::handle_ethernet_frame(
&interface,
&fake_ethernet_frame.to_immutable(),
tx.clone(),
);
continue;
}
}
}
Expand Down Expand Up @@ -381,6 +430,7 @@ impl PacketDump {
PacketTypeEnum::Tcp => self.tcp_packets.get_vec(),
PacketTypeEnum::Udp => self.udp_packets.get_vec(),
PacketTypeEnum::Icmp => self.icmp_packets.get_vec(),
PacketTypeEnum::Icmp6 => self.icmp6_packets.get_vec(),
PacketTypeEnum::All => self.all_packets.get_vec(),
}
}
Expand Down Expand Up @@ -486,6 +536,54 @@ impl PacketDump {
spans.push(Span::styled(")", Style::default().fg(Color::Yellow)));
}
// -----------------------------
// -- ICMP6
PacketsInfoTypesEnum::Icmp6(icmp) => {
spans.push(Span::styled(
format!("[{}] ", icmp.interface_name.clone()),
Style::default().fg(Color::Green),
));
spans.push(Span::styled(
"ICMP6",
Style::default().fg(Color::Red).bg(Color::Black),
));

let mut icmp_type_str = "unknown";
match icmp.icmp_type {
Icmpv6Types::EchoRequest => {
icmp_type_str = " echo request";
}
Icmpv6Types::EchoReply => {
icmp_type_str = " echo reply";
}
Icmpv6Types::NeighborAdvert => {
icmp_type_str = " neighbor advert";
}
Icmpv6Types::NeighborSolicit => {
icmp_type_str = " neighbor solicit";
}
Icmpv6Types::Redirect => {
icmp_type_str = " redirect";
}
_ => {}
}
spans.push(Span::styled(
icmp_type_str,
Style::default().fg(Color::Yellow),
));

spans.push(Span::styled(
format!("{}", icmp.source.to_string()),
Style::default().fg(Color::Blue),
));
spans.push(Span::styled(" -> ", Style::default().fg(Color::Yellow)));
spans.push(Span::styled(
format!("{}", icmp.destination.to_string()),
Style::default().fg(Color::Blue),
));
spans.push(Span::styled(", ", Style::default().fg(Color::Yellow)));
spans.push(Span::styled(")", Style::default().fg(Color::Yellow)));
}
// -----------------------------
// -- UDP
PacketsInfoTypesEnum::Udp(udp) => {
spans.push(Span::styled(
Expand Down
13 changes: 12 additions & 1 deletion src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::net::{IpAddr, Ipv4Addr};
use pnet::{
packet::{
arp::{ArpOperation, ArpOperations},
icmp::IcmpType,
icmp::IcmpType, icmpv6::Icmpv6Type,
},
util::MacAddr,
};
Expand Down Expand Up @@ -49,12 +49,21 @@ pub struct ICMPPacketInfo {
pub icmp_type: IcmpType,
}

#[derive(Debug, Clone, PartialEq)]
pub struct ICMP6PacketInfo {
pub interface_name: String,
pub source: IpAddr,
pub destination: IpAddr,
pub icmp_type: Icmpv6Type,
}

#[derive(Debug, Clone, PartialEq)]
pub enum PacketsInfoTypesEnum {
Arp(ARPPacketInfo),
Tcp(TCPPacketInfo),
Udp(UDPPacketInfo),
Icmp(ICMPPacketInfo),
Icmp6(ICMP6PacketInfo),
}

#[derive(Default, Clone, Copy, Display, FromRepr, EnumIter, EnumCount, PartialEq, Debug)]
Expand All @@ -70,6 +79,8 @@ pub enum PacketTypeEnum {
Udp,
#[strum(to_string = "ICMP")]
Icmp,
#[strum(to_string = "ICMP6")]
Icmp6,
}

impl PacketTypeEnum {
Expand Down
30 changes: 0 additions & 30 deletions src/network.rs

This file was deleted.

0 comments on commit 39520d6

Please sign in to comment.