Skip to content
Draft
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
8 changes: 1 addition & 7 deletions doc/scapy.1
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ arping, tcpdump, tshark, p0f, ...
.PP
\fBScapy\fP uses the Python interpreter as a command board. That means that
you can use directly Python language (assign variables, use loops,
define functions, etc.) If you give a file a parameter when you run
\fBScapy\fP, your session (variables, functions, instances, ...) will be saved
when you leave the interpreter and restored the next time you launch
\fBScapy\fP.
define functions, etc.)
.PP
The idea is simple. Those kinds of tools do two things : sending packets
and receiving answers. That's what \fBScapy\fP does : you define a set of
Expand Down Expand Up @@ -48,9 +45,6 @@ header-less mode, also reduces verbosity.
\fB\-d\fR
increase log verbosity. Can be used many times.
.TP
\fB\-s\fR FILE
use FILE to save/load session values (variables, functions, instances, ...)
.TP
\fB\-p\fR PRESTART_FILE
use PRESTART_FILE instead of $HOME/.config/scapy/prestart.py as pre-startup file
.TP
Expand Down
53 changes: 0 additions & 53 deletions doc/scapy/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -991,59 +991,6 @@ We can reimport the produced binary string by selecting the appropriate first la
\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e
\x1f !"#$%&\'()*+,-./01234567' |>>>>

Base64
^^^^^^

Using the ``export_object()`` function, Scapy can export a base64 encoded Python data structure representing a packet::

>>> pkt
<Ether dst=00:50:56:fc:ce:50 src=00:0c:29:2b:53:19 type=0x800 |<IP version=4L
ihl=5L tos=0x0 len=84 id=0 flags=DF frag=0L ttl=64 proto=icmp chksum=0x5a7c
src=192.168.25.130 dst=4.2.2.1 options='' |<ICMP type=echo-request code=0
chksum=0x9c90 id=0x5a61 seq=0x1 |<Raw load='\xe6\xdapI\xb6\xe5\x08\x00\x08\t\n
\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f
!"#$%&\'()*+,-./01234567' |>>>>
>>> export_object(pkt)
eNplVwd4FNcRPt2dTqdTQ0JUUYwN+CgS0gkJONFEs5WxFDB+CdiI8+pupVl0d7uzRUiYtcEGG4ST
OD1OnB6nN6c4cXrvwQmk2U5xA9tgO70XMm+1rA78qdzbfTP/lDfzz7tD4WwmU1C0YiaT2Gqjaiao
bMlhCrsUSYrYoKbmcxZFXSpPiohlZikm6ltb063ZdGpNOjWQ7mhPt62hChHJWTbFvb0O/u1MD2bT
WZXXVCmi9pihUqI3FHdEQslriiVfWFTVT9VYpog6Q7fsjG0qRWtQNwsW1fRTrUg4xZxq5pUx1aS6
...

The output above can be reimported back into Scapy using ``import_object()``::

>>> new_pkt = import_object()
eNplVwd4FNcRPt2dTqdTQ0JUUYwN+CgS0gkJONFEs5WxFDB+CdiI8+pupVl0d7uzRUiYtcEGG4ST
OD1OnB6nN6c4cXrvwQmk2U5xA9tgO70XMm+1rA78qdzbfTP/lDfzz7tD4WwmU1C0YiaT2Gqjaiao
bMlhCrsUSYrYoKbmcxZFXSpPiohlZikm6ltb063ZdGpNOjWQ7mhPt62hChHJWTbFvb0O/u1MD2bT
WZXXVCmi9pihUqI3FHdEQslriiVfWFTVT9VYpog6Q7fsjG0qRWtQNwsW1fRTrUg4xZxq5pUx1aS6
...
>>> new_pkt
<Ether dst=00:50:56:fc:ce:50 src=00:0c:29:2b:53:19 type=0x800 |<IP version=4L
ihl=5L tos=0x0 len=84 id=0 flags=DF frag=0L ttl=64 proto=icmp chksum=0x5a7c
src=192.168.25.130 dst=4.2.2.1 options='' |<ICMP type=echo-request code=0
chksum=0x9c90 id=0x5a61 seq=0x1 |<Raw load='\xe6\xdapI\xb6\xe5\x08\x00\x08\t\n
\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f
!"#$%&\'()*+,-./01234567' |>>>>

