diff --git a/src/display/components/table.rs b/src/display/components/table.rs index 2b823d7fc..ff5a148f8 100644 --- a/src/display/components/table.rs +++ b/src/display/components/table.rs @@ -9,7 +9,7 @@ use ::tui::widgets::{Block, Borders, Row, Widget}; use crate::display::{Bandwidth, DisplayBandwidth, UIState}; use crate::network::{display_connection_string, display_ip_or_host}; -use ::std::net::Ipv4Addr; +use ::std::net::IpAddr; use std::iter::FromIterator; const FIRST_WIDTH_BREAKPOINT: u16 = 50; @@ -54,10 +54,7 @@ pub struct Table<'a> { } impl<'a> Table<'a> { - pub fn create_connections_table( - state: &UIState, - ip_to_host: &HashMap, - ) -> Self { + pub fn create_connections_table(state: &UIState, ip_to_host: &HashMap) -> Self { let mut connections_list = Vec::from_iter(&state.connections); sort_by_bandwidth(&mut connections_list); let connections_rows = connections_list @@ -105,7 +102,7 @@ impl<'a> Table<'a> { } pub fn create_remote_addresses_table( state: &UIState, - ip_to_host: &HashMap, + ip_to_host: &HashMap, ) -> Self { let mut remote_addresses_list = Vec::from_iter(&state.remote_addresses); sort_by_bandwidth(&mut remote_addresses_list); diff --git a/src/display/ui.rs b/src/display/ui.rs index 0c4d36a19..2c44d23d4 100644 --- a/src/display/ui.rs +++ b/src/display/ui.rs @@ -7,7 +7,7 @@ use crate::display::components::{HelpText, Layout, Table, TotalBandwidth}; use crate::display::UIState; use crate::network::{display_connection_string, display_ip_or_host, LocalSocket, Utilization}; -use ::std::net::Ipv4Addr; +use ::std::net::IpAddr; use chrono::prelude::*; @@ -17,7 +17,7 @@ where { terminal: Terminal, state: UIState, - ip_to_host: HashMap, + ip_to_host: HashMap, } impl Ui @@ -101,7 +101,7 @@ where &mut self, connections_to_procs: HashMap, utilization: Utilization, - ip_to_host: HashMap, + ip_to_host: HashMap, ) { self.state.update(connections_to_procs, utilization); self.ip_to_host.extend(ip_to_host); diff --git a/src/display/ui_state.rs b/src/display/ui_state.rs index 7a22c6d02..7e8bb780a 100644 --- a/src/display/ui_state.rs +++ b/src/display/ui_state.rs @@ -65,7 +65,7 @@ pub struct UtilizationData { #[derive(Default)] pub struct UIState { pub processes: BTreeMap, - pub remote_addresses: BTreeMap, + pub remote_addresses: BTreeMap, pub connections: BTreeMap, pub total_bytes_downloaded: u128, pub total_bytes_uploaded: u128, @@ -106,7 +106,7 @@ impl UIState { self.utilization_data.pop_front(); } let mut processes: BTreeMap = BTreeMap::new(); - let mut remote_addresses: BTreeMap = BTreeMap::new(); + let mut remote_addresses: BTreeMap = BTreeMap::new(); let mut connections: BTreeMap = BTreeMap::new(); let mut total_bytes_downloaded: u128 = 0; let mut total_bytes_uploaded: u128 = 0; diff --git a/src/network/connection.rs b/src/network/connection.rs index bdbf4484b..c0c35eacb 100644 --- a/src/network/connection.rs +++ b/src/network/connection.rs @@ -1,6 +1,6 @@ use ::std::collections::HashMap; use ::std::fmt; -use ::std::net::{IpAddr, Ipv4Addr}; +use ::std::net::IpAddr; use ::std::net::SocketAddr; @@ -35,7 +35,7 @@ impl fmt::Display for Protocol { #[derive(Clone, Ord, PartialOrd, PartialEq, Eq, Hash, Debug, Copy)] pub struct Socket { - pub ip: Ipv4Addr, + pub ip: IpAddr, pub port: u16, } @@ -52,7 +52,7 @@ pub struct Connection { pub local_socket: LocalSocket, } -pub fn display_ip_or_host(ip: Ipv4Addr, ip_to_host: &HashMap) -> String { +pub fn display_ip_or_host(ip: IpAddr, ip_to_host: &HashMap) -> String { match ip_to_host.get(&ip) { Some(host) => host.clone(), None => ip.to_string(), @@ -61,7 +61,7 @@ pub fn display_ip_or_host(ip: Ipv4Addr, ip_to_host: &HashMap) pub fn display_connection_string( connection: &Connection, - ip_to_host: &HashMap, + ip_to_host: &HashMap, interface_name: &str, ) -> String { format!( @@ -80,20 +80,17 @@ impl Connection { local_ip: IpAddr, local_port: u16, protocol: Protocol, - ) -> Option { - match remote_socket { - SocketAddr::V4(remote_socket) => Some(Connection { - remote_socket: Socket { - ip: *remote_socket.ip(), - port: remote_socket.port(), - }, - local_socket: LocalSocket { - ip: local_ip, - port: local_port, - protocol, - }, - }), - _ => None, + ) -> Self { + Connection { + remote_socket: Socket { + ip: remote_socket.ip(), + port: remote_socket.port(), + }, + local_socket: LocalSocket { + ip: local_ip, + port: local_port, + protocol, + }, } } } diff --git a/src/network/dns/client.rs b/src/network/dns/client.rs index f9d12ed0c..9e13604c8 100644 --- a/src/network/dns/client.rs +++ b/src/network/dns/client.rs @@ -1,7 +1,7 @@ use crate::network::dns::{resolver::Lookup, IpTable}; use std::{ collections::HashSet, - net::Ipv4Addr, + net::IpAddr, sync::{Arc, Mutex}, thread::{Builder, JoinHandle}, }; @@ -10,14 +10,14 @@ use tokio::{ sync::mpsc::{self, Sender}, }; -type PendingAddrs = HashSet; +type PendingAddrs = HashSet; const CHANNEL_SIZE: usize = 1_000; pub struct Client { cache: Arc>, pending: Arc>, - tx: Option>>, + tx: Option>>, handle: Option>, } @@ -28,7 +28,7 @@ impl Client { { let cache = Arc::new(Mutex::new(IpTable::new())); let pending = Arc::new(Mutex::new(PendingAddrs::new())); - let (tx, mut rx) = mpsc::channel::>(CHANNEL_SIZE); + let (tx, mut rx) = mpsc::channel::>(CHANNEL_SIZE); let handle = Builder::new().name("resolver".into()).spawn({ let cache = cache.clone(); @@ -65,7 +65,7 @@ impl Client { }) } - pub fn resolve(&mut self, ips: Vec) { + pub fn resolve(&mut self, ips: Vec) { // Remove ips that are already being resolved let ips = ips .into_iter() diff --git a/src/network/dns/mod.rs b/src/network/dns/mod.rs index be1464e1e..2c911b08d 100644 --- a/src/network/dns/mod.rs +++ b/src/network/dns/mod.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, net::Ipv4Addr}; +use std::{collections::HashMap, net::IpAddr}; mod client; mod resolver; @@ -6,4 +6,4 @@ mod resolver; pub use client::*; pub use resolver::*; -pub type IpTable = HashMap; +pub type IpTable = HashMap; diff --git a/src/network/dns/resolver.rs b/src/network/dns/resolver.rs index 007c48561..074f46e52 100644 --- a/src/network/dns/resolver.rs +++ b/src/network/dns/resolver.rs @@ -1,11 +1,11 @@ use async_trait::async_trait; -use std::net::Ipv4Addr; +use std::net::IpAddr; use tokio::runtime::Handle; use trust_dns_resolver::{error::ResolveErrorKind, TokioAsyncResolver}; #[async_trait] pub trait Lookup { - async fn lookup(&self, ip: Ipv4Addr) -> Option; + async fn lookup(&self, ip: IpAddr) -> Option; } pub struct Resolver(TokioAsyncResolver); @@ -19,8 +19,8 @@ impl Resolver { #[async_trait] impl Lookup for Resolver { - async fn lookup(&self, ip: Ipv4Addr) -> Option { - let lookup_future = self.0.reverse_lookup(ip.into()); + async fn lookup(&self, ip: IpAddr) -> Option { + let lookup_future = self.0.reverse_lookup(ip); match lookup_future.await { Ok(names) => { // Take the first result and convert it to a string diff --git a/src/network/sniffer.rs b/src/network/sniffer.rs index ae737145b..442643871 100644 --- a/src/network/sniffer.rs +++ b/src/network/sniffer.rs @@ -2,8 +2,9 @@ use ::std::boxed::Box; use ::pnet_bandwhich_fork::datalink::{DataLinkReceiver, NetworkInterface}; use ::pnet_bandwhich_fork::packet::ethernet::{EtherTypes, EthernetPacket}; -use ::pnet_bandwhich_fork::packet::ip::IpNextHeaderProtocols; +use ::pnet_bandwhich_fork::packet::ip::{IpNextHeaderProtocol, IpNextHeaderProtocols}; use ::pnet_bandwhich_fork::packet::ipv4::Ipv4Packet; +use ::pnet_bandwhich_fork::packet::ipv6::Ipv6Packet; use ::pnet_bandwhich_fork::packet::tcp::TcpPacket; use ::pnet_bandwhich_fork::packet::udp::UdpPacket; use ::pnet_bandwhich_fork::packet::Packet; @@ -13,6 +14,7 @@ use ::std::net::{IpAddr, SocketAddr}; use crate::network::{Connection, Protocol}; +#[derive(Debug)] pub struct Segment { pub interface_name: String, pub connection: Connection, @@ -27,10 +29,10 @@ pub enum Direction { } impl Direction { - pub fn new(network_interface_ips: &[IpNetwork], ip_packet: &Ipv4Packet) -> Self { + pub fn new(network_interface_ips: &[IpNetwork], source: IpAddr) -> Self { if network_interface_ips .iter() - .any(|ip_network| ip_network.ip() == ip_packet.get_source()) + .any(|ip_network| ip_network.ip() == source) { Direction::Upload } else { @@ -39,6 +41,42 @@ impl Direction { } } +trait NextLevelProtocol { + fn get_next_level_protocol(&self) -> IpNextHeaderProtocol; +} + +impl NextLevelProtocol for Ipv6Packet<'_> { + fn get_next_level_protocol(&self) -> IpNextHeaderProtocol { + self.get_next_header() + } +} + +macro_rules! extract_transport_protocol { + ( $ip_packet: ident ) => {{ + match $ip_packet.get_next_level_protocol() { + IpNextHeaderProtocols::Tcp => { + let message = TcpPacket::new($ip_packet.payload())?; + ( + Protocol::Tcp, + message.get_source(), + message.get_destination(), + $ip_packet.payload().len() as u128, + ) + } + IpNextHeaderProtocols::Udp => { + let datagram = UdpPacket::new($ip_packet.payload())?; + ( + Protocol::Udp, + datagram.get_source(), + datagram.get_destination(), + $ip_packet.payload().len() as u128, + ) + } + _ => return None, + } + }}; +} + pub struct Sniffer { network_interface: NetworkInterface, network_frames: Box, @@ -56,55 +94,68 @@ impl Sniffer { } pub fn next(&mut self) -> Option { let bytes = self.network_frames.next().ok()?; - let ip_packet = Ipv4Packet::new(&bytes)?; + // See https://github.com/libpnet/libpnet/blob/master/examples/packetdump.rs + let payload_offset = if self.network_interface.is_loopback() && 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 version = ip_packet.get_version(); match version { 4 => Self::handle_v4(ip_packet, &self.network_interface), - 6 => None, // FIXME v6 support! + 6 => Self::handle_v6( + Ipv6Packet::new(&bytes[payload_offset..])?, + &self.network_interface, + ), _ => { let pkg = EthernetPacket::new(bytes)?; match pkg.get_ethertype() { EtherTypes::Ipv4 => { Self::handle_v4(Ipv4Packet::new(pkg.payload())?, &self.network_interface) } + EtherTypes::Ipv6 => { + Self::handle_v6(Ipv6Packet::new(pkg.payload())?, &self.network_interface) + } _ => None, } } } } + fn handle_v6(ip_packet: Ipv6Packet, network_interface: &NetworkInterface) -> Option { + let (protocol, source_port, destination_port, data_length) = + extract_transport_protocol!(ip_packet); + + let interface_name = network_interface.name.clone(); + let direction = Direction::new(&network_interface.ips, ip_packet.get_source().into()); + let from = SocketAddr::new(ip_packet.get_source().into(), source_port); + let to = SocketAddr::new(ip_packet.get_destination().into(), destination_port); + + let connection = match direction { + Direction::Download => Connection::new(from, to.ip(), destination_port, protocol), + Direction::Upload => Connection::new(to, from.ip(), source_port, protocol), + }; + Some(Segment { + interface_name, + connection, + data_length, + direction, + }) + } fn handle_v4(ip_packet: Ipv4Packet, network_interface: &NetworkInterface) -> Option { let (protocol, source_port, destination_port, data_length) = - match ip_packet.get_next_level_protocol() { - IpNextHeaderProtocols::Tcp => { - let message = TcpPacket::new(ip_packet.payload())?; - ( - Protocol::Tcp, - message.get_source(), - message.get_destination(), - ip_packet.payload().len() as u128, - ) - } - IpNextHeaderProtocols::Udp => { - let datagram = UdpPacket::new(ip_packet.payload())?; - ( - Protocol::Udp, - datagram.get_source(), - datagram.get_destination(), - ip_packet.payload().len() as u128, - ) - } - _ => return None, - }; + extract_transport_protocol!(ip_packet); let interface_name = network_interface.name.clone(); - let direction = Direction::new(&network_interface.ips, &ip_packet); - let from = SocketAddr::new(IpAddr::V4(ip_packet.get_source()), source_port); - let to = SocketAddr::new(IpAddr::V4(ip_packet.get_destination()), destination_port); + let direction = Direction::new(&network_interface.ips, ip_packet.get_source().into()); + let from = SocketAddr::new(ip_packet.get_source().into(), source_port); + let to = SocketAddr::new(ip_packet.get_destination().into(), destination_port); let connection = match direction { - Direction::Download => Connection::new(from, to.ip(), destination_port, protocol)?, - Direction::Upload => Connection::new(to, from.ip(), source_port, protocol)?, + Direction::Download => Connection::new(from, to.ip(), destination_port, protocol), + Direction::Upload => Connection::new(to, from.ip(), source_port, protocol), }; Some(Segment { interface_name, diff --git a/src/os/linux.rs b/src/os/linux.rs index e863e4fee..ada04fbea 100644 --- a/src/os/linux.rs +++ b/src/os/linux.rs @@ -23,11 +23,14 @@ pub(crate) fn get_open_sockets() -> OpenSockets { } } - if let Ok(tcp) = ::procfs::net::tcp() { + if let Ok(mut tcp) = ::procfs::net::tcp() { + if let Ok(mut tcp6) = ::procfs::net::tcp6() { + tcp.append(&mut tcp6); + } for entry in tcp.into_iter() { let local_port = entry.local_address.port(); let local_ip = entry.local_address.ip(); - if let (Some(connection), Some(procname)) = ( + if let (connection, Some(procname)) = ( Connection::new(entry.remote_address, local_ip, local_port, Protocol::Tcp), inode_to_procname.get(&entry.inode), ) { @@ -37,11 +40,14 @@ pub(crate) fn get_open_sockets() -> OpenSockets { } } - if let Ok(udp) = ::procfs::net::udp() { + if let Ok(mut udp) = ::procfs::net::udp() { + if let Ok(mut udp6) = ::procfs::net::udp6() { + udp.append(&mut udp6); + } for entry in udp.into_iter() { let local_port = entry.local_address.port(); let local_ip = entry.local_address.ip(); - if let (Some(connection), Some(procname)) = ( + if let (connection, Some(procname)) = ( Connection::new(entry.remote_address, local_ip, local_port, Protocol::Udp), inode_to_procname.get(&entry.inode), ) { diff --git a/src/os/lsof.rs b/src/os/lsof.rs index 68b4badd6..31e32668a 100644 --- a/src/os/lsof.rs +++ b/src/os/lsof.rs @@ -29,7 +29,7 @@ pub(crate) fn get_open_sockets() -> OpenSockets { let local_port = raw_connection.get_local_port(); let socket_addr = SocketAddr::new(remote_ip, remote_port); - let connection = Connection::new(socket_addr, local_ip, local_port, protocol).unwrap(); + let connection = Connection::new(socket_addr, local_ip, local_port, protocol); open_sockets.insert(connection.local_socket, raw_connection.process_name.clone()); connections_vec.push(connection); diff --git a/src/os/lsof_utils.rs b/src/os/lsof_utils.rs index 17b978164..fa51fa197 100644 --- a/src/os/lsof_utils.rs +++ b/src/os/lsof_utils.rs @@ -18,7 +18,7 @@ pub struct RawConnection { lazy_static! { static ref CONNECTION_REGEX: Regex = Regex::new(r"\[?([^\s\]]*)\]?:(\d+)->\[?([^\s\]]*)\]?:(\d+)").unwrap(); - static ref LISTEN_REGEX: Regex = Regex::new(r"(.*):(.*)").unwrap(); + static ref LISTEN_REGEX: Regex = Regex::new(r"\[?([^\s\[\]]*)\]?:(.*)").unwrap(); } fn get_null_addr(ip_type: &str) -> &str { @@ -124,7 +124,7 @@ impl RawConnection { } pub fn get_connections() -> RawConnections { - let content = run(&["-n", "-P", "-i4", "+c", "0"]); + let content = run(&["-n", "-P", "-i4", "-i6", "+c", "0"]); RawConnections::new(content) } @@ -168,6 +168,7 @@ impl Iterator for RawConnections { mod tests { use super::*; + const IPV6_LINE_RAW_OUTPUT: &str = "ProcessName 29266 user 9u IPv6 0x5d53dfe5445cee01 0t0 UDP [fe80:4::aede:48ff:fe00:1122]:1111->[fe80:4::aede:48ff:fe33:4455]:2222"; const LINE_RAW_OUTPUT: &str = "ProcessName 29266 user 39u IPv4 0x28ffb9c0021196bf 0t0 UDP 192.168.0.1:1111->198.252.206.25:2222"; const FULL_RAW_OUTPUT: &str = r#" com.apple 590 etoledom 193u IPv4 0x28ffb9c041115627 0t0 TCP 192.168.1.37:60298->31.13.83.36:443 (ESTABLISHED) @@ -184,19 +185,15 @@ com.apple 590 etoledom 204u IPv4 0x28ffb9c04111253f 0t0 TCP 192.168.1. } #[test] - fn test_iterator() { - let iterator = RawConnections::new(String::from(LINE_RAW_OUTPUT)); - let mut worked = false; - for raw_connection in iterator { - worked = true; - assert_eq!(raw_connection.process_name, String::from("ProcessName")); - } - assert!(worked); + fn test_raw_connection_is_created_from_raw_output_ipv4() { + test_raw_connection_is_created_from_raw_output(LINE_RAW_OUTPUT); } - #[test] - fn test_raw_connection_is_created_from_raw_output() { - let connection = RawConnection::new(LINE_RAW_OUTPUT); + fn test_raw_connection_is_created_from_raw_output_ipv6() { + test_raw_connection_is_created_from_raw_output(IPV6_LINE_RAW_OUTPUT); + } + fn test_raw_connection_is_created_from_raw_output(raw_output: &str) { + let connection = RawConnection::new(raw_output); assert!(connection.is_some()); } @@ -207,35 +204,67 @@ com.apple 590 etoledom 204u IPv4 0x28ffb9c04111253f 0t0 TCP 192.168.1. } #[test] - fn test_raw_connection_parse_remote_port() { - let connection = RawConnection::new(LINE_RAW_OUTPUT).unwrap(); + fn test_raw_connection_parse_remote_port_ipv4() { + test_raw_connection_parse_remote_port(LINE_RAW_OUTPUT); + } + #[test] + fn test_raw_connection_parse_remote_port_ipv6() { + test_raw_connection_parse_remote_port(IPV6_LINE_RAW_OUTPUT); + } + fn test_raw_connection_parse_remote_port(raw_output: &str) { + let connection = RawConnection::new(raw_output).unwrap(); assert_eq!(connection.get_remote_port(), 2222); } #[test] - fn test_raw_connection_parse_local_port() { - let connection = RawConnection::new(LINE_RAW_OUTPUT).unwrap(); + fn test_raw_connection_parse_local_port_ipv4() { + test_raw_connection_parse_local_port(LINE_RAW_OUTPUT); + } + #[test] + fn test_raw_connection_parse_local_port_ipv6() { + test_raw_connection_parse_local_port(IPV6_LINE_RAW_OUTPUT); + } + fn test_raw_connection_parse_local_port(raw_output: &str) { + let connection = RawConnection::new(raw_output).unwrap(); assert_eq!(connection.get_local_port(), 1111); } #[test] - fn test_raw_connection_parse_ip_address() { - let connection = RawConnection::new(LINE_RAW_OUTPUT).unwrap(); - assert_eq!( - connection.get_remote_ip().to_string(), - String::from("198.252.206.25") - ); + fn test_raw_connection_parse_ip_address_ipv4() { + test_raw_connection_parse_ip_address(LINE_RAW_OUTPUT, "198.252.206.25"); + } + #[test] + fn test_raw_connection_parse_ip_address_ipv6() { + test_raw_connection_parse_ip_address(IPV6_LINE_RAW_OUTPUT, "fe80:4::aede:48ff:fe33:4455"); + } + fn test_raw_connection_parse_ip_address(raw_output: &str, ip: &str) { + let connection = RawConnection::new(raw_output).unwrap(); + assert_eq!(connection.get_remote_ip().to_string(), String::from(ip)); } #[test] - fn test_raw_connection_parse_protocol() { - let connection = RawConnection::new(LINE_RAW_OUTPUT).unwrap(); + fn test_raw_connection_parse_protocol_ipv4() { + test_raw_connection_parse_protocol(LINE_RAW_OUTPUT); + } + #[test] + fn test_raw_connection_parse_protocol_ipv6() { + test_raw_connection_parse_protocol(IPV6_LINE_RAW_OUTPUT); + } + fn test_raw_connection_parse_protocol(raw_line: &str) { + let connection = RawConnection::new(raw_line).unwrap(); assert_eq!(connection.get_protocol(), Protocol::Udp); } #[test] - fn test_raw_connection_parse_process_name() { - let connection = RawConnection::new(LINE_RAW_OUTPUT).unwrap(); + fn test_raw_connection_parse_process_name_ipv4() { + test_raw_connection_parse_process_name(LINE_RAW_OUTPUT); + } + #[test] + fn test_raw_connection_parse_process_name_ipv6() { + test_raw_connection_parse_process_name(IPV6_LINE_RAW_OUTPUT); + } + fn test_raw_connection_parse_process_name(raw_line: &str) { + let connection = RawConnection::new(raw_line).unwrap(); assert_eq!(connection.process_name, String::from("ProcessName")); } } diff --git a/src/tests/fakes/fake_input.rs b/src/tests/fakes/fake_input.rs index 253082efb..3290ac2fd 100644 --- a/src/tests/fakes/fake_input.rs +++ b/src/tests/fakes/fake_input.rs @@ -93,8 +93,7 @@ pub fn get_open_sockets() -> OpenSockets { local_ip, 443, Protocol::Tcp, - ) - .unwrap(), + ), String::from("1"), ); open_sockets.insert( @@ -103,8 +102,7 @@ pub fn get_open_sockets() -> OpenSockets { local_ip, 4434, Protocol::Tcp, - ) - .unwrap(), + ), String::from("4"), ); open_sockets.insert( @@ -113,8 +111,7 @@ pub fn get_open_sockets() -> OpenSockets { local_ip, 4435, Protocol::Tcp, - ) - .unwrap(), + ), String::from("5"), ); open_sockets.insert( @@ -123,8 +120,7 @@ pub fn get_open_sockets() -> OpenSockets { local_ip, 4432, Protocol::Tcp, - ) - .unwrap(), + ), String::from("2"), ); open_sockets.insert( @@ -133,8 +129,7 @@ pub fn get_open_sockets() -> OpenSockets { local_ip, 443, Protocol::Tcp, - ) - .unwrap(), + ), String::from("1"), ); let mut local_socket_to_procs = HashMap::new(); @@ -156,7 +151,10 @@ pub fn get_interfaces() -> Vec { index: 42, mac: None, ips: vec![IpNetwork::V4("10.0.0.2".parse().unwrap())], - flags: 42, + // It's important that the IFF_LOOPBACK bit is set to 0. + // Otherwise sniffer will attempt to start parse packets + // at offset 14 + flags: 0, }] } @@ -179,8 +177,7 @@ struct FakeResolver(HashMap); #[async_trait] impl Lookup for FakeResolver { - async fn lookup(&self, ip: Ipv4Addr) -> Option { - let ip = IpAddr::from(ip); + async fn lookup(&self, ip: IpAddr) -> Option { self.0.get(&ip).cloned() } }