Skip to content
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
14 changes: 8 additions & 6 deletions scapy/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -1590,9 +1590,11 @@ def getfield(self,
# type: (...) -> Tuple[bytes, K]
i = self.m2i(pkt, s)
remain = b""
if conf.padding_layer in i:
r = i[conf.padding_layer]
del r.underlayer.payload
# Dissection always appends Padding last, so checking the topmost
# layer avoids a full recursive haslayer()+getlayer() lookup.
r = i.lastlayer()
if isinstance(r, conf.padding_layer):
del r.underlayer.payload # type: ignore
remain = r.load
return remain, i # type: ignore

Expand Down Expand Up @@ -1835,10 +1837,10 @@ def getfield(self, pkt, s):
p = conf.raw_layer(load=remain)
remain = b""
else:
if conf.padding_layer in p:
pad = p[conf.padding_layer]
pad = p.lastlayer()
if isinstance(pad, conf.padding_layer):
remain = pad.load
del pad.underlayer.payload
del pad.underlayer.payload # type: ignore
if self.next_cls_cb is not None:
cls = self.next_cls_cb(pkt, lst, p, remain)
if cls is not None:
Expand Down
84 changes: 55 additions & 29 deletions scapy/packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,29 @@ class Packet(
"comments",
"process_information"
]
name = None
# Types of the __slots__ above: __init__ sets them through
# object.__setattr__, which leaves nowhere to put an inline type comment.
time: Union[EDecimal, float]
sent_time: Union[EDecimal, float, None]
default_fields: Dict[str, Any]
fields: Dict[str, Any]
fieldtype: Dict[str, AnyField]
overloaded_fields: Dict[str, Any]
packetfields: List[AnyField]
original: bytes
explicit: int
raw_packet_cache: Optional[bytes]
raw_packet_cache_fields: Optional[Dict[str, Any]]
stop_dissection_after: Optional[Type['Packet']]
payload: 'Packet'
underlayer: Optional['Packet']
parent: Optional['Packet']
direction: Optional[int]
sniffed_on: Optional[_GlobInterfaceType]
wirelen: Optional[int]
comments: Optional[List[bytes]]
process_information: Optional[Dict[str, Any]]
name = None # type: Optional[str]
fields_desc = [] # type: ClassVar[List[AnyField]]
deprecated_fields = {} # type: Dict[str, Tuple[str, str]]
overload_fields = {} # type: Dict[Type[Packet], Dict[str, Any]]
Expand Down Expand Up @@ -155,33 +177,36 @@ def __init__(self,
**fields # type: Any
):
# type: (...) -> None
self.time = 0.0 if _internal else time.time() # type: Union[EDecimal, float]
self.sent_time = None # type: Union[EDecimal, float, None]
self.name = (self.__class__.__name__
if self._name is None else
self._name)
self.default_fields = {} # type: Dict[str, Any]
self.overload_fields = self._overload_fields
self.overloaded_fields = {} # type: Dict[str, Any]
self.fields = {} # type: Dict[str, Any]
self.fieldtype = {} # type: Dict[str, AnyField]
self.packetfields = [] # type: List[AnyField]
self.payload = NoPayload() # type: Packet
# Every attribute set below is a __slots__ member, so bypass
# __setattr__: resolving field names there costs more than the
# assignment itself, and this runs for every dissected layer.
_set = object.__setattr__
_set(self, "time", 0.0 if _internal else time.time())
_set(self, "sent_time", None)
_set(self, "name", self.__class__.__name__
if self._name is None else self._name)
_set(self, "default_fields", {})
_set(self, "overload_fields", self._overload_fields)
_set(self, "overloaded_fields", {})
_set(self, "fields", {})
_set(self, "fieldtype", {})
_set(self, "packetfields", [])
_set(self, "payload", NoPayload())
self.init_fields(bool(_pkt))
self.underlayer = _underlayer
self.parent = _parent
_set(self, "underlayer", _underlayer)
_set(self, "parent", _parent)
if isinstance(_pkt, bytearray):
_pkt = bytes(_pkt)
self.original = _pkt
self.explicit = 0
self.raw_packet_cache = None # type: Optional[bytes]
self.raw_packet_cache_fields = None # type: Optional[Dict[str, Any]] # noqa: E501
self.wirelen = None # type: Optional[int]
self.direction = None # type: Optional[int]
self.sniffed_on = None # type: Optional[_GlobInterfaceType]
self.comments = None # type: Optional[List[bytes]]
self.process_information = None # type: Optional[Dict[str, Any]]
self.stop_dissection_after = stop_dissection_after
_set(self, "original", _pkt)
_set(self, "explicit", 0)
_set(self, "raw_packet_cache", None)
_set(self, "raw_packet_cache_fields", None)
_set(self, "wirelen", None)
_set(self, "direction", None)
_set(self, "sniffed_on", None)
_set(self, "comments", None)
_set(self, "process_information", None)
_set(self, "stop_dissection_after", stop_dissection_after)
if _pkt:
self.dissect(_pkt)
if not _internal:
Expand Down Expand Up @@ -536,11 +561,11 @@ 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]
return self.fieldtype[attr], self.fields[attr]
if attr in self.overloaded_fields:
return self.get_field(attr), self.overloaded_fields[attr]
return self.fieldtype[attr], self.overloaded_fields[attr]
if attr in self.default_fields:
return self.get_field(attr), self.default_fields[attr]
return self.fieldtype[attr], self.default_fields[attr]
raise ValueError

def __getattr__(self, attr):
Expand Down Expand Up @@ -726,7 +751,8 @@ def copy_fields_dict(self, fields):
# type: (_T) -> _T
if fields is None:
return None
return {fname: self.copy_field_value(fname, fval)
fieldtype = self.fieldtype
return {fname: fieldtype[fname].do_copy(fval)
for fname, fval in fields.items()}

def _raw_packet_cache_field_value(self, fld, val, copy=False):
Expand Down
Loading