Skip to content

Commit 85d5e94

Browse files
authored
Support for PCAPNG Packet Block (#630)
1 parent e38d18d commit 85d5e94

File tree

1 file changed

+119
-0
lines changed

1 file changed

+119
-0
lines changed

dpkt/pcapng.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,55 @@ class EnhancedPacketBlockLE(EnhancedPacketBlock):
359359
__byte_order__ = '<'
360360

361361

362+
class PacketBlock(EnhancedPacketBlock):
363+
"""Packet block (deprecated)"""
364+
365+
__hdr__ = (
366+
('type', 'I', PCAPNG_BT_PB),
367+
('len', 'I', 64),
368+
('iface_id', 'H', 0),
369+
('drops_count', 'H', 0), # local drop counter
370+
('ts_high', 'I', 0), # timestamp high
371+
('ts_low', 'I', 0), # timestamp low
372+
('caplen', 'I', 0), # captured len, size of pkt_data
373+
('pkt_len', 'I', 0), # actual packet len
374+
# ( pkt_data, variable size )
375+
# ( options, variable size )
376+
('_len', 'I', 64)
377+
)
378+
379+
def __bytes__(self):
380+
pkt_buf = self.pkt_data
381+
382+
pkt_len = len(pkt_buf)
383+
self.caplen = pkt_len
384+
self.pkt_len = pkt_len
385+
386+
opts_buf = self._do_pack_options()
387+
388+
n = self.__hdr_len__ + _align32b(self.caplen) + len(opts_buf)
389+
self.len = n
390+
self._len = n
391+
392+
hdr_buf = self._pack_hdr(
393+
self.type,
394+
n,
395+
self.iface_id,
396+
self.drops_count,
397+
self.ts_high,
398+
self.ts_low,
399+
pkt_len,
400+
pkt_len,
401+
n
402+
)
403+
404+
return b''.join([hdr_buf[:-4], _padded(pkt_buf), opts_buf, hdr_buf[-4:]])
405+
406+
407+
class PacketBlockLE(PacketBlock):
408+
__byte_order__ = '<'
409+
410+
362411
class Writer(object):
363412
"""Simple pcapng dumpfile writer."""
364413

@@ -646,6 +695,10 @@ def __iter__(self):
646695
epb = EnhancedPacketBlockLE(buf) if self.__le else EnhancedPacketBlock(buf)
647696
ts = self._tsoffset + (((epb.ts_high << 32) | epb.ts_low) / self._divisor)
648697
yield (ts, epb.pkt_data)
698+
elif blk_type == PCAPNG_BT_PB:
699+
pb = PacketBlockLE(buf) if self.__le else PacketBlock(buf)
700+
ts = self._tsoffset + (((pb.ts_high << 32) | pb.ts_low) / self._divisor)
701+
yield (ts, pb.pkt_data)
649702

650703
# just ignore other blocks
651704

@@ -765,6 +818,72 @@ def test_epb():
765818
assert len(epb) == len(buf)
766819

767820

821+
def test_pb():
822+
"""Test PB with a non-ascii comment option"""
823+
buf = (
824+
b'\x02\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x73\xe6\x04\x00\xbe\x37\xe2\x19\x4a\x00'
825+
b'\x00\x00\x4a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x45\x00'
826+
b'\x00\x3c\x5d\xb3\x40\x00\x40\x06\xdf\x06\x7f\x00\x00\x01\x7f\x00\x00\x01\x98\x34\x11\x4e'
827+
b'\x95\xcb\x2d\x3a\x00\x00\x00\x00\xa0\x02\xaa\xaa\xfe\x30\x00\x00\x02\x04\xff\xd7\x04\x02'
828+
b'\x08\x0a\x05\x8f\x70\x89\x00\x00\x00\x00\x01\x03\x03\x07\x00\x00\x01\x00\x0a\x00\xd0\xbf'
829+
b'\xd0\xb0\xd0\xba\xd0\xb5\xd1\x82\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00')
830+
831+
# block unpacking
832+
pb = PacketBlockLE(buf)
833+
assert pb.type == PCAPNG_BT_PB
834+
assert pb.caplen == len(pb.pkt_data)
835+
assert pb.iface_id == 0
836+
assert pb.drops_count == 0
837+
assert pb.pkt_len == len(pb.pkt_data)
838+
assert pb.caplen == 74
839+
assert pb.ts_high == 321139
840+
assert pb.ts_low == 434255806
841+
assert pb.data == ''
842+
843+
# options unpacking
844+
assert len(pb.opts) == 2
845+
assert pb.opts[0].code == PCAPNG_OPT_COMMENT
846+
assert pb.opts[0].text == u'\u043f\u0430\u043a\u0435\u0442'
847+
848+
assert pb.opts[1].code == PCAPNG_OPT_ENDOFOPT
849+
assert pb.opts[1].len == 0
850+
851+
# option packing
852+
assert bytes(pb.opts[0]) == b'\x01\x00\x0a\x00\xd0\xbf\xd0\xb0\xd0\xba\xd0\xb5\xd1\x82\x00\x00'
853+
assert len(pb.opts[0]) == 16
854+
assert bytes(pb.opts[1]) == b'\x00\x00\x00\x00'
855+
856+
# block packing
857+
assert bytes(pb) == bytes(buf)
858+
assert str(pb) == str(buf)
859+
assert len(pb) == len(buf)
860+
861+
862+
def test_pb_read():
863+
""" Test PB parsing as part of file """
864+
pb_packet = (
865+
b'\x02\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x73\xe6\x04\x00\xbe\x37\xe2\x19\x4a\x00'
866+
b'\x00\x00\x4a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x45\x00'
867+
b'\x00\x3c\x5d\xb3\x40\x00\x40\x06\xdf\x06\x7f\x00\x00\x01\x7f\x00\x00\x01\x98\x34\x11\x4e'
868+
b'\x95\xcb\x2d\x3a\x00\x00\x00\x00\xa0\x02\xaa\xaa\xfe\x30\x00\x00\x02\x04\xff\xd7\x04\x02'
869+
b'\x08\x0a\x05\x8f\x70\x89\x00\x00\x00\x00\x01\x03\x03\x07\x00\x00\x01\x00\x0a\x00\xd0\xbf'
870+
b'\xd0\xb0\xd0\xba\xd0\xb5\xd1\x82\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00')
871+
872+
buf = define_testdata().valid_pcapng + pb_packet
873+
fobj = BytesIO(buf)
874+
875+
# test reading
876+
reader = Reader(fobj)
877+
878+
# first packet is EPB and comes from define_testdata().valid_pcapng
879+
ts, buf1 = next(iter(reader))
880+
assert ts == 1442984653.210838
881+
882+
# second packet is concatenated PB, pb_packet defined above
883+
ts, buf2 = next(iter(reader))
884+
assert ts == 1379281936.72595
885+
886+
768887
def test_epb_ascii_comment_option():
769888
"""Test EPB with an ascii comment option"""
770889
buf = (

0 commit comments

Comments
 (0)