use crate::data::{PacketData, ETHERTYPE_IPV4, ETHERTYPE_IPV6};
use nom::number::streaming::{be_u16, le_u16, le_u8};
use nom::{complete, cond, do_parse, many0, named, take};
#[derive(Copy, Clone)]
#[repr(u16)]
pub enum NfAttrType {
PacketHdr = 1,
Mark = 2,
Timestamp = 3,
IfIndexInDev = 4,
IfIndexOutDev = 5,
IfIndexPhysInDev = 6,
IfIndexPhysOutDev = 7,
HwAddr = 8,
Payload = 9,
Prefix = 10,
Uid = 11,
Seq = 12,
SeqGlobal = 13,
Gid = 14,
HwType = 15,
HwHeader = 16,
HwLen = 17,
Ct = 18,
CtInfo = 19,
}
#[derive(Debug)]
pub struct NflogTlv<'a> {
pub l: u16,
pub t: u16,
pub v: &'a [u8],
}
named! {
pub parse_nflog_tlv<NflogTlv>,
do_parse!(
l: le_u16 >>
t: le_u16 >>
v: take!(l-4) >>
_padding: cond!(l % 4 != 0,take!(4-(l%4))) >>
( NflogTlv{l,t,v} )
)
}
#[derive(Debug)]
pub struct NflogHdr {
pub af: u8,
pub vers: u8,
pub res_id: u16,
}
#[derive(Debug)]
pub struct NflogPacket<'a> {
pub header: NflogHdr,
pub data: Vec<NflogTlv<'a>>,
}
named! {
pub parse_nflog_header<NflogHdr>,
do_parse!(
af: le_u8 >>
v: le_u8 >>
id: be_u16 >>
(
NflogHdr{
af,
vers: v,
res_id: id,
}
)
)
}
impl<'a> NflogPacket<'a> {
pub fn get(&self, attr: NfAttrType) -> Option<&NflogTlv> {
self.data.iter().find(|v| v.t == attr as u16)
}
pub fn get_payload(&self) -> Option<&[u8]> {
self.get(NfAttrType::Payload).map(|tlv| tlv.v)
}
}
named! {
pub parse_nflog<NflogPacket>,
do_parse!(
header: parse_nflog_header >>
data: many0!(complete!(parse_nflog_tlv)) >>
(
NflogPacket{ header, data }
)
)
}
pub fn get_packetdata_nflog(i: &[u8], _caplen: usize) -> Option<PacketData> {
match parse_nflog(i) {
Ok((_, res)) => {
let ethertype = match res.header.af {
2 => ETHERTYPE_IPV4,
10 => ETHERTYPE_IPV6,
_ => 0,
};
match res
.data
.into_iter()
.find(|v| v.t == NfAttrType::Payload as u16)
{
Some(v) => Some(PacketData::L3(ethertype, v.v)),
None => None,
}
}
_ => None,
}
}