Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed ek packet parsing when there are repeated protocol layers + added raw to each layer #677

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/pyshark/packet/packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ def __dir__(self):
return dir(type(self)) + list(self.__dict__.keys()) + [l.layer_name for l in self.layers]

def get_raw_packet(self) -> bytes:
assert "FRAME_RAW" in self, "Packet contains no raw data. In order to contains it, " \
assert self.frame_info.has_field('raw'), "Packet contains no raw data. In order to contains it, " \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
assert self.frame_info.has_field('raw'), "Packet contains no raw data. In order to contains it, " \
assert self.frame_info.has_field('raw'), "Packet contains no raw data. In order to include raw data, " \

"make sure that use_json and include_raw are set to True " \
"in the Capture object"
raw_packet = b''
byte_values = [''.join(x) for x in zip(self.frame_raw.value[0::2], self.frame_raw.value[1::2])]
byte_values = [''.join(x) for x in zip(self.frame_info.raw[0::2], self.frame_info.raw[1::2])]
for value in byte_values:
raw_packet += binascii.unhexlify(value)
return raw_packet
Expand Down
43 changes: 32 additions & 11 deletions src/pyshark/tshark/output_parser/tshark_ek.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,46 @@ def _extract_packet_from_data(self, data, got_first_packet=True):

return data[start_index:linesep_location], data[linesep_location + 1:]


def packet_from_ek_packet(json_pkt):
def packet_from_ek_packet_new(json_pkt):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you mean to rename this func

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm seeing this when trying to use this branch:

>>> import pyshark
>>> file = "http_1.pcap"
>>> cap = pyshark.FileCapture(file, use_ek=True)
>>> pkt = cap[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/andrew/pyshark-fixed/src/pyshark/capture/file_capture.py", line 72, in __getitem__
    self.next()
  File "/home/andrew/pyshark-fixed/src/pyshark/capture/file_capture.py", line 62, in next
    packet = self._packet_generator.send(None)
  File "/home/andrew/pyshark-fixed/src/pyshark/capture/capture.py", line 222, in _packets_from_tshark_sync
    packet, data = self.eventloop.run_until_complete(
  File "/usr/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
    return future.result()
  File "/home/andrew/pyshark-fixed/src/pyshark/tshark/output_parser/base_parser.py", line 15, in get_packets_from_stream
    packet = self._parse_single_packet(packet)
  File "/home/andrew/pyshark-fixed/src/pyshark/tshark/output_parser/tshark_ek.py", line 21, in _parse_single_packet
    return packet_from_ek_packet(packet)
NameError: name 'packet_from_ek_packet' is not defined. Did you mean: 'packet_from_ek_packet_new'?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def packet_from_ek_packet_new(json_pkt):
def packet_from_ek_packet(json_pkt):

if USE_UJSON:
pkt_dict = ujson.loads(json_pkt)
else:
pkt_dict = json.loads(json_pkt.decode('utf-8'))

# We use the frame dict here and not the object access because it's faster.
frame_dict = pkt_dict['layers'].pop('frame')
layers = []
for layer in frame_dict['frame_frame_protocols'].split(':'):
layer_dict = pkt_dict['layers'].pop(layer, None)
if layer_dict is not None:
layers.append(EkLayer(layer, layer_dict))
layers = pkt_dict['layers']
frame_dict = layers.pop('frame')
if 'frame_raw' in layers:
frame_dict['frame_frame_raw'] = layers.pop('frame_raw')

# Sort the frame protocol layers first
ek_layers = []
for name in frame_dict['frame_frame_protocols'].split(':'):
raw_name = f"{name}_raw"
if name in layers:
layer = layers.get(name)
layer_raw = layers.get(raw_name)
if not layer:
continue
elif isinstance(layer, list):
layer = layer.pop(0)
layer_raw = layer_raw.pop(0) if layer_raw else None
else:
layers.pop(name, None)
layers.pop(raw_name, None)
layer[f"{name}_{raw_name}"] = layer_raw
ek_layer = EkLayer(name, layer)
ek_layers.append(ek_layer)

# Add all leftovers
for name, layer in pkt_dict['layers'].items():
layers.append(EkLayer(name, layer))
for name, layer in layers.items():
if isinstance(layer, list):
for sub_layer in layer:
ek_layers.append(EkLayer(name, sub_layer) )
else:
ek_layers.append(EkLayer(name, layer))

return Packet(layers=layers, frame_info=EkLayer('frame', frame_dict),
return Packet(layers=ek_layers, frame_info=EkLayer('frame', frame_dict),
number=int(frame_dict.get('frame_frame_number', 0)),
length=int(frame_dict['frame_frame_len']),
sniff_time=frame_dict['frame_frame_time_epoch'],
Expand Down