Skip to content

Commit

Permalink
decoder: support marshalling
Browse files Browse the repository at this point in the history
* support marshal objects instead of direct message classes
* message representation: json dump
  • Loading branch information
svinota committed Mar 19, 2024
1 parent 10204d2 commit cd28b69
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 18 deletions.
56 changes: 49 additions & 7 deletions pyroute2/decoder/loader.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import io
import json
import shlex
import struct
from collections import namedtuple
from importlib import import_module

from pyroute2.common import hexdump

PcapMetaData = namedtuple(
"pCAPMetaData",
(
Expand All @@ -26,6 +29,46 @@
)


class Message:

def __init__(self, packet_header, ll_header, met, data):
self.packet_header = packet_header
self.ll_header = ll_header
self.cls = None
self.met = met
self.data = data
self.exception = None
self.msg = None

def get_message_class(self):
if hasattr(self.met, 'msg_map'):
(msg_type,) = struct.unpack('H', self.data[4:6])
return self.met.msg_map[msg_type]
return self.met

def decode(self):
try:
self.cls = self.get_message_class()
self.msg = self.cls(self.data)
self.msg.decode()
self.msg = self.msg.dump()
except Exception as e:
self.exception = repr(e)
self.msg = hexdump(self.data)

def __repr__(self):
return json.dumps(
{
"pcap header": repr(self.packet_header),
"link layer header": repr(self.ll_header),
"message class": repr(self.cls),
"exception": self.exception,
"data": self.msg,
},
indent=4,
)


class Match:

@staticmethod
Expand Down Expand Up @@ -127,9 +170,6 @@ def decode_ll_header(self, data, offset):
*struct.unpack(">HHIIHH", data[offset : offset + 16]) + (16,)
)

def get_message_class(self, packet_header, ll_header, data, offset):
return self.cls

def match(self, packet_header, ll_header, data, offset):
stack = []
for method in self.parser.filters:
Expand All @@ -144,11 +184,13 @@ def data(self):
ll_header = self.decode_ll_header(self.raw, self.offset)
self.offset += ll_header.header_len
length = packet_header.incl_len - ll_header.header_len
met = self.get_message_class(
packet_header, ll_header, self.raw, self.offset
)
if self.match(packet_header, ll_header, self.raw, self.offset):
msg = met(self.raw[self.offset : self.offset + length])
msg = Message(
packet_header,
ll_header,
self.cls,
self.raw[self.offset : self.offset + length],
)
msg.decode()
yield msg
self.offset += length
Expand Down
65 changes: 54 additions & 11 deletions tests/decoder/decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,73 @@
Module is a name within rtnl hierarchy. File should be a
binary data in the escaped string format (see samples).
'''
import sys
import argparse
import struct
from importlib import import_module
from pprint import pprint

from pyroute2.common import hexdump, load_dump

mod = sys.argv[1]
argument_parser = argparse.ArgumentParser()
argument_parser.add_argument(
'message_class', help='message class to use for decoding the data'
)
argument_parser.add_argument('data_file', help='data dump file')
argument_parser.add_argument(
'-f', '--format', default='hex', help='data file format: hex, pcap'
)
argument_parser.add_argument(
'-m',
'--match',
default=0,
type=int,
help='match protocol family (only for pcap data)',
)
args = argument_parser.parse_args()

mod = args.message_class
mod = mod.replace('/', '.')
f = open(sys.argv[2], 'r')
s = mod.split('.')
package = '.'.join(s[:-1])
module = s[-1]
print(package, module)
m = import_module(package)
met = getattr(m, module)
data = None


data = load_dump(f)
if args.format == 'hex':
with open(args.data_file, 'r') as f:
data = load_dump(f)
elif args.format == 'pcap':
with open(args.data_file, 'rb') as f:
data = f.read()

offset = 0
inbox = []
if args.format == 'pcap':
# read the global header
pcap_header = struct.unpack('IHHiIII', data[:24])
offset = 24
while offset < len(data):
msg = met(data[offset:])
msg.decode()
print(hexdump(msg.data))
pprint(msg)
print('.' * 40)
offset += msg['header']['length']
msg = None
if args.format == 'pcap':
packet_header = struct.unpack('IIII', data[offset : offset + 16])
print('pcap packet header', hexdump(data[offset : offset + 16]))
offset += 16
length = packet_header[2]
print('length', length)
print('link layer header', hexdump(data[offset : offset + 16]))
ll_header = struct.unpack('HHIIHH', data[offset : offset + 16])
print('family', ll_header[5])
if args.match == ll_header[5]:
msg = met(data[offset + 16 : offset + length])
offset += length
else:
msg = met(data[offset:])
if msg is not None:
msg.decode()
print(hexdump(msg.data))
pprint(msg)
print('.' * 40)
if args.format == 'hex':
offset += msg['header']['length']

0 comments on commit cd28b69

Please sign in to comment.