fork of https://github.com/shellrow/default-net/tree/v0.16.2 fixes an unsafe bug in sockaddr_to_network_addr
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

126 lines
4.4 KiB

use crate::gateway::Gateway;
use crate::interface::MacAddr;
use std::convert::TryInto;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::u16;
pub const ETHER_TYPE_IPV4: [u8; 2] = [8, 0];
pub const ETHER_TYPE_IPV6: [u8; 2] = [134, 221];
pub const NEXT_HEADER_ICMP: u8 = 1;
pub const NEXT_HEADER_ICMPV6: u8 = 58;
pub const ICMP_TYPE_TIME_EXCEEDED: u8 = 11;
pub const ICMPV6_TYPE_TIME_EXCEEDED: u8 = 3;
#[allow(dead_code)]
pub enum Frame {
SrcMacAddr,
DstMacAddr,
EtherType,
SrcIpv4Addr,
DstIpv4Addr,
SrcIpv6Addr,
DstIpv6Addr,
NextHeaderProtocolIpv4,
NextHeaderProtocolIpv6,
IcmpType,
Icmpv6Type,
}
impl Frame {
fn start_index(&self) -> usize {
match *self {
Frame::SrcMacAddr => 6,
Frame::DstMacAddr => 0,
Frame::EtherType => 12,
Frame::SrcIpv4Addr => 26,
Frame::DstIpv4Addr => 30,
Frame::SrcIpv6Addr => 22,
Frame::DstIpv6Addr => 38,
Frame::NextHeaderProtocolIpv4 => 23,
Frame::NextHeaderProtocolIpv6 => 20,
Frame::IcmpType => 34,
Frame::Icmpv6Type => 54,
}
}
fn end_index(&self) -> usize {
match *self {
Frame::SrcMacAddr => 12,
Frame::DstMacAddr => 6,
Frame::EtherType => 14,
Frame::SrcIpv4Addr => 30,
Frame::DstIpv4Addr => 34,
Frame::SrcIpv6Addr => 38,
Frame::DstIpv6Addr => 54,
Frame::NextHeaderProtocolIpv4 => 24,
Frame::NextHeaderProtocolIpv6 => 21,
Frame::IcmpType => 35,
Frame::Icmpv6Type => 55,
}
}
}
fn convert_ipv4_bytes(bytes: [u8; 4]) -> Ipv4Addr {
Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3])
}
fn convert_ipv6_bytes(bytes: [u8; 16]) -> Ipv6Addr {
let h1: u16 = ((bytes[0] as u16) << 8) | bytes[1] as u16;
let h2: u16 = ((bytes[2] as u16) << 8) | bytes[3] as u16;
let h3: u16 = ((bytes[4] as u16) << 8) | bytes[5] as u16;
let h4: u16 = ((bytes[6] as u16) << 8) | bytes[7] as u16;
let h5: u16 = ((bytes[8] as u16) << 8) | bytes[9] as u16;
let h6: u16 = ((bytes[10] as u16) << 8) | bytes[11] as u16;
let h7: u16 = ((bytes[12] as u16) << 8) | bytes[13] as u16;
let h8: u16 = ((bytes[14] as u16) << 8) | bytes[15] as u16;
Ipv6Addr::new(h1, h2, h3, h4, h5, h6, h7, h8)
}
pub fn parse_frame(frame: &[u8]) -> Result<Gateway, ()> {
let src_mac: [u8; 6] = frame[Frame::SrcMacAddr.start_index()..Frame::SrcMacAddr.end_index()]
.try_into()
.unwrap();
let ether_type: [u8; 2] = frame[Frame::EtherType.start_index()..Frame::EtherType.end_index()]
.try_into()
.unwrap();
match ether_type {
ETHER_TYPE_IPV4 => {
let src_ip: [u8; 4] = frame
[Frame::SrcIpv4Addr.start_index()..Frame::SrcIpv4Addr.end_index()]
.try_into()
.unwrap();
let next_header_protocol: u8 = frame[Frame::NextHeaderProtocolIpv4.start_index()];
if next_header_protocol == NEXT_HEADER_ICMP {
let icmp_type: u8 = frame[Frame::IcmpType.start_index()];
if icmp_type == ICMP_TYPE_TIME_EXCEEDED {
let gateway = Gateway {
mac_addr: MacAddr::new(src_mac),
ip_addr: IpAddr::V4(convert_ipv4_bytes(src_ip)),
};
return Ok(gateway);
}
}
}
ETHER_TYPE_IPV6 => {
let src_ip: [u8; 16] = frame
[Frame::SrcIpv6Addr.start_index()..Frame::SrcIpv6Addr.end_index()]
.try_into()
.unwrap();
let next_header_protocol: u8 = frame[Frame::NextHeaderProtocolIpv6.start_index()];
if next_header_protocol == NEXT_HEADER_ICMPV6 {
let icmp_type: u8 = frame[Frame::Icmpv6Type.start_index()];
if icmp_type == ICMPV6_TYPE_TIME_EXCEEDED {
let icmp_type: u8 = frame[Frame::Icmpv6Type.start_index()];
if icmp_type == ICMPV6_TYPE_TIME_EXCEEDED {
let gateway = Gateway {
mac_addr: MacAddr::new(src_mac),
ip_addr: IpAddr::V6(convert_ipv6_bytes(src_ip)),
};
return Ok(gateway);
}
}
}
}
_ => {}
}
Err(())
}