Linux support

main
shellrow 3 years ago
parent f6159a5ef8
commit 97195bef06
  1. 82
      src/gateway/linux.rs
  2. 21
      src/gateway/mod.rs
  3. 23
      src/gateway/unix.rs
  4. 13
      src/interface/mod.rs
  5. 4
      src/interface/unix.rs
  6. 4
      src/lib.rs

@ -1,24 +1,76 @@
use std::net::UdpSocket; use std::net::{IpAddr, Ipv4Addr};
use std::fs::read_to_string;
use crate::interface::MacAddr;
use super::Gateway; use super::Gateway;
fn send_udp_packet() -> Result<(), String> { const PATH_PROC_NET_ROUTE: &str = "/proc/net/route";
let buf = [0u8; 0]; const PATH_PROC_NET_ARP: &str = "/proc/net/arp";
let socket = match UdpSocket::bind("0.0.0.0:0") {
Ok(s) => s, fn convert_hex_ipv4(hex_ip: &str) -> Ipv4Addr {
Err(e) => return Err(format!("Failed to create UDP socket {}", e)), if hex_ip.len() != 8 {
}; return Ipv4Addr::UNSPECIFIED;
let dst: &str = "1.1.1.1:80";
match socket.set_ttl(1) {
Ok(_) => (),
Err(e) => return Err(format!("Failed to set TTL {}", e)),
} }
match socket.send_to(&buf, dst) { let o1: u8 = u8::from_str_radix(&hex_ip[6..8], 0x10).unwrap_or(0);
Ok(_) => (), let o2: u8 = u8::from_str_radix(&hex_ip[4..6], 0x10).unwrap_or(0);
Err(e) => return Err(format!("Failed to send data {}", e)), let o3: u8 = u8::from_str_radix(&hex_ip[2..4], 0x10).unwrap_or(0);
let o4: u8 = u8::from_str_radix(&hex_ip[0..2], 0x10).unwrap_or(0);
Ipv4Addr::new(o1, o2, o3, o4)
}
#[allow(dead_code)]
fn convert_hex_ipv6(hex_ip: &str) -> Ipv6Addr {
if hex_ip.len() != 32 {
return Ipv6Addr::UNSPECIFIED;
} }
Ok(()) let h1: u16 = u16::from_str_radix(&hex_ip[0..4], 0x10).unwrap_or(0);
let h2: u16 = u16::from_str_radix(&hex_ip[4..8], 0x10).unwrap_or(0);
let h3: u16 = u16::from_str_radix(&hex_ip[8..12], 0x10).unwrap_or(0);
let h4: u16 = u16::from_str_radix(&hex_ip[12..16], 0x10).unwrap_or(0);
let h5: u16 = u16::from_str_radix(&hex_ip[16..20], 0x10).unwrap_or(0);
let h6: u16 = u16::from_str_radix(&hex_ip[20..24], 0x10).unwrap_or(0);
let h7: u16 = u16::from_str_radix(&hex_ip[24..28], 0x10).unwrap_or(0);
let h8: u16 = u16::from_str_radix(&hex_ip[28..32], 0x10).unwrap_or(0);
Ipv6Addr::new(h1, h2, h3, h4, h5, h6, h7, h8)
} }
pub fn get_default_gateway(interface_name: String) -> Result<Gateway, String> { pub fn get_default_gateway(interface_name: String) -> Result<Gateway, String> {
match super::send_udp_packet() {
Ok(_) => {},
Err(e) => return Err(format!("Failed to send UDP packet {}", e)),
}
let route_data = read_to_string(PATH_PROC_NET_ROUTE);
let route_text = match route_data {
Ok(content) => content,
Err(_) => String::new(),
};
let route_table: Vec<&str> = route_text.trim().split("\n").collect();
let mut gateway_ip: IpAddr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
for row in route_table {
let fields: Vec<&str> = row.split("\t").collect();
if fields.len() >= 3 {
if fields[0] == interface_name && fields[2] != "00000000" {
gateway_ip = IpAddr::V4(convert_hex_ipv4(fields[2]));
}
}
}
let arp_data = read_to_string(PATH_PROC_NET_ARP);
let arp_text = match arp_data {
Ok(content) => content,
Err(_) => String::new(),
};
let arp_table: Vec<&str> = arp_text.trim().split("\n").collect();
for row in arp_table {
let mut fields: Vec<&str> = row.split(" ").collect();
fields.retain(|value| *value != "");
if fields.len() >= 6 {
if fields[0] == gateway_ip.to_string() && fields[5] == interface_name {
let gateway: Gateway = Gateway {
mac_addr: MacAddr::from_hex_format(fields[3]),
ip_addr: gateway_ip,
};
return Ok(gateway);
}
}
}
Err(String::new()) Err(String::new())
} }

