1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
/// Windows specific code
use anyhow::{anyhow, Result};
use std::net::Ipv4Addr;
#[cfg(target_os = "windows")]
use winreg::{enums::HKEY_LOCAL_MACHINE, RegKey};
use crate::repair_and_verify::check_is_valid_game_path;
/// Gets Titanfall2 install location on Origin
pub fn origin_install_location_detection() -> Result<String, anyhow::Error> {
#[cfg(target_os = "windows")]
{
let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
match hklm.open_subkey("SOFTWARE\\Respawn\\Titanfall2") {
Ok(tf) => {
let game_path_str: String = tf.get_value("Install Dir")?;
match check_is_valid_game_path(&game_path_str) {
Ok(()) => {
return Ok(game_path_str.to_string());
}
Err(err) => {
log::warn!("{err}");
}
}
}
Err(err) => {
log::warn!("{err}");
}
}
}
Err(anyhow!("No Origin / EA App install path found"))
}
/// Check whether the current device might be behind a CGNAT
pub async fn check_cgnat() -> Result<String, String> {
// Use external service to grap IP
let url = "https://api.ipify.org";
let response = reqwest::get(url).await.unwrap().text().await.unwrap();
// Check if valid IPv4 address and return early if not
if response.parse::<Ipv4Addr>().is_err() {
return Err(format!("Not valid IPv4 address: {}", response));
}
let hops_count = run_tracert(&response)?;
Ok(format!("Counted {} hops to {}", hops_count, response))
}
/// Count number of hops in tracert output
fn count_hops(output: &str) -> usize {
// Split the output into lines
let lines: Vec<&str> = output.lines().collect();
// Filter lines that appear to represent hops
let hop_lines: Vec<&str> = lines
.iter()
.filter(|&line| line.contains("ms") || line.contains("*")) // TODO check if it contains just the `ms` surrounded by whitespace, otherwise it might falsely pick up some domain names as well
.cloned()
.collect();
// Return the number of hops
hop_lines.len()
}
/// Run `tracert`
fn run_tracert(target_ip: &str) -> Result<usize, String> {
// Ensure valid IPv4 address to avoid prevent command injection
assert!(target_ip.parse::<Ipv4Addr>().is_ok());
// Execute the `tracert` command
let output = match std::process::Command::new("tracert")
.arg("-4") // Force IPv4
.arg("-d") // Prevent resolving intermediate IP addresses
.arg("-w") // Set timeout to 1 second
.arg("1000")
.arg("-h") // Set max hop count
.arg("5")
.arg(target_ip)
.output()
{
Ok(res) => res,
Err(err) => return Err(format!("Failed running tracert: {}", err)),
};
// Check if the command was successful
if output.status.success() {
// Convert the output to a string
let stdout =
std::str::from_utf8(&output.stdout).expect("Invalid UTF-8 sequence in command output");
println!("{}", stdout);
// Count the number of hops
let hop_count = count_hops(stdout);
Ok(hop_count)
} else {
let stderr = std::str::from_utf8(&output.stderr)
.expect("Invalid UTF-8 sequence in command error output");
println!("{}", stderr);
Err(format!("Failed collecting tracert output: {}", stderr))
}
}
|