Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
28 changes: 24 additions & 4 deletions scapy/packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class Packet(
"direction", "sniffed_on",
# handle snaplen Vs real length
"wirelen",
"comment",
"comments",
"process_information"
]
name = None
Expand Down Expand Up @@ -179,7 +179,7 @@ def __init__(self,
self.wirelen = None # type: Optional[int]
self.direction = None # type: Optional[int]
self.sniffed_on = None # type: Optional[_GlobInterfaceType]
self.comment = None # type: Optional[bytes]
self.comments = None # type: Optional[List[bytes]]
self.process_information = None # type: Optional[Dict[str, Any]]
self.stop_dissection_after = stop_dissection_after
if _pkt:
Expand Down Expand Up @@ -223,6 +223,26 @@ def __init__(self,
Optional[bytes],
]

@property
def comment(self):
# type: () -> Optional[bytes]
"""Get the comment of the packet"""
if self.comments is not None and len(self.comments) > 0:
Comment thread
bkayranci marked this conversation as resolved.
Outdated
return self.comments[-1]
Comment thread
bkayranci marked this conversation as resolved.
Outdated
return None

@comment.setter
def comment(self, value):
# type: (Optional[bytes]) -> None
"""
Set the comment of the packet.
If value is None, it will clear the comments.
"""
if value is not None:
self.comments = [value]
else:
self.comments = None
Comment thread
gpotter2 marked this conversation as resolved.

def __reduce__(self):
# type: () -> Tuple[Type[Packet], Tuple[bytes], Packet._PickleType]
"""Used by pickling methods"""
Expand Down Expand Up @@ -435,7 +455,7 @@ def copy(self) -> Self:
clone.payload = self.payload.copy()
clone.payload.add_underlayer(clone)
clone.time = self.time
clone.comment = self.comment
clone.comments = self.comments
clone.direction = self.direction
clone.sniffed_on = self.sniffed_on
return clone
Expand Down Expand Up @@ -1145,7 +1165,7 @@ def clone_with(self, payload=None, **kargs):
self.raw_packet_cache_fields
)
pkt.wirelen = self.wirelen
pkt.comment = self.comment
pkt.comments = self.comments
pkt.sniffed_on = self.sniffed_on
pkt.direction = self.direction
if payload is not None:
Expand Down
65 changes: 45 additions & 20 deletions scapy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1649,10 +1649,10 @@ class RawPcapNgReader(RawPcapReader):
["linktype", "tsresol",
"tshigh", "tslow", "wirelen",
"comment", "ifname", "direction",
Comment thread
gpotter2 marked this conversation as resolved.
"process_information"])
"process_information", "comments", ])

def __init__(self, filename, fdesc=None, magic=None): # type: ignore
# type: (str, IO[bytes], bytes) -> None
def __init__(self, filename, fdesc=None, magic=None, comments=None): # type: ignore
Comment thread
gpotter2 marked this conversation as resolved.
Outdated
# type: (str, IO[bytes], bytes, List[bytes]) -> None
self.filename = filename
self.f = fdesc
# A list of (linktype, snaplen, tsresol); will be populated by IDBs.
Expand All @@ -1675,6 +1675,7 @@ def __init__(self, filename, fdesc=None, magic=None): # type: ignore
}
self.endian = "!" # Will be overwritten by first SHB
self.process_information = [] # type: List[Dict[str, Any]]
self.comments = comments