@ -4,6 +4,7 @@ pub mod unix;
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]
pub mod linux; pub mod linux;
use std::net::UdpSocket;
use std::net::{IpAddr, Ipv4Addr}; use std::net::{IpAddr, Ipv4Addr};
use crate::interface::{self, MacAddr, Interface}; use crate::interface::{self, MacAddr, Interface};
@ -18,7 +19,7 @@ impl Gateway {
pub fn new() -> Gateway { pub fn new() -> Gateway {
Gateway { Gateway {
mac_addr: MacAddr::zero(), mac_addr: MacAddr::zero(),
ip_addr: IpAddr::V4(Ipv4Addr::LOCALHOST), ip_addr: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
} }
} }
} }
@ -51,6 +52,24 @@ pub fn get_default_gateway() -> Result<Gateway, String> {
Err(String::from("Default Gateway not found")) Err(String::from("Default Gateway not found"))
} }
fn send_udp_packet() -> Result<(), String> {
let buf = [0u8; 0];
let socket = match UdpSocket::bind("0.0.0.0:0") {
Ok(s) => s,
Err(e) => return Err(format!("Failed to create UDP socket {}", e)),
};
let dst: &str = "1.1.1.1:80";
match socket.set_ttl(1) {
Ok(_) => (),
Err(e) => return Err(format!("Failed to set TTL {}", e)),
}
match socket.send_to(&buf, dst) {
Ok(_) => (),
Err(e) => return Err(format!("Failed to send data {}", e)),
}
Ok(())
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

@ -1,28 +1,9 @@
use std::net::UdpSocket;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use crate::socket; use crate::socket;
use super::Gateway; use super::Gateway;
const TIMEOUT: u64 = 3000; const TIMEOUT: u64 = 3000;
fn send_udp_packet() -> Result<(), String> {
let buf = [0u8; 0];
let socket = match UdpSocket::bind("0.0.0.0:0") {
Ok(s) => s,
Err(e) => return Err(format!("Failed to create UDP socket {}", e)),
};
let dst: &str = "1.1.1.1:80";
match socket.set_ttl(1) {
Ok(_) => (),
Err(e) => return Err(format!("Failed to set TTL {}", e)),
}
match socket.send_to(&buf, dst) {
Ok(_) => (),
Err(e) => return Err(format!("Failed to send data {}", e)),
}
Ok(())
}
pub fn get_default_gateway(interface_name: String) -> Result<Gateway, String> { pub fn get_default_gateway(interface_name: String) -> Result<Gateway, String> {
let timeout = Duration::from_millis(TIMEOUT); let timeout = Duration::from_millis(TIMEOUT);
let start_time = Instant::now(); let start_time = Instant::now();
@ -39,7 +20,7 @@ pub fn get_default_gateway(interface_name: String) -> Result<Gateway, String> {
Ok(socket::Channel::Ethernet(tx, rx)) => (tx, rx), Ok(socket::Channel::Ethernet(tx, rx)) => (tx, rx),
Err(e) => panic!("Failed to create channel {}", e), Err(e) => panic!("Failed to create channel {}", e),
}; };
match send_udp_packet() { match super::send_udp_packet() {
Ok(_) => (), Ok(_) => (),
Err(e) => return Err(format!("Failed to send UDP packet {}", e)), Err(e) => return Err(format!("Failed to send UDP packet {}", e)),
} }
@ -58,7 +39,7 @@ pub fn get_default_gateway(interface_name: String) -> Result<Gateway, String> {
if Instant::now().duration_since(start_time) > timeout { if Instant::now().duration_since(start_time) > timeout {
return Err(String::from("Recieve timeout")); return Err(String::from("Recieve timeout"));
}else{ }else{
match send_udp_packet() { match super::send_udp_packet() {
Ok(_) => (), Ok(_) => (),
Err(e) => return Err(format!("Failed to send UDP packet {}", e)), Err(e) => return Err(format!("Failed to send UDP packet {}", e)),
} }

@ -34,6 +34,19 @@ impl MacAddr {
pub fn zero() -> MacAddr { pub fn zero() -> MacAddr {
MacAddr(0,0,0,0,0,0) MacAddr(0,0,0,0,0,0)
} }
pub fn from_hex_format(hex_mac_addr: &str) -> MacAddr {
if hex_mac_addr.len() != 17 {
return MacAddr(0,0,0,0,0,0)
}
let fields: Vec<&str> = hex_mac_addr.split(":").collect();
let o1: u8 = u8::from_str_radix(&fields[0], 0x10).unwrap_or(0);
let o2: u8 = u8::from_str_radix(&fields[1], 0x10).unwrap_or(0);
let o3: u8 = u8::from_str_radix(&fields[2], 0x10).unwrap_or(0);
let o4: u8 = u8::from_str_radix(&fields[3], 0x10).unwrap_or(0);
let o5: u8 = u8::from_str_radix(&fields[4], 0x10).unwrap_or(0);
let o6: u8 = u8::from_str_radix(&fields[5], 0x10).unwrap_or(0);
MacAddr(o1, o2, o3, o4, o5, o6)
}
} }
impl std::fmt::Display for MacAddr { impl std::fmt::Display for MacAddr {

@ -55,7 +55,7 @@ pub fn interfaces() -> Vec<Interface> {
match local_ip { match local_ip {
IpAddr::V4(local_ipv4) => { IpAddr::V4(local_ipv4) => {
if iface.ipv4.contains(&local_ipv4) { if iface.ipv4.contains(&local_ipv4) {
match gateway::unix::get_default_gateway(iface.name.clone()) { match gateway::linux::get_default_gateway(iface.name.clone()) {
Ok(gateway) => { Ok(gateway) => {
iface.gateway = Some(gateway); iface.gateway = Some(gateway);
}, },
@ -65,7 +65,7 @@ pub fn interfaces() -> Vec<Interface> {
}, },
IpAddr::V6(local_ipv6) => { IpAddr::V6(local_ipv6) => {
if iface.ipv6.contains(&local_ipv6) { if iface.ipv6.contains(&local_ipv6) {
match gateway::unix::get_default_gateway(iface.name.clone()) { match gateway::linux::get_default_gateway(iface.name.clone()) {
Ok(gateway) => { Ok(gateway) => {
iface.gateway = Some(gateway); iface.gateway = Some(gateway);
}, },

@ -1,8 +1,8 @@
#[cfg(not(target_os="windows"))] #[cfg(not(target_os="windows"))]
mod sys; mod sys;
#[cfg(not(target_os="windows"))] #[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "ios"))]
mod bpf; mod bpf;
#[cfg(not(target_os="windows"))] #[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "ios"))]
mod socket; mod socket;
pub mod interface; pub mod interface;

Loading…
Cancel
Save