sysmonk/resources/
network.rs

1use crate::squire;
2use reqwest;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use std::net::UdpSocket;
6
7/// Function to retrieve the public IP address
8///
9/// # Returns
10///
11/// An `Option` containing the public IP address as a `String` if found, otherwise `None`
12async fn public_ip_address() -> Option<String> {
13    let ip_regex = squire::util::ip_regex();
14    let mapping = squire::util::public_ip_mapping();
15
16    for (url, expects_text) in mapping {
17        match reqwest::get(&url).await {
18            Ok(response) => {
19                let extracted_ip = if expects_text {
20                    response.text().await.unwrap_or_default().trim().to_string()
21                } else {
22                    response.json::<serde_json::Value>().await.ok()
23                        .and_then(|json| json["origin"].as_str().map(str::to_string))
24                        .unwrap_or_default()
25                };
26
27                if ip_regex.is_match(&extracted_ip) {
28                    return Some(extracted_ip);
29                }
30            }
31            Err(err) => {
32                log::error!("Failed to fetch from {}: {}", &url, err);
33                continue; // Move on to the next URL
34            }
35        }
36    }
37
38    None
39}
40
41/// Function to retrieve the private IP address
42///
43/// # Returns
44///
45/// An `Option` containing the private IP address as a `String` if found, otherwise `None`
46fn private_ip_address() -> Option<String> {
47    let socket = match UdpSocket::bind("0.0.0.0:0") {
48        Ok(s) => s,
49        Err(err) => {
50            log::error!("Failed to bind to a socket: {}", err);
51            return None;
52        }
53    };
54    if socket.connect("8.8.8.8:80").is_err() {
55        log::error!("Failed to connect to a socket");
56        return None;
57    }
58    let local_addr = match socket.local_addr() {
59        Ok(addr) => addr,
60        Err(err) => {
61            log::error!("Failed to get local IP address: {}", err);
62            return None;
63        }
64    };
65    Some(local_addr.ip().to_string())
66}
67
68/// Struct to hold the network information of the system
69///
70/// This struct holds the private and public IP addresses of the system.
71///
72/// # Fields
73///
74/// * `private_ip_address` - The private IP address of the system
75/// * `public_ip_address` - The public IP address of the system
76#[derive(Serialize, Deserialize, Debug)]
77pub struct SystemInfoNetwork {
78    private_ip_address_raw: String,
79    public_ip_address_raw: String,
80}
81
82/// Function to get network information
83///
84/// This function retrieves the private and public IP addresses of the system.
85pub async fn get_network_info() -> HashMap<&'static str, String> {
86    let private_ip = private_ip_address().unwrap_or_default();
87    let public_ip = public_ip_address().await.unwrap_or_default();
88    HashMap::from([
89        ("Private IP address", private_ip),
90        ("Public IP address", public_ip),
91    ])
92}