kbandla / dpkt

fast, simple packet creation / parsing, with definitions for the basic TCP/IP protocols
Other
1.09k stars 270 forks source link

Mostly zero ethernet frame throws exception #442

Closed kylekeppler closed 5 years ago

kylekeppler commented 5 years ago

The attached pcap has a single packet that causes a NeedData exception in dpkt 1.9.2.

capture.zip

The frame looks like:

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 16
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 32
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 48
00 00 00 00 00 00 00 00 00 00 00 00 08 89 12 04 | 64

Example:

for timestamp, buf in dpkt.pcap.Reader(f):
    eth = dpkt.ethernet.Ethernet(buf)
    print(eth)

Since the ethertype field is 0, it is being treated as logical link control, and throwing an exception:

---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
c:\workspace\dpkt\dpkt\dpkt\dpkt.py in __init__(self, *args, **kwargs)
     88             try:
---> 89                 self.unpack(args[0])
     90             except struct.error:

c:\workspace\dpkt\dpkt\dpkt\llc.py in unpack(self, buf)
     35
---> 36         dpkt.Packet.unpack(self, buf)
     37         if self.is_snap:

c:\workspace\dpkt\dpkt\dpkt\dpkt.py in unpack(self, buf)
    170         for k, v in compat_izip(self.__hdr_fields__,
--> 171                                 struct.unpack(self.__hdr_fmt__, buf[:self.__hdr_len__])):
    172             setattr(self, k, v)

error: unpack requires a buffer of 3 bytes

During handling of the above exception, another exception occurred:

NeedData                                  Traceback (most recent call last)
<ipython-input-5-a483b3f3f387> in <module>
      1 for timestamp, buf in dpkt.pcap.Reader(f):
----> 2     eth = dpkt.ethernet.Ethernet(buf)
      3     print(eth)
      4

c:\workspace\dpkt\dpkt\dpkt\ethernet.py in __init__(self, *args, **kwargs)
     77
     78     def __init__(self, *args, **kwargs):
---> 79         dpkt.Packet.__init__(self, *args, **kwargs)
     80         # if data was given in kwargs, try to unpack it
     81         if self.data:

c:\workspace\dpkt\dpkt\dpkt\dpkt.py in __init__(self, *args, **kwargs)
     87         if args:
     88             try:
---> 89                 self.unpack(args[0])
     90             except struct.error:
     91                 if len(args[0]) < self.__hdr_len__:

c:\workspace\dpkt\dpkt\dpkt\ethernet.py in unpack(self, buf)
    166                         self.fcs = struct.unpack('>I', self.data[-4:])[0]
    167                         self.trailer = self.data[eth_len:-4]
--> 168             self.data = self.llc = llc.LLC(self.data[:eth_len])
    169
    170     def pack_hdr(self):

c:\workspace\dpkt\dpkt\dpkt\dpkt.py in __init__(self, *args, **kwargs)
     90             except struct.error:
     91                 if len(args[0]) < self.__hdr_len__:
---> 92                     raise NeedData
     93                 raise UnpackError('invalid %s: %r' %
     94                                   (self.__class__.__name__, args[0]))

NeedData:

Anyone ever seen this? Ideas on what to do about this ethernet frame? Should we check for the ethertype 0 case in Ethernet.unpack instead of letting it fall through the if to the else case that interprets as logic link control?

Right now I am just checking for zero ethertype and throwing away:

for timestamp, buf in dpkt.pcap.Reader(f):
    if len(buf) > 14 and buf[12:14] == b'\x00\x00':
        continue
    eth = dpkt.ethernet.Ethernet(buf)

Should we check for this case in Ethernet.upack()?