From 4695544de5bdd95e1eb599e114b34ef294f2dbff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro?= Date: Sun, 21 Jun 2026 18:22:36 -0300 Subject: [PATCH] feat(dns): capture and parse DNS traffic in the packet pipeline Detect DNS traffic (UDP/TCP port 53) in the capture loop and parse the message from the transport payload, extracted from `headers.payload` before `analyze_headers` consumes the headers (the slice borrows `packet.data`, so it outlives the move). DNS over TCP's 2-byte length prefix is stripped before parsing. Parsed messages are pushed to a new `InfoTraffic::dns_events` vector, carried to the GUI on each tick and reset by `take_but_leave_something`; `refresh` intentionally ignores it (events are drained GUI-side). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/networking/parse_packets.rs | 36 +++++++++++++++++++++++++++- src/networking/types/info_traffic.rs | 4 ++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/networking/parse_packets.rs b/src/networking/parse_packets.rs index b18981d8..010e9d05 100644 --- a/src/networking/parse_packets.rs +++ b/src/networking/parse_packets.rs @@ -5,6 +5,8 @@ use crate::location; use crate::mmdb::asn::get_asn; use crate::mmdb::country::get_country; use crate::mmdb::types::mmdb_reader::MmdbReaders; +use crate::networking::dns::parser::parse_dns; +use crate::networking::dns::types::DnsEvent; use crate::networking::manage_packets::{ analyze_headers, get_address_to_lookup, get_traffic_type, is_local_connection, modify_or_insert_in_map, @@ -20,13 +22,14 @@ use crate::networking::types::icmp_type::IcmpType; use crate::networking::types::info_traffic::InfoTraffic; use crate::networking::types::ip_blacklist::IpBlacklist; use crate::networking::types::my_link_type::MyLinkType; +use crate::networking::types::protocol::Protocol; use crate::networking::types::traffic_direction::TrafficDirection; use crate::utils::error_logger::{ErrorLogger, Location}; use crate::utils::formatted_strings::get_domain_from_r_dns; use crate::utils::types::timestamp::Timestamp; use async_channel::Sender; use dns_lookup::lookup_addr; -use etherparse::{EtherType, LaxPacketHeaders}; +use etherparse::{EtherType, LaxPacketHeaders, LaxPayloadSlice}; use pcap::{Address, Packet, PacketHeader}; use std::collections::HashMap; use std::net::IpAddr; @@ -155,6 +158,15 @@ pub fn parse_packets( let mut icmp_type = IcmpType::default(); let mut arp_type = ArpType::default(); + // Capture the UDP/TCP payload before `analyze_headers` consumes + // `headers`. The returned slice borrows `packet.data`, not + // `headers`, so it remains valid after the move. + let transport_payload: Option<&[u8]> = match &headers.payload { + LaxPayloadSlice::Udp { payload, .. } + | LaxPayloadSlice::Tcp { payload, .. } => Some(payload), + _ => None, + }; + let key_option = analyze_headers( headers, &mut mac_addresses, @@ -167,6 +179,28 @@ pub fn parse_packets( continue; }; + // If this is DNS traffic (port 53), parse the message from the + // transport payload and record it as a DNS event. + if key.sport == Some(53) || key.dport == Some(53) { + if let Some(payload) = transport_payload { + // DNS over TCP is prefixed by a 2-byte length field. + let dns_bytes = if key.protocol == Protocol::TCP { + payload.get(2..) + } else { + Some(payload) + }; + if let Some(message) = dns_bytes.and_then(parse_dns) { + info_traffic_msg.dns_events.push(DnsEvent { + timestamp: next_packet_timestamp, + src: key.source, + dst: key.dest, + transport: key.protocol, + message, + }); + } + } + } + // save this packet to PCAP file if let Some(file) = savefile.as_mut() { file.write(&Packet { diff --git a/src/networking/types/info_traffic.rs b/src/networking/types/info_traffic.rs index 6a9b8150..2fe096aa 100644 --- a/src/networking/types/info_traffic.rs +++ b/src/networking/types/info_traffic.rs @@ -1,4 +1,5 @@ use crate::Service; +use crate::networking::dns::types::DnsEvent; use crate::networking::manage_packets::get_local_port; use crate::networking::types::address_port_pair::AddressPortPair; use crate::networking::types::data_info::DataInfo; @@ -26,6 +27,9 @@ pub struct InfoTraffic { pub services: HashMap, /// Map of the hosts with their data info pub hosts: HashMap, + /// DNS messages parsed during the current interval (drained by the GUI each + /// tick; not accumulated in the global `InfoTraffic`). + pub dns_events: Vec, } impl InfoTraffic {