diff --git a/Cargo.toml b/Cargo.toml index ca8a330..6bd13cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pcapng" -version = "0.0.4" +version = "0.0.5" authors = ["Richo Healey "] repository = "https://github.com/richo/pcapng-rs" @@ -9,4 +9,4 @@ license = "MIT" documentation = "http://richo.psych0tik.net/pcapng-rs/pcapng/" [dependencies] -nom = "^3.0" +nom = "^4.0" diff --git a/examples/producer_errors.rs b/examples/producer_errors.rs deleted file mode 100644 index c5ad8f0..0000000 --- a/examples/producer_errors.rs +++ /dev/null @@ -1,29 +0,0 @@ -#[macro_use] -extern crate nom; -extern crate pcapng; - -use std::env; -use nom::{IResult,FileProducer,Producer,ConsumerState}; -use pcapng::block::parse_block; - -use std::fmt::Debug; -pub fn print_block(input: T) -> IResult { - println!("{:?}", input); - IResult::Done(input, ()) -} - -consumer_from_parser!(Printer<()>, - flat_map!(parse_block, print_block)); - -fn main() { - let args: Vec<_> = env::args().collect(); - if args.len() != 2 { - println!("Usage: {} ", args[0]); - return; - } - - let mut producer = FileProducer::new(&args[1][..], 64).unwrap(); - let mut consumer = Printer::new(); - while let &ConsumerState::Continue(_) = producer.apply(&mut consumer) { - } -} diff --git a/examples/read_pcapng.rs b/examples/read_pcapng.rs index e331b1b..90b578d 100644 --- a/examples/read_pcapng.rs +++ b/examples/read_pcapng.rs @@ -1,11 +1,9 @@ -#[macro_use] extern crate nom; extern crate pcapng; use std::env; use std::fs; use std::io::Read; -use nom::IResult; use pcapng::block::parse_blocks; fn main() { @@ -20,14 +18,15 @@ fn main() { let _ = fh.read_to_end(&mut buf); match parse_blocks(buf.as_slice()) { - IResult::Done(_, blocks) => { + Ok((_, blocks)) => { for i in blocks { - if let IResult::Done(_, blk) = i.parse() { + if let Ok((_, blk)) = i.parse() { println!("{:?}", blk); } } } - IResult::Error(e) => panic!("Error: {:?}", e), - IResult::Incomplete(i) => panic!("Incomplete: {:?}", i), + Err(nom::Err::Error(e)) => panic!("Error: {:?}", e), + Err(nom::Err::Incomplete(i)) => panic!("Incomplete: {:?}", i), + Err(nom::Err::Failure(f)) => panic!("Failure: {:?}", f), } } diff --git a/src/block.rs b/src/block.rs index 716c02f..16d2fc5 100644 --- a/src/block.rs +++ b/src/block.rs @@ -34,50 +34,46 @@ pub struct RawBlock<'a> { } impl<'a> RawBlock<'a> { - pub fn parse(self) -> IResult<&'a [u8], Block<'a>> { + pub fn parse(self) -> IResult<&'a [u8], Block<'a> > { match self.ty { blocks::section_header::TY => { match blocks::section_header::parse(self) { - IResult::Done(left, blk) => IResult::Done(left, Block::SectionHeader(blk)), - IResult::Error(e) => IResult::Error(e), - IResult::Incomplete(e) => IResult::Incomplete(e), + Ok((left, blk)) => Ok((left, Block::SectionHeader(blk))), + Err(e) => Err(e), } } blocks::enhanced_packet::TY => { match blocks::enhanced_packet::parse(self) { - IResult::Done(left, blk) => IResult::Done(left, Block::EnhancedPacket(blk)), - IResult::Error(e) => IResult::Error(e), - IResult::Incomplete(e) => IResult::Incomplete(e), + Ok((left, blk)) => Ok((left, Block::EnhancedPacket(blk))), + Err(e) => Err(e), } } blocks::interface_stats::TY => { match blocks::interface_stats::parse(self) { - IResult::Done(left, blk) => { - IResult::Done(left, Block::InterfaceStatistics(blk)) - } - IResult::Error(e) => IResult::Error(e), - IResult::Incomplete(e) => IResult::Incomplete(e), + Ok((left, blk)) => { + Ok((left, Block::InterfaceStatistics(blk))) + }, + Err(e) => Err(e), } } blocks::interface_description::TY => { match blocks::interface_description::parse(self) { - IResult::Done(left, blk) => { - IResult::Done(left, Block::InterfaceDescription(blk)) - } - IResult::Error(e) => IResult::Error(e), - IResult::Incomplete(e) => IResult::Incomplete(e), + Ok((left, blk)) => { + Ok((left, Block::InterfaceDescription(blk))) + }, + Err(e) => Err(e), } } - _ => IResult::Done(&self.body[0..0], Block::UnknownBlock(self)), + _ => Ok((&[], Block::UnknownBlock(self))), } } } -named!(pub parse_block< &[u8],RawBlock >, +named!(pub parse_block, do_parse!( ty: le_u32 >> block_length: le_u32 @@ -94,16 +90,20 @@ named!(pub parse_block< &[u8],RawBlock >, ) ); -named!(pub parse_blocks< &[u8],Vec >, - many1!(parse_block) +named!(pub parse_blocks >, + many1!(complete!(parse_block)) ); +#[cfg(test)] +mod tests { +use super::*; + #[test] fn test_parse_block() { let input = b"\n\r\r\n\x1c\x00\x00\x00M<+\x1a\x01\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x1c\x00\x00\x00"; match parse_block(input) { - IResult::Done(left, RawBlock { ty, block_length, body, check_length }) => { + Ok((left, RawBlock { ty, block_length, body, check_length })) => { // Ignored because we do not currently parse the whole block assert_eq!(left, b""); assert_eq!(ty, 0x0A0D0D0A); @@ -122,7 +122,7 @@ fn test_parse_blocks() { let input = b"\n\r\r\n\x1c\x00\x00\x00M<+\x1a\x01\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x1c\x00\x00\x00\ \n\r\r\n\x1c\x00\x00\x00M<+\x1a\x01\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x1c\x00\x00\x00"; match parse_blocks(input) { - IResult::Done(left, blocks) => { + Ok((left, blocks)) => { assert_eq!(blocks.len(), 2); for i in blocks { let RawBlock { ty, block_length, body, check_length } = i; @@ -134,7 +134,8 @@ fn test_parse_blocks() { assert_eq!(check_length, 28); } } - _ => { + err => { + println!("error: {:?}", err); assert_eq!(1, 2); } } @@ -144,7 +145,7 @@ fn test_parse_blocks() { fn test_parse_weird_length_block() { let input = b"\n\r\r\n\x1b\x00\x00\x00<+\x1a\x01\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x1b\x00\x00\x00"; match parse_block(input) { - IResult::Done(left, RawBlock { ty, block_length, body, check_length }) => { + Ok((left, RawBlock { ty, block_length, body, check_length })) => { // Ignored because we do not currently parse the whole block assert_eq!(left, b""); assert_eq!(ty, 0x0A0D0D0A); @@ -166,31 +167,34 @@ fn test_multiple_options() { \x6f\x77\x73\x20\x58\x50\x00\x00\x04\x00\x0c\x00\x54\x65\x73\x74\ \x30\x30\x34\x2e\x65\x78\x65\x00\x00\x00\x00\x00\x40\x00\x00\x00"; match parse_block(input) { - IResult::Done(left, block) => { + Ok((left, block)) => { assert_eq!(left, b""); - if let IResult::Done(_, Block::SectionHeader(blk)) = block.parse() { - if let Some(opts) = blk.options { - assert_eq!(opts.options.len(), 3); - - let o = &opts.options[0]; - assert_eq!(o.code, 0x03); - assert_eq!(o.length, 0x0b); - assert_eq!(&o.value[..], b"Windows XP\x00"); - - let o = &opts.options[1]; - assert_eq!(o.code, 0x04); - assert_eq!(o.length, 0x0c); - assert_eq!(&o.value[..], b"Test004.exe\x00"); - - let o = &opts.options[2]; - assert_eq!(o.code, 0x00); - assert_eq!(o.length, 0x00); - assert_eq!(&o.value[..], b""); - } else { - unreachable!(); + match block.parse() { + Ok((_, Block::SectionHeader(blk))) => { + if let Some(opts) = blk.options { + assert_eq!(opts.options.len(), 3); + + let o = &opts.options[0]; + assert_eq!(o.code, 0x03); + assert_eq!(o.length, 0x0b); + assert_eq!(&o.value[..], b"Windows XP\x00"); + + let o = &opts.options[1]; + assert_eq!(o.code, 0x04); + assert_eq!(o.length, 0x0c); + assert_eq!(&o.value[..], b"Test004.exe\x00"); + + let o = &opts.options[2]; + assert_eq!(o.code, 0x00); + assert_eq!(o.length, 0x00); + assert_eq!(&o.value[..], b""); + } else { + unreachable!(); + } + } , + err =>{ + panic!("error: {:?}", err); } - } else { - unreachable!(); } } _ => { @@ -198,3 +202,4 @@ fn test_multiple_options() { } } } +} diff --git a/src/blocks/enhanced_packet.rs b/src/blocks/enhanced_packet.rs index a01c622..a3c3bd7 100644 --- a/src/blocks/enhanced_packet.rs +++ b/src/blocks/enhanced_packet.rs @@ -34,7 +34,7 @@ pub const TY: u32 = 0x00000006; // | Block Total Length | // +---------------------------------------------------------------+ -named!(enhanced_packet_body<&[u8],EnhancedPacket>, +named!(enhanced_packet_body, do_parse!( interface_id: le_u32 >> timestamp_hi: le_u32 @@ -50,7 +50,7 @@ named!(enhanced_packet_body<&[u8],EnhancedPacket>, // Field to a 32-bit boundary >> data: take!(captured_len as usize) >> take!(util::pad_to_32bits(captured_len as usize)) - >> options: opt!(complete!(parse_options)) + >> options: opt!(parse_options) >> ( @@ -73,13 +73,12 @@ named!(enhanced_packet_body<&[u8],EnhancedPacket>, pub fn parse(blk: RawBlock) -> IResult<&[u8], EnhancedPacket> { match enhanced_packet_body(blk.body) { // FIXME(richo) actually do something with the leftover bytes - IResult::Done(left, mut block) => { + Ok((left, mut block)) => { block.block_length = blk.block_length; block.check_length = blk.check_length; - IResult::Done(left, block) - } - IResult::Error(e) => IResult::Error(e), - IResult::Incomplete(e) => IResult::Incomplete(e), + Ok((left, block)) + }, + other => other } } diff --git a/src/blocks/interface_description.rs b/src/blocks/interface_description.rs index 3eb209b..f9f96f6 100644 --- a/src/blocks/interface_description.rs +++ b/src/blocks/interface_description.rs @@ -22,12 +22,12 @@ pub const TY: u32 = 0x00000001; // | Block Total Length | // +---------------------------------------------------------------+ -named!(interface_description_body<&[u8],InterfaceDescription>, +named!(interface_description_body<&[u8], InterfaceDescription>, do_parse!( link_type: le_u16 >> reserved: le_u16 >> snap_len: le_u32 - >> options: opt!(complete!(parse_options)) + >> options: opt!(parse_options) >> ( InterfaceDescription { ty: TY, @@ -58,21 +58,18 @@ pub struct InterfaceDescription<'a> { pub fn parse(blk: RawBlock) -> IResult<&[u8], InterfaceDescription> { match interface_description_body(blk.body) { // FIXME(richo) Actually do something with the leftover bytes - IResult::Done(left, mut block) => { + Ok((left, mut block)) => { block.block_length = blk.block_length; block.check_length = blk.check_length; - IResult::Done(left, block) - } - IResult::Error(e) => IResult::Error(e), - IResult::Incomplete(e) => IResult::Incomplete(e), + Ok((left, block)) + }, + other => other } } #[cfg(test)] mod tests { - use nom::IResult; - use super::*; use block::parse_block; use blocks::constants::{BlockType, LinkType, LinkTypeOptions}; @@ -88,47 +85,54 @@ mod tests { \x00\x00\x00\x88\x00\x00\x00"; match parse_block(input) { - IResult::Done(_, block) => { - if let IResult::Done(left, interface_description_header) = parse(block) { - assert_eq!(left, b""); - assert_eq!(interface_description_header.ty, BlockType::InterfaceDescription as u32); - assert_eq!(interface_description_header.block_length, 136); - assert_eq!(interface_description_header.link_type, LinkType::ETHERNET as u16); - assert_eq!(interface_description_header.snap_len, 0x40000); - assert_eq!(interface_description_header.check_length, 136); - - if let Some(opts) = interface_description_header.options { - assert_eq!(opts.options.len(), 4); - - let o = &opts.options[0]; - assert_eq!(o.code, LinkTypeOptions::Name as u16); - assert_eq!(o.length, 0x32); - assert_eq!(o.value[..], b"\\Device\\NPF_{E4C14128-41F5-42C5-9A55-D6223B02C2B1}"[..]); - - let o = &opts.options[1]; - assert_eq!(o.code, LinkTypeOptions::TsResol as u16); - assert_eq!(o.length, 1); - assert_eq!(o.value[..], b"\x06"[..]); - - let o = &opts.options[2]; - assert_eq!(o.code, LinkTypeOptions::OS as u16); - assert_eq!(o.value[..], b"32-bit Windows 7 Service Pack 1, build 7601"[..]); - - } else { - panic!("expected options."); + Ok((_, block)) => { + match parse(block) { + Ok((left, interface_description_header)) => { + assert_eq!(left, []); + assert_eq!(interface_description_header.ty, BlockType::InterfaceDescription as u32); + assert_eq!(interface_description_header.block_length, 136); + assert_eq!(interface_description_header.link_type, LinkType::ETHERNET as u16); + assert_eq!(interface_description_header.snap_len, 0x40000); + assert_eq!(interface_description_header.check_length, 136); + + if let Some(opts) = interface_description_header.options { + assert_eq!(opts.options.len(), 4); + + let o = &opts.options[0]; + assert_eq!(o.code, LinkTypeOptions::Name as u16); + assert_eq!(o.length, 0x32); + assert_eq!(o.value[..], b"\\Device\\NPF_{E4C14128-41F5-42C5-9A55-D6223B02C2B1}"[..]); + + let o = &opts.options[1]; + assert_eq!(o.code, LinkTypeOptions::TsResol as u16); + assert_eq!(o.length, 1); + assert_eq!(o.value[..], b"\x06"[..]); + + let o = &opts.options[2]; + assert_eq!(o.code, LinkTypeOptions::OS as u16); + assert_eq!(o.value[..], b"32-bit Windows 7 Service Pack 1, build 7601"[..]); + + } else { + panic!("expected options."); + } + }, + err => { + panic!("failed to parse interface_description block: {:?}", err); } - } else { - panic!("failed to parse interface_description block"); } - } - IResult::Incomplete(e) => { + }, + Err(nom::Err::Incomplete(e)) => { println!("Incomplete: {:?}", e); assert!(false, "failed to parse interface_description header"); } - IResult::Error(e) => { + Err(nom::Err::Error(e)) => { println!("Error: {:?}", e); assert!(false, "failed to parse interface_description header"); } + Err(nom::Err::Failure(f)) => { + println!("Failure: {:?}", f); + assert!(false, "failed to parse interface_description header"); + } } } } diff --git a/src/blocks/interface_stats.rs b/src/blocks/interface_stats.rs index e65e7f9..a05604f 100644 --- a/src/blocks/interface_stats.rs +++ b/src/blocks/interface_stats.rs @@ -30,7 +30,7 @@ named!(interface_stats_body<&[u8], InterfaceStatistics>, interface_id: le_u32 >> timestamp_high: le_u32 >> timestamp_low: le_u32 >> - options: opt!(complete!(parse_options)) >> + options: opt!(parse_options) >> ( InterfaceStatistics { ty: TY, @@ -60,22 +60,18 @@ pub struct InterfaceStatistics<'a> { pub fn parse(blk: RawBlock) -> IResult<&[u8], InterfaceStatistics> { match interface_stats_body(blk.body) { // FIXME(richo) Actually do something with the leftover bytes - IResult::Done(left, mut block) => { + Ok((left, mut block)) => { block.block_length = blk.block_length; block.check_length = blk.check_length; - IResult::Done(left, block) - } - - IResult::Error(e) => IResult::Error(e), - IResult::Incomplete(e) => IResult::Incomplete(e), + Ok((left, block)) + }, + other => other } } #[cfg(test)] mod tests { - use nom::IResult; - use super::*; use block::parse_block; @@ -88,8 +84,8 @@ mod tests { \x05\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6C\x00\x00\x00"; match parse_block(input) { - IResult::Done(_, block) => { - if let IResult::Done(left, interface_stats_header) = parse(block) { + Ok((_, block)) => { + if let Ok((left, interface_stats_header)) = parse(block) { assert_eq!(left, b""); assert_eq!(interface_stats_header.ty, TY); @@ -97,14 +93,18 @@ mod tests { assert!(false, "failed to parse interface_stats_header"); } } - IResult::Incomplete(e) => { + Err(nom::Err::Incomplete(e)) => { println!("Incomplete: {:?}", e); assert!(false, "failed to parse interface_stats header"); } - IResult::Error(e) => { + Err(nom::Err::Error(e)) => { println!("Error: {:?}", e); assert!(false, "failed to parse interface_stats header"); } + Err(nom::Err::Failure(f)) => { + println!("Failure: {:?}", f); + assert!(false, "failed to parse interface_stats header"); + } } } } diff --git a/src/blocks/section_header.rs b/src/blocks/section_header.rs index 407ec4d..fca4cfc 100644 --- a/src/blocks/section_header.rs +++ b/src/blocks/section_header.rs @@ -27,13 +27,13 @@ pub const TY: u32 = 0x0A0D0D0A; // | Block Total Length | // +---------------------------------------------------------------+ -named!(section_header_body<&[u8],SectionHeader>, +named!(section_header_body, do_parse!( magic: le_u32 >> major_version: le_u16 >> minor_version: le_u16 >> _section_length: le_u64 - >> options: opt!(complete!(parse_options)) + >> options: opt!(parse_options) // Can we get the blocks by virtue of knowing how much data we have left here? >> ( { @@ -53,8 +53,8 @@ named!(section_header_body<&[u8],SectionHeader>, section_length: section_length, options: options, check_length: 0, - } } ) - ) + } } ) +) ); #[derive(PartialEq,Debug)] @@ -81,20 +81,17 @@ pub fn parse(blk: RawBlock) -> IResult<&[u8], SectionHeader> { // dealing with slices by this point to our advantage match section_header_body(blk.body) { // FIXME(richo) actually do something with the leftover bytes - IResult::Done(left, mut block) => { + Ok((left, mut block)) => { block.block_length = blk.block_length; block.check_length = blk.check_length; - IResult::Done(left, block) - } - IResult::Error(e) => IResult::Error(e), - IResult::Incomplete(e) => IResult::Incomplete(e), + Ok((left, block)) + }, + other => other } } #[cfg(test)] mod tests { - use nom::IResult; - use super::*; use block::parse_block; use blocks::constants::BlockType; @@ -103,8 +100,8 @@ mod tests { fn test_parse_section_header() { let input = b"\n\r\r\n\x1c\x00\x00\x00M<+\x1a\x01\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x1c\x00\x00\x00"; match parse_block(input) { - IResult::Done(_, block) => { - if let IResult::Done(left, section_header) = parse(block) { + Ok((_, block)) => { + if let Ok((left, section_header)) = parse(block) { // Ignored because we do not currently parse the whole block assert_eq!(left, b""); diff --git a/src/options.rs b/src/options.rs index 4487107..050b577 100644 --- a/src/options.rs +++ b/src/options.rs @@ -1,4 +1,4 @@ -use nom::le_u16; +use nom::*; use util; // FIXME(richo) Flesh this out properly with it's own discrete parser. @@ -29,11 +29,11 @@ pub struct Opt<'a> { // | Option Code == opt_endofopt | Option Length == 0 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -named!(option<&[u8],Opt>, +named!(option, do_parse!( code: le_u16 >> length: le_u16 - >> value: take!(length as usize) + >> value: take!(length as usize ) >> take!(util::pad_to_32bits(length as usize)) >> ( Opt { @@ -49,9 +49,9 @@ named!(option<&[u8],Opt>, // My belief is that because we're operating on a &[u8] that was carved out of the high level // buffer, and that *it* is a fat pointer with a length, the runtime will stop us from running off // the end, but it needs to be actually proven. -named!(pub parse_options< &[u8],Options >, +named!(pub parse_options, do_parse!( - opts: many1!(option) + opts: many1!(complete!(option)) >> ( { // It's also not super clear to me that we actually want to include the final option // in the vector. @@ -67,13 +67,13 @@ named!(pub parse_options< &[u8],Options >, ); #[cfg(test)] -use nom::IResult; + #[test] fn test_parse_options() { let input = b"\x12\x42\x08\x00asdfasdf\x00\x00\x00\x00"; match parse_options(input) { - IResult::Done(left, opts) => { + Ok((left, opts)) => { assert_eq!(left, b""); assert_eq!(opts.options.len(), 2); let o = &opts.options[0]; @@ -82,8 +82,8 @@ fn test_parse_options() { assert_eq!(o.value, b"asdfasdf"); } - _ => { - panic!("Hit a codepath we shouldn't have"); + err => { + panic!("Hit a codepath we shouldn't have: {:?}", err); } } } @@ -94,8 +94,8 @@ fn test_multiple_options() { \x6f\x77\x73\x20\x58\x50\x00\x00\x04\x00\x0c\x00\x54\x65\x73\x74\ \x30\x30\x34\x2e\x65\x78\x65\x00\x00\x00\x00\x00"; match parse_options(input) { - IResult::Done(left, opts) => { - assert_eq!(left, b""); + Ok((left, opts)) => { + assert_eq!(left, []); assert_eq!(opts.options.len(), 3); let o = &opts.options[0]; @@ -113,8 +113,8 @@ fn test_multiple_options() { assert_eq!(o.length, 0x00); assert_eq!(&o.value[..], b""); } - _ => { - panic!("Hit a codepath we shouldn't have"); + err => { + panic!("Hit a codepath we shouldn't have: {:?}", err); } } }