Sessions
^^^^^^^^

At last Scapy is capable of saving all session variables using the ``save_session()`` function:

>>> dir()
['__builtins__', 'conf', 'new_pkt', 'pkt', 'pkt_export', 'pkt_hex', 'pkt_raw', 'pkts']
>>> save_session("session.scapy")

Next time you start Scapy you can load the previous saved session using the ``load_session()`` command::

>>> dir()
['__builtins__', 'conf']
>>> load_session("session.scapy")
>>> dir()
['__builtins__', 'conf', 'new_pkt', 'pkt', 'pkt_export', 'pkt_hex', 'pkt_raw', 'pkts']


Making tables
-------------

Expand Down
2 changes: 1 addition & 1 deletion scapy/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ def scapy_data_cache(name):
if SCAPY_CACHE_FOLDER is None:
# Cannot cache.
return lambda x: x
cachepath = SCAPY_CACHE_FOLDER / name
cachepath = SCAPY_CACHE_FOLDER / (name + ".pickle")

def _cached_loader(func, name=name):
# type: (DecoratorCallable, str) -> DecoratorCallable
Expand Down
168 changes: 8 additions & 160 deletions scapy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,13 @@
import code
import getopt
import glob
import gzip
import importlib
import io
import logging
import os
import pathlib
import pickle
import shutil
import sys
import types
import warnings

