diff --git a/scapy/layers/dot11.py b/scapy/layers/dot11.py index 397d4ff8d52..ab18230a95c 100644 --- a/scapy/layers/dot11.py +++ b/scapy/layers/dot11.py @@ -247,6 +247,11 @@ def guess_payload_class(self, pay): class RadioTap(Packet): name = "RadioTap dummy" + deprecated_fields = { + "Channel": ("ChannelFrequency", "2.4.3"), + "ChannelFlags2": ("ChannelPlusFlags", "2.4.3"), + "ChannelNumber": ("ChannelPlusNumber", "2.4.3"), + } fields_desc = [ ByteField('version', 0), ByteField('pad', 0), @@ -278,7 +283,7 @@ class RadioTap(Packet): # Channel ConditionalField( _RadiotapReversePadField( - LEShortField("Channel", 0) + LEShortField("ChannelFrequency", 0) ), lambda pkt: pkt.present and pkt.present.Channel), ConditionalField( @@ -323,14 +328,14 @@ class RadioTap(Packet): # ChannelPlus ConditionalField( _RadiotapReversePadField( - FlagsField("ChannelFlags2", None, -32, _rt_channelflags2) + FlagsField("ChannelPlusFlags", None, -32, _rt_channelflags2) ), lambda pkt: pkt.present and pkt.present.ChannelPlus), ConditionalField( - LEShortField("ChannelFrequency", 0), + LEShortField("ChannelPlusFrequency", 0), lambda pkt: pkt.present and pkt.present.ChannelPlus), ConditionalField( - ByteField("ChannelNumber", 0), + ByteField("ChannelPlusNumber", 0), lambda pkt: pkt.present and pkt.present.ChannelPlus), # MCS ConditionalField( diff --git a/scapy/main.py b/scapy/main.py index 433a465b435..371f73b8389 100644 --- a/scapy/main.py +++ b/scapy/main.py @@ -17,10 +17,11 @@ import gzip import glob import importlib +import io import logging -from random import choice import types -import io +import warnings +from random import choice # Never add any global import, in main.py, that would trigger a warning message # noqa: E501 # before the console handlers gets added in interact() @@ -83,7 +84,11 @@ def _read_config_file(cf, _globals=globals(), _locals=locals(), interactive=True """ log_loading.debug("Loading config file [%s]", cf) try: - exec(compile(open(cf).read(), cf, 'exec'), _globals, _locals) + with open(cf) as cfgf: + exec( + compile(cfgf.read(), cf, 'exec'), + _globals, _locals + ) except IOError as e: if interactive: raise @@ -473,6 +478,9 @@ def interact(mydict=None, argv=None, mybanner=None, loglevel=logging.INFO): ) log_scapy.addHandler(console_handler) + # We're in interactive mode, let's throw the DeprecationWarnings + warnings.simplefilter("always") + from scapy.config import conf conf.interactive = True conf.color_theme = DefaultTheme() diff --git a/scapy/packet.py b/scapy/packet.py index c2596480cda..1cfe85c5894 100644 --- a/scapy/packet.py +++ b/scapy/packet.py @@ -14,6 +14,7 @@ import itertools import copy import types +import warnings from scapy.fields import StrField, ConditionalField, Emph, PacketListField, \ BitField, MultiEnumField, EnumField, FlagsField, MultipleTypeField @@ -51,8 +52,9 @@ def __repr__(self): class Packet(six.with_metaclass(Packet_metaclass, BasePacket, _CanvasDumpExtended)): __slots__ = [ - "time", "sent_time", "name", "default_fields", - "overload_fields", "overloaded_fields", "fields", "fieldtype", + "time", "sent_time", "name", + "default_fields", "fields", "fieldtype", + "overload_fields", "overloaded_fields", "packetfields", "original", "explicit", "raw_packet_cache", "raw_packet_cache_fields", "_pkt", "post_transforms", @@ -70,6 +72,7 @@ class Packet(six.with_metaclass(Packet_metaclass, BasePacket, ] name = None fields_desc = [] + deprecated_fields = {} overload_fields = {} payload_guess = [] show_indent = 1 @@ -155,7 +158,13 @@ def __init__(self, _pkt=b"", post_transform=None, _internal=0, _underlayer=None, continue self.fields[fname] = self.get_field(fname).any2i(self, value) # The remaining fields are unknown - for fname, _ in fields: + for fname in fields: + if fname in self.deprecated_fields: + # Resolve deprecated fields + value = fields[fname] + fname = self._resolve_alias(fname) + self.fields[fname] = self.get_field(fname).any2i(self, value) + continue raise AttributeError(fname) if isinstance(post_transform, list): self.post_transforms = post_transform @@ -307,7 +316,18 @@ def copy(self): clone.time = self.time return clone + def _resolve_alias(self, attr): + new_attr, version = self.deprecated_fields[attr] + warnings.warn( + "%s has been deprecated in favor of %s since %s !" % ( + attr, new_attr, version + ), DeprecationWarning + ) + return new_attr + def getfieldval(self, attr): + if self.deprecated_fields and attr in self.deprecated_fields: + attr = self._resolve_alias(attr) if attr in self.fields: return self.fields[attr] if attr in self.overloaded_fields: @@ -317,6 +337,8 @@ def getfieldval(self, attr): return self.payload.getfieldval(attr) def getfield_and_val(self, attr): + if self.deprecated_fields and attr in self.deprecated_fields: + attr = self._resolve_alias(attr) if attr in self.fields: return self.get_field(attr), self.fields[attr] if attr in self.overloaded_fields: @@ -334,6 +356,8 @@ def __getattr__(self, attr): return v def setfieldval(self, attr, val): + if self.deprecated_fields and attr in self.deprecated_fields: + attr = self._resolve_alias(attr) if attr in self.default_fields: fld = self.get_field(attr) if fld is None: diff --git a/test/fields.uts b/test/fields.uts index 0659b0e5073..87e0d630b3f 100644 --- a/test/fields.uts +++ b/test/fields.uts @@ -1809,6 +1809,37 @@ r = m.m2i(None, data_129["str_with_fx"]) assert(r == data_129["extended"]) +############ +############ ++ Deprecated fields in Packet +~ deprecated + += Field Deprecation test + +class TestPacket(Packet): + fields_desc = [ + ByteField("a", 0), + LEShortField("b", 15), + ] + deprecated_fields = { + "dpr": ("a", "1.0"), + "B": ("b", "1.0"), + } + +pkt = TestPacket(a=2, B=3) +assert pkt.B == 3 +assert pkt.b == 3 +assert pkt.a == 2 + +import warnings + +with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + assert pkt.dpr == 2 + assert len(w) == 1 + assert issubclass(w[-1].category, DeprecationWarning) + + ############ ############ + FCSField diff --git a/test/regression.uts b/test/regression.uts index 07c08b5efc4..bfcb5f141cd 100644 --- a/test/regression.uts +++ b/test/regression.uts @@ -1076,6 +1076,7 @@ r = RadioTap(data) r = RadioTap(raw(r)) assert r.dBm_AntSignal == -59 assert r.ChannelFrequency == 5785 +assert r.ChannelPlusFrequency == 5785 assert r.present == 3410027 assert r.A_MPDU_ref == 2821 assert r.KnownVHT == 511