Add Interface and Gateway

main
shellrow 4 years ago
parent e9c39c30db
commit ecae4273e4
  1. 8
      examples/default_gateway.rs
  2. 15
      examples/default_interface.rs
  3. 301
      src/gateway.rs
  4. 106
      src/interface.rs
  5. 259
      src/lib.rs

@ -1,8 +1,8 @@
use default_net;
fn main(){
match default_net::get_default_gateway() {
Ok(default_gateway) => {println!("Default Gateway: {}",default_gateway)},
Err(e) => {println!("{}",e)},
}
let default_gateway = default_net::get_default_gateway();
println!("Default Gateway");
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;
}
}

@ -1,250 +1,15 @@
use std::net::UdpSocket;
use std::time::{Duration, Instant};
use std::net::IpAddr;
use pnet::datalink;
#[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::packet::Packet;
pub fn get_default_gateway() -> 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 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))]
pub 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 = 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
}
}
pub 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_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{
match ip.ip() {
IpAddr::V4(ipv4) => {
if local_ip == ipv4.to_string() {
return Some(iface.index)
}
},
IpAddr::V6(ipv6) => {
if local_ip == ipv6.to_string() {
return Some(iface.index)
}
},
}
}
}
return None;
}else{
return None;
}
}
mod interface;
mod gateway;
pub use interface::Interface;
pub use interface::get_default_interface;
pub use interface::get_default_interface_index;
pub use interface::get_default_interface_name;
pub use gateway::Gateway;
pub use gateway::get_default_gateway;
pub use gateway::get_default_gateway_ip;
pub use gateway::get_default_gateway_mac;
#[cfg(test)]
mod tests {

Loading…
Cancel
Save