diff --git a/src/display/ui.rs b/src/display/ui.rs index 24de0835b..9cba16326 100644 --- a/src/display/ui.rs +++ b/src/display/ui.rs @@ -31,10 +31,7 @@ where let mut terminal = Terminal::new(terminal_backend).unwrap(); terminal.clear().unwrap(); terminal.hide_cursor().unwrap(); - let state = UIState { - cumulative_mode: opts.total_utilization, - ..Default::default() - }; + let state = UIState::with_cumulative_mode(opts.total_utilization); Ui { terminal, state, diff --git a/src/display/ui_state.rs b/src/display/ui_state.rs index 8601a5c24..bc42442fe 100644 --- a/src/display/ui_state.rs +++ b/src/display/ui_state.rs @@ -86,6 +86,13 @@ pub struct UIState { } impl UIState { + pub fn with_cumulative_mode(cumulative_mode: bool) -> Self { + UIState { + cumulative_mode, + ..Default::default() + } + } + fn get_proc_name<'a>( connections_to_procs: &'a HashMap, local_socket: &LocalSocket, diff --git a/src/main.rs b/src/main.rs index 39319f7a5..9408b5734 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,6 +52,10 @@ pub struct Opt { #[structopt(short, long)] /// A dns server ip to use instead of the system default dns_server: Option, + #[cfg_attr(not(target_os = "macos"), structopt(skip = false))] + #[cfg_attr(target_os = "macos", structopt(short = "o", long))] + /// Add a 14-byte payload offset needed for some utun (Point-to-Point) interfaces + add_payload_offset: bool, } #[derive(StructOpt, Debug, Copy, Clone)] @@ -289,12 +293,13 @@ where let name = format!("sniffing_handler_{}", iface.name); let running = running.clone(); let show_dns = opts.show_dns; + let with_payload_offset = opts.add_payload_offset; let network_utilization = network_utilization.clone(); thread::Builder::new() .name(name) .spawn(move || { - let mut sniffer = Sniffer::new(iface, frames, show_dns); + let mut sniffer = Sniffer::new(iface, frames, show_dns, with_payload_offset); while running.load(Ordering::Acquire) { if let Some(segment) = sniffer.next() { diff --git a/src/network/sniffer.rs b/src/network/sniffer.rs index de587beae..35c9b144b 100644 --- a/src/network/sniffer.rs +++ b/src/network/sniffer.rs @@ -87,6 +87,7 @@ pub struct Sniffer { network_interface: NetworkInterface, network_frames: Box, dns_shown: bool, + payload_offset: usize, } impl Sniffer { @@ -94,11 +95,26 @@ impl Sniffer { network_interface: NetworkInterface, network_frames: Box, dns_shown: bool, + with_payload_offset: bool, ) -> Self { + let payload_offset = { + // See https://github.com/libpnet/libpnet/blob/master/examples/packetdump.rs + // The pnet code for BPF loopback adds a zero'd out Ethernet header + if cfg!(target_os = "macos") + && (network_interface.is_loopback() + // utun interfaces shouldn't need the offset, but user can add with a flag + || (with_payload_offset && network_interface.is_point_to_point())) + { + 14 + } else { + 0 + } + }; Sniffer { network_interface, network_frames, dns_shown, + payload_offset, } } pub fn next(&mut self) -> Option { @@ -116,24 +132,14 @@ impl Sniffer { } }, }; - // See https://github.com/libpnet/libpnet/blob/master/examples/packetdump.rs - // VPN interfaces (such as utun0, utun1, etc) have POINT_TO_POINT bit set to 1 - let payload_offset = if (self.network_interface.is_loopback() - || self.network_interface.is_point_to_point()) - && cfg!(target_os = "macos") - { - // The pnet code for BPF loopback adds a zero'd out Ethernet header - 14 - } else { - 0 - }; - let ip_packet = Ipv4Packet::new(&bytes[payload_offset..])?; + + let ip_packet = Ipv4Packet::new(&bytes[self.payload_offset..])?; let version = ip_packet.get_version(); match version { 4 => Self::handle_v4(ip_packet, &self.network_interface, self.dns_shown), 6 => Self::handle_v6( - Ipv6Packet::new(&bytes[payload_offset..])?, + Ipv6Packet::new(&bytes[self.payload_offset..])?, &self.network_interface, ), _ => { diff --git a/src/tests/cases/raw_mode.rs b/src/tests/cases/raw_mode.rs index bee763d97..995c36008 100644 --- a/src/tests/cases/raw_mode.rs +++ b/src/tests/cases/raw_mode.rs @@ -584,6 +584,7 @@ fn no_resolve_mode() { processes: false, total_utilization: false, }, + add_payload_offset: false, }; start(backend, os_input, opts); let stdout = Arc::try_unwrap(stdout).unwrap().into_inner().unwrap(); diff --git a/src/tests/cases/test_utils.rs b/src/tests/cases/test_utils.rs index ab8e50200..79283e86c 100644 --- a/src/tests/cases/test_utils.rs +++ b/src/tests/cases/test_utils.rs @@ -165,6 +165,7 @@ fn opts_factory(raw: bool) -> Opt { processes: false, total_utilization: false, }, + add_payload_offset: false, } } type BackendWithStreams = ( diff --git a/src/tests/cases/ui.rs b/src/tests/cases/ui.rs index 14bf8613d..86f21339c 100644 --- a/src/tests/cases/ui.rs +++ b/src/tests/cases/ui.rs @@ -181,6 +181,7 @@ fn basic_only_processes() { processes: true, total_utilization: false, }, + add_payload_offset: false, }; start(backend, os_input, opts); @@ -208,6 +209,7 @@ fn basic_processes_with_dns_queries() { processes: true, total_utilization: false, }, + add_payload_offset: false, }; start(backend, os_input, opts); @@ -235,6 +237,7 @@ fn basic_only_connections() { processes: false, total_utilization: false, }, + add_payload_offset: false, }; start(backend, os_input, opts); @@ -262,6 +265,7 @@ fn basic_only_addresses() { processes: false, total_utilization: false, }, + add_payload_offset: false, }; start(backend, os_input, opts); @@ -287,6 +291,7 @@ fn two_packets_only_processes() { processes: true, total_utilization: false, }, + add_payload_offset: false, }; start(backend, os_input, opts); @@ -313,6 +318,7 @@ fn two_packets_only_connections() { processes: false, total_utilization: false, }, + add_payload_offset: false, }; start(backend, os_input, opts); @@ -339,6 +345,7 @@ fn two_packets_only_addresses() { processes: false, total_utilization: false, }, + add_payload_offset: false, }; start(backend, os_input, opts); @@ -367,6 +374,7 @@ fn two_windows_split_horizontally() { processes: false, total_utilization: false, }, + add_payload_offset: false, }; start(backend, os_input, opts); @@ -394,6 +402,7 @@ fn two_windows_split_vertically() { processes: false, total_utilization: false, }, + add_payload_offset: false, }; start(backend, os_input, opts);