use std::fs::OpenOptions; use std::time::{SystemTime, UNIX_EPOCH}; use extcap::*; use log::{debug, LevelFilter}; use pcap_file::{pcap::PcapHeader, DataLink, PcapWriter}; use simplelog::{Config, SimpleLogger, WriteLogger}; const OPT_SERVER: &str = "server"; const OPT_SERVER_VALID: &str = "\\\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\b"; const OPT_DLT_MAX: &str = "dlt-max"; const OPT_DLT_MAX_DEFAULT: u32 = 162; const OPT_DLT: &str = "dlt"; const OPT_DLT_DEFAULT: u32 = 147; struct TestArgDump {} impl ExtcapListener for TestArgDump { fn init_log(&mut self, _extcap: &Extcap, debug: bool, debug_file: Option<&str>) { let lvl = if debug { LevelFilter::Debug } else { LevelFilter::Warn }; if let Some(file) = debug_file { let _ = WriteLogger::init( lvl, Config::default(), OpenOptions::new() .create(true) .append(true) .open(file) .unwrap(), ); } else { let _ = SimpleLogger::init(lvl, Config::default()); } } fn reload_option( &mut self, extcap: &Extcap, _ifc: &IFace, _arg: &IfArg, ) -> Option> { let dlt_max = extcap .get_matches() .value_of(OPT_DLT_MAX) .and_then(|s| s.parse::().ok()) .unwrap_or(OPT_DLT_MAX_DEFAULT); debug!("reload_option() dlt_max={}", dlt_max); let vals = (u32::from(DataLink::USER0)..=dlt_max) .map(|dlt| { IfArgVal::new(dlt).display(&format!("DLT_USER{}", dlt - u32::from(DataLink::USER0))) }) .collect::>(); Some(vals) } fn capture_header(&mut self, extcap: &Extcap, _ifc: &IFace) -> PcapHeader { let dlt = extcap .get_matches() .value_of(OPT_DLT) .and_then(|s| s.parse::().ok()) .unwrap_or(OPT_DLT_DEFAULT); debug!("capture_header() dlt={}", dlt); PcapHeader { datalink: DataLink::from(dlt), ..Default::default() } } fn capture( &mut self, extcap: &Extcap, _ifc: &IFace, mut pcap_writer: PcapWriter, ) -> ExtcapResult<()> { let mut msg = "Test arguments:\n".to_string(); for a in &[OPT_SERVER, OPT_DLT_MAX, OPT_DLT] { if let Some(v) = extcap.get_matches().value_of(a) { msg += &format!("{}={}\n", a, v); } } debug!("capture() {}", msg); let ts = SystemTime::now() .duration_since(UNIX_EPOCH) .expect("SystemTime before UNIX EPOCH"); let _ = pcap_writer.write( ts.as_secs() as u32, ts.subsec_micros(), msg.as_bytes(), msg.as_bytes().len() as u32, ); debug!("capture() finished"); Ok(()) } } fn main() -> Result<(), Box> { let mut ex = Extcap::new("test_arg_dump"); ex.version("0.0.1"); ex.about("Test extcap arguments (Rust extcap example)"); // Interface let mut tadump = IFace::new("tadump") .description("Test extcap arguments") .dlt(OPT_DLT_DEFAULT) .dltdescription("DLT_USER0 or non-default value"); // Interface arguments tadump.add_arg( IfArg::new_string(OPT_SERVER) .display("Server IP") .validation(&OPT_SERVER_VALID), ); let mut arg_dlt_max = IfArg::new_selector(OPT_DLT_MAX) .display("Max. DLT number") .default(&OPT_DLT_MAX_DEFAULT) .tooltip("DLT_USER0-DLT_USER15"); for dlt in u32::from(DataLink::USER0)..=u32::from(DataLink::USER15) { arg_dlt_max.add_val( IfArgVal::new(dlt).display(&format!("DLT_USER{}", dlt - u32::from(DataLink::USER0))), ); } tadump.add_arg(arg_dlt_max); let arg_dlt = IfArg::new_selector(OPT_DLT) .display("DLT number") .default(&OPT_DLT_DEFAULT) .reload(true) .placeholder("Load DLTs...") .tooltip("DLT_USER0-DLT_USERmax"); tadump.add_arg(arg_dlt); tadump.config_debug(); ex.add_interface(tadump); let user = TestArgDump {}; ex.run(user)?; debug!("DONE"); Ok(()) }