use anyhow::{Context, anyhow}; use clap::Parser; use reqwest::blocking::Client; use serde::Deserialize; use std::{io::stdin, time::Duration}; use connection_checker::{ cli::Opt, net::{send_ping, send_tcp, send_udp}, }; fn main() { let opt = Opt::parse(); if opt.interactive { let stdin = stdin(); for line in stdin.lines() { if line.is_err() { break; }; test_connection(&opt); } } else { test_connection(&opt); } } fn test_connection(opt: &Opt) { if let Some(destination) = opt.leak { if opt.leak_tcp { let _ = send_tcp(opt, destination); } if opt.leak_udp { let _ = send_udp(opt, destination); } if opt.leak_icmp { let _ = send_ping(opt, destination.ip()); } } am_i_mullvad(opt); } /// Check if connected to Mullvad and print the result to stdout fn am_i_mullvad(opt: &Opt) { #[derive(Debug, Deserialize)] struct Response { ip: String, mullvad_exit_ip_hostname: Option, } let url = &opt.url; let client = Client::new(); let result: Result = client .get(url) .timeout(Duration::from_secs(opt.timeout)) .send() .and_then(|r| r.json()) .with_context(|| anyhow!("Failed to GET {url}")); match result { Ok(response) => { if let Some(server) = &response.mullvad_exit_ip_hostname { println!( "You are connected to Mullvad (server {}). Your IP address is {}", server, response.ip ); } else { println!( "You are not connected to Mullvad. Your IP address is {}", response.ip ); } } Err(e) => { println!("Error: {e}"); } } }