From a644787bb4854815969159a485311389f812cb3d Mon Sep 17 00:00:00 2001 From: gpotter2 Date: Sun, 19 May 2019 12:09:53 +0200 Subject: [PATCH 1/2] Fix FlagsField & dissection improvements --- scapy/contrib/ibeacon.uts | 2 +- scapy/fields.py | 12 +++++------ scapy/packet.py | 43 ++++++++++++++++++++++++++++----------- test/regression.uts | 9 -------- 4 files changed, 37 insertions(+), 29 deletions(-) diff --git a/scapy/contrib/ibeacon.uts b/scapy/contrib/ibeacon.uts index e5c67dbd74f..420fb53dc9a 100644 --- a/scapy/contrib/ibeacon.uts +++ b/scapy/contrib/ibeacon.uts @@ -42,7 +42,7 @@ assert d == d2 = iBeacon (encode LE Set Advertising Data) -d = hex_bytes('1E0201021AFF4C000215FB0B57A2822844CD913A94A122BA120600010002D100') +d = hex_bytes('1E0201061AFF4C000215FB0B57A2822844CD913A94A122BA120600010002D100') p = Apple_BLE_Submessage()/IBeacon_Data( uuid='fb0b57a2-8228-44cd-913a-94a122ba1206', major=1, minor=2, tx_power=-47) diff --git a/scapy/fields.py b/scapy/fields.py index d623849f180..ddb34945c65 100644 --- a/scapy/fields.py +++ b/scapy/fields.py @@ -1971,13 +1971,11 @@ def _fixup_val(self, x): used in *2i() and i2*() methods. """ - if isinstance(x, (list, tuple)): - return type(x)( - v if v is None or isinstance(v, FlagValue) - else FlagValue(v, self.names) - for v in x - ) - return x if x is None or isinstance(x, FlagValue) else FlagValue(x, self.names) # noqa: E501 + if isinstance(x, FlagValue): + return x + if x is None: + return None + return FlagValue(x, self.names) def any2i(self, pkt, x): return self._fixup_val(super(FlagsField, self).any2i(pkt, x)) diff --git a/scapy/packet.py b/scapy/packet.py index 9411927ca09..7a655c3d94d 100644 --- a/scapy/packet.py +++ b/scapy/packet.py @@ -435,8 +435,13 @@ def __repr__(self): repr(self.payload), ct.punct(">")) - def __str__(self): - return str(self.build()) + if six.PY2: + def __str__(self): + return self.build() + else: + def __str__(self): + warning("Calling str(pkt) on Python 3 makes no sense!") + return str(self.build()) def __bytes__(self): return self.build() @@ -488,9 +493,14 @@ def copy_fields_dict(self, fields): def clear_cache(self): """Clear the raw packet cache for the field and all its subfields""" self.raw_packet_cache = None - for _, fval in six.iteritems(self.fields): - if isinstance(fval, Packet): - fval.clear_cache() + for fld, fval in six.iteritems(self.fields): + fld = self.get_field(fld) + if fld.holds_packets: + if isinstance(fval, Packet): + fval.clear_cache() + elif isinstance(fval, list): + for fsubval in fval: + fsubval.clear_cache() self.payload.clear_cache() def self_build(self, field_pos_list=None): @@ -838,9 +848,12 @@ def guess_payload_class(self, payload): """ for t in self.aliastypes: for fval, cls in t.payload_guess: - if all(hasattr(self, k) and v == self.getfieldval(k) - for k, v in six.iteritems(fval)): - return cls + try: + if all(v == self.getfieldval(k) + for k, v in six.iteritems(fval)): + return cls + except AttributeError: + pass return self.default_payload_class(payload) def default_payload_class(self, payload): @@ -924,19 +937,25 @@ def __iterlen__(self): six.iteritems(self.overloaded_fields)) if isinstance(val, VolatileValue)] + list(self.fields) length = 1 + + def is_valid_gen_tuple(x): + if not isinstance(x, tuple): + return False + return len(x) == 2 and all(isinstance(z, int) for z in x) + for field in fields: fld, val = self.getfield_and_val(field) if hasattr(val, "__iterlen__"): length *= val.__iterlen__() - elif isinstance(val, tuple) and len(val) == 2 and all(hasattr(z, "__int__") for z in val): # noqa: E501 - length *= (val[1] - val[0]) + elif is_valid_gen_tuple(val): + length *= (val[1] - val[0] + 1) elif isinstance(val, list) and not fld.islist: len2 = 0 for x in val: if hasattr(x, "__iterlen__"): len2 += x.__iterlen__() - elif isinstance(x, tuple) and len(x) == 2 and all(hasattr(z, "__int__") for z in x): # noqa: E501 - len2 += (x[1] - x[0]) + elif is_valid_gen_tuple(x): + len2 += (x[1] - x[0] + 1) elif isinstance(x, list): len2 += len(x) else: diff --git a/test/regression.uts b/test/regression.uts index 4f6f7c3184d..6f35a28361c 100644 --- a/test/regression.uts +++ b/test/regression.uts @@ -10706,15 +10706,6 @@ assert not any(getattr(p1.flags | p2.flags, f) for f in 'FRPECN') assert TCP(flags="SA").flags & TCP(flags="S").flags == TCP(flags="S").flags assert TCP(flags="SA").flags | TCP(flags="S").flags == TCP(flags="SA").flags -= Using tuples and lists as flag values -~ IP TCP - -plist = PacketList(list(IP()/TCP(flags=(0, 2**9 - 1)))) -assert [p[TCP].flags for p in plist] == [x for x in range(512)] - -plist = PacketList(list(IP()/TCP(flags=["S", "SA", "A"]))) -assert [p[TCP].flags for p in plist] == [2, 18, 16] - ############ ############ From ee21f2bc44c3f6a32c6bfc0bf1999e8f43299bfb Mon Sep 17 00:00:00 2001 From: gpotter2 Date: Sat, 1 Jun 2019 02:09:56 +0200 Subject: [PATCH 2/2] Improve cache-copy performances --- scapy/packet.py | 8 ++++++-- scapy/volatile.py | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/scapy/packet.py b/scapy/packet.py index 7a655c3d94d..d839c390491 100644 --- a/scapy/packet.py +++ b/scapy/packet.py @@ -204,8 +204,12 @@ def do_init_cached_fields(self): # Deepcopy default references for fname in Packet.class_default_fields_ref[cls_name]: - value = copy.deepcopy(self.default_fields[fname]) - setattr(self, fname, value) + value = self.default_fields[fname] + try: + self.fields[fname] = value.copy() + except AttributeError: + # Python 2.7 - list only + self.fields[fname] = value[:] def prepare_cached_fields(self, flist): """ diff --git a/scapy/volatile.py b/scapy/volatile.py index e96a875cae5..837b38a0bd5 100644 --- a/scapy/volatile.py +++ b/scapy/volatile.py @@ -10,6 +10,7 @@ """ from __future__ import absolute_import +import copy import random import time import math @@ -104,6 +105,9 @@ def __bytes__(self): def __len__(self): return len(self._fix()) + def copy(self): + return copy.copy(self) + def _fix(self): return None