Skip to content
Merged
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
18 changes: 16 additions & 2 deletions doc/scapy/_ext/scapy_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"""

import subprocess
from scapy.packet import Packet, _pkt_ls
import os
from scapy.packet import Packet, _pkt_ls, rfc

from sphinx.ext.autodoc import AttributeDocumenter

Expand Down Expand Up @@ -71,6 +72,18 @@ def get_fields_desc(obj):
output.insert(0, ".. table:: %s fields" % obj.__name__)
output.insert(1, " :widths: grid")
output.insert(2, " ")
# Add RFC-like graph
try:
graph = list(tab(rfc(obj, ret=True).split("\n")))
except AttributeError:
return output
s = "Display RFC-like schema"
graph.insert(0, ".. raw:: html")
graph.insert(1, "")
graph.insert(2, " <details><summary>%s</summary><code><pre>" % s)
graph.append(" </pre></code></details>")
graph.append("")
return graph + output
return output

# Documenter
Expand Down Expand Up @@ -125,7 +138,8 @@ def call_parent():

def builder_inited_handler(app):
"""Generate API tree"""
subprocess.call(['tox', '-e', 'apitree'])
if int(os.environ.get("SCAPY_APITREE", True)):
subprocess.call(['tox', '-e', 'apitree'])


def setup(app):
Expand Down
1 change: 0 additions & 1 deletion doc/scapy/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.coverage',
'sphinx.ext.napoleon',
'scapy_doc'
]
Expand Down
16 changes: 9 additions & 7 deletions doc/scapy/sphinx_apidoc_postprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,16 @@
if f.endswith("scapy.rst"):
content[0] = "Scapy API reference\n"
content[1] = "=" * (len(content[0]) - 1) + "\n"
for i, line in enumerate(content):
if "toctree" in line:
content[i] = line + " :titlesonly:\n"
_e = True
# File / module file
for name in ["package", "module"]:
if name in content[0]:
content[0] = content[0].replace(" " + name, "")
content[1] = "=" * (len(content[0]) - 1) + "\n"
_e = True
else:
# File / module file
for name in ["package", "module"]:
if name in content[0]:
content[0] = content[0].replace(" " + name, "")
content[1] = "=" * (len(content[0]) - 1) + "\n"
_e = True
if _e:
print("Post-processed '%s'" % f)
with open(f, "w") as fd:
Expand Down
2 changes: 1 addition & 1 deletion scapy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
Scapy: create, send, sniff, dissect and manipulate network packets.

Usable either from an interactive console or as a Python library.
http://www.secdev.org/projects/scapy
https://scapy.net
"""

import os
Expand Down
3 changes: 3 additions & 0 deletions scapy/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -1534,6 +1534,7 @@ def __init__(self, name, default, size):
Field.__init__(self, name, default)
self.rev = size < 0
self.size = abs(size)
self.sz = self.size / 8.

def reverse(self, val):
if self.size == 16:
Expand Down Expand Up @@ -1739,6 +1740,7 @@ def __init__(self, name, default, size, enum):
_EnumField.__init__(self, name, default, enum)
self.rev = size < 0
self.size = abs(size)
self.sz = self.size / 8.

def any2i(self, pkt, x):
return _EnumField.any2i(self, pkt, x)
Expand Down Expand Up @@ -1849,6 +1851,7 @@ def __init__(self, name, default, size, enum, depends_on):
_MultiEnumField.__init__(self, name, default, enum, depends_on)
self.rev = size < 0
self.size = abs(size)
self.sz = self.size / 8.

def any2i(self, pkt, x):
return _MultiEnumField.any2i(self, pkt, x)
Expand Down
2 changes: 1 addition & 1 deletion scapy/layers/ipsec.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #
# General Public License for more details. #
#############################################################################
"""
r"""
IPsec layer
===========