if magic != b"\x0a\x0d\x0d\x0a": # PcapNg:
raise Scapy_Exception(
Expand Down Expand Up @@ -1792,8 +1793,8 @@ def _read_packet(self, size=MTU): # type: ignore
return res

def _read_options(self, options):
# type: (bytes) -> Dict[int, bytes]
opts = dict()
# type: (bytes) -> Dict[int, Union[bytes, List[bytes]]]
opts = dict() # type: Dict[int, Union[bytes, List[bytes]]]
while len(options) >= 4:
try:
code, length = struct.unpack(self.endian + "HH", options[:4])
Expand All @@ -1802,7 +1803,12 @@ def _read_options(self, options):
"%d !" % len(options))
raise EOFError
if code != 0 and 4 + length <= len(options):
opts[code] = options[4:4 + length]
if code in [1, 2988, 2989, 19372, 19373]:
Comment thread
gpotter2 marked this conversation as resolved.
Comment thread
gpotter2 marked this conversation as resolved.
if code not in opts:
opts[code] = []
cast(List[bytes], opts[code]).append(options[4:4 + length])
Comment thread
bkayranci marked this conversation as resolved.
Outdated
else:
opts[code] = options[4:4 + length]
if code == 0:
if length != 0:
warning("PcapNg: invalid option "
Expand All @@ -1821,6 +1827,10 @@ def _read_block_idb(self, block, _):
options_raw = self._read_options(block[8:])
options = self.default_options.copy() # type: Dict[str, Any]
for c, v in options_raw.items():
if isinstance(v, list):
# If the option is a list, we take the last value
# (as per pcapng spec)
Comment thread
gpotter2 marked this conversation as resolved.
Outdated
v = v[-1]
if c == 9:
length = len(v)
if length == 1:
Expand Down Expand Up @@ -1877,6 +1887,7 @@ def _read_block_epb(self, block, size):
process_information = {}
for code, value in options.items():
if code in [0x8001, 0x8003]: # PCAPNG_EPB_PIB_INDEX, PCAPNG_EPB_E_PIB_INDEX
value = cast(bytes, value)
Comment thread
bkayranci marked this conversation as resolved.
Outdated
try:
proc_index = struct.unpack(self.endian + "I", value)[0]
except struct.error:
Expand All @@ -1890,9 +1901,11 @@ def _read_block_epb(self, block, size):
warning("PcapNg: EPB invalid process information index "
"(%d/%d) !" % (proc_index, len(self.process_information)))

comment = options.get(1, None)
comments = options.get(1, None)
comment = comments[-1] if comments is not None and len(comments) > 0 else None
epb_flags_raw = options.get(2, None)
if epb_flags_raw:
epb_flags_raw = cast(bytes, epb_flags_raw)
Comment thread
bkayranci marked this conversation as resolved.
Outdated
try:
epb_flags, = struct.unpack(self.endian + "I", epb_flags_raw)
except struct.error:
Expand All @@ -1916,7 +1929,8 @@ def _read_block_epb(self, block, size):
comment=comment,
ifname=ifname,
direction=direction,
process_information=process_information))
process_information=process_information,
comments=comments))

def _read_block_spb(self, block, size):
# type: (bytes, int) -> Tuple[bytes, RawPcapNgReader.PacketMetadata]
Expand All @@ -1943,7 +1957,8 @@ def _read_block_spb(self, block, size):
comment=None,
ifname=None,
direction=None,
process_information={}))
process_information={},
comments=None))

def _read_block_pkt(self, block, size):
# type: (bytes, int) -> Tuple[bytes, RawPcapNgReader.PacketMetadata]
Expand All @@ -1967,7 +1982,8 @@ def _read_block_pkt(self, block, size):
comment=None,
ifname=None,
direction=None,
process_information={}))
process_information={},
comments=None))

