esp32_bluetooth_classic_sni.../libs/scapy/base_classes.py
Matheus Eduardo Garbelini 86890704fd initial commit
todo: add documentation & wireshark dissector
2021-08-31 19:51:03 +08:00

360 lines
12 KiB
Python
Executable file

# This file is part of Scapy
# See http://www.secdev.org/projects/scapy for more information
# Copyright (C) Philippe Biondi <phil@secdev.org>
# This program is published under a GPLv2 license
"""
Generators and packet meta classes.
"""
################
# Generators #
################
from __future__ import absolute_import
from functools import reduce
import operator
import os
import re
import random
import socket
import subprocess
import types
from scapy.consts import WINDOWS
from scapy.modules.six.moves import range
class Gen(object):
__slots__ = []
def __iter__(self):
return iter([])
def __iterlen__(self):
return sum(1 for _ in iter(self))
def _get_values(value):
"""Generate a range object from (start, stop[, step]) tuples, or
return value.
"""
if (isinstance(value, tuple) and (2 <= len(value) <= 3) and
all(hasattr(i, "__int__") for i in value)):
# We use values[1] + 1 as stop value for (x)range to maintain
# the behavior of using tuples as field `values`
return range(*((int(value[0]), int(value[1]) + 1) +
tuple(int(v) for v in value[2:])))
return value
class SetGen(Gen):
def __init__(self, values, _iterpacket=1):
self._iterpacket = _iterpacket
if isinstance(values, (list, BasePacketList)):
self.values = [_get_values(val) for val in values]
else:
self.values = [_get_values(values)]
def transf(self, element):
return element
def __iter__(self):
for i in self.values:
if (isinstance(i, Gen) and
(self._iterpacket or not isinstance(i, BasePacket))) or (
isinstance(i, (range, types.GeneratorType))):
for j in i:
yield j
else:
yield i
def __repr__(self):
return "<SetGen %r>" % self.values
class Net(Gen):
"""Generate a list of IPs from a network address or a name"""
name = "ip"
ip_regex = re.compile(r"^(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)\.(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)\.(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)\.(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)(/[0-3]?[0-9])?$") # noqa: E501
@staticmethod
def _parse_digit(a, netmask):
netmask = min(8, max(netmask, 0))
if a == "*":
a = (0, 256)
elif a.find("-") >= 0:
x, y = [int(d) for d in a.split('-')]
if x > y:
y = x
a = (x & (0xff << netmask), max(y, (x | (0xff >> (8 - netmask)))) + 1) # noqa: E501
else:
a = (int(a) & (0xff << netmask), (int(a) | (0xff >> (8 - netmask))) + 1) # noqa: E501
return a
@classmethod
def _parse_net(cls, net):
tmp = net.split('/') + ["32"]
if not cls.ip_regex.match(net):
tmp[0] = socket.gethostbyname(tmp[0])
netmask = int(tmp[1])
ret_list = [cls._parse_digit(x, y - netmask) for (x, y) in zip(tmp[0].split('.'), [8, 16, 24, 32])] # noqa: E501
return ret_list, netmask
def __init__(self, net):
self.repr = net
self.parsed, self.netmask = self._parse_net(net)
def __str__(self):
return next(self.__iter__(), None)
def __iter__(self):
for d in range(*self.parsed[3]):
for c in range(*self.parsed[2]):
for b in range(*self.parsed[1]):
for a in range(*self.parsed[0]):
yield "%i.%i.%i.%i" % (a, b, c, d)
def __iterlen__(self):
return reduce(operator.mul, ((y - x) for (x, y) in self.parsed), 1)
def choice(self):
return ".".join(str(random.randint(v[0], v[1] - 1)) for v in self.parsed) # noqa: E501
def __repr__(self):
return "Net(%r)" % self.repr
def __eq__(self, other):
if not other:
return False
if hasattr(other, "parsed"):
p2 = other.parsed
else:
p2, nm2 = self._parse_net(other)
return self.parsed == p2
def __ne__(self, other):
# Python 2.7 compat
return not self == other
__hash__ = None
def __contains__(self, other):
if hasattr(other, "parsed"):
p2 = other.parsed
else:
p2, nm2 = self._parse_net(other)
return all(a1 <= a2 and b1 >= b2 for (a1, b1), (a2, b2) in zip(self.parsed, p2)) # noqa: E501
def __rcontains__(self, other):
return self in self.__class__(other)
class OID(Gen):
name = "OID"
def __init__(self, oid):
self.oid = oid
self.cmpt = []
fmt = []
for i in oid.split("."):
if "-" in i:
fmt.append("%i")
self.cmpt.append(tuple(map(int, i.split("-"))))
else:
fmt.append(i)
self.fmt = ".".join(fmt)
def __repr__(self):
return "OID(%r)" % self.oid
def __iter__(self):
ii = [k[0] for k in self.cmpt]
while True:
yield self.fmt % tuple(ii)
i = 0
while True:
if i >= len(ii):
return
if ii[i] < self.cmpt[i][1]:
ii[i] += 1
break
else:
ii[i] = self.cmpt[i][0]
i += 1
def __iterlen__(self):
return reduce(operator.mul, (max(y - x, 0) + 1 for (x, y) in self.cmpt), 1) # noqa: E501
######################################
# Packet abstract and base classes #
######################################
class Packet_metaclass(type):
def __new__(cls, name, bases, dct):
if "fields_desc" in dct: # perform resolution of references to other packets # noqa: E501
current_fld = dct["fields_desc"]
resolved_fld = []
for f in current_fld:
if isinstance(f, Packet_metaclass): # reference to another fields_desc # noqa: E501
for f2 in f.fields_desc:
resolved_fld.append(f2)
else:
resolved_fld.append(f)
else: # look for a fields_desc in parent classes
resolved_fld = None
for b in bases:
if hasattr(b, "fields_desc"):
resolved_fld = b.fields_desc
break
if resolved_fld: # perform default value replacements
final_fld = []
for f in resolved_fld:
if f.name in dct:
f = f.copy()
f.default = dct[f.name]
del(dct[f.name])
final_fld.append(f)
dct["fields_desc"] = final_fld
dct.setdefault("__slots__", [])
for attr in ["name", "overload_fields"]:
try:
dct["_%s" % attr] = dct.pop(attr)
except KeyError:
pass
newcls = super(Packet_metaclass, cls).__new__(cls, name, bases, dct)
newcls.__all_slots__ = set(
attr
for cls in newcls.__mro__ if hasattr(cls, "__slots__")
for attr in cls.__slots__
)
newcls.aliastypes = [newcls] + getattr(newcls, "aliastypes", [])
if hasattr(newcls, "register_variant"):
newcls.register_variant()
for f in newcls.fields_desc:
if hasattr(f, "register_owner"):
f.register_owner(newcls)
if newcls.__name__[0] != "_":
from scapy import config
config.conf.layers.register(newcls)
return newcls
def __getattr__(self, attr):
for k in self.fields_desc:
if k.name == attr:
return k
raise AttributeError(attr)
def __call__(cls, *args, **kargs):
if "dispatch_hook" in cls.__dict__:
try:
cls = cls.dispatch_hook(*args, **kargs)
except Exception:
from scapy import config
if config.conf.debug_dissector:
raise
cls = config.conf.raw_layer
i = cls.__new__(cls, cls.__name__, cls.__bases__, cls.__dict__)
i.__init__(*args, **kargs)
return i
class Field_metaclass(type):
def __new__(cls, name, bases, dct):
dct.setdefault("__slots__", [])
newcls = super(Field_metaclass, cls).__new__(cls, name, bases, dct)
return newcls
class BasePacket(Gen):
__slots__ = []
#############################
# Packet list base class #
#############################
class BasePacketList(object):
__slots__ = []
class _CanvasDumpExtended(object):
def psdump(self, filename=None, **kargs):
"""
psdump(filename=None, layer_shift=0, rebuild=1)
Creates an EPS file describing a packet. If filename is not provided a
temporary file is created and gs is called.
:param filename: the file's filename
"""
from scapy.config import conf
from scapy.utils import get_temp_file, ContextManagerSubprocess
canvas = self.canvas_dump(**kargs)
if filename is None:
fname = get_temp_file(autoext=kargs.get("suffix", ".eps"))
canvas.writeEPSfile(fname)
if WINDOWS and conf.prog.psreader is None:
os.startfile(fname)
else:
with ContextManagerSubprocess(conf.prog.psreader):
subprocess.Popen([conf.prog.psreader, fname])
else:
canvas.writeEPSfile(filename)
print()
def pdfdump(self, filename=None, **kargs):
"""
pdfdump(filename=None, layer_shift=0, rebuild=1)
Creates a PDF file describing a packet. If filename is not provided a
temporary file is created and xpdf is called.
:param filename: the file's filename
"""
from scapy.config import conf
from scapy.utils import get_temp_file, ContextManagerSubprocess
canvas = self.canvas_dump(**kargs)
if filename is None:
fname = get_temp_file(autoext=kargs.get("suffix", ".pdf"))
canvas.writePDFfile(fname)
if WINDOWS and conf.prog.pdfreader is None:
os.startfile(fname)
else:
with ContextManagerSubprocess(conf.prog.pdfreader):
subprocess.Popen([conf.prog.pdfreader, fname])
else:
canvas.writePDFfile(filename)
print()
def svgdump(self, filename=None, **kargs):
"""
svgdump(filename=None, layer_shift=0, rebuild=1)
Creates an SVG file describing a packet. If filename is not provided a
temporary file is created and gs is called.
:param filename: the file's filename
"""
from scapy.config import conf
from scapy.utils import get_temp_file, ContextManagerSubprocess
canvas = self.canvas_dump(**kargs)
if filename is None:
fname = get_temp_file(autoext=kargs.get("suffix", ".svg"))
canvas.writeSVGfile(fname)
if WINDOWS and conf.prog.svgreader is None:
os.startfile(fname)
else:
with ContextManagerSubprocess(conf.prog.svgreader):
subprocess.Popen([conf.prog.svgreader, fname])
else:
canvas.writeSVGfile(filename)
print()