parent
e9c39c30db
commit
ecae4273e4
@ -1,8 +1,8 @@ |
|||||||
use default_net; |
use default_net; |
||||||
|
|
||||||
fn main(){ |
fn main(){ |
||||||
match default_net::get_default_gateway() { |
let default_gateway = default_net::get_default_gateway(); |
||||||
Ok(default_gateway) => {println!("Default Gateway: {}",default_gateway)}, |
println!("Default Gateway"); |
||||||
Err(e) => {println!("{}",e)}, |
println!("IP {:?}", default_gateway.ip); |
||||||
} |
println!("MAC {:?}", default_gateway.mac); |
||||||
} |
} |
||||||
|
@ -0,0 +1,15 @@ |
|||||||
|
use default_net; |
||||||
|
|
||||||
|
fn main(){ |
||||||
|
if let Some(default_interface) = default_net::get_default_interface(){ |
||||||
|
println!("Index {}", default_interface.index); |
||||||
|
println!("Name {}", default_interface.name); |
||||||
|
println!("MAC {:?}", default_interface.mac); |
||||||
|
println!("IPv4 {:?}", default_interface.ipv4); |
||||||
|
println!("IPv6 {:?}", default_interface.ipv6); |
||||||
|
println!("Gateway IP {:?}", default_interface.gateway.ip); |
||||||
|
println!("Gateway MAC {:?}", default_interface.gateway.mac); |
||||||
|
}else{ |
||||||
|
println!("Failed to get default interface info"); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,301 @@ |
|||||||
|
use std::net::UdpSocket; |
||||||
|
use std::time::{Duration, Instant}; |
||||||
|
use std::net::{IpAddr, Ipv4Addr}; |
||||||
|
use pnet::packet::Packet; |
||||||
|
use pnet::packet::MutablePacket; |
||||||
|
|
||||||
|
#[cfg(any(unix, macos))] |
||||||
|
use pnet::transport::TransportChannelType::Layer4; |
||||||
|
#[cfg(any(unix, macos))] |
||||||
|
use pnet::transport::TransportProtocol::Ipv4; |
||||||
|
#[cfg(any(unix, macos))] |
||||||
|
use pnet::transport::icmp_packet_iter; |
||||||
|
|
||||||
|
#[cfg(target_os = "windows")] |
||||||
|
use pnet::datalink; |
||||||
|
|
||||||
|
use crate::interface; |
||||||
|
|
||||||
|
pub struct Gateway { |
||||||
|
pub ip: Option<String>, |
||||||
|
pub mac: Option<String>, |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get_default_gateway() -> Gateway { |
||||||
|
let mut gateway: Gateway = Gateway { |
||||||
|
ip: None, |
||||||
|
mac: None, |
||||||
|
}; |
||||||
|
let default_gateway_ip: Option<String> = match get_default_gateway_ip(){ |
||||||
|
Ok(gateway_ip) => Some(gateway_ip), |
||||||
|
Err(_) => None, |
||||||
|
}; |
||||||
|
gateway.ip = default_gateway_ip.clone(); |
||||||
|
if let Some(gateway_ip) = default_gateway_ip.clone(){ |
||||||
|
let default_gateway_mac: Option<String> = match get_default_gateway_mac(gateway_ip.to_string()) { |
||||||
|
Ok(gateway_mac) => Some(gateway_mac), |
||||||
|
Err(_) => None, |
||||||
|
}; |
||||||
|
gateway.mac = default_gateway_mac; |
||||||
|
} |
||||||
|
return gateway; |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get_default_gateway_ip() -> Result<String,String>{ |
||||||
|
send_udp_packet(); |
||||||
|
let timeout = Duration::from_millis(3000); |
||||||
|
let r = receive_icmp_packets(pnet::packet::icmp::IcmpTypes::TimeExceeded, &timeout); |
||||||
|
return r; |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get_default_gateway_mac(gateway_ip: String) -> Result<String,String>{ |
||||||
|
match gateway_ip.parse::<Ipv4Addr>(){ |
||||||
|
Ok(ipv4_addr) => { |
||||||
|
if let Some(gateway_mac) = get_mac_through_arp(ipv4_addr){ |
||||||
|
return Ok(gateway_mac); |
||||||
|
}else{ |
||||||
|
return Err(String::from("Failed to get gateway mac address")); |
||||||
|
} |
||||||
|
}, |
||||||
|
Err(_) => return Err(String::from("Failed to get gateway mac address")), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn send_udp_packet(){ |
||||||
|
let buf = [0u8; 0]; |
||||||
|
let socket = match UdpSocket::bind("0.0.0.0:0") { |
||||||
|
Ok(s) => s, |
||||||
|
Err(_) => panic!("error!"), |
||||||
|
}; |
||||||
|
let dest: &str = "8.8.8.8:80"; |
||||||
|
socket.set_ttl(1).unwrap(); |
||||||
|
socket.send_to(&buf, dest).unwrap(); |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(any(unix, macos))] |
||||||
|
fn receive_icmp_packets(icmp_type: pnet::packet::icmp::IcmpType, timeout: &Duration) -> Result<String, String>{ |
||||||
|
let protocol = Layer4(Ipv4(pnet::packet::ip::IpNextHeaderProtocols::Icmp)); |
||||||
|
let (mut _tx, mut rx) = match pnet::transport::transport_channel(4096, protocol) { |
||||||
|
Ok((tx, rx)) => (tx, rx), |
||||||
|
Err(e) => panic!("Error happened {}", e), |
||||||
|
}; |
||||||
|
let mut iter = icmp_packet_iter(&mut rx); |
||||||
|
let start_time = Instant::now(); |
||||||
|
loop { |
||||||
|
match iter.next_with_timeout(*timeout) { |
||||||
|
Ok(r) => { |
||||||
|
if let Some((packet, addr)) = r { |
||||||
|
if packet.get_icmp_type() == icmp_type { |
||||||
|
match addr { |
||||||
|
IpAddr::V4(ipv4_addr) =>{return Ok(ipv4_addr.to_string())}, |
||||||
|
IpAddr::V6(ipv6_addr) =>{return Ok(ipv6_addr.to_string())}, |
||||||
|
} |
||||||
|
} |
||||||
|
}else{ |
||||||
|
return Err(String::from("Failed to read packet")); |
||||||
|
} |
||||||
|
}, |
||||||
|
Err(e) => { |
||||||
|
return Err(format!("An error occurred while reading: {}", e)); |
||||||
|
} |
||||||
|
} |
||||||
|
if Instant::now().duration_since(start_time) > *timeout { |
||||||
|
return Err(String::from("timeout")); |
||||||
|
}else{ |
||||||
|
send_udp_packet(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "windows")] |
||||||
|
fn receive_icmp_packets(icmp_type: pnet::packet::icmp::IcmpType, timeout: &Duration) -> Result<String, String>{ |
||||||
|
/* |
||||||
|
let protocol = Layer4(Ipv4(pnet::packet::ip::IpNextHeaderProtocols::Icmp)); |
||||||
|
let (mut _tx, mut rx) = match pnet::transport::transport_channel(4096, protocol) { |
||||||
|
Ok((tx, rx)) => (tx, rx), |
||||||
|
Err(e) => panic!("Error happened {}", e), |
||||||
|
}; |
||||||
|
let mut iter = icmp_packet_iter(&mut rx); |
||||||
|
let start_time = Instant::now(); |
||||||
|
loop { |
||||||
|
match iter.next() { |
||||||
|
Ok((packet, addr)) => { |
||||||
|
if packet.get_icmp_type() == icmp_type { |
||||||
|
match addr { |
||||||
|
IpAddr::V4(ipv4_addr) =>{return Ok(ipv4_addr.to_string())}, |
||||||
|
IpAddr::V6(ipv6_addr) =>{return Ok(ipv6_addr.to_string())}, |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
Err(e) => { |
||||||
|
return Err(format!("An error occurred while reading: {}", e)); |
||||||
|
} |
||||||
|
} |
||||||
|
if Instant::now().duration_since(start_time) > *timeout { |
||||||
|
return Err(String::from("timeout")); |
||||||
|
}else{ |
||||||
|
send_udp_packet(); |
||||||
|
} |
||||||
|
} |
||||||
|
*/ |
||||||
|
let default_idx = interface::get_default_interface_index().unwrap(); |
||||||
|
let interfaces = pnet::datalink::interfaces(); |
||||||
|
let interface = interfaces.into_iter().filter(|interface: &pnet::datalink::NetworkInterface| interface.index == default_idx).next().expect("Failed to get Interface"); |
||||||
|
let (mut _tx, mut rx) = match datalink::channel(&interface, Default::default()) { |
||||||
|
Ok(pnet::datalink::Channel::Ethernet(tx, rx)) => (tx, rx), |
||||||
|
Ok(_) => panic!("Unknown channel type"), |
||||||
|
Err(e) => panic!("Error happened {}", e), |
||||||
|
}; |
||||||
|
receive_packets(&mut rx, icmp_type, timeout) |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "windows")] |
||||||
|
fn receive_packets(rx: &mut Box<dyn pnet::datalink::DataLinkReceiver>, icmp_type: pnet::packet::icmp::IcmpType, timeout: &Duration) -> Result<String, String>{ |
||||||
|
let start_time = Instant::now(); |
||||||
|
loop { |
||||||
|
match rx.next() { |
||||||
|
Ok(frame) => { |
||||||
|
let frame = pnet::packet::ethernet::EthernetPacket::new(frame).unwrap(); |
||||||
|
match frame.get_ethertype() { |
||||||
|
pnet::packet::ethernet::EtherTypes::Ipv4 => { |
||||||
|
if let Some(ip_addr) = ipv4_handler(&frame, icmp_type){ |
||||||
|
return Ok(ip_addr); |
||||||
|
} |
||||||
|
}, |
||||||
|
pnet::packet::ethernet::EtherTypes::Ipv6 => { |
||||||
|
if let Some(ip_addr) = ipv6_handler(&frame, icmp_type){ |
||||||
|
return Ok(ip_addr); |
||||||
|
} |
||||||
|
}, |
||||||
|
_ => { |
||||||
|
//println!("Not a ipv4 or ipv6");
|
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
Err(e) => { |
||||||
|
return Err(format!("An error occurred while reading: {}", e)); |
||||||
|
} |
||||||
|
} |
||||||
|
if Instant::now().duration_since(start_time) > *timeout { |
||||||
|
return Err(String::from("timeout")); |
||||||
|
}else{ |
||||||
|
send_udp_packet(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "windows")] |
||||||
|
fn ipv4_handler(ethernet: &pnet::packet::ethernet::EthernetPacket, icmp_type: pnet::packet::icmp::IcmpType) -> Option<String> { |
||||||
|
if let Some(packet) = pnet::packet::ipv4::Ipv4Packet::new(ethernet.payload()){ |
||||||
|
match packet.get_next_level_protocol() { |
||||||
|
pnet::packet::ip::IpNextHeaderProtocols::Icmp => { |
||||||
|
return icmp_handler(&packet, icmp_type); |
||||||
|
}, |
||||||
|
_ => { |
||||||
|
None |
||||||
|
} |
||||||
|
} |
||||||
|
}else{ |
||||||
|
None |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "windows")] |
||||||
|
fn ipv6_handler(ethernet: &pnet::packet::ethernet::EthernetPacket, icmp_type: pnet::packet::icmp::IcmpType) -> Option<String> { |
||||||
|
if let Some(packet) = pnet::packet::ipv6::Ipv6Packet::new(ethernet.payload()){ |
||||||
|
match packet.get_next_header() { |
||||||
|
pnet::packet::ip::IpNextHeaderProtocols::Icmpv6 => { |
||||||
|
return icmpv6_handler(&packet, icmp_type); |
||||||
|
}, |
||||||
|
_ => { |
||||||
|
None |
||||||
|
} |
||||||
|
} |
||||||
|
}else{ |
||||||
|
None |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "windows")] |
||||||
|
fn icmp_handler(ip_packet: &pnet::packet::ipv4::Ipv4Packet, icmp_type: pnet::packet::icmp::IcmpType) -> Option<String> { |
||||||
|
if let Some(packet) = pnet::packet::icmp::IcmpPacket::new(ip_packet.payload()){ |
||||||
|
if packet.get_icmp_type() == icmp_type { |
||||||
|
let ipv4_addr = ip_packet.get_source(); |
||||||
|
return Some(ipv4_addr.to_string()) |
||||||
|
}else{ |
||||||
|
None |
||||||
|
} |
||||||
|
}else{ |
||||||
|
None |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_os = "windows")] |
||||||
|
fn icmpv6_handler(ip_packet: &pnet::packet::ipv6::Ipv6Packet, icmp_type: pnet::packet::icmp::IcmpType) -> Option<String> { |
||||||
|
if let Some(packet) = pnet::packet::icmp::IcmpPacket::new(ip_packet.payload()){ |
||||||
|
if packet.get_icmp_type() == icmp_type { |
||||||
|
let ipv6_addr = ip_packet.get_source(); |
||||||
|
return Some(ipv6_addr.to_string()) |
||||||
|
}else{ |
||||||
|
None |
||||||
|
} |
||||||
|
}else{ |
||||||
|
None |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn get_mac_through_arp(dst_ip: Ipv4Addr) -> Option<String> { |
||||||
|
let default_idx = interface::get_default_interface_index().unwrap(); |
||||||
|
let interfaces = pnet::datalink::interfaces(); |
||||||
|
let interface = interfaces.into_iter().filter(|interface: &pnet::datalink::NetworkInterface| interface.index == default_idx).next().expect("Failed to get Interface"); |
||||||
|
let src_ip = interface.ips.iter().find(|ip| ip.is_ipv4()) |
||||||
|
.map(|ip| match ip.ip() { |
||||||
|
IpAddr::V4(ip) => ip, |
||||||
|
_ => unreachable!(), |
||||||
|
}) |
||||||
|
.unwrap(); |
||||||
|
let (mut sender, mut receiver) = match pnet::datalink::channel(&interface, Default::default()) { |
||||||
|
Ok(pnet::datalink::Channel::Ethernet(tx, rx)) => (tx, rx), |
||||||
|
Ok(_) => panic!("Unknown channel type"), |
||||||
|
Err(e) => panic!("Error happened {}", e), |
||||||
|
}; |
||||||
|
|
||||||
|
let mut ethernet_buffer = [0u8; 42]; |
||||||
|
let mut ethernet_packet = pnet::packet::ethernet::MutableEthernetPacket::new(&mut ethernet_buffer).unwrap(); |
||||||
|
|
||||||
|
ethernet_packet.set_destination(pnet::datalink::MacAddr::broadcast()); |
||||||
|
ethernet_packet.set_source(interface.mac.unwrap()); |
||||||
|
ethernet_packet.set_ethertype(pnet::packet::ethernet::EtherTypes::Arp); |
||||||
|
|
||||||
|
let mut arp_buffer = [0u8; 28]; |
||||||
|
let mut arp_packet = pnet::packet::arp::MutableArpPacket::new(&mut arp_buffer).unwrap(); |
||||||
|
|
||||||
|
arp_packet.set_hardware_type(pnet::packet::arp::ArpHardwareTypes::Ethernet); |
||||||
|
arp_packet.set_protocol_type(pnet::packet::ethernet::EtherTypes::Ipv4); |
||||||
|
arp_packet.set_hw_addr_len(6); |
||||||
|
arp_packet.set_proto_addr_len(4); |
||||||
|
arp_packet.set_operation(pnet::packet::arp::ArpOperations::Request); |
||||||
|
arp_packet.set_sender_hw_addr(interface.mac.unwrap()); |
||||||
|
arp_packet.set_sender_proto_addr(src_ip); |
||||||
|
arp_packet.set_target_hw_addr(pnet::datalink::MacAddr::zero()); |
||||||
|
arp_packet.set_target_proto_addr(dst_ip); |
||||||
|
|
||||||
|
ethernet_packet.set_payload(arp_packet.packet_mut()); |
||||||
|
|
||||||
|
sender.send_to(ethernet_packet.packet(), None).unwrap().unwrap(); |
||||||
|
|
||||||
|
let mut target_mac_addr: pnet::datalink::MacAddr = pnet::datalink::MacAddr::zero(); |
||||||
|
|
||||||
|
for _x in 0..2 { |
||||||
|
let buf = receiver.next().unwrap(); |
||||||
|
let arp = pnet::packet::arp::ArpPacket::new(&buf[pnet::packet::ethernet::MutableEthernetPacket::minimum_packet_size()..]).unwrap(); |
||||||
|
if arp.get_sender_hw_addr() != interface.mac.unwrap() { |
||||||
|
target_mac_addr = arp.get_sender_hw_addr(); |
||||||
|
} |
||||||
|
} |
||||||
|
if target_mac_addr == pnet::datalink::MacAddr::zero() { |
||||||
|
return None; |
||||||
|
}else{ |
||||||
|
return Some(target_mac_addr.to_string()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,106 @@ |
|||||||
|
use std::net::UdpSocket; |
||||||
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; |
||||||
|
use pnet::datalink; |
||||||
|
use crate::gateway; |
||||||
|
|
||||||
|
pub struct Interface { |
||||||
|
pub index: u32, |
||||||
|
pub name: String, |
||||||
|
pub mac: Option<String>, |
||||||
|
pub ipv4: Vec<Ipv4Addr>, |
||||||
|
pub ipv6: Vec<Ipv6Addr>, |
||||||
|
pub gateway: gateway::Gateway, |
||||||
|
} |
||||||
|
|
||||||
|
fn get_local_ipaddr() -> Option<String> { |
||||||
|
let socket = match UdpSocket::bind("0.0.0.0:0") { |
||||||
|
Ok(s) => s, |
||||||
|
Err(_) => return None, |
||||||
|
}; |
||||||
|
|
||||||
|
match socket.connect("8.8.8.8:80") { |
||||||
|
Ok(()) => (), |
||||||
|
Err(_) => return None, |
||||||
|
}; |
||||||
|
|
||||||
|
match socket.local_addr() { |
||||||
|
Ok(addr) => return Some(addr.ip().to_string()), |
||||||
|
Err(_) => return None, |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get_default_interface()-> Option<Interface> { |
||||||
|
let local_ip = get_local_ipaddr(); |
||||||
|
let all_interfaces = datalink::interfaces(); |
||||||
|
if let Some(local_ip) = local_ip { |
||||||
|
for iface in all_interfaces{ |
||||||
|
for ip in &iface.ips{ |
||||||
|
if local_ip == ip.ip().to_string() { |
||||||
|
let mac_addr: Option<String> = match iface.mac { |
||||||
|
Some(mac_addr) => Some(mac_addr.to_string()), |
||||||
|
None => None, |
||||||
|
}; |
||||||
|
let mut ipv4_vec: Vec<Ipv4Addr> = vec![]; |
||||||
|
let mut ipv6_vec: Vec<Ipv6Addr> = vec![]; |
||||||
|
for ip in &iface.ips { |
||||||
|
match ip.ip() { |
||||||
|
IpAddr::V4(ipv4_addr) => { |
||||||
|
ipv4_vec.push(ipv4_addr); |
||||||
|
}, |
||||||
|
IpAddr::V6(ipv6_addr) => { |
||||||
|
ipv6_vec.push(ipv6_addr); |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
let default_gateway = gateway::get_default_gateway(); |
||||||
|
let interface: Interface = Interface{ |
||||||
|
index: iface.index, |
||||||
|
name: iface.name, |
||||||
|
mac: mac_addr, |
||||||
|
ipv4: ipv4_vec, |
||||||
|
ipv6: ipv6_vec, |
||||||
|
gateway: default_gateway, |
||||||
|
}; |
||||||
|
return Some(interface); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return None; |
||||||
|
}else{ |
||||||
|
return None; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get_default_interface_index() -> Option<u32> { |
||||||
|
let local_ip = get_local_ipaddr(); |
||||||
|
let all_interfaces = datalink::interfaces(); |
||||||
|
if let Some(local_ip) = local_ip { |
||||||
|
for iface in all_interfaces{ |
||||||
|
for ip in iface.ips{ |
||||||
|
if local_ip == ip.ip().to_string() { |
||||||
|
return Some(iface.index) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return None; |
||||||
|
}else{ |
||||||
|
return None; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get_default_interface_name() -> Option<String> { |
||||||
|
let local_ip = get_local_ipaddr(); |
||||||
|
let all_interfaces = datalink::interfaces(); |
||||||
|
if let Some(local_ip) = local_ip { |
||||||
|
for iface in all_interfaces{ |
||||||
|
for ip in iface.ips{ |
||||||
|
if local_ip == ip.ip().to_string() { |
||||||
|
return Some(iface.name) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return None; |
||||||
|
}else{ |
||||||
|
return None; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue