diff options
author | Ulf Lamping <ulf.lamping@web.de> | 2008-01-19 12:09:00 +0000 |
---|---|---|
committer | Ulf Lamping <ulf.lamping@web.de> | 2008-01-19 12:09:00 +0000 |
commit | 39114205fe4126c432602d0065cadf454e59b94d (patch) | |
tree | 9ee683c29087fe647c6d5fa63c9aa0511ba34ac7 /wiretap | |
parent | 86358dc0326b4659ec73f6c13ebac294562df8d5 (diff) | |
download | wireshark-39114205fe4126c432602d0065cadf454e59b94d.tar.gz wireshark-39114205fe4126c432602d0065cadf454e59b94d.tar.bz2 wireshark-39114205fe4126c432602d0065cadf454e59b94d.zip |
various enhancements:
- read simple packet block
- read various options
- jump over unknown block types
- more sanity checks
svn path=/trunk/; revision=24139
Diffstat (limited to 'wiretap')
-rw-r--r-- | wiretap/pcapng.c | 592 |
1 files changed, 436 insertions, 156 deletions
diff --git a/wiretap/pcapng.c b/wiretap/pcapng.c index 96a487825b..6eb84c2a43 100644 --- a/wiretap/pcapng.c +++ b/wiretap/pcapng.c @@ -25,6 +25,8 @@ /* File format reference: * http://www.winpcap.org/ntar/draft/PCAP-DumpFileFormat.html + * Related Wiki page: + * http://wiki.wireshark.org/Development/PcapNg */ #ifdef HAVE_CONFIG_H @@ -102,12 +104,19 @@ typedef struct pcapng_enhanced_packet_block_s { /* ... Options ... */ } pcapng_enhanced_packet_block_t; +/* pcapng: simple packet block */ +typedef struct pcapng_simple_packet_block_s { + guint32 packet_len; + /* ... Packet Data ... */ + /* ... Padding ... */ +} pcapng_simple_packet_block_t; + /* pcapng: common option header for every option type */ typedef struct pcapng_option_header_s { guint16 option_code; guint16 option_length; - /* x bytes option_body */ - /* alignment to 32 bits */ + /* ... x bytes Option Body ... */ + /* ... Padding ... */ } pcapng_option_header_t; /* Block types */ @@ -158,17 +167,25 @@ typedef struct wtapng_packet_s { /* mandatory */ guint32 ts_high; /* seconds since 1.1.1970 */ guint32 ts_low; /* fraction of seconds, depends on if_tsaccur */ - guint32 cap_len; - guint32 packet_len; + guint32 cap_len; /* data length in the file */ + guint32 packet_len; /* data length on the wire */ /* options */ gchar *opt_comment; /* NULL if not available */ guint64 drop_count; /* 0xFFFFFFFF if unknown */ - /* pack_flags */ + guint32 pack_flags; /* XXX - 0 for now (any value for "we don't have it"?) */ /* pack_hash */ /* XXX - put the packet data / pseudo_header here as well? */ } wtapng_packet_t; +/* Simple Packets */ +typedef struct wtapng_simple_packet_s { + /* mandatory */ + guint32 cap_len; /* data length in the file */ + guint32 packet_len; /* data length on the wire */ + /* XXX - put the packet data / pseudo_header here as well? */ +} wtapng_simple_packet_t; + /* Name Resolution */ typedef struct wtapng_name_res_s { /* options */ @@ -199,11 +216,12 @@ typedef struct wtapng_if_stats_s { typedef struct wtapng_block_s { guint32 type; /* block_type as defined by pcapng */ union { - wtapng_section_t section; - wtapng_if_descr_t if_descr; - wtapng_packet_t packet; - wtapng_name_res_t name_res; - wtapng_if_stats_t if_stats; + wtapng_section_t section; + wtapng_if_descr_t if_descr; + wtapng_packet_t packet; + wtapng_simple_packet_t simple_packet; + wtapng_name_res_t name_res; + wtapng_if_stats_t if_stats; } data; /* XXX - currently don't know how to handle these! */ @@ -213,12 +231,72 @@ typedef struct wtapng_block_s { static int +pcapng_read_option(FILE_T fh, pcapng_t *pn, pcapng_option_header_t *oh, char *content, int len, int *err, gchar **err_info _U_) +{ + int bytes_read; + int block_read; + guint64 file_offset64; + + + /* read option header */ + errno = WTAP_ERR_CANT_READ; + bytes_read = file_read(oh, 1, sizeof oh, fh); + if (bytes_read != sizeof oh) { + g_warning("pcapng_read_option: failed to read option"); + *err = file_error(fh); + if (*err != 0) + return -1; + return 0; + } + block_read = sizeof oh; + if(pn->byte_swapped) { + oh->option_code = BSWAP16(oh->option_code); + oh->option_length = BSWAP32(oh->option_length); + } + + /* sanity check: option length */ + if (oh->option_length > len) { + g_warning("pcapng_read_option: option_length %u larger than buffer (%u)", + oh->option_length, len); + return 0; + } + + /* read option content */ + errno = WTAP_ERR_CANT_READ; + bytes_read = file_read(content, 1, oh->option_length, fh); + if (bytes_read != oh->option_length) { + g_warning("pcapng_read_if_descr_block: failed to read content of option %u", oh->option_code); + *err = file_error(fh); + if (*err != 0) + return -1; + return 0; + } + block_read += oh->option_length; + + /* jump over potential padding bytes at end of option */ + if( (oh->option_length % 4) != 0) { + file_offset64 = file_seek(fh, 4 - (oh->option_length % 4), SEEK_CUR, err); + if (file_offset64 <= 0) { + if (*err != 0) + return -1; + return 0; + } + block_read += 4 - (oh->option_length % 4); + } + + return block_read; +} + + +static int pcapng_read_section_header_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock, int *err, gchar **err_info _U_) { int bytes_read; + int block_read; int to_read; pcapng_section_header_block_t shb; - guint64 file_offset64; + pcapng_option_header_t oh; + char option_content[100]; /* XXX - size might need to be increased, if we see longer options */ /* read block content */ @@ -230,6 +308,7 @@ pcapng_read_section_header_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t return -1; return 0; } + block_read = bytes_read; /* is the magic number one we expect? */ switch(shb.magic) { @@ -270,24 +349,76 @@ pcapng_read_section_header_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t /* XXX - no proper way to read/swap 64 bit values -> so ignore the 64bit section_length for now! */ wblock->data.section.section_length = -1; /* shb.section_length */ - /* XXX - we ignore SHB options for now */ - /* "Section Header Block" jump over the Options (and the repeated block length at the end) */ - errno = WTAP_ERR_CANT_READ; - to_read = bh->block_total_length - sizeof(pcapng_block_header_t) - sizeof (pcapng_section_header_block_t); - file_offset64 = file_seek(fh, to_read, SEEK_CUR, err); - if (file_offset64 <= 0) { - if (*err != 0) - return -1; - return 0; - } - - /* options */ + /* Option defaults */ wblock->data.section.opt_comment = NULL; wblock->data.section.shb_hardware = NULL; wblock->data.section.shb_os = NULL; wblock->data.section.shb_user_appl = NULL; - return bytes_read + to_read; + /* Options */ + errno = WTAP_ERR_CANT_READ; + to_read = bh->block_total_length + - sizeof(pcapng_block_header_t) + - sizeof (pcapng_section_header_block_t) + - sizeof(bh->block_total_length); + while(to_read > 0) { + /* read option */ + bytes_read = pcapng_read_option(fh, pn, &oh, option_content, sizeof(option_content), err, err_info); + if (bytes_read <= 0) { + g_warning("pcapng_read_section_header_block: failed to read option"); + return bytes_read; + } + block_read += bytes_read; + to_read -= bytes_read; + + /* handle option content */ + switch(oh.option_code) { + case(0): /* opt_endofopt */ + if(to_read != 0) { + g_warning("pcapng_read_section_header_block: %u bytes after opt_endofopt", to_read); + } + /* padding should be ok here, just get out of this */ + to_read = 0; + break; + case(1): /* opt_comment */ + if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) { + wblock->data.section.opt_comment = g_strndup(option_content, sizeof(option_content)); + g_warning("pcapng_read_section_header_block: opt_comment %s", wblock->data.section.opt_comment); + } else { + g_warning("pcapng_read_section_header_block: opt_comment length %u seems strange", oh.option_length); + } + break; + case(2): /* shb_hardware */ + if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) { + wblock->data.section.shb_hardware = g_strndup(option_content, sizeof(option_content)); + g_warning("pcapng_read_section_header_block: shb_hardware %s", wblock->data.section.shb_hardware); + } else { + g_warning("pcapng_read_section_header_block: shb_hardware length %u seems strange", oh.option_length); + } + break; + case(3): /* shb_os */ + if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) { + wblock->data.section.shb_os = g_strndup(option_content, sizeof(option_content)); + g_warning("pcapng_read_section_header_block: shb_os %s", wblock->data.section.shb_os); + } else { + g_warning("pcapng_read_section_header_block: shb_os length %u seems strange", oh.option_length); + } + break; + case(4): /* shb_userappl */ + if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) { + wblock->data.section.shb_user_appl = g_strndup(option_content, sizeof(option_content)); + g_warning("pcapng_read_section_header_block: shb_userappl %s", wblock->data.section.shb_user_appl); + } else { + g_warning("pcapng_read_section_header_block: shb_userappl length %u seems strange", oh.option_length); + } + break; + default: + g_warning("pcapng_read_section_header_block: unknown option %u - ignoring %u bytes", + oh.option_code, oh.option_length); + } + } + + return block_read; } @@ -298,10 +429,9 @@ pcapng_read_if_descr_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, w int bytes_read; int block_read; int to_read; - guint64 file_offset64; pcapng_interface_description_block_t idb; pcapng_option_header_t oh; - char option_content[100]; + char option_content[100]; /* XXX - size might need to be increased, if we see longer options */ /* read block content */ @@ -316,7 +446,7 @@ pcapng_read_if_descr_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, w } block_read = bytes_read; - /* mandatory value */ + /* mandatory values */ if(pn->byte_swapped) { wblock->data.if_descr.link_type = BSWAP16(idb.linktype); wblock->data.if_descr.snap_len = BSWAP32(idb.snaplen); @@ -330,7 +460,7 @@ pcapng_read_if_descr_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, w /* XXX - sanity check of snapshot length */ /* XXX - while a very big snapshot length is valid, it's more likely that it's a bug in the file */ - /* XXX - so do a sanity check for now, it's likely a byte swap order problem */ + /* XXX - so do a sanity check for now, it's likely e.g. a byte swap order problem */ if(wblock->data.if_descr.snap_len > 65535) { g_warning("pcapng_read_if_descr_block: snapshot length %u unrealistic", wblock->data.if_descr.snap_len); @@ -338,7 +468,7 @@ pcapng_read_if_descr_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, w return 0; } - /* default values for IDB options */ + /* Option defaults */ wblock->data.if_descr.opt_comment = NULL; wblock->data.if_descr.if_name = NULL; wblock->data.if_descr.if_description = NULL; @@ -354,56 +484,67 @@ pcapng_read_if_descr_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, w /* XXX: guint64 if_tsoffset; */ - /* IDB options */ + /* Options */ errno = WTAP_ERR_CANT_READ; - to_read = bh->block_total_length - sizeof(pcapng_block_header_t) - sizeof (pcapng_interface_description_block_t); + to_read = bh->block_total_length + - sizeof(pcapng_block_header_t) + - sizeof (pcapng_interface_description_block_t) + - sizeof(bh->block_total_length); while(to_read > 0) { - /* read option header */ - errno = WTAP_ERR_CANT_READ; - bytes_read = file_read(&oh, 1, sizeof oh, fh); - if (bytes_read != sizeof oh) { - g_warning("pcapng_read_if_descr_block: failed to read option"); - *err = file_error(fh); - if (*err != 0) - return -1; - return 0; + /* read option */ + bytes_read = pcapng_read_option(fh, pn, &oh, option_content, sizeof(option_content), err, err_info); + if (bytes_read <= 0) { + g_warning("pcapng_read_if_descr_block: failed to read option"); + return bytes_read; } - block_read += sizeof oh; - to_read -= sizeof oh; - if(pn->byte_swapped) { - oh.option_code = BSWAP16(oh.option_code); - oh.option_length = BSWAP32(oh.option_length); - } - - /* sanity check: option length */ - /* XXX - might need to be increased, if we see longer options */ - if (oh.option_length > sizeof option_content) { - g_warning("pcapng_read_if_descr_block: option_length %u seems pretty large", oh.option_length); - return 0; - } - - /* read option content */ - errno = WTAP_ERR_CANT_READ; - bytes_read = file_read(option_content, 1, oh.option_length, fh); - if (bytes_read != oh.option_length) { - g_warning("pcapng_read_if_descr_block: failed to read content of option %u", oh.option_code); - *err = file_error(fh); - if (*err != 0) - return -1; - return 0; - } - block_read += oh.option_length; - to_read -= oh.option_length; + block_read += bytes_read; + to_read -= bytes_read; /* handle option content */ switch(oh.option_code) { case(0): /* opt_endofopt */ - if(to_read != 4) { - g_warning("pcapng_read_if_descr_block: %u bytes after opt_endofopt", to_read - 4); + if(to_read != 0) { + g_warning("pcapng_read_if_descr_block: %u bytes after opt_endofopt", to_read); } /* padding should be ok here, just get out of this */ to_read = 0; break; + case(1): /* opt_comment */ + if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) { + wblock->data.section.opt_comment = g_strndup(option_content, sizeof(option_content)); + g_warning("pcapng_read_if_descr_block: opt_comment %s", wblock->data.section.opt_comment); + } else { + g_warning("pcapng_read_if_descr_block: opt_comment length %u seems strange", oh.option_length); + } + break; + case(2): /* if_name */ + if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) { + wblock->data.if_descr.if_name = g_strndup(option_content, sizeof(option_content)); + g_warning("pcapng_read_if_descr_block: if_name %s", wblock->data.if_descr.if_name); + } else { + g_warning("pcapng_read_if_descr_block: if_name length %u seems strange", oh.option_length); + } + break; + case(3): /* if_description */ + if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) { + wblock->data.if_descr.if_description = g_strndup(option_content, sizeof(option_content)); + g_warning("pcapng_read_if_descr_block: if_description %s", wblock->data.if_descr.if_description); + } else { + g_warning("pcapng_read_if_descr_block: if_description length %u seems strange", oh.option_length); + } + break; + case(8): /* if_speed */ + if(oh.option_length == 8) { + wblock->data.if_descr.if_speed = *((guint64 *)option_content); + /* XXX - need 64 bit byte swap */ + /*if(pn->byte_swapped) + wblock->data.if_descr.if_speed = BSWAP64(wblock->data.if_descr.if_speed);*/ + + g_warning("pcapng_read_if_descr_block: if_speed %u (bps)", wblock->data.if_descr.if_speed); + } else { + g_warning("pcapng_read_if_descr_block: if_speed length %u not 8 as expected", oh.option_length); + } + break; case(9): /* if_tsaccur */ if(oh.option_length == 1) { wblock->data.if_descr.if_tsaccur = option_content[0]; @@ -426,31 +567,8 @@ pcapng_read_if_descr_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, w g_warning("pcapng_read_if_descr_block: unknown option %u - ignoring %u bytes", oh.option_code, oh.option_length); } - - /* jump over potential padding bytes at end of option */ - if( (oh.option_length % 4) != 0) { - file_offset64 = file_seek(fh, 4 - (oh.option_length % 4), SEEK_CUR, err); - if (file_offset64 <= 0) { - if (*err != 0) - return -1; - return 0; - } - block_read += 4 - (oh.option_length % 4); - to_read -= 4 - (oh.option_length % 4); - } - } - /* jump over the repeated block length at the end of the block */ - /* XXX - add a sanity check here? */ - file_offset64 = file_seek(fh, 4, SEEK_CUR, err); - if (file_offset64 <= 0) { - if (*err != 0) - return -1; - return 0; - } - block_read += 4; - return block_read; } @@ -459,14 +577,16 @@ static int pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock,int *err, gchar **err_info _U_) { int bytes_read; - guint64 bytes_read64; + int block_read; int to_read; + guint64 file_offset64; pcapng_enhanced_packet_block_t epb; - int read_len = 0; guint32 block_total_length; + pcapng_option_header_t oh; + char option_content[100]; /* XXX - size might need to be increased, if we see longer options */ - /* "(Enhanced) Packet Block" read content */ + /* "(Enhanced) Packet Block" read fixed part */ errno = WTAP_ERR_CANT_READ; bytes_read = file_read(&epb, 1, sizeof epb, fh); if (bytes_read != sizeof epb) { @@ -474,8 +594,7 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta *err = file_error(fh); return 0; } - - read_len += sizeof epb; + block_read = bytes_read; /* XXX - as we currently ignore the interface id, both packet blocks are the same for us */ if(pn->byte_swapped) { @@ -501,9 +620,10 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta /* Ethernet FCS length, might be overwritten by "per packet" options */ ((union wtap_pseudo_header *) wblock->pseudo_header)->eth.fcs_len = pn->if_fcslen; + /* "(Enhanced) Packet Block" read capture data */ errno = WTAP_ERR_CANT_READ; bytes_read = file_read((guchar *) (wblock->frame_buffer), 1, wblock->data.packet.cap_len, fh); - if (bytes_read != (int) wblock->data.packet.cap_len) { + if (bytes_read != wblock->data.packet.cap_len) { *err = file_error(fh); g_warning("pcapng_read_packet_block: couldn't read %u bytes of captured data", wblock->data.packet.cap_len); @@ -511,69 +631,201 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta *err = WTAP_ERR_SHORT_READ; return FALSE; } - read_len += wblock->data.packet.cap_len; - - /* XXX - ignore Packet options for now */ - /* Packet jump over the Options (and the repeated block length at the end) */ + block_read += bytes_read; + + /* jump over potential padding bytes at end of the packet data */ + if( (wblock->data.packet.cap_len % 4) != 0) { + file_offset64 = file_seek(fh, 4 - (wblock->data.packet.cap_len % 4), SEEK_CUR, err); + if (file_offset64 <= 0) { + if (*err != 0) + return -1; + return 0; + } + block_read += 4 - (wblock->data.packet.cap_len % 4); + } - /* XXX - the "block total length" of some example files don't contain the padding bytes! */ + /* add padding bytes to "block total length" */ + /* (the "block total length" of some example files don't contain the packet data padding bytes!) */ if(bh->block_total_length % 4) { block_total_length = bh->block_total_length + 4 - (bh->block_total_length % 4); } else { block_total_length = bh->block_total_length; } - to_read = block_total_length - sizeof(pcapng_block_header_t) - sizeof (pcapng_enhanced_packet_block_t) - wblock->data.packet.cap_len; + /* Option defaults */ + wblock->data.packet.opt_comment = NULL; + wblock->data.packet.drop_count = -1; + wblock->data.packet.pack_flags = 0; /* XXX - is 0 ok to signal "not used"? */ - /* jump over the data padding and the Options, but not the repeated block length */ - to_read -= 4; + /* Options */ errno = WTAP_ERR_CANT_READ; - bytes_read64 = file_seek(fh, to_read, SEEK_CUR, err); - if (bytes_read64 <= 0) { - return 0; /* Seek error */ - } + to_read = block_total_length + - sizeof(pcapng_block_header_t) + - block_read /* fixed and variable part, including padding */ + - sizeof(bh->block_total_length); + while(to_read > 0) { + /* read option */ + bytes_read = pcapng_read_option(fh, pn, &oh, option_content, sizeof(option_content), err, err_info); + if (bytes_read <= 0) { + g_warning("pcapng_read_packet_block: failed to read option"); + return bytes_read; + } + block_read += bytes_read; + to_read -= bytes_read; - /* sanity check: first and second block lengths must match */ - /* XXX - move this out of the individual blocks into some common place? */ + /* handle option content */ + switch(oh.option_code) { + case(0): /* opt_endofopt */ + if(to_read != 0) { + g_warning("pcapng_read_packet_block: %u bytes after opt_endofopt", to_read); + } + /* padding should be ok here, just get out of this */ + to_read = 0; + break; + case(1): /* opt_comment */ + if(oh.option_length > 0 && oh.option_length < sizeof(option_content)) { + wblock->data.section.opt_comment = g_strndup(option_content, sizeof(option_content)); + g_warning("pcapng_read_packet_block: opt_comment %s", wblock->data.section.opt_comment); + } else { + g_warning("pcapng_read_packet_block: opt_comment length %u seems strange", oh.option_length); + } + break; + case(2): /* pack_flags / epb_flags */ + if(oh.option_length == 4) { + wblock->data.packet.pack_flags = *((guint32 *)option_content); + if(pn->byte_swapped) + wblock->data.packet.pack_flags = BSWAP32(wblock->data.packet.pack_flags); + g_warning("pcapng_read_if_descr_block: pack_flags %u (ignored)", wblock->data.packet.pack_flags); + } else { + g_warning("pcapng_read_if_descr_block: pack_flags length %u not 4 as expected", oh.option_length); + } + break; + default: + g_warning("pcapng_read_packet_block: unknown option %u - ignoring %u bytes", + oh.option_code, oh.option_length); + } + } + + return block_read; +} + + +static int +pcapng_read_simple_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock,int *err, gchar **err_info _U_) +{ + int bytes_read; + int block_read; + guint64 file_offset64; + pcapng_simple_packet_block_t spb; + + + /* "Simple Packet Block" read fixed part */ errno = WTAP_ERR_CANT_READ; - bytes_read = file_read(&block_total_length, 1, sizeof block_total_length, fh); - if (bytes_read != sizeof block_total_length) { + bytes_read = file_read(&spb, 1, sizeof spb, fh); + if (bytes_read != sizeof spb) { + g_warning("pcapng_read_simple_packet_block: failed to read packet data"); *err = file_error(fh); return 0; } - if( !(block_total_length == bh->block_total_length) && - !((BSWAP32(block_total_length)) == bh->block_total_length) ) { - g_warning("pcapng_read_packet_block: total block lengths (first %u and second %u) don't match", - bh->block_total_length, block_total_length); - return 0; + block_read = bytes_read; + + if(pn->byte_swapped) { + wblock->data.simple_packet.packet_len = BSWAP32(spb.packet_len); + } else { + wblock->data.simple_packet.packet_len = spb.packet_len; + } + + wblock->data.simple_packet.cap_len = bh->block_total_length + - sizeof(pcapng_simple_packet_block_t) + - sizeof(bh->block_total_length); + + /*g_warning("pcapng_read_simple_packet_block: packet data: packet_len %u", + wblock->data.simple_packet.packet_len);*/ + + /* XXX - implement other linktypes then Ethernet */ + /* (or even better share the code with libpcap.c) */ + + /* Ethernet FCS length, might be overwritten by "per packet" options */ + ((union wtap_pseudo_header *) wblock->pseudo_header)->eth.fcs_len = pn->if_fcslen; + + /* "Simple Packet Block" read capture data */ + errno = WTAP_ERR_CANT_READ; + bytes_read = file_read((guchar *) (wblock->frame_buffer), 1, wblock->data.simple_packet.cap_len, fh); + if (bytes_read != wblock->data.simple_packet.cap_len) { + *err = file_error(fh); + g_warning("pcapng_read_simple_packet_block: couldn't read %u bytes of captured data", + wblock->data.simple_packet.cap_len); + if (*err == 0) + *err = WTAP_ERR_SHORT_READ; + return FALSE; } + block_read += bytes_read; + + /* jump over potential padding bytes at end of the packet data */ + if( (wblock->data.simple_packet.cap_len % 4) != 0) { + file_offset64 = file_seek(fh, 4 - (wblock->data.simple_packet.cap_len % 4), SEEK_CUR, err); + if (file_offset64 <= 0) { + if (*err != 0) + return -1; + return 0; + } + block_read += 4 - (wblock->data.simple_packet.cap_len % 4); + } - /* We read the packet successfully. */ - return read_len + to_read + 4; + return block_read; } +static int +pcapng_read_unknown_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock,int *err, gchar **err_info _U_) +{ + int block_read; + guint64 file_offset64; + guint32 block_total_length; + + + /* add padding bytes to "block total length" */ + /* (the "block total length" of some example files don't contain any padding bytes!) */ + if(bh->block_total_length % 4) { + block_total_length = bh->block_total_length + 4 - (bh->block_total_length % 4); + } else { + block_total_length = bh->block_total_length; + } + + block_read = block_total_length - sizeof(bh->block_total_length); + + /* jump over this unknown block */ + file_offset64 = file_seek(fh, block_read, SEEK_CUR, err); + if (file_offset64 <= 0) { + if (*err != 0) + return -1; + return 0; + } + + return block_read; +} static int pcapng_read_block(FILE_T fh, pcapng_t *pn, wtapng_block_t *wblock, int *err, gchar **err_info) { - int bytes_read_header; - int bytes_read_content; + int block_read; + int bytes_read; pcapng_block_header_t bh; + guint32 block_total_length; /* Try to read the (next) block header */ errno = WTAP_ERR_CANT_READ; - bytes_read_header = file_read(&bh, 1, sizeof bh, fh); - if (bytes_read_header != sizeof bh) { - g_warning("pcapng_read_block: no more bytes"); + bytes_read = file_read(&bh, 1, sizeof bh, fh); + if (bytes_read != sizeof bh) { + g_warning("pcapng_read_block: end of file"); *err = file_error(fh); if (*err != 0) return -1; return 0; } - + block_read = bytes_read; if(pn->byte_swapped) { bh.block_type = BSWAP32(bh.block_type); bh.block_total_length = BSWAP32(bh.block_total_length); @@ -585,23 +837,49 @@ pcapng_read_block(FILE_T fh, pcapng_t *pn, wtapng_block_t *wblock, int *err, gch switch(bh.block_type) { case(BLOCK_TYPE_SHB): - bytes_read_content = pcapng_read_section_header_block(fh, &bh, pn, wblock, err, err_info); + bytes_read = pcapng_read_section_header_block(fh, &bh, pn, wblock, err, err_info); break; case(BLOCK_TYPE_IDB): - bytes_read_content = pcapng_read_if_descr_block(fh, &bh, pn, wblock, err, err_info); + bytes_read = pcapng_read_if_descr_block(fh, &bh, pn, wblock, err, err_info); break; case(BLOCK_TYPE_PB): - bytes_read_content = pcapng_read_packet_block(fh, &bh, pn, wblock, err, err_info); + bytes_read = pcapng_read_packet_block(fh, &bh, pn, wblock, err, err_info); + break; + case(BLOCK_TYPE_SPB): + bytes_read = pcapng_read_simple_packet_block(fh, &bh, pn, wblock, err, err_info); break; case(BLOCK_TYPE_EPB): - bytes_read_content = pcapng_read_packet_block(fh, &bh, pn, wblock, err, err_info); + bytes_read = pcapng_read_packet_block(fh, &bh, pn, wblock, err, err_info); break; default: - g_warning("pcapng_read_block: Unknown block_type: 0x%x", bh.block_type); - bytes_read_content = 0; + g_warning("pcapng_read_block: Unknown block_type: 0x%x (block ignored)", bh.block_type); + bytes_read = pcapng_read_unknown_block(fh, &bh, pn, wblock, err, err_info); + } + if(bytes_read <= 0) { + return bytes_read; + } + block_read += bytes_read; + + /* sanity check: first and second block lengths must match */ + errno = WTAP_ERR_CANT_READ; + bytes_read = file_read(&block_total_length, 1, sizeof block_total_length, fh); + if (bytes_read != sizeof block_total_length) { + g_warning("pcapng_read_block: couldn't read second block length"); + *err = file_error(fh); + return 0; } + block_read += bytes_read; + + if(pn->byte_swapped) + block_total_length = BSWAP32(block_total_length); - return (bytes_read_content == 0) ? 0 : bytes_read_header + bytes_read_content; + if( !(block_total_length == bh.block_total_length) ) { + g_warning("pcapng_read_block: total block lengths (first %u and second %u) don't match", + bh.block_total_length, block_total_length); + return 0; + } + + return block_read; } @@ -624,6 +902,7 @@ pcapng_open(wtap *wth, int *err, gchar **err_info) wblock.frame_buffer = NULL; wblock.pseudo_header = NULL; + /* read first block */ bytes_read = pcapng_read_block(wth->fh, &pn, &wblock, err, err_info); if (bytes_read <= 0) { @@ -709,33 +988,34 @@ pcapng_read(wtap *wth, int *err, gchar **err_info, wblock.pseudo_header = &wth->pseudo_header; /* read next block */ - bytes_read = pcapng_read_block(wth->fh, wth->capture.pcapng, &wblock, err, err_info); - if (bytes_read <= 0) { - *err = file_error(wth->fh); - /*g_warning("pcapng_read: couldn't read packet block");*/ - if (*err != 0) - return -1; - return 0; - } + while(1) { + bytes_read = pcapng_read_block(wth->fh, wth->capture.pcapng, &wblock, err, err_info); + if (bytes_read <= 0) { + *err = file_error(wth->fh); + /*g_warning("pcapng_read: couldn't read packet block");*/ + if (*err != 0) + return -1; + return 0; + } - /* block must be a "Packet Block" or an "Enhanced Packet Block" */ - if(wblock.type != BLOCK_TYPE_PB && wblock.type != BLOCK_TYPE_EPB) { + /* block must be a "Packet Block" or an "Enhanced Packet Block" -> otherwise continue */ + if(wblock.type == BLOCK_TYPE_PB || wblock.type == BLOCK_TYPE_EPB) { + break; + } + + /* XXX - improve handling of "unknown" blocks */ g_warning("pcapng_read: block type 0x%x not PB/EPB", wblock.type); - return 0; - } + } - if(bytes_read > 0) { - wth->phdr.caplen = wblock.data.packet.cap_len; - wth->phdr.len = wblock.data.packet.packet_len; - wth->phdr.ts.secs = wblock.data.packet.ts_high; - wth->phdr.ts.nsecs = wblock.data.packet.ts_low; + wth->phdr.caplen = wblock.data.packet.cap_len; + wth->phdr.len = wblock.data.packet.packet_len; + wth->phdr.ts.secs = wblock.data.packet.ts_high; + wth->phdr.ts.nsecs = wblock.data.packet.ts_low; - /*g_warning("Read length: %u Packet length: %u", bytes_read, wth->phdr.caplen);*/ - wth->data_offset += bytes_read; - return TRUE; - } else { - return FALSE; - } + /*g_warning("Read length: %u Packet length: %u", bytes_read, wth->phdr.caplen);*/ + wth->data_offset += bytes_read; + + return TRUE; } |