Skip to main content

pcap_processor/tshark/
validator.rs

1use crate::error::{PcapError, Result};
2use crate::tshark::TsharkRunner;
3use glob::glob;
4use std::path::PathBuf;
5
6pub struct TsharkValidator<'a> {
7    runner: &'a TsharkRunner,
8    field_cache: Option<String>,
9}
10
11impl<'a> TsharkValidator<'a> {
12    pub fn new(runner: &'a TsharkRunner) -> Self {
13        Self {
14            runner,
15            field_cache: None,
16        }
17    }
18
19    pub fn validate_field(&mut self, field: &str) -> Result<()> {
20        let fields = match &self.field_cache {
21            Some(cache) => cache.clone(),
22            None => {
23                let fields = self.runner.get_field_list()?;
24                self.field_cache = Some(fields.clone());
25                fields
26            }
27        };
28
29        // Field entries in tshark -G fields output have format:
30        // F\tfield.name\t...
31        let field_pattern = format!("\t{}\t", field);
32        if fields.contains(&field_pattern) {
33            return Ok(());
34        }
35
36        // Also check for exact field name at start of line (some fields)
37        for line in fields.lines() {
38            let parts: Vec<&str> = line.split('\t').collect();
39            if parts.len() >= 3 && parts[2] == field {
40                return Ok(());
41            }
42        }
43
44        Err(PcapError::InvalidField {
45            field: field.to_string(),
46        })
47    }
48
49    pub fn validate_filter(&self, filter: &str) -> Result<()> {
50        self.runner.validate_filter(filter)
51    }
52
53    pub fn expand_files(&self, patterns: &[String]) -> Result<Vec<PathBuf>> {
54        let mut files = Vec::new();
55
56        for pattern in patterns {
57            // Check if it's a glob pattern or a direct file
58            if pattern.contains('*') || pattern.contains('?') || pattern.contains('[') {
59                let matches: Vec<_> = glob(pattern)
60                    .map_err(|e| PcapError::FileRead {
61                        path: PathBuf::from(pattern),
62                        message: e.to_string(),
63                    })?
64                    .filter_map(|r| r.ok())
65                    .collect();
66
67                if matches.is_empty() {
68                    return Err(PcapError::NoFilesMatched {
69                        pattern: pattern.clone(),
70                    });
71                }
72
73                files.extend(matches);
74            } else {
75                let path = PathBuf::from(pattern);
76                if !path.exists() {
77                    return Err(PcapError::FileNotFound { path });
78                }
79                files.push(path);
80            }
81        }
82
83        if files.is_empty() {
84            return Err(PcapError::NoFilesMatched {
85                pattern: patterns.join(", "),
86            });
87        }
88
89        Ok(files)
90    }
91}