diff options
| author | Erik Larkö <erik@mullvad.net> | 2017-11-28 08:19:40 +0100 |
|---|---|---|
| committer | Erik Larkö <erik@mullvad.net> | 2017-11-28 08:19:40 +0100 |
| commit | 96dbc3e8ba1d5478bad5fbda7ff0a9e92e7ee4f1 (patch) | |
| tree | bc1494bbad8c114dd490494cc52794a60624cb87 | |
| parent | c21825964986a3759d1bc103a6184aff9887f7c4 (diff) | |
| parent | 07104a432eb71e4ce1cd22f1c262d61fc0050378 (diff) | |
| download | mullvadvpn-96dbc3e8ba1d5478bad5fbda7ff0a9e92e7ee4f1.tar.xz mullvadvpn-96dbc3e8ba1d5478bad5fbda7ff0a9e92e7ee4f1.zip | |
Merge branch 'redact-ips-and-mac'
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | mullvad-daemon/Cargo.toml | 1 | ||||
| -rw-r--r-- | mullvad-daemon/src/bin/problem-report.rs | 159 | ||||
| -rw-r--r-- | mullvad-daemon/src/main.rs | 8 |
4 files changed, 158 insertions, 11 deletions
diff --git a/Cargo.lock b/Cargo.lock index 69ceab80f7..bb9982afc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -684,6 +684,7 @@ dependencies = [ "mullvad-rpc 0.1.0", "mullvad-types 0.1.0", "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/mullvad-daemon/Cargo.toml b/mullvad-daemon/Cargo.toml index 82ae9b021a..3e7e52970e 100644 --- a/mullvad-daemon/Cargo.toml +++ b/mullvad-daemon/Cargo.toml @@ -37,6 +37,7 @@ uuid = { version = "0.5", features = ["v4"] } lazy_static = "0.2" rand = "0.3" tokio-timer = "0.1" +regex = "0.2" mullvad-types = { path = "../mullvad-types" } mullvad-rpc = { path = "../mullvad-rpc" } diff --git a/mullvad-daemon/src/bin/problem-report.rs b/mullvad-daemon/src/bin/problem-report.rs index 45033b7e6a..67d784dc64 100644 --- a/mullvad-daemon/src/bin/problem-report.rs +++ b/mullvad-daemon/src/bin/problem-report.rs @@ -10,10 +10,12 @@ extern crate clap; #[macro_use] extern crate error_chain; +extern crate regex; extern crate mullvad_rpc; use error_chain::ChainedError; +use regex::Regex; use std::cmp::min; use std::env; @@ -117,7 +119,7 @@ fn run() -> Result<()> { let matches = app.get_matches(); if let Some(collect_matches) = matches.subcommand_matches("collect") { - let redacts = collect_matches + let redact_custom_strings = collect_matches .values_of_lossy("redact") .unwrap_or(Vec::new()); let log_paths = collect_matches @@ -125,7 +127,7 @@ fn run() -> Result<()> { .map(|os_values| os_values.map(Path::new).collect()) .unwrap_or(Vec::new()); let output_path = Path::new(collect_matches.value_of_os("output").unwrap()); - collect_report(&log_paths, output_path, redacts) + collect_report(&log_paths, output_path, redact_custom_strings) } else if let Some(send_matches) = matches.subcommand_matches("send") { let report_path = Path::new(send_matches.value_of_os("report").unwrap()); let user_email = send_matches.value_of("email").unwrap_or(""); @@ -136,8 +138,12 @@ fn run() -> Result<()> { } } -fn collect_report(log_paths: &[&Path], output_path: &Path, redacts: Vec<String>) -> Result<()> { - let mut problem_report = ProblemReport::new(redacts); +fn collect_report( + log_paths: &[&Path], + output_path: &Path, + redact_custom_strings: Vec<String>, +) -> Result<()> { + let mut problem_report = ProblemReport::new(redact_custom_strings); for log_path in log_paths { problem_report.add_log(log_path); } @@ -170,17 +176,17 @@ fn write_problem_report(path: &Path, problem_report: ProblemReport) -> io::Resul struct ProblemReport { system_info: Vec<String>, logs: Vec<(String, String)>, - redacts: Vec<String>, + redact_custom_strings: Vec<String>, } impl ProblemReport { /// Creates a new problem report with system information. Logs can be added with `add_log`. - /// Logs will have all strings in `redacts` removed from them. - pub fn new(redacts: Vec<String>) -> Self { + /// Logs will have all strings in `redact_custom_strings` removed from them. + pub fn new(redact_custom_strings: Vec<String>) -> Self { ProblemReport { system_info: Self::collect_system_info(), logs: Vec::new(), - redacts, + redact_custom_strings, } } @@ -204,11 +210,86 @@ impl ProblemReport { } fn redact(&self, input: String) -> String { - let mut out = match env::home_dir() { + let mut out = self.redact_home_dir(input); + + out = self.redact_mac_addresses(&out); + out = self.redact_ip_addresses(&out); + + self.redact_custom_strings(out) + } + + fn redact_home_dir(&self, input: String) -> String { + match env::home_dir() { Some(home) => input.replace(home.to_string_lossy().as_ref(), "~"), None => input, - }; - for redact in &self.redacts { + } + } + + fn redact_mac_addresses(&self, input: &str) -> String { + let octet = "[[:xdigit:]]{2}"; // 0 - ff + + // five pairs of two hexadecimal chars followed by colon or dash + // followed by a pair of hexadecimal chars + let mac_re = format!("\\b({0}[:-]){{5}}({0})\\b", octet); + + let re = Regex::new(&mac_re).unwrap(); + re.replace_all(input, "[REDACTED MAC]").to_string() + } + + fn redact_ip_addresses(&self, input: &str) -> String { + let out = self.redact_ipv4(input); + self.redact_ipv6(&out) + } + + fn redact_ipv4(&self, input: &str) -> String { + // regex adapted from https://www.regular-expressions.info/ip.html + + let above_250 = "25[0-5]"; + let above_200 = "2[0-4][0-9]"; + let above_100 = "1[0-9][0-9]"; + + // 100-119 | 120-126 | 128-129 | 130 - 199 + let above_100_not_127 = "1(?:[01][0-9]|2[0-6]|2[89]|[3-9][0-9])"; + + let above_0 = "0?[0-9][0-9]?"; + + // matches 0-255, except 127 + let first_octet = format!( + "(?:{}|{}|{}|{})", + above_250, + above_200, + above_100_not_127, + above_0 + ); + + // matches 0-255 + let ip_octet = format!("(?:{}|{}|{}|{})", above_250, above_200, above_100, above_0); + + let ip_regex = format!("\\b{0}\\.{1}\\.{1}\\.{1}\\b", first_octet, ip_octet); + let re = Regex::new(&ip_regex).unwrap(); + + re.replace_all(input, "[REDACTED IPv4]").to_string() + } + + fn redact_ipv6(&self, input: &str) -> String { + let hextet = "[[:xdigit:]]{1,4}"; // 0 - ffff + + // Matches 1-7 hextets followed by one or two colons + // and one last hextet. + // + // This means that there are many + // invalid IPv6 addresses that matches this. E.g. + // all that has more than one instance of '::', but we + // don't really care. + let ipv6_ish = format!("\\b({0}::?){{1,7}}{0}\\b", hextet); + + let re = Regex::new(&ipv6_ish).unwrap(); + re.replace_all(input, "[REDACTED IPv6]").to_string() + } + + fn redact_custom_strings(&self, input: String) -> String { + let mut out = input; + for redact in &self.redact_custom_strings { out = out.replace(redact, "[REDACTED]") } out @@ -290,3 +371,59 @@ fn command_stdout_lossy(cmd: &str, args: &[&str]) -> Option<String> { }) .ok() } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_redacts_ipv4() { + assert_redacts_ipv4("1.2.3.4"); + assert_redacts_ipv4("10.127.0.1"); + assert_redacts_ipv4("192.168.1.1"); + assert_redacts_ipv4("10.0.16.1"); + assert_redacts_ipv4("173.54.12.32"); + assert_redacts_ipv4("68.4.4.1"); + } + + fn assert_redacts_ipv4(input: &str) { + let report = ProblemReport::new(vec![]); + let actual = report.redact(format!("pre {} post", input)); + assert_eq!("pre [REDACTED IPv4] post", actual); + } + + #[test] + fn test_does_not_redact_localhost_ipv4() { + let report = ProblemReport::new(vec![]); + let res = report.redact("127.0.0.1".to_owned()); + assert_eq!("127.0.0.1", res); + } + + #[test] + fn test_redacts_ipv6() { + assert_redacts_ipv6("2001:0db8:85a3:0000:0000:8a2e:0370:7334"); + assert_redacts_ipv6("2001:db8:85a3:0:0:8a2e:370:7334"); + assert_redacts_ipv6("2001:db8:85a3::8a2e:370:7334"); + assert_redacts_ipv6("2001:db8:0:0:0:0:2:1"); + assert_redacts_ipv6("2001:db8::2:1"); + assert_redacts_ipv6("2001:db8:0000:1:1:1:1:1"); + assert_redacts_ipv6("2001:db8:0:1:1:1:1:1"); + assert_redacts_ipv6("2001:db8:0:0:1:0:0:1"); + assert_redacts_ipv6("2001:db8::1:0:0:1"); + assert_redacts_ipv6("0::0"); + assert_redacts_ipv6("0:0:0:0::1"); + } + + fn assert_redacts_ipv6(input: &str) { + let report = ProblemReport::new(vec![]); + let actual = report.redact(format!("pre {} post", input)); + assert_eq!("pre [REDACTED IPv6] post", actual); + } + + #[test] + fn test_does_not_redact_localhost_ipv6() { + let report = ProblemReport::new(vec![]); + let res = report.redact("::1".to_owned()); + assert_eq!("::1", res); + } +} diff --git a/mullvad-daemon/src/main.rs b/mullvad-daemon/src/main.rs index c9493d3778..08bb9bccec 100644 --- a/mullvad-daemon/src/main.rs +++ b/mullvad-daemon/src/main.rs @@ -76,6 +76,8 @@ use talpid_core::mpsc::IntoSender; use talpid_core::tunnel::{self, TunnelEvent, TunnelMetadata, TunnelMonitor}; use talpid_types::net::TunnelEndpoint; +use std::fs; + error_chain!{ errors { @@ -595,6 +597,12 @@ impl Daemon { self.set_security_policy()?; + if let Some(ref file) = self.tunnel_log { + let _ = fs::remove_file(file); + fs::File::create(file) + .chain_err(|| "Unable to create the tunnel log file")?; + } + let tunnel_monitor = self.spawn_tunnel_monitor(self.tunnel_endpoint.unwrap(), &account_token)?; self.tunnel_close_handle = Some(tunnel_monitor.close_handle()); |
