rtshark 4.3.0

A Rust interface for TShark
Documentation
use crate::metadata::Metadata;

/// A group of [Metadata] sharing a common parent field, as found in the original packet tree.
/// Returned by [Layer::groups].
pub struct MetadataGroup<'a> {
    /// The parent field (e.g. `tls.record`)
    pub parent: &'a Metadata,
    /// The child fields that fall within the parent's byte range
    pub fields: Vec<&'a Metadata>,
}

/// A layer is a protocol in the protocol stack of a packet (example: IP layer). It may contain multiple [Metadata].
#[derive(Default, Clone, Debug, PartialEq)]
pub struct Layer {
    /// Name of this layer
    name: String,
    /// Number of this layer for this packet in the stack of layers. Starts at 0 with "frame" virtual layer.
    index: usize,
    /// List of metadata associated to this layer
    metadata: Vec<Metadata>,
}

impl Layer {
    /// Creates a new layer. This function is useless for most applications.
    ///
    /// # Example
    ///
    /// ```
    /// let ip_layer = rtshark::Layer::new("ip".to_string(), 1);
    /// ```
    pub fn new(name: String, index: usize) -> Self {
        Layer {
            name,
            index,
            metadata: vec![],
        }
    }
    /// Retrieves the layer name of this layer object. This name is a protocol name returned by TShark.
    ///
    /// # Example
    ///
    /// ```
    /// let mut ip_layer = rtshark::Layer::new("ip".to_string(), 1);
    /// assert_eq!(ip_layer.name(), "ip")
    /// ```
    pub fn name(&self) -> &str {
        self.name.as_str()
    }

    /// Retrieves this layer index (number of this layer in the stack of the packet's layers).
    ///
    /// # Example
    ///
    /// ```
    /// let mut ip_layer = rtshark::Layer::new("ip".to_string(), 1);
    /// assert_eq!(ip_layer.index(), 1)
    /// ```
    pub fn index(&self) -> usize {
        self.index
    }

    /// Adds a metadata in the list of metadata for this layer. This function is useless for most applications.
    ///
    /// # Example
    ///
    /// ```
    /// let mut ip_layer = rtshark::Layer::new("ip".to_string(), 1);
    /// let ip_src = rtshark::Metadata::new("ip.src".to_string(), "127.0.0.1".to_string(), None, None, None);
    /// ip_layer.add(ip_src);
    /// ```
    pub fn add(&mut self, metadata: Metadata) {
        self.metadata.push(metadata);
    }

    /// Get a metadata by its name.
    ///
    /// # Example
    ///
    /// ```
    /// let mut ip_layer = rtshark::Layer::new("ip".to_string(), 1);
    /// let ip_src = rtshark::Metadata::new("ip.src".to_string(), "127.0.0.1".to_string(), Some("Source: 127.0.0.1".to_string()), None, None);
    /// ip_layer.add(ip_src);
    /// let ip_src = ip_layer.metadata("ip.src").unwrap();
    /// assert_eq!(ip_src.display(), Some("Source: 127.0.0.1"))
    /// ```
    pub fn metadata(&self, name: &str) -> Option<&Metadata> {
        self.metadata.iter().find(|m| m.name().eq(name))
    }

    /// Group metadata by a named parent field using byte-range containment.
    ///
    /// Returns one [MetadataGroup] per occurrence of `parent_name`, each containing
    /// the child fields whose position falls within the parent's byte range.
    /// Requires the parent field to be in the whitelist so its `pos`/`size` are populated.
    ///
    /// # Example
    ///
    /// ```
    /// // With "tls.record", "tls.record.content_type", "tls.record.length" in the whitelist:
    /// // for group in tls_layer.groups("tls.record") {
    /// //     println!("{:?}", group.parent.display());
    /// //     for field in &group.fields {
    /// //         println!("  {} = {}", field.name(), field.value());
    /// //     }
    /// // }
    /// ```
    pub fn groups<'a>(&'a self, parent_name: &str) -> Vec<MetadataGroup<'a>> {
        self.metadata
            .iter()
            .filter(|m| m.name() == parent_name)
            .map(|parent| {
                let fields = match (parent.position(), parent.size()) {
                    (Some(r_pos), Some(r_size)) => self
                        .metadata
                        .iter()
                        .filter(|m| {
                            m.name() != parent_name
                                && m.position()
                                    .is_some_and(|p| p >= r_pos && p < r_pos + r_size)
                        })
                        .collect(),
                    _ => vec![],
                };
                MetadataGroup { parent, fields }
            })
            .collect()
    }

    /// Get an iterator on the list of [Metadata] for this [Layer].
    /// This iterator does not take ownership of returned [Metadata].
    /// This is the opposite of the "into"-iterator which returns owned objects.
    ///
    /// # Example
    ///
    /// ```
    /// let mut ip_layer = rtshark::Layer::new("ip".to_string(), 1);
    /// let ip_src = rtshark::Metadata::new("ip.src".to_string(), "127.0.0.1".to_string(), Some("Source: 127.0.0.1".to_string()), None, None);
    /// ip_layer.add(ip_src);
    /// let metadata = ip_layer.iter().next().unwrap();
    /// assert_eq!(metadata.display(), Some("Source: 127.0.0.1"))
    /// ```
    pub fn iter(&self) -> impl Iterator<Item = &Metadata> {
        self.metadata.iter()
    }
}

impl IntoIterator for Layer {
    type Item = Metadata;
    type IntoIter = std::vec::IntoIter<Self::Item>;

    /// Get an "into" iterator on the list of [Metadata] for this [Layer].
    /// This iterator takes ownership of returned [Metadata].
    /// This is the opposite of an iterator by reference.
    ///
    /// # Example 1
    ///
    /// ```
    /// let mut ip_layer = rtshark::Layer::new("ip".to_string(), 1);
    /// let ip_src = rtshark::Metadata::new("ip.src".to_string(), "127.0.0.1".to_string(), Some("Source: 127.0.0.1".to_string()), None, None);
    /// ip_layer.add(ip_src);
    /// for metadata in ip_layer {
    ///     assert_eq!(metadata.display(), Some("Source: 127.0.0.1"))
    /// }
    /// ```
    /// # Example 2
    ///
    /// ```
    /// # let mut ip_layer = rtshark::Layer::new("ip".to_string(), 1);
    /// # let ip_src = rtshark::Metadata::new("ip.src".to_string(), "127.0.0.1".to_string(), Some("Source: 127.0.0.1".to_string()), None, None);
    /// # ip_layer.add(ip_src);
    /// let metadata = ip_layer.into_iter().next().unwrap();
    /// assert_eq!(metadata.display(), Some("Source: 127.0.0.1"))
    /// ```
    fn into_iter(self) -> Self::IntoIter {
        self.metadata.into_iter()
    }
}
#[cfg(test)]
mod tests {}