def _read_block_dsb(self, block, size):
# type: (bytes, int) -> None
Expand Down Expand Up @@ -2038,6 +2054,7 @@ def _read_block_pib(self, block, _):
# Get Options
options = self._read_options(block)
for code, value in options.items():
value = cast(bytes, value)
Comment thread
bkayranci marked this conversation as resolved.
Outdated
if code == 2:
process_information["name"] = value.decode("ascii", "backslashreplace")
elif code == 4:
Expand Down Expand Up @@ -2068,7 +2085,7 @@ def read_packet(self, size=MTU, **kwargs):
rp = super(PcapNgReader, self)._read_packet(size=size)
if rp is None:
raise EOFError
s, (linktype, tsresol, tshigh, tslow, wirelen, comment, ifname, direction, process_information) = rp # noqa: E501
s, (linktype, tsresol, tshigh, tslow, wirelen, comment, ifname, direction, process_information, comments) = rp # noqa: E501
try:
cls = conf.l2types.num2layer[linktype] # type: Type[Packet]
p = cls(s, **kwargs) # type: Packet
Expand All @@ -2084,7 +2101,9 @@ def read_packet(self, size=MTU, **kwargs):
if tshigh is not None:
p.time = EDecimal((tshigh << 32) + tslow) / tsresol
p.wirelen = wirelen
p.comment = comment
p.comments = comments
if p.comments is None:
p.comment = comment
Comment thread
gpotter2 marked this conversation as resolved.
Outdated
p.direction = direction
p.process_information = process_information.copy()
if ifname is not None:
Expand Down Expand Up @@ -2113,6 +2132,7 @@ def _write_packet(self,
comment=None, # type: Optional[bytes]
ifname=None, # type: Optional[bytes]
direction=None, # type: Optional[int]
comments=None, # type: Optional[List[bytes]]
):
# type: (...) -> None
raise NotImplementedError
Expand Down Expand Up @@ -2194,6 +2214,7 @@ def write_packet(self,
wirelen = caplen

comment = getattr(packet, "comment", None)
Comment thread
gpotter2 marked this conversation as resolved.
Outdated
comments = getattr(packet, "comments", None)
ifname = getattr(packet, "sniffed_on", None)
direction = getattr(packet, "direction", None)
if not isinstance(packet, bytes):
Expand All @@ -2211,7 +2232,8 @@ def write_packet(self,
comment=comment,
Comment thread
gpotter2 marked this conversation as resolved.
Outdated
ifname=ifname,
direction=direction,
linktype=linktype
linktype=linktype,
comments=comments,
)


Expand Down Expand Up @@ -2366,6 +2388,7 @@ def _write_packet(self,
comment=None, # type: Optional[bytes]
Comment thread
gpotter2 marked this conversation as resolved.
Outdated
ifname=None, # type: Optional[bytes]
direction=None, # type: Optional[int]
comments=None, # type: Optional[List[bytes]]
):
# type: (...) -> None
"""
Expand Down Expand Up @@ -2541,7 +2564,7 @@ def _write_block_epb(self,
timestamp=None, # type: Optional[Union[EDecimal, float]] # noqa: E501
caplen=None, # type: Optional[int]
orglen=None, # type: Optional[int]
comment=None, # type: Optional[bytes]
comments=None, # type: Optional[List[bytes]]
flags=None, # type: Optional[int]
):
# type: (...) -> None
Expand Down Expand Up @@ -2576,11 +2599,12 @@ def _write_block_epb(self,

# Options
opts = b''
if comment is not None:
comment = bytes_encode(comment)
opts += struct.pack(self.endian + "HH", 1, len(comment))
# Pad Option Value to 32 bits
opts += self._add_padding(comment)
if comments is not None and len(comments) > 0:
Comment thread
bkayranci marked this conversation as resolved.
Outdated
for c in comments:
comment = bytes_encode(c)
opts += struct.pack(self.endian + "HH", 1, len(comment))
# Pad Option Value to 32 bits
opts += self._add_padding(comment)
if type(flags) == int:
opts += struct.pack(self.endian + "HH", 2, 4)
opts += struct.pack(self.endian + "I", flags)
Expand All @@ -2600,6 +2624,7 @@ def _write_packet(self, # type: ignore
comment=None, # type: Optional[bytes]
Comment thread
gpotter2 marked this conversation as resolved.
Outdated
ifname=None, # type: Optional[bytes]
direction=None, # type: Optional[int]
comments=None, # type: Optional[List[bytes]]
):
# type: (...) -> None
"""
Expand Down Expand Up @@ -2655,7 +2680,7 @@ def _write_packet(self, # type: ignore
flags = None

self._write_block_epb(packet, timestamp=sec, caplen=caplen,
orglen=wirelen, comment=comment, ifid=ifid, flags=flags)
orglen=wirelen, comments=comments, ifid=ifid, flags=flags)
if self.sync:
self.f.flush()

Expand Down
6 changes: 6 additions & 0 deletions test/regression.uts
Original file line number Diff line number Diff line change
Expand Up @@ -2250,6 +2250,12 @@ wrpcapng(tmpfile, p)
l = rdpcap(tmpfile)
assert l[0].comment == p.comment

p = Ether() / IPv6() / TCP()
p.comments = [b"Hello!", b"Scapy!", b"Pcapng!"]
wrpcapng(tmpfile, p)
l = rdpcap(tmpfile)
assert l[0].comments == p.comments

= rdpcap on fifo
~ linux
f = get_temp_file()
Expand Down