Expand Down
14 changes: 9 additions & 5 deletions scapy/layers/netflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,25 @@
"""
Cisco NetFlow protocol v1, v5, v9 and v10 (IPFix)

HowTo dissect NetflowV9/10 (IPFix) packets:
HowTo dissect NetflowV9/10 (IPFix) packets

# From a pcap / list of packets

Using sniff and sessions:
>>> sniff(offline=open("my_great_pcap.pcap", "rb"), session=NetflowSession)
Using sniff and sessions::

>>> sniff(offline=open("my_great_pcap.pcap", "rb"), session=NetflowSession)

Using the netflowv9_defragment/ipfix_defragment commands:

- get a list of packets containing NetflowV9/10 packets
- call `netflowv9_defragment(plist)` to defragment the list

(ipfix_defragment is an alias for netflowv9_defragment)

# Live / on-the-flow / other: use NetflowSession
>>> sniff(session=NetflowSession, prn=[...])
# Live / on-the-flow / other: use NetflowSession::

>>> sniff(session=NetflowSession, prn=[...])

"""

import socket
Expand Down
6 changes: 6 additions & 0 deletions scapy/layers/rtp.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@

"""
RTP (Real-time Transport Protocol).

Remember to use::

bind_layers(UDP, RTP, dport=XXX)

To register the port you are using
"""

from scapy.packet import Packet, bind_layers
Expand Down
104 changes: 104 additions & 0 deletions scapy/packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -2107,6 +2107,110 @@ def ls(obj=None, case_sensitive=False, verbose=False):
print("Not a packet class or name. Type 'ls()' to list packet classes.") # noqa: E501


@conf.commands.register
def rfc(cls, ret=False, legend=True):
"""
Generate an RFC-like representation of a packet def.

:param cls: the Packet class
:param ret: return the result instead of printing (def. False)
:param legend: show text under the diagram (default True)

Ex::

>>> rfc(Ether)

"""
if not issubclass(cls, Packet):
raise TypeError("Packet class expected")
cur_len = 0
cur_line = []
lines = []
# Get the size (width) that a field will take
# when formatted, from its length in bits
clsize = lambda x: 2 * x - 1
ident = 0 # Fields UUID
# Generate packet groups
for f in cls.fields_desc:
flen = int(f.sz * 8)
cur_len += flen
ident += 1
# Fancy field name
fname = f.name.upper().replace("_", " ")
# The field might exceed the current line or
# take more than one line. Copy it as required
while True:
over = max(0, cur_len - 32) # Exceed
len1 = clsize(flen - over) # What fits
cur_line.append((fname[:len1], len1, ident))
if cur_len >= 32:
# Current line is full. start a new line
lines.append(cur_line)
cur_len = flen = over
fname = "" # do not repeat the field
cur_line = []
if not over:
# there is no data left
break
else:
# End of the field
break
# Add the last line if un-finished
if cur_line:
lines.append(cur_line)
# Calculate separations between lines
seps = []
seps.append("+-" * 32 + "+\n")
for i in range(len(lines) - 1):
# Start with a full line
sep = "+-" * 32 + "+\n"
# Get the line above and below the current
# separation
above, below = lines[i], lines[i + 1]
# The last field of above is shared with below
if above[-1][2] == below[0][2]:
# where the field in "above" starts
pos_above = sum(x[1] for x in above[:-1])
# where the field in "below" ends
pos_below = below[0][1]
if pos_above < pos_below:
# they are overlapping.
# Now crop the space between those pos
# and fill it with " "
pos_above = pos_above + pos_above % 2
sep = (
sep[:1 + pos_above] +
" " * (pos_below - pos_above) +
sep[1 + pos_below:]
)
# line is complete
seps.append(sep)
# Graph
result = ""
# Bytes markers
result += " " + (" " * 19).join(
str(x) for x in range(4)
) + "\n"
# Bits markers
result += " " + " ".join(
str(x % 10) for x in range(32)
) + "\n"
# Add fields and their separations
for line, sep in zip(lines, seps):
result += sep
for elt, flen, _ in line:
result += "|" + elt.center(flen, " ")
result += "|\n"
result += "+-" * (cur_len or 32) + "+\n"
# Annotate with the figure name
if legend:
result += "\n" + ("Fig. " + cls.__name__).center(66, " ")
# return if asked for, else print
if ret:
return result
print(result)


#############
# Fuzzing #
#############
Expand Down
Loading