Skip to content

Commit

Permalink
Create inverse map from layer name to EtherType
Browse files Browse the repository at this point in the history
This will be used when sculpting to select an EtherType based on the
upcoming layer.

Signed-off-by: Mohammad Aadil Shabier <aadilshabier1@gmail.com>
  • Loading branch information
aadilshabier committed Jul 13, 2024
1 parent 8111765 commit 75c636c
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 40 deletions.
4 changes: 3 additions & 1 deletion src/layers/arp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ pub const ARP_HEADER_LENGTH: usize = 28_usize;

// Register outselves with Ethernet layer
pub(crate) fn register_defaults() -> Result<(), Error> {
ethernet::register_ethertype(ETHERTYPE_ARP, ARP::creator)
let name = ARP::default().name();
ethernet::register_ethertype(ETHERTYPE_ARP, name, ARP::creator)?;
Ok(())
}

/// Structure representing a dissected ARP protocol payload.
Expand Down
65 changes: 42 additions & 23 deletions src/layers/ethernet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,23 @@ use crate::{Layer, Packet, ENCAP_TYPE_ETH};

pub const ETH_HEADER_LENGTH: usize = 14_usize;

/// A Map maintaining EtherType -> Creator fns for Layer Creators of L3 Layers.
///
/// The creator function simply creates a `default` L3 struct that implements the dissector
/// for the Layer.
pub fn get_ethertypes_map() -> &'static RwLock<HashMap<EtherType, LayerCreatorFn>> {
/// A Map maintaining EtherType -> Creator fns for Layer Creators of L3 Layers.
///
/// The creator function simply creates a `default` L3 struct that implements the dissector
/// for the Layer.
pub(crate) static ETHERTYPES_MAP: OnceLock<RwLock<HashMap<EtherType, LayerCreatorFn>>> =
OnceLock::new();
static ETHERTYPES_MAP: OnceLock<RwLock<HashMap<EtherType, LayerCreatorFn>>> = OnceLock::new();
ETHERTYPES_MAP.get_or_init(|| RwLock::new(HashMap::new()))
}

/// A Map maintaining String -> EtherType of L3 Layers.
pub fn get_inv_ethertypes_map() -> &'static RwLock<HashMap<String, EtherType>> {
static INV_ETHERTYPES_MAP: OnceLock<RwLock<HashMap<String, EtherType>>> = OnceLock::new();
INV_ETHERTYPES_MAP.get_or_init(|| RwLock::new(HashMap::new()))
}

// Register our Encap Types with the Packet.
pub(crate) fn register_defaults() -> Result<(), Error> {
get_ethertypes_map();

Packet::register_encap_type(ENCAP_TYPE_ETH, Ethernet::creator)
}

