diff --git a/src/ip.rs b/src/ip.rs index 272fc6f..5b558a3 100644 --- a/src/ip.rs +++ b/src/ip.rs @@ -1,8 +1,13 @@ -use crate::structs::{config::Config, Ipify}; +use crate::structs::config::Config; use local_ip_address::list_afinet_netifas; use mac_address::get_mac_address; use reqwest::Client as HttpClient; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +use std::{ + collections::HashMap, + net::{IpAddr, Ipv4Addr, Ipv6Addr}, + str::FromStr, + time::Duration, +}; pub(crate) async fn determine_ip(config: &Config) -> (Option, Option) { let ipv4 = determine_ipv4().await; @@ -10,43 +15,79 @@ pub(crate) async fn determine_ip(config: &Config) -> (Option, Option Option { +pub(crate) async fn query_ip(ip_enum: IpAddr) -> Option { + let local_ip: IpAddr = match ip_enum { + IpAddr::V4(_) => IpAddr::V4(Ipv4Addr::UNSPECIFIED), + IpAddr::V6(_) => IpAddr::V6(Ipv6Addr::UNSPECIFIED), + }; + let http = HttpClient::builder() - .local_address(Some(IpAddr::V4(Ipv4Addr::UNSPECIFIED))) + .local_address(local_ip) + .timeout(Duration::from_secs(30)) .build() .ok()?; - let response: Ipify = http - .get("https://api64.ipify.org?format=json") + let response = http + .get("https://one.one.one.one/cdn-cgi/trace") .send() .await .ok()? - .json() + .text() .await .ok()?; - match response.ip { + let data: HashMap = response + .lines() + .map(|x| match x.split_once('=') { + Some((key, value)) => (key.to_owned(), value.to_owned()), + None => (String::new(), String::new()), + }) + .collect(); + + let ip = data.get("ip")?; + let ip_address = IpAddr::from_str(ip).ok()?; + Some(ip_address) +} + +fn split_ipv6(ipv6: &Ipv6Addr) -> Option<([u8; 8], [u8; 8])> { + let octets = ipv6.octets(); + let (p, s) = octets.split_at(8); + let prefix: [u8; 8] = p.try_into().ok()?; + let suffix: [u8; 8] = s.try_into().ok()?; + Some((prefix, suffix)) +} + +fn eui48_to_modified_eui64(eui48: &[u8; 6]) -> Option<[u8; 8]> { + let (p, s) = eui48.split_at(3); + let prefix: [u8; 3] = p.try_into().ok()?; + let suffix: [u8; 3] = s.try_into().ok()?; + let eui64 = [ + prefix[0], prefix[1], prefix[2], 0xff, 0xfe, suffix[0], suffix[1], suffix[2], + ]; + let mut modified_eui64 = eui64; + modified_eui64[0] ^= 0b0000_0010; + Some(modified_eui64) +} + +pub(crate) async fn determine_ipv4() -> Option { + let ipv4_unspecified = IpAddr::V4(Ipv4Addr::UNSPECIFIED); + + let ip = query_ip(ipv4_unspecified).await?; + + let ipv4 = match ip { IpAddr::V4(x) => Some(x), IpAddr::V6(_) => None, - } + }?; + + Some(ipv4) } pub(crate) async fn determine_ipv6(config: &Config) -> Option { - let http = HttpClient::builder() - .local_address(Some(IpAddr::V6(Ipv6Addr::UNSPECIFIED))) - .build() - .ok()?; + let ipv6_unspecified = IpAddr::V6(Ipv6Addr::UNSPECIFIED); - let response: Ipify = http - .get("https://api64.ipify.org?format=json") - .send() - .await - .ok()? - .json() - .await - .ok()?; + let ip = query_ip(ipv6_unspecified).await?; - let ipv6 = match response.ip { + let ipv6 = match ip { IpAddr::V4(_) => None, IpAddr::V6(x) => Some(x), }?; @@ -93,23 +134,3 @@ pub(crate) async fn determine_ipv6(config: &Config) -> Option { .first() .cloned(); } - -fn split_ipv6(ipv6: &Ipv6Addr) -> Option<([u8; 8], [u8; 8])> { - let octets = ipv6.octets(); - let (p, s) = octets.split_at(8); - let prefix: [u8; 8] = p.try_into().ok()?; - let suffix: [u8; 8] = s.try_into().ok()?; - Some((prefix, suffix)) -} - -fn eui48_to_modified_eui64(eui48: &[u8; 6]) -> Option<[u8; 8]> { - let (p, s) = eui48.split_at(3); - let prefix: [u8; 3] = p.try_into().ok()?; - let suffix: [u8; 3] = s.try_into().ok()?; - let eui64 = [ - prefix[0], prefix[1], prefix[2], 0xff, 0xfe, suffix[0], suffix[1], suffix[2], - ]; - let mut modified_eui64 = eui64; - modified_eui64[0] ^= 0b0000_0010; - Some(modified_eui64) -} diff --git a/src/structs.rs b/src/structs.rs index f2a064b..622a3f1 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -3,7 +3,7 @@ pub(crate) mod config; use clap::Parser; use serde::{Deserialize, Serialize}; -use std::{net::IpAddr, path::PathBuf}; +use std::path::PathBuf; #[derive(Debug, Parser)] pub(crate) struct Args { @@ -18,11 +18,6 @@ pub(crate) struct Args { pub version: bool, } -#[derive(Debug, Serialize, Deserialize)] -pub(crate) struct Ipify { - pub ip: IpAddr, -} - #[derive(Debug, Serialize, Deserialize)] pub(crate) struct RecordIds { pub v4: Vec,