initial commit

master
Lauren Liberda 2021-12-26 13:55:29 +01:00
commit 5ccbc5e144
No known key found for this signature in database
GPG Key ID: 734C629FD04BD319
9 changed files with 1297 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

1115
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

15
Cargo.toml Normal file
View File

@ -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"] }

29
src/connection_check.rs Normal file
View File

@ -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)
}

89
src/connectors/macos.rs Normal file
View File

@ -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)
}
}

2
src/connectors/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod macos;
pub mod types;

View File

19
src/connectors/types.rs Normal file
View File

@ -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>,
}

27
src/main.rs Normal file
View File

@ -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(())
}