from itertools import zip_longest
Expand Down Expand Up @@ -260,7 +257,7 @@ def _validate_local(k):
def _usage():
# type: () -> None
print(
"Usage: scapy.py [-s sessionfile] [-c new_startup_file] "
"Usage: scapy.py [-c new_startup_file] "
"[-p new_prestart_file] [-C] [-P] [-H]\n"
"Args:\n"
"\t-H: header-less start\n"
Expand Down Expand Up @@ -494,178 +491,35 @@ def _scapy_exts():
return res


def save_session(fname="", session=None, pickleProto=-1):
# type: (str, Optional[Dict[str, Any]], int) -> None
"""Save current Scapy session to the file specified in the fname arg.

params:
- fname: file to save the scapy session in
- session: scapy session to use. If None, the console one will be used
- pickleProto: pickle proto version (default: -1 = latest)"""
from scapy import utils
from scapy.config import conf, ConfClass
if not fname:
fname = conf.session
if not fname:
conf.session = fname = utils.get_temp_file(keep=True)
log_interactive.info("Saving session into [%s]", fname)

if not session:
if conf.interactive_shell in ["ipython", "ptipython"]:
from IPython import get_ipython
session = get_ipython().user_ns
else:
session = builtins.__dict__["scapy_session"]

if not session:
log_interactive.error("No session found ?!")
return

ignore = session.get("_scpybuiltins", [])
hard_ignore = ["scapy_session", "In", "Out", "open"]
to_be_saved = session.copy()

for k in list(to_be_saved):
i = to_be_saved[k]
if k[0] == "_":
del to_be_saved[k]
elif hasattr(i, "__module__") and i.__module__.startswith("IPython"):
del to_be_saved[k]
elif isinstance(i, ConfClass):
del to_be_saved[k]
elif k in ignore or k in hard_ignore:
del to_be_saved[k]
elif isinstance(i, (type, types.ModuleType, types.FunctionType)):
if k[0] != "_":
log_interactive.warning("[%s] (%s) can't be saved.", k, type(i))
del to_be_saved[k]
else:
try:
pickle.dumps(i)
except Exception:
log_interactive.warning("[%s] (%s) can't be saved.", k, type(i))

try:
os.rename(fname, fname + ".bak")
except OSError:
pass

f = gzip.open(fname, "wb")
pickle.dump(to_be_saved, f, pickleProto)
f.close()


def load_session(fname=None):
# type: (Optional[Union[str, None]]) -> None
"""Load current Scapy session from the file specified in the fname arg.
This will erase any existing session.

params:
- fname: file to load the scapy session from"""
from scapy.config import conf
if fname is None:
fname = conf.session
try:
s = pickle.load(gzip.open(fname, "rb"))
except IOError:
try:
s = pickle.load(open(fname, "rb"))
except IOError:
# Raise "No such file exception"
raise

scapy_session = builtins.__dict__["scapy_session"]
s.update({k: scapy_session[k] for k in scapy_session["_scpybuiltins"]})
scapy_session.clear()
scapy_session.update(s)
update_ipython_session(scapy_session)

log_loading.info("Loaded session [%s]", fname)


def update_session(fname=None):
# type: (Optional[Union[str, None]]) -> None
"""Update current Scapy session from the file specified in the fname arg.

params:
- fname: file to load the scapy session from"""
from scapy.config import conf
if fname is None:
fname = conf.session
try:
s = pickle.load(gzip.open(fname, "rb"))
except IOError:
s = pickle.load(open(fname, "rb"))
scapy_session = builtins.__dict__["scapy_session"]
scapy_session.update(s)
update_ipython_session(scapy_session)


@overload
def init_session(session_name, # type: Optional[Union[str, None]]
mydict, # type: Optional[Union[Dict[str, Any], None]]
def init_session(mydict, # type: Optional[Union[Dict[str, Any], None]]
ret, # type: Literal[True]
):
# type: (...) -> Dict[str, Any]
pass


@overload
def init_session(session_name, # type: Optional[Union[str, None]]
mydict=None, # type: Optional[Union[Dict[str, Any], None]]
def init_session(mydict=None, # type: Optional[Union[Dict[str, Any], None]]
ret=False, # type: Literal[False]
):
# type: (...) -> None
pass


def init_session(session_name, # type: Optional[Union[str, None]]
mydict=None, # type: Optional[Union[Dict[str, Any], None]]
def init_session(mydict=None, # type: Optional[Union[Dict[str, Any], None]]
ret=False, # type: bool
):
# type: (...) -> Union[Dict[str, Any], None]
from scapy.config import conf
SESSION = {} # type: Optional[Dict[str, Any]]

# Load Scapy
scapy_builtins = _scapy_builtins()

# Load exts
scapy_builtins.update(_scapy_exts())

if session_name:
try:
os.stat(session_name)
except OSError:
log_loading.info("New session [%s]", session_name)
else:
try:
try:
SESSION = pickle.load(gzip.open(session_name, "rb"))
except IOError:
SESSION = pickle.load(open(session_name, "rb"))
log_loading.info("Using existing session [%s]", session_name)
except ValueError:
msg = "Error opening Python3 pickled session on Python2 [%s]"
log_loading.error(msg, session_name)
except EOFError:
log_loading.error("Error opening session [%s]", session_name)
except AttributeError:
log_loading.error("Error opening session [%s]. "
"Attribute missing", session_name)

if SESSION:
if "conf" in SESSION:
conf.configure(SESSION["conf"])
conf.session = session_name
SESSION["conf"] = conf
else:
conf.session = session_name
else:
conf.session = session_name
SESSION = {"conf": conf}
else:
SESSION = {"conf": conf}
SESSION = {"conf": conf} # type: Dict[str, Any]

SESSION.update(scapy_builtins)
SESSION["_scpybuiltins"] = scapy_builtins.keys()
Expand All @@ -678,6 +532,7 @@ def init_session(session_name, # type: Optional[Union[str, None]]
return SESSION
return None


################
# Main #
################
Expand Down Expand Up @@ -810,8 +665,6 @@ def interact(mydict=None,
STARTUP_FILE = DEFAULT_STARTUP_FILE
PRESTART_FILE = DEFAULT_PRESTART_FILE

session_name = None

if argv is None:
argv = sys.argv

Expand All @@ -824,8 +677,6 @@ def interact(mydict=None,
conf.fancy_banner = False
conf.verb = 1
conf.logLevel = logging.WARNING
elif opt == "-s":
session_name = param
elif opt == "-c":
STARTUP_FILE = param
elif opt == "-C":
Expand Down Expand Up @@ -857,7 +708,7 @@ def interact(mydict=None,
default=DEFAULT_PRESTART,
)

SESSION = init_session(session_name, mydict=mydict, ret=True)
SESSION = init_session(mydict=mydict, ret=True)

if STARTUP_FILE:
_read_config_file(
Expand Down Expand Up @@ -1090,13 +941,10 @@ def ptpython_configure(repl):
)
# Start Python
elif conf.interactive_shell == "python":
code.interact(banner=banner_text, local=SESSION)
code.interact(banner=banner_text)
else:
raise ValueError("Invalid conf.interactive_shell")

if conf.session:
save_session(conf.session, SESSION)


if __name__ == "__main__":
interact()
Loading