Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 = Some(ARP::default().name());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use short_name (short_name is convenient and usually all lowercase)

ethernet::register_ethertype(ETHERTYPE_ARP, name, ARP::creator)?;
Ok(())
}

/// Structure representing a dissected ARP protocol payload.
Expand Down
70 changes: 45 additions & 25 deletions src/layers/ethernet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,55 @@ 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.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add more description for the map as a documentation. If we simply read this documentation it is not clear why this map exists and how it is to be used. For example something like this.

/// This map will be used during sculpting a packet. For example for IPv4 you the entry
/// in the map will look like `ip -> 0x0800`

pub fn get_inv_ethertypes_map() -> &'static RwLock<HashMap<String, EtherType>> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be this function is gated by cfg(packet_sculpting) ? Because this map and API is not used outside sculpting.

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)
}

/// Register for a given EtherType
///
/// 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)));
/// by calling this function. An optional name value can be provided to be used during packet creation.
/// For example [`crate::layers::ipv4`] would call `register_ethertype` with [`EtherType`]
/// value of 0x0800, and a name value of "IPv4" passing the creator function for that layer.
pub fn register_ethertype(
eth_type: EtherType,
name: Option<&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);
}

if let Some(name) = name {
let mut inv_map = get_inv_ethertypes_map().write().unwrap();
if inv_map.contains_key(name) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if inv_map.contains_key(&name.to_lowercase())

return Err(Error::RegisterError(format!(
"Cannot find EtherType for : {}",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error should be Already Exists and not cannot find. Also Better to let the user know what value exists in the inv_ map. So may be get and check for Some value?

name
)));
}
inv_map.insert(name.to_string(), eth_type);
}
map.insert(eth_type, layer);

Ok(())
}
Expand Down Expand Up @@ -103,16 +124,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
38 changes: 25 additions & 13 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 = Some(IPv4::default().name());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

short_name as above in ARP.

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

Expand Down Expand Up @@ -85,7 +82,10 @@ pub enum IPOption {
pub struct IPv4 {
version: u8,
hdr_len: u8,
tos: u8,
#[serde(serialize_with = "crate::types::hex::serialize_lower_hex_u8")]
dscp: u8,
#[serde(serialize_with = "crate::types::hex::serialize_lower_hex_u8")]
ecn: u8,
len: u16,
#[serde(serialize_with = "crate::types::hex::serialize_lower_hex_u16")]
id: u16,
Expand Down Expand Up @@ -256,8 +256,16 @@ impl IPv4 {
}

#[cfg(feature = "sculpting")]
fn calculate_checksum(_bytes: &[u8]) -> u16 {
0
fn calculate_checksum(bytes: &[u8]) -> u16 {
// 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());
csum += word as u32;
}
csum = ((csum >> 16) + (csum & 0xffff)) as u32;
(!csum & 0xffff) as u16
}
}

Expand All @@ -279,7 +287,8 @@ impl Layer for IPv4 {
data: hex::encode(bytes),
});
}
self.tos = bytes[1];
self.dscp = bytes[1] >> 2;
self.ecn = bytes[1] & 0b11;
self.len = u16::from_be_bytes(bytes[2..4].try_into().unwrap());
self.id = u16::from_be_bytes(bytes[4..6].try_into().unwrap());
let flags_offset = u16::from_be_bytes(bytes[6..8].try_into().unwrap());
Expand Down Expand Up @@ -337,9 +346,11 @@ impl Layer for IPv4 {

let mut result = Vec::with_capacity(self.len as usize);

let byte = (self.version << 4) | self.hdr_len;
let mut byte = (self.version << 4) | self.hdr_len;
result.push(byte);

byte = (self.dscp << 2) | self.ecn;
result.push(byte);
result.push(self.tos);
result.extend(self.len.to_be_bytes());
result.extend(self.id.to_be_bytes());

Expand All @@ -357,10 +368,11 @@ impl Layer for IPv4 {
todo!();
}

result.extend(next_layer.unwrap_or_default());

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 = Some(IPv6::default().name());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

short_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 = Some(MPLS::default().name());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

short_name

ethernet::register_ethertype(ETHERTYPE_MPLS_UNICAST, name, MPLS::creator)?;
ethernet::register_ethertype(ETHERTYPE_MPLS_MULTICAST, None, 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
3 changes: 2 additions & 1 deletion src/types/ethertype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
pub type EtherType = u16;

pub static ETHERTYPE_IP: EtherType = 0x0800_u16;
pub static ETHERTYPE_IP6: EtherType = 0x86dd_u16;
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;