Created
October 2, 2023 16:08
-
-
Save ssrlive/8d73616337bf984dced666d76bd5147f to your computer and use it in GitHub Desktop.
macos gateway
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use libc::{ | |
c_int, c_long, c_uint, c_void, freeifaddrs, getifaddrs, ifaddrs, sockaddr, sockaddr_in, | |
sockaddr_in6, AF_INET, AF_INET6, IFF_BROADCAST, IFF_LOOPBACK, IFF_MULTICAST, IFF_RUNNING, | |
IFF_UP, RTF_GATEWAY, | |
}; | |
use std::{ | |
ffi::CStr, | |
io, mem, | |
net::{IpAddr, Ipv4Addr}, | |
ptr, | |
}; | |
fn main() -> io::Result<()> { | |
let mut ifaddrs_ptr: *mut ifaddrs = ptr::null_mut(); | |
unsafe { | |
if getifaddrs(&mut ifaddrs_ptr) != 0 { | |
return Err(io::Error::last_os_error()); | |
} | |
let mut address: Option<IpAddr> = None; | |
let mut interface: Option<String> = None; | |
let mut ifa_ptr = ifaddrs_ptr; | |
while !ifa_ptr.is_null() { | |
let ifa = &*ifa_ptr; | |
let flags = ifa.ifa_flags as i32; | |
if flags & IFF_LOOPBACK == 0 | |
&& flags & IFF_RUNNING != 0 | |
&& flags & IFF_BROADCAST != 0 | |
&& flags & IFF_MULTICAST != 0 | |
&& flags & IFF_UP != 0 | |
&& flags & RTF_GATEWAY != 0 | |
{ | |
let ip = extract_ip(ifa.ifa_addr); | |
if ip.is_some() && ip.unwrap().is_ipv4() { | |
let name = CStr::from_ptr(ifa.ifa_name).to_string_lossy().into_owned(); | |
println!("Interface: {}", name); | |
let dst = extract_ip(ifa.ifa_dstaddr); | |
println!("Destination: {:?}", dst); | |
let mask = extract_ip(ifa.ifa_netmask); | |
println!("Mask: {:?}", mask); | |
address = ip; | |
interface = Some(name); | |
break; | |
} | |
} | |
ifa_ptr = ifa.ifa_next; | |
} | |
freeifaddrs(ifaddrs_ptr); | |
match (address, interface) { | |
(Some(gw), Some(iface)) => { | |
println!("Gateway: {}", gw); | |
println!("Interface: {}", iface); | |
} | |
_ => println!("Failed to retrieve gateway and interface information"), | |
} | |
} | |
let v = get_active_gateway()?; | |
println!("Active gateway: {:?}", v); | |
let _v = main4()?; | |
Ok(()) | |
} | |
fn extract_ip(addr: *const sockaddr) -> Option<IpAddr> { | |
unsafe { | |
match (*addr).sa_family as c_int { | |
AF_INET => { | |
let sin = *(addr as *const sockaddr_in); | |
let ip = &sin.sin_addr.s_addr as *const c_uint as *const u8; | |
let ip: [u8; 4] = std::slice::from_raw_parts(ip, 4).try_into().ok()?; | |
Some(IpAddr::from(ip)) | |
} | |
AF_INET6 => { | |
let sin6 = *(addr as *const sockaddr_in6); | |
let ip = sin6.sin6_addr.s6_addr; | |
Some(IpAddr::from(ip)) | |
} | |
_ => None, | |
} | |
} | |
} | |
fn get_active_gateway() -> std::io::Result<Ipv4Addr> { | |
// Command: `netstat -rn | grep default | grep -E -o "[0-9\.]+" | head -n 1` | |
let output = std::process::Command::new("netstat").arg("-rn").output()?; | |
let output_str = String::from_utf8_lossy(&output.stdout); | |
let gateway = output_str | |
.lines() | |
.filter(|line| line.contains("default")) | |
.filter_map(|line| { | |
let parts: Vec<&str> = line.split_whitespace().collect(); | |
if parts.len() >= 2 { | |
Some(parts[1]) | |
} else { | |
None | |
} | |
}) | |
.filter_map(|ip| ip.parse::<Ipv4Addr>().ok()) | |
.next(); | |
use std::io::ErrorKind::Other; | |
let err = "Failed to parse default gateway from \"netstat\" output"; | |
Ok(gateway.ok_or(std::io::Error::new(Other, err))?) | |
} | |
// use std::io; | |
// use std::mem; | |
// use std::net::{IpAddr, Ipv4Addr}; | |
// use std::process::Command; | |
// use std::ptr; | |
#[repr(C)] | |
#[allow(non_camel_case_types)] | |
struct rt_msghdr { | |
rtm_msglen: u16, | |
rtm_version: u8, | |
rtm_type: u8, | |
rtm_index: i16, | |
rtm_flags: i32, | |
rtm_addrs: i32, | |
rtm_pid: i32, | |
rtm_seq: i32, | |
rtm_errno: i32, | |
rtm_use: i32, | |
rtm_inits: u32, | |
rtm_rmx: rt_metrics, | |
} | |
#[repr(C)] | |
#[allow(non_camel_case_types)] | |
struct rt_metrics { | |
rmx_locks: u32, | |
rmx_mtu: u32, | |
rmx_hopcount: u32, | |
rmx_expire: u32, | |
rmx_recvpipe: u32, | |
rmx_sendpipe: u32, | |
rmx_ssthresh: u32, | |
rmx_rtt: u32, | |
rmx_rttvar: u32, | |
rmx_pksent: u32, | |
rmx_filler: [u32; 4], | |
} | |
fn sa_size(sa: *const libc::sockaddr) -> usize { | |
if sa.is_null() { | |
return mem::size_of::<c_long>(); | |
} | |
let sa_len = unsafe { (*sa).sa_len } as usize; | |
if sa_len == 0 { | |
mem::size_of::<c_long>() | |
} else { | |
1 + ((sa_len - 1) | (mem::size_of::<c_long>() - 1)) | |
} | |
} | |
fn main4() -> io::Result<()> { | |
let mut mib: [i32; 6] = [0; 6]; | |
let mut needed: usize = 0; | |
mib[0] = libc::CTL_NET; | |
mib[1] = libc::PF_ROUTE; | |
mib[4] = libc::NET_RT_DUMP; | |
let null = ptr::null_mut::<c_void>(); | |
if unsafe { libc::sysctl(mib.as_mut_ptr(), 6, null, &mut needed, null, 0) } < 0 { | |
return Err(io::Error::last_os_error()); | |
} | |
let buf = vec![0u8; needed]; | |
let buf_ptr = buf.as_ptr() as *mut libc::c_void; | |
if unsafe { libc::sysctl(mib.as_mut_ptr(), 6, buf_ptr, &mut needed, null, 0) } < 0 { | |
return Err(io::Error::last_os_error()); | |
} | |
let lim = unsafe { buf_ptr.offset(needed as isize) }; | |
let mut next = buf_ptr; | |
let count = mem::size_of::<rt_msghdr>() as isize; | |
loop { | |
let rtm = unsafe { &mut *(next as *mut rt_msghdr) }; | |
let sa = unsafe { &mut *(next.offset(count) as *mut sockaddr) }; | |
let sa_size = sa_size(sa) as isize; | |
let sa = unsafe { (sa as *mut sockaddr as *mut c_void).offset(sa_size) }; | |
let sockin = unsafe { &mut *(sa as *mut sockaddr_in) }; | |
match sockin.sin_family as i32 { | |
libc::AF_INET => { | |
let ip = &sockin.sin_addr.s_addr as *const c_uint as *const u8; | |
let ip: [u8; 4] = unsafe { std::slice::from_raw_parts(ip, 4).try_into().unwrap() }; | |
let ip = IpAddr::from(ip); | |
println!("defaultrouter={}", ip); | |
break; | |
} | |
libc::AF_INET6 => { | |
let sockin6 = unsafe { &mut *(sa as *mut sockaddr_in6) }; | |
let ip = sockin6.sin6_addr.s6_addr; | |
let ip = IpAddr::from(ip); | |
println!("defaultrouter ipv6={}", ip); | |
} | |
_ => {} | |
} | |
next = unsafe { next.offset(rtm.rtm_msglen as isize) }; | |
if next >= lim { | |
break; | |
} | |
} | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
set interface mtu