Skip to content

Commit 59a1483

Browse files
authored
Merge pull request #957 from GyulyVGC/fix-updates
Explicitly set a timeout for the packet capture using a channel
2 parents 9ec5a70 + fff3fc9 commit 59a1483

3 files changed

Lines changed: 42 additions & 12 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ All Sniffnet releases with the relative changes are documented in this file.
2020
- Romanian ([#890](https://github.com/GyulyVGC/sniffnet/pull/890))
2121
- Traditional Chinese (Taiwan) ([#904](https://github.com/GyulyVGC/sniffnet/pull/904))
2222
- Indonesian ([#909](https://github.com/GyulyVGC/sniffnet/pull/909))
23+
- Fix live chart not being updated when packets aren't captured on Linux ([#957](https://github.com/GyulyVGC/sniffnet/pull/957) — fixes [#951](https://github.com/GyulyVGC/sniffnet/issues/951))
2324
- Fix support for IPinfo's databases (the most recent version renamed the `country` field to `country_code`)
2425

2526
## [1.4.0] - 2025-06-27

src/networking/parse_packets.rs

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::networking::manage_packets::{
1111
use crate::networking::types::address_port_pair::AddressPortPair;
1212
use crate::networking::types::arp_type::ArpType;
1313
use crate::networking::types::bogon::is_bogon;
14-
use crate::networking::types::capture_context::{CaptureContext, CaptureSource};
14+
use crate::networking::types::capture_context::{CaptureContext, CaptureSource, CaptureType};
1515
use crate::networking::types::data_info::DataInfo;
1616
use crate::networking::types::data_info_host::DataInfoHost;
1717
use crate::networking::types::host::{Host, HostMessage};
@@ -26,7 +26,7 @@ use crate::utils::types::timestamp::Timestamp;
2626
use async_channel::Sender;
2727
use dns_lookup::lookup_addr;
2828
use etherparse::{EtherType, LaxPacketHeaders};
29-
use pcap::{Address, Packet};
29+
use pcap::{Address, Packet, PacketHeader};
3030
use std::collections::HashMap;
3131
use std::net::IpAddr;
3232
use std::sync::{Arc, Mutex};
@@ -42,7 +42,7 @@ pub fn parse_packets(
4242
tx: &Sender<BackendTrafficMessage>,
4343
) {
4444
let my_link_type = capture_context.my_link_type();
45-
let (mut cap, mut savefile) = capture_context.consume();
45+
let (cap, mut savefile) = capture_context.consume();
4646

4747
let mut info_traffic_msg = InfoTraffic::default();
4848
let resolutions_state = Arc::new(Mutex::new(AddressesResolutionState::default()));
@@ -52,8 +52,16 @@ pub fn parse_packets(
5252
// instant of the first parsed packet plus multiples of 1 second (only used in live captures)
5353
let mut first_packet_ticks = None;
5454

55+
let (pcap_tx, pcap_rx) = std::sync::mpsc::sync_channel(10_000);
56+
let _ = thread::Builder::new()
57+
.name("thread_packet_stream".to_string())
58+
.spawn(move || packet_stream(cap, &pcap_tx))
59+
.log_err(location!());
60+
5561
loop {
56-
let packet_res = cap.next_packet();
62+
let (packet_res, cap_stats) = pcap_rx
63+
.recv_timeout(Duration::from_millis(150))
64+
.unwrap_or((Err(pcap::Error::TimeoutExpired), None));
5765

5866
if tx.is_closed() {
5967
return;
@@ -93,7 +101,7 @@ pub fn parse_packets(
93101
}
94102
}
95103
Ok(packet) => {
96-
if let Some(headers) = get_sniffable_headers(&packet, my_link_type) {
104+
if let Some(headers) = get_sniffable_headers(&packet.data, my_link_type) {
97105
#[allow(clippy::useless_conversion)]
98106
let secs = i64::from(packet.header.ts.tv_sec);
99107
#[allow(clippy::useless_conversion)]
@@ -135,7 +143,10 @@ pub fn parse_packets(
135143

136144
// save this packet to PCAP file
137145
if let Some(file) = savefile.as_mut() {
138-
file.write(&packet);
146+
file.write(&Packet {
147+
header: &packet.header,
148+
data: &packet.data,
149+
});
139150
}
140151
// update the map
141152
let (traffic_direction, service) = modify_or_insert_in_map(
@@ -267,7 +278,7 @@ pub fn parse_packets(
267278
});
268279

269280
// update dropped packets number
270-
if let Ok(stats) = cap.stats() {
281+
if let Some(stats) = cap_stats {
271282
info_traffic_msg.dropped_packets = stats.dropped;
272283
}
273284
}
@@ -276,10 +287,7 @@ pub fn parse_packets(
276287
}
277288
}
278289

279-
fn get_sniffable_headers<'a>(
280-
packet: &'a Packet,
281-
my_link_type: MyLinkType,
282-
) -> Option<LaxPacketHeaders<'a>> {
290+
fn get_sniffable_headers(packet: &[u8], my_link_type: MyLinkType) -> Option<LaxPacketHeaders<'_>> {
283291
match my_link_type {
284292
MyLinkType::Ethernet(_) | MyLinkType::Unsupported(_) | MyLinkType::NotYetAssigned => {
285293
LaxPacketHeaders::from_ethernet(packet).ok()
@@ -474,3 +482,24 @@ fn maybe_send_tick_run_offline(
474482
}
475483
}
476484
}
485+
486+
fn packet_stream(
487+
mut cap: CaptureType,
488+
tx: &std::sync::mpsc::SyncSender<(Result<PacketOwned, pcap::Error>, Option<pcap::Stat>)>,
489+
) {
490+
loop {
491+
let packet_res = cap.next_packet();
492+
let packet_owned = packet_res.map(|p| PacketOwned {
493+
header: *p.header,
494+
data: p.data.into(),
495+
});
496+
if tx.send((packet_owned, cap.stats().ok())).is_err() {
497+
return;
498+
}
499+
}
500+
}
501+
502+
struct PacketOwned {
503+
pub header: PacketHeader,
504+
pub data: Box<[u8]>,
505+
}

src/networking/types/capture_context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ impl CaptureType {
129129
let inactive = Capture::from_device(device.to_pcap_device())?;
130130
let cap = inactive
131131
.promisc(true)
132-
.buffer_size(2_000_000) // 2MB buffer
132+
.buffer_size(2_000_000) // 2MB buffer -> 10k packets of 200 bytes
133133
.snaplen(if pcap_out_path.is_some() {
134134
i32::from(u16::MAX)
135135
} else {

0 commit comments

Comments
 (0)