From 620568592d2f9159d4de680fb6dbd5fcb211c512 Mon Sep 17 00:00:00 2001 From: FujiApple Date: Mon, 12 Feb 2024 21:34:32 +0800 Subject: [PATCH] feat(config): restrict flows to Paris and Dublin strategies (#1007) --- src/config.rs | 34 ++++++++++++++++++++++++----- src/main.rs | 4 ++-- test_resources/completions_fish.txt | 2 +- test_resources/completions_zsh.txt | 12 +++++----- test_resources/usage_long.txt | 6 ++--- trippy-config-sample.toml | 9 +++++--- 6 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/config.rs b/src/config.rs index 419f9aa36..277321bba 100644 --- a/src/config.rs +++ b/src/config.rs @@ -36,9 +36,9 @@ pub enum Mode { Tui, /// Display a continuous stream of tracing data Stream, - /// Generate an pretty text table report for N cycles. + /// Generate a pretty text table report for N cycles. Pretty, - /// Generate a markdown text table report for N cycles. + /// Generate a Markdown text table report for N cycles. Markdown, /// Generate a CSV report for N cycles. Csv, @@ -46,7 +46,7 @@ pub enum Mode { Json, /// Generate a Graphviz DOT file for N cycles. Dot, - /// Display all flows. + /// Display all flows for N cycles. Flows, /// Do not generate any tracing output for N cycles. Silent, @@ -334,6 +334,16 @@ impl TrippyConfig { Self::build_config(args, cfg_file, platform) } + /// The maximum number of flows allowed. + /// + /// This is restricted to 1 for the classic strategy. + pub fn max_flows(&self) -> usize { + match self.multipath_strategy { + MultipathStrategy::Classic => 1, + _ => self.tui_max_flows, + } + } + #[allow(clippy::too_many_lines)] fn build_config(args: Args, cfg_file: ConfigFile, platform: &Platform) -> anyhow::Result { let &Platform { @@ -641,6 +651,7 @@ impl TrippyConfig { validate_strategy(multipath_strategy, unprivileged)?; validate_protocol_strategy(protocol, multipath_strategy)?; validate_multi(mode, protocol, &args.targets, dns_resolve_all)?; + validate_flows(mode, multipath_strategy)?; validate_ttl(first_ttl, max_ttl)?; validate_max_inflight(max_inflight)?; validate_read_timeout(read_timeout)?; @@ -918,6 +929,17 @@ fn validate_multi( } } +/// Validate that flows and dot mode are only used with paris or dublin +/// multipath strategy. +fn validate_flows(mode: Mode, strategy: MultipathStrategy) -> anyhow::Result<()> { + match (mode, strategy) { + (Mode::Flows | Mode::Dot, MultipathStrategy::Classic) => Err(anyhow!( + "this mode requires the paris or dublin multipath strategy" + )), + _ => Ok(()), + } +} + /// Validate `first_ttl` and `max_ttl`. fn validate_ttl(first_ttl: u8, max_ttl: u8) -> anyhow::Result<()> { if (first_ttl as usize) < 1 || (first_ttl as usize) > MAX_HOPS { @@ -1150,11 +1172,13 @@ mod tests { #[test_case("trip example.com --mode markdown", Ok(cfg().mode(Mode::Markdown).max_rounds(Some(10)).build()); "markdown mode")] #[test_case("trip example.com --mode csv", Ok(cfg().mode(Mode::Csv).max_rounds(Some(10)).build()); "csv mode")] #[test_case("trip example.com --mode json", Ok(cfg().mode(Mode::Json).max_rounds(Some(10)).build()); "json mode")] - #[test_case("trip example.com --mode dot", Ok(cfg().mode(Mode::Dot).max_rounds(Some(10)).build()); "dot mode")] - #[test_case("trip example.com --mode flows", Ok(cfg().mode(Mode::Flows).max_rounds(Some(10)).build()); "flows mode")] + #[test_case("trip example.com --mode dot --udp -R paris", Ok(cfg().mode(Mode::Dot).max_rounds(Some(10)).multipath_strategy(MultipathStrategy::Paris).protocol(Protocol::Udp).port_direction(PortDirection::FixedSrc(Port(1024))).build()); "dot mode")] + #[test_case("trip example.com --mode flows --udp -R paris", Ok(cfg().mode(Mode::Flows).max_rounds(Some(10)).multipath_strategy(MultipathStrategy::Paris).protocol(Protocol::Udp).port_direction(PortDirection::FixedSrc(Port(1024))).build()); "flows mode")] #[test_case("trip example.com --mode silent", Ok(cfg().mode(Mode::Silent).max_rounds(Some(10)).build()); "silent mode")] #[test_case("trip example.com -m tui", Ok(cfg().mode(Mode::Tui).build()); "tui mode short")] #[test_case("trip example.com --mode foo", Err(anyhow!(format!("error: one of the values isn't valid for an argument"))); "invalid mode")] + #[test_case("trip example.com --mode dot", Err(anyhow!(format!("this mode requires the paris or dublin multipath strategy"))); "invalid dot mode")] + #[test_case("trip example.com --mode flows", Err(anyhow!(format!("this mode requires the paris or dublin multipath strategy"))); "invalid flows mode")] fn test_mode(cmd: &str, expected: anyhow::Result) { compare(parse_config(cmd), expected); } diff --git a/src/main.rs b/src/main.rs index 2690391d1..5c065629a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -218,7 +218,7 @@ fn start_tracer( tracer_config, channel_config, cfg.tui_max_samples, - cfg.tui_max_flows, + cfg.max_flows(), ); let trace_data = backend.trace(); thread::Builder::new() @@ -344,7 +344,7 @@ fn make_tui_config(args: &TrippyConfig) -> TuiConfig { args.tui_geoip_mode, args.tui_max_addrs, args.tui_max_samples, - args.tui_max_flows, + args.max_flows(), args.tui_theme, &args.tui_bindings, &args.tui_custom_columns, diff --git a/test_resources/completions_fish.txt b/test_resources/completions_fish.txt index 37b276a4d..b291578c3 100644 --- a/test_resources/completions_fish.txt +++ b/test_resources/completions_fish.txt @@ -1,5 +1,5 @@ complete -c trip -s c -l config-file -d 'Config file' -r -F -complete -c trip -s m -l mode -d 'Output mode [default: tui]' -r -f -a "{tui 'Display interactive TUI',stream 'Display a continuous stream of tracing data',pretty 'Generate an pretty text table report for N cycles',markdown 'Generate a markdown text table report for N cycles',csv 'Generate a CSV report for N cycles',json 'Generate a JSON report for N cycles',dot 'Generate a Graphviz DOT file for N cycles',flows 'Display all flows',silent 'Do not generate any tracing output for N cycles'}" +complete -c trip -s m -l mode -d 'Output mode [default: tui]' -r -f -a "{tui 'Display interactive TUI',stream 'Display a continuous stream of tracing data',pretty 'Generate a pretty text table report for N cycles',markdown 'Generate a Markdown text table report for N cycles',csv 'Generate a CSV report for N cycles',json 'Generate a JSON report for N cycles',dot 'Generate a Graphviz DOT file for N cycles',flows 'Display all flows for N cycles',silent 'Do not generate any tracing output for N cycles'}" complete -c trip -s p -l protocol -d 'Tracing protocol [default: icmp]' -r -f -a "{icmp 'Internet Control Message Protocol',udp 'User Datagram Protocol',tcp 'Transmission Control Protocol'}" complete -c trip -s F -l addr-family -d 'The address family [default: Ipv4thenIpv6]' -r -f -a "{ipv4 'Ipv4 only',ipv6 'Ipv6 only',ipv6-then-ipv4 'Ipv6 with a fallback to Ipv4',ipv4-then-ipv6 'Ipv4 with a fallback to Ipv6'}" complete -c trip -s P -l target-port -d 'The target port (TCP & UDP only) [default: 80]' -r diff --git a/test_resources/completions_zsh.txt b/test_resources/completions_zsh.txt index 2c0186a2e..b0bb2648a 100644 --- a/test_resources/completions_zsh.txt +++ b/test_resources/completions_zsh.txt @@ -19,21 +19,21 @@ _trip() { '--config-file=[Config file]:CONFIG_FILE:_files' \ '-m+[Output mode \[default\: tui\]]:MODE:((tui\:"Display interactive TUI" stream\:"Display a continuous stream of tracing data" -pretty\:"Generate an pretty text table report for N cycles" -markdown\:"Generate a markdown text table report for N cycles" +pretty\:"Generate a pretty text table report for N cycles" +markdown\:"Generate a Markdown text table report for N cycles" csv\:"Generate a CSV report for N cycles" json\:"Generate a JSON report for N cycles" dot\:"Generate a Graphviz DOT file for N cycles" -flows\:"Display all flows" +flows\:"Display all flows for N cycles" silent\:"Do not generate any tracing output for N cycles"))' \ '--mode=[Output mode \[default\: tui\]]:MODE:((tui\:"Display interactive TUI" stream\:"Display a continuous stream of tracing data" -pretty\:"Generate an pretty text table report for N cycles" -markdown\:"Generate a markdown text table report for N cycles" +pretty\:"Generate a pretty text table report for N cycles" +markdown\:"Generate a Markdown text table report for N cycles" csv\:"Generate a CSV report for N cycles" json\:"Generate a JSON report for N cycles" dot\:"Generate a Graphviz DOT file for N cycles" -flows\:"Display all flows" +flows\:"Display all flows for N cycles" silent\:"Do not generate any tracing output for N cycles"))' \ '-p+[Tracing protocol \[default\: icmp\]]:PROTOCOL:((icmp\:"Internet Control Message Protocol" udp\:"User Datagram Protocol" diff --git a/test_resources/usage_long.txt b/test_resources/usage_long.txt index 1e1225396..ebfa241af 100644 --- a/test_resources/usage_long.txt +++ b/test_resources/usage_long.txt @@ -16,12 +16,12 @@ Options: Possible values: - tui: Display interactive TUI - stream: Display a continuous stream of tracing data - - pretty: Generate an pretty text table report for N cycles - - markdown: Generate a markdown text table report for N cycles + - pretty: Generate a pretty text table report for N cycles + - markdown: Generate a Markdown text table report for N cycles - csv: Generate a CSV report for N cycles - json: Generate a JSON report for N cycles - dot: Generate a Graphviz DOT file for N cycles - - flows: Display all flows + - flows: Display all flows for N cycles - silent: Do not generate any tracing output for N cycles -u, --unprivileged diff --git a/trippy-config-sample.toml b/trippy-config-sample.toml index 717affbc3..f970ed4e6 100644 --- a/trippy-config-sample.toml +++ b/trippy-config-sample.toml @@ -25,13 +25,16 @@ # Allowed values are: # tui - Display interactive Tui [default] # stream - Display a continuous stream of tracing data -# pretty - Generate an pretty text table report for N cycles -# markdown - Generate a markdown text table report for N cycles +# pretty - Generate a pretty text table report for N cycles +# markdown - Generate a Markdown text table report for N cycles # csv - Generate a CSV report for N cycles # json - Generate a JSON report for N cycles # dot - Generate a Graphviz DOT report for N cycles -# flows - Display all flows +# flows - Display all flows for N cycles # silent - Do not generate any output for N cycles +# +# Note: the dot and flows modes are only allowed with paris or dublin +# multipath strategy. mode = "tui" # Trace without requiring elevated privileges [default: false]