diff --git a/examples/pcap-info.rs b/examples/pcap-info.rs index 7217433..2ba709c 100644 --- a/examples/pcap-info.rs +++ b/examples/pcap-info.rs @@ -106,6 +106,33 @@ fn print_block_info_ng(block: &Block) { println!("\t\t\tif_tsoffset: {}", option.unwrap_or(0)); } } + Block::InterfaceStatistics(isb) => { + println!("\t\tStatistics:"); + if let Some(option) = isb.isb_starttime() { + let (ts_high, ts_low) = option.unwrap_or((0, 0)); + println!("\t\t\tisb_starttime: 0x{:x}:0x{:x}", ts_high, ts_low); + // to decode, this require the ts_offset and resolution from the matching IDB block + // for ex: + // let resolution = build_ts_resolution(6).unwrap(); + // let ts = build_ts(ts_high, ts_low, 0, resolution); + // println!("\t\t\t\t{}.{}", ts.0, ts.1); + } + if let Some(option) = isb.isb_ifrecv() { + println!("\t\t\tisb_ifrecv: {}", option.unwrap_or(0)); + } + if let Some(option) = isb.isb_ifdrop() { + println!("\t\t\tisb_ifdrop: {}", option.unwrap_or(0)); + } + if let Some(option) = isb.isb_filteraccept() { + println!("\t\t\tisb_filteraccept: {}", option.unwrap_or(0)); + } + if let Some(option) = isb.isb_osdrop() { + println!("\t\t\tisb_osdrop: {}", option.unwrap_or(0)); + } + if let Some(option) = isb.isb_usrdeliv() { + println!("\t\t\tisb_usrdeliv: {}", option.unwrap_or(0)); + } + } _ => (), } } diff --git a/src/pcapng/interface_statistics.rs b/src/pcapng/interface_statistics.rs index fc2b237..2ffab4a 100644 --- a/src/pcapng/interface_statistics.rs +++ b/src/pcapng/interface_statistics.rs @@ -17,6 +17,86 @@ pub struct InterfaceStatisticsBlock<'a> { pub block_len2: u32, } +impl<'a> InterfaceStatisticsBlock<'a> { + /// Return the `isb_starttime` option value, if present + /// + /// The returned value is `(ts_high,ts_low)`. To convert to a full timestamp, + /// use the [build_ts] function with the `ts_offset` and `resolution` values from + /// the `InterfaceDescriptionBlock` matching `self.if_id`. + /// + /// If the option is present multiple times, the first value is returned. + /// + /// Returns `None` if option is not present, `Some(Ok(value))` if the value is present and valid, + /// or `Some(Err(_))` if value is present but invalid + pub fn isb_starttime(&self) -> Option> { + options_get_as_ts(&self.options, OptionCode::IsbStartTime) + } + + /// Return the `isb_endtime` option value, if present + /// + /// The returned value is `(ts_high,ts_low)`. To convert to a full timestamp, + /// use the [build_ts] function with the `ts_offset` and `resolution` values from + /// the `InterfaceDescriptionBlock` matching `self.if_id`. + /// + /// If the option is present multiple times, the first value is returned. + /// + /// Returns `None` if option is not present, `Some(Ok(value))` if the value is present and valid, + /// or `Some(Err(_))` if value is present but invalid + pub fn isb_endtime(&self) -> Option> { + options_get_as_ts(&self.options, OptionCode::IsbEndTime) + } + + /// Return the `isb_ifrecv` option value, if present + /// + /// If the option is present multiple times, the first value is returned. + /// + /// Returns `None` if option is not present, `Some(Ok(value))` if the value is present and valid, + /// or `Some(Err(_))` if value is present but invalid + pub fn isb_ifrecv(&self) -> Option> { + options_get_as_u64_le(&self.options, OptionCode::IsbIfRecv) + } + + /// Return the `isb_ifdrop` option value, if present + /// + /// If the option is present multiple times, the first value is returned. + /// + /// Returns `None` if option is not present, `Some(Ok(value))` if the value is present and valid, + /// or `Some(Err(_))` if value is present but invalid + pub fn isb_ifdrop(&self) -> Option> { + options_get_as_u64_le(&self.options, OptionCode::IsbIfDrop) + } + + /// Return the `isb_filteraccept` option value, if present + /// + /// If the option is present multiple times, the first value is returned. + /// + /// Returns `None` if option is not present, `Some(Ok(value))` if the value is present and valid, + /// or `Some(Err(_))` if value is present but invalid + pub fn isb_filteraccept(&self) -> Option> { + options_get_as_u64_le(&self.options, OptionCode::IsbFilterAccept) + } + + /// Return the `isb_osdrop` option value, if present + /// + /// If the option is present multiple times, the first value is returned. + /// + /// Returns `None` if option is not present, `Some(Ok(value))` if the value is present and valid, + /// or `Some(Err(_))` if value is present but invalid + pub fn isb_osdrop(&self) -> Option> { + options_get_as_u64_le(&self.options, OptionCode::IsbOsDrop) + } + + /// Return the `isb_usrdeliv` option value, if present + /// + /// If the option is present multiple times, the first value is returned. + /// + /// Returns `None` if option is not present, `Some(Ok(value))` if the value is present and valid, + /// or `Some(Err(_))` if value is present but invalid + pub fn isb_usrdeliv(&self) -> Option> { + options_get_as_u64_le(&self.options, OptionCode::IsbUsrDeliv) + } +} + impl<'a, En: PcapEndianness> PcapNGBlockParser<'a, En, InterfaceStatisticsBlock<'a>> for InterfaceStatisticsBlock<'a> { diff --git a/src/pcapng/option.rs b/src/pcapng/option.rs index 938fade..192d4fe 100644 --- a/src/pcapng/option.rs +++ b/src/pcapng/option.rs @@ -19,13 +19,20 @@ impl debug OptionCode { Comment = 1, ShbHardware = 2, IfName = 2, + IsbStartTime = 2, ShbOs = 3, IfDescription = 3, + IsbEndTime = 3, ShbUserAppl = 4, IfIpv4Addr = 4, + IsbIfRecv = 4, + IsbIfDrop = 5, IfMacAddr = 6, + IsbFilterAccept = 6, IfEuiAddr = 7, + IsbOsDrop = 7, IfSpeed = 8, + IsbUsrDeliv = 8, IfTsresol = 9, IfFilter = 11, IfOs = 12, @@ -247,3 +254,23 @@ pub(crate) fn options_get_as_u64_le( ) -> Option> { options_find_map(options, code, |opt| opt.as_u64_le()) } + +pub(crate) fn options_get_as_ts( + options: &[PcapNGOption], + code: OptionCode, +) -> Option> { + options_find_map(options, code, |opt| { + let value = opt.value(); + if opt.len == 8 && value.len() == 8 { + let bytes_ts_high = + <[u8; 4]>::try_from(&value[..4]).or(Err(PcapNGOptionError::InvalidLength))?; + let bytes_ts_low = + <[u8; 4]>::try_from(&value[4..8]).or(Err(PcapNGOptionError::InvalidLength))?; + let ts_high = u32::from_le_bytes(bytes_ts_high); + let ts_low = u32::from_le_bytes(bytes_ts_low); + Ok((ts_high, ts_low)) + } else { + Err(PcapNGOptionError::InvalidLength) + } + }) +}