From f6e7efa37198f5174550cf1a19e541acdeaa444a Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Tue, 3 Dec 2024 18:39:08 +0100 Subject: [PATCH] Implement `sq config inspect network`. - Fixes #431. --- src/cli/config/inspect.rs | 2 + src/cli/config/inspect/network.rs | 32 +++++++++ src/commands/config/inspect.rs | 115 ++++++++++++++++++++++++++++++ src/config.rs | 12 ++-- 4 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 src/cli/config/inspect/network.rs diff --git a/src/cli/config/inspect.rs b/src/cli/config/inspect.rs index 905f34eb..af03a2eb 100644 --- a/src/cli/config/inspect.rs +++ b/src/cli/config/inspect.rs @@ -5,6 +5,7 @@ use clap::{ Subcommand, }; +pub mod network; pub mod paths; pub mod policy; @@ -32,5 +33,6 @@ pub struct Command { #[non_exhaustive] pub enum Subcommands { Paths(paths::Command), + Network(network::Command), Policy(policy::Command), } diff --git a/src/cli/config/inspect/network.rs b/src/cli/config/inspect/network.rs new file mode 100644 index 00000000..412c2d5d --- /dev/null +++ b/src/cli/config/inspect/network.rs @@ -0,0 +1,32 @@ +//! Command-line parser for `sq config inspect network`. + +use clap::Args; + +use crate::cli::examples::*; + +#[derive(Debug, Args)] +#[clap( + name = "network", + about = "Inspect the network configuration", + long_about = "\ +Inspect the network configuration + +Prints the network configuration. This can be used to gauge the \ +metadata leakage resulting from network operations. +", + after_help = EXAMPLES, +)] +pub struct Command { +} + +const EXAMPLES: Actions = Actions { + actions: &[ + Action::example() + .comment("Inspect the network configuration.") + .command(&[ + "sq", "config", "inspect", "network", + ]) + .build(), + ], +}; +test_examples!(sq_config_inspect_network, EXAMPLES); diff --git a/src/commands/config/inspect.rs b/src/commands/config/inspect.rs index c7b11df9..adcf109d 100644 --- a/src/commands/config/inspect.rs +++ b/src/commands/config/inspect.rs @@ -12,6 +12,7 @@ use sequoia_policy_config::{ use crate::{ Sq, cli::config::inspect, + cli::network, config::ConfigFile, }; @@ -19,11 +20,125 @@ pub fn dispatch(sq: Sq, cmd: inspect::Command) -> Result<()> { match cmd.subcommand { + inspect::Subcommands::Network(c) => network(sq, c), inspect::Subcommands::Paths(c) => paths(sq, c), inspect::Subcommands::Policy(c) => policy(sq, c), } } +/// Implements `sq config inspect network`. +fn network(sq: Sq, _: inspect::network::Command) -> Result<()> { + fn may_use(what: &str, enabled: bool) -> String { + format!("will {}use {}", + if enabled { "" } else { "not " }, + what) + } + + // First, sq network search, the most general interface. + wprintln!(initial_indent = " - ", "sq network search"); + wprintln!(initial_indent = " - ", "{}", + may_use("WKD", sq.config.network_search_wkd())); + wprintln!(initial_indent = " - ", + "relevant setting: network.search.use-wkd"); + if sq.config.network_search_wkd() { + wprintln!(initial_indent = " - ", "see below for impact"); + } + + wprintln!(initial_indent = " - ", "{}", + may_use("DANE", sq.config.network_search_dane())); + wprintln!(initial_indent = " - ", + "relevant setting: network.search.use-dane"); + if sq.config.network_search_dane() { + wprintln!(initial_indent = " - ", "see below for impact"); + } + + let key_servers = sq.config.key_servers( + &network::keyserver::DEFAULT_KEYSERVERS, + Some(clap::parser::ValueSource::DefaultValue)) + .collect::>(); + + if key_servers.is_empty() { + wprintln!(initial_indent = " - ", + "will use no key servers by default"); + } else { + wprintln!(initial_indent = " - ", + "will use the following key servers"); + for s in &key_servers { + wprintln!(initial_indent = " - ", "{}", s); + } + } + wprintln!(initial_indent = " - ", + "relevant setting: network.keyservers"); + if ! key_servers.is_empty() { + wprintln!(initial_indent = " - ", "see below for impact"); + } + + if sq.config.network_search_iterations() > 1 { + wprintln!(initial_indent = " - ", + "will iteratively search up to {} steps from \ + your original query to discover related \ + certificates", + sq.config.network_search_iterations().saturating_sub(1)); + wprintln!(initial_indent = " - ", + "this will query certificates that you did not \ + request, hopefully finding relevant related \ + certificates, but increases the metadata \ + leakage and may query \"suspicious\" \ + certificates"); + } + + // Then, sq network keyserver search. + wprintln!(); + wprintln!(initial_indent = " - ", "sq network keyserver search"); + if key_servers.is_empty() { + wprintln!(initial_indent = " - ", + "will use no key servers by default"); + } else { + wprintln!(initial_indent = " - ", + "will use the following key servers"); + for s in &key_servers { + wprintln!(initial_indent = " - ", "{}", s); + } + } + wprintln!(initial_indent = " - ", + "relevant setting: network.keyservers"); + wprintln!(initial_indent = " - ", "impact:"); + wprintln!(initial_indent = " - ", + "key servers and their operators can see all requests, \ + and learn about your contacts, and track you"); + wprintln!(initial_indent = " - ", + "although the traffic is encrypted, network observers \ + can use traffic analysis and observe the size of requests \ + and responses, and infer information about you and \ + your contacts, and track you"); + + // Then, sq network wkd search. + wprintln!(); + wprintln!(initial_indent = " - ", "sq network wkd search"); + wprintln!(initial_indent = " - ", "impact:"); + wprintln!(initial_indent = " - ", + "WKD servers and their operators can see all requests, \ + and learn about your contacts, and track you"); + wprintln!(initial_indent = " - ", + "although the traffic is encrypted, network observers \ + can use traffic analysis, and observe the size of requests \ + and responses, and infer information about you and \ + your contacts, and possibly track you"); + + // Then, sq network dane search. + wprintln!(); + wprintln!(initial_indent = " - ", "sq network dane search"); + wprintln!(initial_indent = " - ", "impact:"); + wprintln!(initial_indent = " - ", + "DNS servers and their operators can see all requests, \ + and learn about your contacts, and track you"); + wprintln!(initial_indent = " - ", + "the traffic is not encrypted, network observers \ + can see all requests, and learn about your contacts, \ + and track you"); + Ok(()) +} + /// Implements `sq config inspect paths`. fn paths(sq: Sq, _: inspect::paths::Command) -> Result<()> { // Whether we have emitted anything. diff --git a/src/config.rs b/src/config.rs index a645dd9c..ce61b49b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -227,18 +227,20 @@ impl Config { /// - If the command line flag is not given, then /// - use the value from the configuration file (if any), /// - or use the default value. - pub fn key_servers<'s>(&'s self, cli: &'s Vec, - source: Option) - -> impl Iterator + 's + pub fn key_servers<'s, S>(&'s self, cli: &'s [S], + source: Option) + -> impl Iterator + 's + where + S: AsRef + 's, { match source.expect("set by the cli parser") { ValueSource::DefaultValue => self.key_servers.as_ref() .map(|s| Box::new(s.iter().map(|s| s.as_str())) as Box>) - .unwrap_or_else(|| Box::new(cli.iter().map(|s| s.as_str())) + .unwrap_or_else(|| Box::new(cli.iter().map(|s| s.as_ref())) as Box>), - _ => Box::new(cli.iter().map(|s| s.as_str())) + _ => Box::new(cli.iter().map(|s| s.as_ref())) as Box>, } }