Implement sq config inspect network.

- Fixes #431.
This commit is contained in:
Justus Winter 2024-12-03 18:39:08 +01:00
parent ac0044a677
commit f6e7efa371
No known key found for this signature in database
GPG Key ID: 686F55B4AB2B3386
4 changed files with 156 additions and 5 deletions

View File

@ -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),
}

View File

@ -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);

View File

@ -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::<Vec<_>>();
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.

View File

@ -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<String>,
source: Option<ValueSource>)
-> impl Iterator<Item = &'s str> + 's
pub fn key_servers<'s, S>(&'s self, cli: &'s [S],
source: Option<ValueSource>)
-> impl Iterator<Item = &'s str> + 's
where
S: AsRef<str> + '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<dyn Iterator<Item = &str>>)
.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<dyn Iterator<Item = &str>>),
_ => Box::new(cli.iter().map(|s| s.as_str()))
_ => Box::new(cli.iter().map(|s| s.as_ref()))
as Box<dyn Iterator<Item = &str>>,
}
}