initial commit
commit
5ccbc5e144
|
@ -0,0 +1 @@
|
||||||
|
/target
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
name = "librefi"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Lauren Liberda <laura@selfisekai.rocks>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
lazy_static = { version = "1.4.0" }
|
||||||
|
plist = { version = "1.3.1" }
|
||||||
|
regex = { version = "1.5.4" }
|
||||||
|
reqwest = { version = "0.11", features = ["json"] }
|
||||||
|
serde = { version = "1.0.132", features = ["derive"] }
|
||||||
|
tokio = { version = "1", features = ["full"] }
|
|
@ -0,0 +1,29 @@
|
||||||
|
use serde::{Deserialize};
|
||||||
|
use reqwest::header::{REFERER, USER_AGENT};
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct IpInfo {
|
||||||
|
ip: String,
|
||||||
|
asn: IpInfoAsn,
|
||||||
|
}
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct IpInfoAsn {
|
||||||
|
asn: String,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct IpInfoProvider {
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn ipv4_info() -> Result<IpInfo, Box<dyn std::error::Error>> {
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
let resp = client.get("https://ipinfo.io/widget")
|
||||||
|
.header(REFERER, "https://ipinfo.io/")
|
||||||
|
.header(USER_AGENT, "librefi")
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.json::<IpInfo>()
|
||||||
|
.await?;
|
||||||
|
Ok(resp)
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
// shell.exec("{networksetup,airport}") goes brrrr
|
||||||
|
|
||||||
|
use crate::connectors::types::{Connector, Network, NetworkInterface};
|
||||||
|
use std::process::Command;
|
||||||
|
extern crate plist;
|
||||||
|
use serde::{Deserialize};
|
||||||
|
use regex::{Regex};
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
pub struct AirportNetwork {
|
||||||
|
#[serde(rename = "SSID_STR")]
|
||||||
|
ssid: String,
|
||||||
|
bssid: String,
|
||||||
|
channel: u8,
|
||||||
|
rssi: i8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AirportNetwork> for Network {
|
||||||
|
fn from(net: AirportNetwork) -> Network {
|
||||||
|
Network {
|
||||||
|
ssid: net.ssid.clone(),
|
||||||
|
bssid: Some(net.bssid.clone()),
|
||||||
|
channel: Some(net.channel.clone()),
|
||||||
|
rssi: Some(net.rssi.clone()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MacOSConnector {}
|
||||||
|
|
||||||
|
impl MacOSConnector {
|
||||||
|
fn call_airport(&self, args: Vec<&str>) -> Result<Vec<u8>, String> {
|
||||||
|
let output = Command::new("/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport")
|
||||||
|
.args(&args)
|
||||||
|
.arg("--xml")
|
||||||
|
.output()
|
||||||
|
.expect("calling airport failed");
|
||||||
|
if !output.status.success() {
|
||||||
|
panic!("airport returned {:} status", output.status);
|
||||||
|
}
|
||||||
|
Ok(output.stdout)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_networksetup(&self, command: &str) -> Result<Vec<u8>, String> {
|
||||||
|
let output = Command::new("/usr/sbin/networksetup")
|
||||||
|
.arg(&command)
|
||||||
|
.output()
|
||||||
|
.expect("calling networksetup failed");
|
||||||
|
if !output.status.success() {
|
||||||
|
panic!("networksetup returned {:} status", output.status);
|
||||||
|
}
|
||||||
|
Ok(output.stdout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Connector for MacOSConnector {
|
||||||
|
fn list_networks(&self) -> Result<Vec<Network>, String> {
|
||||||
|
let output = self.call_airport(vec!["-s"])
|
||||||
|
.expect("airport idk what actually");
|
||||||
|
let res: Vec<AirportNetwork> = plist::from_bytes(&output).expect("airport returned shit");
|
||||||
|
let networks = res.into_iter().map(|net| Network::from(net)).collect();
|
||||||
|
Ok(networks)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list_network_interfaces(&self) -> Result<Vec<NetworkInterface>, String> {
|
||||||
|
// order returns both names
|
||||||
|
let output = String::from_utf8(
|
||||||
|
self.call_networksetup("-listnetworkserviceorder")
|
||||||
|
.expect("networksetup idk what actually"))
|
||||||
|
.expect("networksetup returned non-utf8 chars???");
|
||||||
|
lazy_static! {
|
||||||
|
static ref RE: Regex = Regex::new(r"(?x)
|
||||||
|
\((?P<order>\d+|\*)\)\ (?P<human>[^\n]+)\n
|
||||||
|
\(Hardware\ Port:\ .+?,\ Device:\ (?P<unix>[a-z]+\d+)\)
|
||||||
|
").unwrap();
|
||||||
|
}
|
||||||
|
let mut ifaces: Vec<NetworkInterface> = vec![];
|
||||||
|
for iface in RE.captures_iter(&output) {
|
||||||
|
ifaces.push(NetworkInterface {
|
||||||
|
enabled: &iface["order"] != "*",
|
||||||
|
machine_name: iface["unix"].to_string(),
|
||||||
|
human_name: Some(iface["human"].to_string()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(ifaces)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod macos;
|
||||||
|
pub mod types;
|
|
@ -0,0 +1,19 @@
|
||||||
|
pub trait Connector {
|
||||||
|
fn list_networks(&self) -> Result<Vec<Network>, String>;
|
||||||
|
fn list_network_interfaces(&self) -> Result<Vec<NetworkInterface>, String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Network {
|
||||||
|
pub ssid: String,
|
||||||
|
pub bssid: Option<String>,
|
||||||
|
pub channel: Option<u8>,
|
||||||
|
pub rssi: Option<i8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct NetworkInterface {
|
||||||
|
pub enabled: bool,
|
||||||
|
pub machine_name: String,
|
||||||
|
pub human_name: Option<String>,
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
mod connection_check;
|
||||||
|
mod connectors;
|
||||||
|
use connectors::types::{Connector};
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// let ip4 = connection_check::ipv4_info().await?;
|
||||||
|
// println!("{:?}", ip4);
|
||||||
|
|
||||||
|
let connector = connectors::macos::MacOSConnector {};
|
||||||
|
|
||||||
|
let ifaces = connector.list_network_interfaces().expect("network interface listing errored");
|
||||||
|
|
||||||
|
for iface in ifaces {
|
||||||
|
println!("{:?}", iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
let networks = connector.list_networks().expect("network listing errored");
|
||||||
|
|
||||||
|
for net in networks {
|
||||||
|
println!("{:?}", net);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue