mod exported_pdu;
mod pcap_nflog;
pub use crate::data::exported_pdu::*;
pub use crate::data::pcap_nflog::*;
use crate::linktype::Linktype;
use crate::read_u32_e;
use nom::number::complete::be_u32;
use nom::number::streaming::{be_u16, be_u64, be_u8};
use nom::IResult;
pub const ETHERTYPE_IPV4: u16 = 0x0800;
pub const ETHERTYPE_IPV6: u16 = 0x86dd;
#[derive(Clone, Debug)]
pub enum PacketData<'a> {
L2(&'a [u8]),
L3(u16, &'a [u8]),
L4(u8, &'a [u8]),
Unsupported(&'a [u8]),
}
pub fn get_packetdata_null(i: &[u8], caplen: usize) -> Option<PacketData<'_>> {
if i.len() < caplen || caplen < 4 {
None
} else {
let vers = read_u32_e!(i, false);
let ethertype = match vers {
2 => ETHERTYPE_IPV4,
24 | 28 | 30 => ETHERTYPE_IPV6,
_ => 0,
};
Some(PacketData::L3(ethertype, &i[4..caplen]))
}
}
pub fn get_packetdata_ethernet(i: &[u8], caplen: usize) -> Option<PacketData<'_>> {
if i.len() < caplen || caplen == 0 {
None
} else {
Some(PacketData::L2(&i[..caplen]))
}
}
pub fn get_packetdata_raw(i: &[u8], caplen: usize) -> Option<PacketData<'_>> {
if i.len() < caplen || caplen == 0 {
None
} else {
let vers = i[0] >> 4;
let ethertype = match vers {
4 => ETHERTYPE_IPV4,
6 => ETHERTYPE_IPV6,
_ => 0,
};
Some(PacketData::L3(ethertype, &i[..caplen]))
}
}
pub fn get_packetdata_linux_sll(i: &[u8], caplen: usize) -> Option<PacketData<'_>> {
if i.len() < caplen || caplen == 0 {
None
} else {
match parse_sll_header(i) {
Err(_) => None,
Ok((rem, sll)) => {
match sll.arphrd_type {
778 => Some(PacketData::L4(47, rem)),
803 |
824 => None,
_ => Some(PacketData::L3(sll.proto, rem)),
}
}
}
}
}
struct SLLHeader {
_packet_type: u16,
arphrd_type: u16,
_ll_addr_len: u16,
_ll_addr: u64,
proto: u16,
}
fn parse_sll_header(i: &[u8]) -> IResult<&[u8], SLLHeader> {
let (i, _packet_type) = be_u16(i)?;
let (i, arphrd_type) = be_u16(i)?;
let (i, _ll_addr_len) = be_u16(i)?;
let (i, _ll_addr) = be_u64(i)?;
let (i, proto) = be_u16(i)?;
let header = SLLHeader {
_packet_type,
arphrd_type,
_ll_addr_len,
_ll_addr,
proto,
};
Ok((i, header))
}
pub fn get_packetdata_linux_sll2(i: &[u8], caplen: usize) -> Option<PacketData<'_>> {
if i.len() < caplen || caplen == 0 {
None
} else {
match parse_sll2_header(i) {
Err(_) => None,
Ok((rem, sll)) => {
match sll.arphrd_type {
778 => Some(PacketData::L4(47, rem)),
803 |
824 => None,
_ => Some(PacketData::L3(sll.protocol_type, rem)),
}
}
}
}
}
struct SLL2Header {
protocol_type: u16,
_reserved: u16,
_interface_index: u32,
arphrd_type: u16,
_packet_type: u8,
_ll_addr_len: u8,
_ll_addr: u64,
}
fn parse_sll2_header(i: &[u8]) -> IResult<&[u8], SLL2Header> {
let (i, protocol_type) = be_u16(i)?;
let (i, _reserved) = be_u16(i)?;
let (i, _interface_index) = be_u32(i)?;
let (i, arphrd_type) = be_u16(i)?;
let (i, _packet_type) = be_u8(i)?;
let (i, _ll_addr_len) = be_u8(i)?;
let (i, _ll_addr) = be_u64(i)?;
let header = SLL2Header {
protocol_type,
_reserved,
_interface_index,
arphrd_type,
_packet_type,
_ll_addr_len,
_ll_addr,
};
Ok((i, header))
}
pub fn get_packetdata_ipv4(i: &[u8], _caplen: usize) -> Option<PacketData<'_>> {
Some(PacketData::L3(ETHERTYPE_IPV4, i))
}
pub fn get_packetdata_ipv6(i: &[u8], _caplen: usize) -> Option<PacketData<'_>> {
Some(PacketData::L3(ETHERTYPE_IPV6, i))
}
pub fn get_packetdata(i: &[u8], linktype: Linktype, caplen: usize) -> Option<PacketData<'_>> {
match linktype {
Linktype::NULL => get_packetdata_null(i, caplen),
Linktype::ETHERNET => get_packetdata_ethernet(i, caplen),
Linktype::RAW => get_packetdata_raw(i, caplen),
Linktype::LINUX_SLL => get_packetdata_linux_sll(i, caplen),
Linktype::LINUX_SLL2 => get_packetdata_linux_sll2(i, caplen),
Linktype::IPV4 => get_packetdata_ipv4(i, caplen),
Linktype::IPV6 => get_packetdata_ipv6(i, caplen),
Linktype::NFLOG => get_packetdata_nflog(i, caplen),
Linktype::WIRESHARK_UPPER_PDU => get_packetdata_wireshark_upper_pdu(i, caplen),
_ => Some(PacketData::Unsupported(i)),
}
}