Expand All @@ -36,12 +39,29 @@ pub(crate) fn register_defaults() -> Result<(), Error> {
/// A Layer that would handle subsequent decoding for a given Ethertype, should register itself
/// by calling this function. For example [`crate::layers::ipv4`] would call `register_ethertype`
/// with [`EtherType`] value of 0x0800, passing the creator function for that layer.
pub fn register_ethertype(eth_type: EtherType, layer: LayerCreatorFn) -> Result<(), Error> {
let mut map = get_ethertypes_map().write().unwrap();
if map.contains_key(&eth_type) {
return Err(Error::RegisterError(format!("ether_type: {}", eth_type)));
pub fn register_ethertype(
eth_type: EtherType,
name: &str,
layer: LayerCreatorFn,
) -> Result<(), Error> {
{
let mut map = get_ethertypes_map().write().unwrap();
if map.contains_key(&eth_type) {
return Err(Error::RegisterError(format!("ether_type: {}", eth_type)));
}
map.insert(eth_type, layer);
}

{
let mut inv_map = get_inv_ethertypes_map().write().unwrap();
if inv_map.contains_key(name) {
return Err(Error::RegisterError(format!(
"Cannot find EtherType for : {}",
name
)));
}
inv_map.insert(name.to_string(), eth_type);
}
map.insert(eth_type, layer);

Ok(())
}
Expand Down Expand Up @@ -103,16 +123,15 @@ impl Layer for Ethernet {
result.extend(self.dst_mac.as_slice());
result.extend(self.src_mac.as_slice());

let ethertype: u16 = match info {
"ARP" => crate::types::ETHERTYPE_ARP,
"IPv4" => crate::types::ETHERTYPE_IP,
"IPv6" => crate::types::ETHERTYPE_IP6,
// FIXME: can also be `ETHERTYPE_MPLS_MULTICAST`
"MPLS" => crate::types::ETHERTYPE_MPLS_UNICAST,
"raw" => 0xffff,
// NOTE: should return Err instead
_ => unimplemented!(),
};
let ethertype = get_inv_ethertypes_map()
.read()
.unwrap()
.get(info)
.copied()
.unwrap_or_else(|| match info {
"raw" => crate::types::ETHERTYPE_RAW,
_ => todo!("Return Err here instead"),
});

result.extend(ethertype.to_be_bytes());
result.extend(next_layer.unwrap_or_default());
Expand Down
13 changes: 5 additions & 8 deletions src/layers/ipv4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,8 @@ fn get_protocol_map() -> &'static RwLock<HashMap<u8, LayerCreatorFn>> {
// Right now only Ethernet is Supported
pub(crate) fn register_defaults() -> Result<(), Error> {
use crate::layers::ethernet::register_ethertype;

get_protocol_map();

register_ethertype(crate::types::ETHERTYPE_IP, IPv4::creator)?;

let name = IPv4::default().name();
register_ethertype(crate::types::ETHERTYPE_IP, name, IPv4::creator)?;
Ok(())
}

Expand Down Expand Up @@ -263,8 +260,8 @@ impl IPv4 {
// 16 bit one's complement of one's complement sum of all 16 bit words
let len = bytes.len();
let mut csum = 0_u32;
for i in 0..len/2 {
let word = u16::from_be_bytes(bytes[2*i..2*(i+1)].try_into().unwrap());
for i in 0..len / 2 {
let word = u16::from_be_bytes(bytes[2 * i..2 * (i + 1)].try_into().unwrap());
csum += word as u32;
}
csum = ((csum >> 16) + (csum & 0xffff)) as u32;
Expand Down Expand Up @@ -373,7 +370,7 @@ impl Layer for IPv4 {

let checksum = IPv4::calculate_checksum(&result);
result[checksum_start..checksum_start + 2].copy_from_slice(&checksum.to_be_bytes());

result.extend(next_layer.unwrap_or_default());

Ok(result)
Expand Down
7 changes: 3 additions & 4 deletions src/layers/ipv6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use core::convert::TryInto;

use std::collections::HashMap;
use std::sync::{RwLock,OnceLock};
use std::sync::{OnceLock, RwLock};

use serde::Serialize;

Expand All @@ -14,7 +14,6 @@ use crate::Layer;
/// Basic Length of the IPv6 Header
pub const IPV6_BASE_HEADER_LENGTH: usize = 40_usize;


fn get_next_headers_map() -> &'static RwLock<HashMap<u8, LayerCreatorFn>> {
static NEXT_HEADERS_MAP: OnceLock<RwLock<HashMap<u8, LayerCreatorFn>>> = OnceLock::new();
NEXT_HEADERS_MAP.get_or_init(|| RwLock::new(HashMap::new()))
Expand All @@ -26,8 +25,8 @@ fn get_next_headers_map() -> &'static RwLock<HashMap<u8, LayerCreatorFn>> {
pub(crate) fn register_defaults() -> Result<(), Error> {
use crate::layers::ethernet::register_ethertype;

get_next_headers_map();
register_ethertype(crate::types::ETHERTYPE_IP6, IPv6::creator)?;
let name = IPv6::default().name();
register_ethertype(crate::types::ETHERTYPE_IP6, name, IPv6::creator)?;

Ok(())
}
Expand Down
6 changes: 4 additions & 2 deletions src/layers/mpls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ pub const MPLS_HEADER_LENGTH: usize = 4_usize;

// Register Ourselves to the Ethernet layer, as this is a 2.5 layer protocol
pub(crate) fn register_defaults() -> Result<(), Error> {
ethernet::register_ethertype(ETHERTYPE_MPLS_UNICAST, MPLS::creator)?;
ethernet::register_ethertype(ETHERTYPE_MPLS_MULTICAST, MPLS::creator)
let name = MPLS::default().name();
ethernet::register_ethertype(ETHERTYPE_MPLS_UNICAST, name, MPLS::creator)?;
ethernet::register_ethertype(ETHERTYPE_MPLS_MULTICAST, "[UNKNOWN]", MPLS::creator)?;
Ok(())
}

#[derive(Debug, Default, Serialize, Copy, Clone)]
Expand Down
3 changes: 1 addition & 2 deletions src/layers/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use core::convert::TryInto;

use std::collections::HashMap;
use std::sync::{RwLock,OnceLock};
use std::sync::{OnceLock, RwLock};

use serde::Serialize;

Expand All @@ -12,7 +12,6 @@ use crate::Layer;

use crate::layers::{ipv4, ipv6};


fn get_tcp_apps_map() -> &'static RwLock<HashMap<u16, LayerCreatorFn>> {
static TCP_APPS_MAP: OnceLock<RwLock<HashMap<u16, LayerCreatorFn>>> = OnceLock::new();
TCP_APPS_MAP.get_or_init(|| RwLock::new(HashMap::new()))
Expand Down
1 change: 1 addition & 0 deletions src/types/ethertype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ pub static ETHERTYPE_IP6: EtherType = 0x86dd_u16;
pub static ETHERTYPE_ARP: EtherType = 0x0806_u16;
pub static ETHERTYPE_MPLS_UNICAST: EtherType = 0x8847_u16;
pub static ETHERTYPE_MPLS_MULTICAST: EtherType = 0x8848_u16;
pub static ETHERTYPE_RAW: EtherType = 0xffff_u16;

0 comments on commit 75c636c

Please sign in to comment.