diff --git a/.appveyor.yml b/.appveyor.yml index d92886c0082..5c698a56f16 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -12,8 +12,9 @@ build: off install: # Install the npcap, windump and wireshark suites - - choco install -y npcap wireshark + - ps: .\.appveyor\InstallNpcap.ps1 - ps: .\.appveyor\InstallWindump.ps1 + - choco install -y wireshark # Install Python modules - "%PYTHON%\\python -m pip install cryptography coverage mock pyreadline" - set PATH="%PYTHON%\\Scripts\\;%PATH%" diff --git a/.appveyor/InstallNpcap.ps1 b/.appveyor/InstallNpcap.ps1 new file mode 100644 index 00000000000..4859548469f --- /dev/null +++ b/.appveyor/InstallNpcap.ps1 @@ -0,0 +1,19 @@ +# Config +$urlPath = "https://nmap.org/npcap/dist/npcap-0.90.exe" +$checksum = "0477a42a9c54f31a7799fb3ee0537826041730f462abfc066fe36d81c50721a7" + +############ +############ +# Download the file +wget $urlPath -UseBasicParsing -OutFile $PSScriptRoot"\npcap.exe" +# Now let's check its checksum +$_chksum = $(CertUtil -hashfile $PSScriptRoot"\npcap.exe" SHA256)[1] -replace " ","" +if ($_chksum -ne $checksum){ + echo "Checksums does NOT match !" + exit +} else { + echo "Checksums matches !" +} +# Run installer +Start-Process $PSScriptRoot"\npcap.exe" -ArgumentList "/loopback_support=yes /S" -wait +echo "Npcap installation completed" \ No newline at end of file diff --git a/.gitattributes b/.gitattributes index 0c210b4e705..7ddf3f340cb 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,3 @@ scapy/__init__.py export-subst +* text=auto +*.bat text eol=crlf diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2522474fbe2..5e101fada83 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -110,6 +110,13 @@ parsed from a string (during a network capture or a PCAP file read). Adding inefficient code here will have a disastrous effect on Scapy's performances. +### Python 2 and 3 compatibility + +The project aims to provide code that works both on Python 2 and Python 3. Therefore, some rules need to be apply to achieve compatibility: +- byte-string must be defined as `b"\x00\x01\x02"` +- exceptions must comply with the new Python 3 format: `except SomeError as e:` +- lambdas must be written using a single argument when using tuples: use `lambda x_y: x_y[0] + f(x_y[1])` instead of `lambda (x, y): x + f(y)`. + ### Code review Maintainers tend to be picky, and you might feel frustrated that your diff --git a/bin/UTscapy.bat b/bin/UTscapy.bat index 3bccb69a072..d9c277f2642 100755 --- a/bin/UTscapy.bat +++ b/bin/UTscapy.bat @@ -1,4 +1,4 @@ -@echo off -REM Use Python to run the UTscapy script from the current directory, passing all parameters -title UTscapy -python "%~dp0\UTscapy" %* +@echo off +REM Use Python to run the UTscapy script from the current directory, passing all parameters +title UTscapy +python "%~dp0\UTscapy" %* diff --git a/bin/scapy.bat b/bin/scapy.bat index cbb17445abb..23e43cba51c 100755 --- a/bin/scapy.bat +++ b/bin/scapy.bat @@ -1,4 +1,4 @@ -@echo off -REM Use Python to run the Scapy script from the current directory, passing all parameters -title scapy -python "%~dp0\scapy" %* +@echo off +REM Use Python to run the Scapy script from the current directory, passing all parameters +title scapy +python "%~dp0\scapy" %* diff --git a/dev/scripts/autoFixer.py b/dev/scripts/autoFixer.py index efb54c7584c..ae8e8e10649 100644 --- a/dev/scripts/autoFixer.py +++ b/dev/scripts/autoFixer.py @@ -15,7 +15,7 @@ def main(): opts, args = getopt.getopt(sys.argv[1:], "t:") if not args: raise getopt.error, "At least one file argument required" - except getopt.error, msg: + except getopt.error as msg: print msg print "usage:", sys.argv[0], "files ..." return @@ -43,7 +43,7 @@ def process(filename, tabsize): f = open(filename) text = f.read() f.close() - except IOError, msg: + except IOError as msg: print "%r: I/O error: %s" % (filename, msg) return # Remove tabs diff --git a/doc/scapy/troubleshooting.rst b/doc/scapy/troubleshooting.rst index 810eea8477d..3249c5c2c40 100644 --- a/doc/scapy/troubleshooting.rst +++ b/doc/scapy/troubleshooting.rst @@ -14,7 +14,7 @@ I can't ping 127.0.0.1. Scapy does not work with 127.0.0.1 or on the loopback in The loopback interface is a very special interface. Packets going through it are not really assembled and disassembled. The kernel routes the packet to its destination while it is still stored an internal structure. What you see with tcpdump -i lo is only a fake to make you think everything is normal. The kernel is not aware of what Scapy is doing behind his back, so what you see on the loopback interface is also a fake. Except this one did not come from a local structure. Thus the kernel will never receive it. -In order to speak to local applications, you need to build your packets one layer upper, using a PF_INET/SOCK_RAW socket instead of a PF_PACKET/SOCK_RAW (or its equivalent on other systems that Linux):: +In order to speak to local applications, you need to build your packets one layer upper, using a PF_INET/SOCK_RAW socket instead of a PF_PACKET/SOCK_RAW (or its equivalent on other systems than Linux):: >>> conf.L3socket diff --git a/run_scapy.bat b/run_scapy.bat index ef1273f7c58..ba0774288ea 100644 --- a/run_scapy.bat +++ b/run_scapy.bat @@ -1,6 +1,6 @@ -@echo off -set PYTHONPATH=%cd% -python -m scapy.__init__ -if errorlevel 1 ( - PAUSE -) +@echo off +set PYTHONPATH=%cd% +python -m scapy.__init__ +if errorlevel 1 ( + PAUSE +) diff --git a/scapy/arch/bpf/core.py b/scapy/arch/bpf/core.py index e862810cbea..75a6035bc66 100644 --- a/scapy/arch/bpf/core.py +++ b/scapy/arch/bpf/core.py @@ -51,7 +51,7 @@ def get_if_raw_addr(ifname): # Get ifconfig output try: fd = os.popen("%s %s" % (conf.prog.ifconfig, ifname)) - except OSError, msg: + except OSError as msg: warning("Failed to execute ifconfig: (%s)" % msg) return b"\0\0\0\0" @@ -78,7 +78,7 @@ def get_if_raw_hwaddr(ifname): # Get ifconfig output try: fd = os.popen("%s %s" % (conf.prog.ifconfig, ifname)) - except OSError, msg: + except OSError as msg: raise Scapy_Exception("Failed to execute ifconfig: (%s)" % msg) # Get MAC addresses @@ -104,7 +104,7 @@ def get_dev_bpf(): try: fd = os.open("/dev/bpf%i" % bpf, os.O_RDWR) return (fd, bpf) - except OSError, err: + except OSError as err: continue raise Scapy_Exception("No /dev/bpf handle is available !") @@ -117,7 +117,7 @@ def attach_filter(fd, iface, bpf_filter_string): command = "%s -i %s -ddd -s 1600 '%s'" % (conf.prog.tcpdump, iface, bpf_filter_string) try: f = os.popen(command) - except OSError, msg: + except OSError as msg: raise Scapy_Exception("Failed to execute tcpdump: (%s)" % msg) # Convert the byte code to a BPF program structure @@ -154,7 +154,7 @@ def get_if_list(): # Get ifconfig output try: fd = os.popen("%s -a" % conf.prog.ifconfig) - except OSError, msg: + except OSError as msg: raise Scapy_Exception("Failed to execute ifconfig: (%s)" % msg) # Get interfaces @@ -184,7 +184,7 @@ def get_working_ifaces(): # Get interface flags try: result = get_if(ifname, SIOCGIFFLAGS) - except IOError, msg: + except IOError as msg: warning("ioctl(SIOCGIFFLAGS) failed on %s !" % ifname) continue @@ -201,7 +201,7 @@ def get_working_ifaces(): try: fcntl.ioctl(fd, BIOCSETIF, struct.pack("16s16x", ifname)) interfaces.append((ifname, int(ifname[-1]))) - except IOError, err: + except IOError as err: pass # Close the file descriptor diff --git a/scapy/arch/bpf/supersocket.py b/scapy/arch/bpf/supersocket.py index 5d03c1bdd12..41865be43a2 100644 --- a/scapy/arch/bpf/supersocket.py +++ b/scapy/arch/bpf/supersocket.py @@ -56,14 +56,14 @@ def __init__(self, iface=None, type=ETH_P_ALL, promisc=None, filter=None, nofilt # Set the BPF buffer length try: fcntl.ioctl(self.ins, BIOCSBLEN, struct.pack('I', BPF_BUFFER_LENGTH)) - except IOError, err: + except IOError as err: msg = "BIOCSBLEN failed on /dev/bpf%i" % self.dev_bpf raise Scapy_Exception(msg) # Assign the network interface to the BPF handle try: fcntl.ioctl(self.ins, BIOCSETIF, struct.pack("16s16x", self.iface)) - except IOError, err: + except IOError as err: msg = "BIOCSETIF failed on %s" % self.iface raise Scapy_Exception(msg) self.assigned_interface = self.iface @@ -75,7 +75,7 @@ def __init__(self, iface=None, type=ETH_P_ALL, promisc=None, filter=None, nofilt # Don't block on read try: fcntl.ioctl(self.ins, BIOCIMMEDIATE, struct.pack('I', 1)) - except IOError, err: + except IOError as err: msg = "BIOCIMMEDIATE failed on /dev/bpf%i" % self.dev_bpf raise Scapy_Exception(msg) @@ -83,7 +83,7 @@ def __init__(self, iface=None, type=ETH_P_ALL, promisc=None, filter=None, nofilt # Otherwise, it is written by the kernel try: fcntl.ioctl(self.ins, BIOCSHDRCMPLT, struct.pack('i', 1)) - except IOError, err: + except IOError as err: msg = "BIOCSHDRCMPLT failed on /dev/bpf%i" % self.dev_bpf raise Scapy_Exception(msg) @@ -105,7 +105,7 @@ def set_promisc(self, value): try: fcntl.ioctl(self.ins, BIOCPROMISC, struct.pack('i', value)) - except IOError, err: + except IOError as err: msg = "Can't put your interface (%s) into promiscuous mode !" % self.iface raise Scapy_Exception(msg) @@ -120,7 +120,7 @@ def guess_cls(self): try: ret = fcntl.ioctl(self.ins, BIOCGDLT, struct.pack('I', 0)) ret = struct.unpack('I', ret)[0] - except IOError, err: + except IOError as err: warning("BIOCGDLT failed: unable to guess type. Using Ethernet !") return Ether @@ -143,7 +143,7 @@ def set_nonblock(self, set_flag=True): if self.fd_flags is None: try: self.fd_flags = fcntl.fcntl(self.ins, fcntl.F_GETFL) - except IOError, err: + except IOError as err: warning("Can't get flags on this file descriptor !") return @@ -165,7 +165,7 @@ def get_stats(self): try: ret = fcntl.ioctl(self.ins, BIOCGSTATS, struct.pack("2I", 0, 0)) return struct.unpack("2I", ret) - except IOError, err: + except IOError as err: warning("Unable to get stats from BPF !") return (None, None) @@ -175,7 +175,7 @@ def get_blen(self): try: ret = fcntl.ioctl(self.ins, BIOCGBLEN, struct.pack("I", 0)) return struct.unpack("I", ret)[0] - except IOError, err: + except IOError as err: warning("Unable to get the BPF buffer length") return @@ -282,7 +282,7 @@ def recv(self, x=BPF_BUFFER_LENGTH): # Get data from BPF try: bpf_buffer = os.read(self.ins, x) - except EnvironmentError, e: + except EnvironmentError as e: if e.errno == errno.EAGAIN: return else: @@ -333,7 +333,7 @@ def send(self, pkt): if self.assigned_interface != iff: try: fcntl.ioctl(self.outs, BIOCSETIF, struct.pack("16s16x", iff)) - except IOError, err: + except IOError as err: msg = "BIOCSETIF failed on %s" % iff raise Scapy_Exception(msg) self.assigned_interface = iff diff --git a/scapy/arch/linux.py b/scapy/arch/linux.py index 28e5db9b686..8d4d7d662cf 100644 --- a/scapy/arch/linux.py +++ b/scapy/arch/linux.py @@ -137,7 +137,7 @@ def attach_filter(s, bpf_filter, iface): conf.iface if iface is None else iface, bpf_filter, )) - except OSError,msg: + except OSError as msg: log_interactive.warning("Failed to execute tcpdump: (%s)") return lines = f.readlines() @@ -146,7 +146,7 @@ def attach_filter(s, bpf_filter, iface): nb = int(lines[0]) bpf = "" for l in lines[1:]: - bpf += struct.pack("HBBI",*map(long,l.split())) + bpf += struct.pack("HBBI", *(int(e) for e in l.split())) # XXX. Argl! We need to give the kernel a pointer on the BPF, # python object header seems to be 20 bytes. 36 bytes for x86 64bits arch. @@ -282,7 +282,7 @@ def in6_getifaddr(): ret = [] try: f = open("/proc/net/if_inet6","r") - except IOError, err: + except IOError as err: return ret l = f.readlines() for i in l: @@ -296,7 +296,7 @@ def in6_getifaddr(): def read_routes6(): try: f = open("/proc/net/ipv6_route","r") - except IOError, err: + except IOError as err: return [] # 1. destination network # 2. destination prefix length @@ -359,9 +359,9 @@ def get_last_packet_timestamp(sock): def _flush_fd(fd): - if type(fd) is not int: + if hasattr(fd, 'fileno'): fd = fd.fileno() - while 1: + while True: r,w,e = select([fd],[],[],0) if r: os.read(fd,MTU) @@ -457,7 +457,7 @@ def send(self, x): x.sent_time = time.time() try: self.outs.sendto(sx, sdto) - except socket.error, msg: + except socket.error as msg: if msg[0] == 22 and len(sx) < conf.min_pkt_size: self.outs.send(sx + b"\x00" * (conf.min_pkt_size - len(sx))) elif conf.auto_fragment and msg[0] == 90: @@ -522,7 +522,7 @@ def recv(self, x=MTU): def send(self, x): try: return SuperSocket.send(self, x) - except socket.error, msg: + except socket.error as msg: if msg[0] == 22 and len(x) < conf.min_pkt_size: padding = b"\x00" * (conf.min_pkt_size - len(x)) if isinstance(x, Packet): diff --git a/scapy/arch/pcapdnet.py b/scapy/arch/pcapdnet.py index d7b42e75f70..b43b77c3ba2 100644 --- a/scapy/arch/pcapdnet.py +++ b/scapy/arch/pcapdnet.py @@ -103,8 +103,7 @@ def get_if_raw_addr(iff): if a.contents.addr.contents.sa_family == socket.AF_INET: ap = a.contents.addr val = cast(ap, POINTER(sockaddr_in)) - #ret = bytes(val.contents.sin_addr[:4]) - ret = "".join([chr(x) for x in val.contents.sin_addr[:4]]) + ret = "".join(chr(x) for x in val.contents.sin_addr[:4]) a = a.contents.next break p = p.contents.next @@ -151,8 +150,7 @@ def next(self): if not c > 0: return ts = self.header.contents.ts.tv_sec - pkt = "".join([ chr(i) for i in self.pkt_data[:self.header.contents.len] ]) - #pkt = bytes(self.pkt_data[:self.header.contents.len]) + pkt = "".join(chr(i) for i in self.pkt_data[:self.header.contents.len]) return ts, pkt def datalink(self): return pcap_datalink(self.pcap) @@ -337,10 +335,10 @@ def send(self, x): if conf.use_pcap: try: import pcap - except ImportError,e: + except ImportError as e: try: import pcapy as pcap - except ImportError,e2: + except ImportError as e2: if conf.interactive: log_loading.error("Unable to import pcap module: %s/%s" % (e,e2)) conf.use_pcap = False @@ -485,7 +483,7 @@ def send(self, x): except ImportError: # Then, try to import dumbnet as dnet import dumbnet as dnet - except ImportError,e: + except ImportError as e: if conf.interactive: log_loading.error("Unable to import dnet module: %s" % e) conf.use_dnet = False diff --git a/scapy/arch/unix.py b/scapy/arch/unix.py index f85f4b6ef44..f73ee70c4a0 100644 --- a/scapy/arch/unix.py +++ b/scapy/arch/unix.py @@ -148,7 +148,7 @@ def _in6_getifaddr(ifname): # Get the output of ifconfig try: f = os.popen("%s %s" % (conf.prog.ifconfig, ifname)) - except OSError,msg: + except OSError as msg: log_interactive.warning("Failed to execute ifconfig.") return [] @@ -188,7 +188,7 @@ def in6_getifaddr(): if OPENBSD: try: f = os.popen("%s" % conf.prog.ifconfig) - except OSError,msg: + except OSError as msg: log_interactive.warning("Failed to execute ifconfig.") return [] @@ -202,7 +202,7 @@ def in6_getifaddr(): else: # FreeBSD, NetBSD or Darwin try: f = os.popen("%s -l" % conf.prog.ifconfig) - except OSError,msg: + except OSError as msg: log_interactive.warning("Failed to execute ifconfig.") return [] diff --git a/scapy/arch/windows/__init__.py b/scapy/arch/windows/__init__.py index 25c7a0dce54..0bb5ed5cf6c 100755 --- a/scapy/arch/windows/__init__.py +++ b/scapy/arch/windows/__init__.py @@ -54,11 +54,15 @@ def is_new_release(ignoreVBS=False): return True return False +def _encapsulate_admin(cmd): + """Encapsulate a command with an Administrator flag""" + # To get admin access, we start a new powershell instance with admin rights, which will execute the command + return "Start-Process PowerShell -windowstyle hidden -Wait -Verb RunAs -ArgumentList '-command &{%s}'" % cmd def _exec_query_ps(cmd, fields): """Execute a PowerShell query""" - if not WINDOWS: - return + if not conf.prog.powershell: + raise OSError("Scapy could not detect powershell !") ps = sp.Popen([conf.prog.powershell] + cmd + ['|', 'select %s' % ', '.join(fields), '|', 'fl'], stdout=sp.PIPE, @@ -78,8 +82,8 @@ def _exec_query_ps(cmd, fields): l=[] def _vbs_exec_code(code, split_tag="@"): - if not WINDOWS: - return + if not conf.prog.cscript: + raise OSError("Scapy could not detect cscript !") tmpfile = tempfile.NamedTemporaryFile(suffix=".vbs", delete=False) tmpfile.write(code) tmpfile.close() @@ -95,24 +99,26 @@ def _vbs_exec_code(code, split_tag="@"): yield l os.unlink(tmpfile.name) -def _vbs_get_iface_guid(devid): - if not WINDOWS: - return +def _vbs_get_hardware_iface_guid(devid): try: devid = str(int(devid) + 1) - guid = _vbs_exec_code("""WScript.Echo CreateObject("WScript.Shell").RegRead("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards\\%s\\ServiceName") -""" % devid).__iter__().next() - if guid.startswith('{') and guid.endswith('}\n'): - return guid[:-1] + guid = iter(_vbs_exec_code("""WScript.Echo CreateObject("WScript.Shell").RegRead("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards\\%s\\ServiceName") +""" % devid)).next() + guid = guid[:-1] if guid.endswith('}\n') else guid + if guid.startswith('{') and guid.endswith('}'): + return guid except StopIteration: - pass + return None # Some names differ between VBS and PS ## None: field will not be returned under VBS _VBS_WMI_FIELDS = { "Win32_NetworkAdapter": { - "InterfaceIndex": "Index", "InterfaceDescription": "Description", + # Note: when using VBS, the GUID is not the same than with Powershell + # So we use get the device ID instead, then use _vbs_get_hardware_iface_guid + # To get its real GUID + "GUID": "DeviceID" } } @@ -124,7 +130,7 @@ def _vbs_get_iface_guid(devid): _VBS_WMI_OUTPUT = { "Win32_NetworkAdapter": { - "DeviceID": _vbs_get_iface_guid, + "DeviceID": _vbs_get_hardware_iface_guid, } } @@ -133,8 +139,6 @@ def _exec_query_vbs(cmd, fields): supported. """ - if not WINDOWS: - return if not(len(cmd) == 2 and cmd[0] == "Get-WmiObject"): return @@ -188,7 +192,7 @@ def has_common_item(l1, l2): return False, None, None def key_in_path(path, key): return key.lower() in path.lower() - deeper_paths = [env_path("ProgramFiles"), env_path("ProgramFiles(x86)")] + deeper_paths = [env_path("ProgramFiles"), env_path("ProgramFiles(x86)")] + env_path("PATH").split(os.path.pathsep) for path in deeper_paths: len_p = len(path) + len(os.path.sep) for root, subFolders, files in os.walk(path): @@ -224,8 +228,6 @@ def _where(filename, dirs=None, env="PATH"): def win_find_exe(filename, installsubdir=None, env="ProgramFiles"): """Find executable in current dir, system path or given ProgramFiles subdir""" - if not WINDOWS: - return fns = [filename] if filename.endswith(".exe") else [filename+".exe", filename] for fn in fns: try: @@ -234,20 +236,24 @@ def win_find_exe(filename, installsubdir=None, env="ProgramFiles"): else: path = _where(fn, dirs=[os.path.join(os.environ[env], installsubdir)]) except IOError: - path = filename + path = None else: break return path class WinProgPath(ConfClass): - # This is a dict containing the name of the .exe and a keyword - # that must be in the path of the file - external_prog_list = {"AcroRd32" : "", "gsview32" : "", "dot" : "graph", "windump" : "", "tshark" : "", - "tcpreplay" : "", "hexer" : "", "sox" : "", "wireshark" : ""} _default = "" def __init__(self): - _deep_lookup(self.external_prog_list) + # This is a dict containing the name of the .exe and a keyword + # that must be in the path of the file + external_prog_list = {"AcroRd32" : "", "gsview32" : "", "dot" : "graph", + "windump" : "", "tshark" : "", "tcpreplay" : "", + "hexer" : "", "sox" : "", "wireshark" : ""} + _deep_lookup(external_prog_list) + self._reload() + + def _reload(self): # We try some magic to find the appropriate executables self.pdfreader = win_find_exe("AcroRd32") self.psreader = win_find_exe("gsview32") @@ -268,17 +274,17 @@ def __init__(self): env="SystemRoot") self.cmd = win_find_exe("cmd", installsubdir="System32", env="SystemRoot") - if self.wireshark != "wireshark": + if self.wireshark: manu_path = load_manuf(os.path.sep.join(self.wireshark.split(os.path.sep)[:-1])+os.path.sep+"manuf") scapy.data.MANUFDB = conf.manufdb = MANUFDB = manu_path + + self.os_access = (self.powershell is not None) or (self.cscript is not None) conf.prog = WinProgPath() -if conf.prog.powershell == "powershell": - conf.prog.powershell = None -if conf.prog.sox == "sox": - conf.prog.sox = None +if not conf.prog.os_access: + warning("Scapy did not detect powershell and cscript ! Routes, interfaces and much more won't work !", True) -if conf.prog.tcpdump != "windump" and conf.use_npcap: +if conf.prog.tcpdump and conf.use_npcap and conf.prog.os_access: def test_windump_npcap(): """Return wether windump version is correct or not""" try: @@ -308,13 +314,15 @@ def is_interface_valid(iface): def get_windows_if_list(): """Returns windows interfaces""" + if not conf.prog.os_access: + return [] if is_new_release(): # This works only starting from Windows 8/2012 and up. For older Windows another solution is needed # Careful: this is weird, but Get-NetAdaptater works like: (Name isn't the interface name) # Name InterfaceDescription ifIndex Status MacAddress LinkSpeed # ---- -------------------- ------- ------ ---------- --------- # Ethernet Killer E2200 Gigabit Ethernet Contro... 13 Up D0-50-99-56-DD-F9 1 Gbps - query = exec_query(['Get-NetAdapter'], + query = exec_query(['Get-NetAdapter -Physical'], ['InterfaceDescription', 'InterfaceIndex', 'Name', 'InterfaceGuid', 'MacAddress']) # It is normal that it is in this order else: @@ -397,11 +405,48 @@ def is_invalid(self): def __repr__(self): return "<%s %s %s>" % (self.__class__.__name__, self.name, self.guid) +def pcap_service_name(): + """Return the pcap adapter service's name""" + return "npcap" if conf.use_npcap else "npf" + +def pcap_service_status(): + """Returns a tuple (name, description, started) of the windows pcap adapter""" + if not conf.prog.powershell: + return (None, None, None) + for i in exec_query(['Get-Service', 'npcap'], ['Name', 'DisplayName', 'Status']): + name = i[0] + description = i[1] + started = (not i[2].lower().strip() == 'stopped') + if name == pcap_service_name(): + return (name, description, started) + return (None, None, None) + +def pcap_service_control(action, askadmin=True): + """Util to run pcap control command""" + if not conf.prog.powershell: + return False + command = action + ' ' + pcap_service_name() + ps = sp.Popen([conf.prog.powershell, _encapsulate_admin(command) if askadmin else command], + stdout=sp.PIPE, + universal_newlines=True) + stdout, stderr = ps.communicate() + return (not "error" in stdout.lower()) + +def pcap_service_start(askadmin=True): + """Starts the pcap adapter. Will ask for admin. Returns True if success""" + return pcap_service_control('Start-Service', askadmin=askadmin) + +def pcap_service_stop(askadmin=True): + """Stops the pcap adapter. Will ask for admin. Returns True if success""" + return pcap_service_control('Stop-Service', askadmin=askadmin) + from UserDict import UserDict class NetworkInterfaceDict(UserDict): """Store information about network interfaces and convert between names""" def load_from_powershell(self): + if not conf.prog.os_access: + return for i in get_windows_if_list(): try: interface = NetworkInterface(i) @@ -410,10 +455,33 @@ def load_from_powershell(self): pass if len(self.data) == 0 and conf.use_winpcapy: - warning("No match between your pcap and windows network interfaces found. " - "You probably won't be able to send packets. " - "Deactivating unneeded interfaces and restarting Scapy might help." - "Check your winpcap and powershell installation, and access rights.", True) + _detect = pcap_service_status() + def _ask_user(): + if not conf.interactive: + return False + while True: + _confir = raw_input("Do you want to start it ? (yes/no) [y]: ").lower().strip() + if _confir in ["yes", "y", ""]: + return True + elif _confir in ["no", "n"]: + return False + return False + _error_msg = "No match between your pcap and windows network interfaces found. " + if _detect[0] and not _detect[2] and ((hasattr(self, "restarted_adapter") and not self.restarted_adapter) + or not hasattr(self, "restarted_adapter")): + warning("Scapy has detected that your pcap service is not running !") + if not conf.interactive or _ask_user(): + succeed = pcap_service_start(askadmin=conf.interactive) + self.restarted_adapter = True + if succeed: + log_loading.info("Pcap service started !") + self.load_from_powershell() + return + _error_msg = "Could not start the pcap service ! " + warning(_error_msg + + "You probably won't be able to send packets. " + "Deactivating unneeded interfaces and restarting Scapy might help. " + "Check your winpcap and powershell installation, and access rights.", True) else: # Loading state: remove invalid interfaces self.remove_invalid_ifaces() @@ -479,7 +547,7 @@ def pcapname(dev): device name. """ - if type(dev) is NetworkInterface: + if isinstance(dev, NetworkInterface): if dev.is_invalid(): return None return dev.pcap_name @@ -552,6 +620,8 @@ def _read_routes_7(): def read_routes(): routes = [] + if not conf.prog.os_access: + return routes release = platform.release() try: if is_new_release(): @@ -561,7 +631,7 @@ def read_routes(): else: routes = _read_routes_7() except Exception as e: - warning("Error building scapy routing table : %s" % str(e), True) + warning("Error building scapy IPv4 routing table : %s" % str(e), True) else: if not routes: warning("No default IPv4 routes found. Your Windows release may no be supported and you have to enter your routes manually", True) @@ -735,13 +805,15 @@ def _read_routes6_7(): def read_routes6(): routes6 = [] + if not conf.prog.os_access: + return routes6 try: if is_new_release(): routes6 = _read_routes6_post2008() else: routes6 = _read_routes6_7() except Exception as e: - warning("Error building scapy routing table : %s" % str(e), True) + warning("Error building scapy IPv6 routing table : %s" % str(e), True) return routes6 if conf.interactive_shell != 'ipython' and conf.interactive: diff --git a/scapy/arch/windows/compatibility.py b/scapy/arch/windows/compatibility.py index 0f717c5cbf8..a9f92a02ac0 100644 --- a/scapy/arch/windows/compatibility.py +++ b/scapy/arch/windows/compatibility.py @@ -97,7 +97,7 @@ def sndrcv(pks, pkt, timeout = 2, inter = 0, verbose=None, chainCC=0, retry=0, m remaintime = None try: try: - while 1: + while True: if stoptime: remaintime = stoptime-time.time() if remaintime <= 0: @@ -206,7 +206,7 @@ def sniff(count=0, store=1, offline=None, prn = None, stop_filter=None, lfilter= if timeout is not None: stoptime = time.time()+timeout remain = None - while 1: + while True: try: if timeout is not None: remain = stoptime-time.time() diff --git a/scapy/as_resolvers.py b/scapy/as_resolvers.py index da4df117e70..d52b4000e4a 100644 --- a/scapy/as_resolvers.py +++ b/scapy/as_resolvers.py @@ -79,7 +79,7 @@ def resolve(self, *ips): s.connect((self.server,self.port)) s.send("begin\r\n"+"\r\n".join(ips)+"\r\nend\r\n") r = "" - while 1: + while True: l = s.recv(8192) if l == "": break @@ -88,7 +88,7 @@ def resolve(self, *ips): for l in r.splitlines()[1:]: if "|" not in l: continue - asn,ip,desc = map(str.strip, l.split("|")) + asn, ip, desc = [elt.strip() for elt in l.split('|')] if asn == "NA": continue asn = "AS" + str(int(asn)) diff --git a/scapy/asn1/asn1.py b/scapy/asn1/asn1.py index 973b24337cf..f44dc7257cb 100644 --- a/scapy/asn1/asn1.py +++ b/scapy/asn1/asn1.py @@ -104,7 +104,7 @@ def register(self, codecnum, codec): def get_codec(self, codec): try: c = self._codec[codec] - except KeyError,msg: + except KeyError as msg: raise ASN1_Error("Codec %r not found for tag %r" % (codec, self)) return c @@ -118,7 +118,7 @@ def __new__(cls, name, bases, dct): # XXX factorise a bit with Enum_metaclass.__ rdict = {} for k,v in dct.iteritems(): - if type(v) is int: + if isinstance(v, int): v = ASN1Tag(k,v) dct[k] = v rdict[v] = v diff --git a/scapy/asn1/ber.py b/scapy/asn1/ber.py index 97fc4a0267c..e9b871aee78 100644 --- a/scapy/asn1/ber.py +++ b/scapy/asn1/ber.py @@ -88,7 +88,7 @@ def BER_num_enc(l, size=1): x[0] |= 0x80 l >>= 7 size -= 1 - return "".join([chr(k) for k in x]) + return "".join(chr(k) for k in x) def BER_num_dec(s, cls_id=0): if len(s) == 0: raise BER_Decoding_Error("BER_num_dec: got empty string", remaining=s) @@ -241,12 +241,12 @@ def dec(cls, s, context=None, safe=False): return cls.do_dec(s, context, safe) try: return cls.do_dec(s, context, safe) - except BER_BadTag_Decoding_Error,e: + except BER_BadTag_Decoding_Error as e: o,remain = BERcodec_Object.dec(e.remaining, context, safe) return ASN1_BADTAG(o),remain - except BER_Decoding_Error, e: + except BER_Decoding_Error as e: return ASN1_DECODING_ERROR(s, exc=e),"" - except ASN1_Error, e: + except ASN1_Error as e: return ASN1_DECODING_ERROR(s, exc=e),"" @classmethod @@ -256,7 +256,7 @@ def safedec(cls, s, context=None): @classmethod def enc(cls, s): - if type(s) is str: + if isinstance(s, basestring): return BERcodec_STRING.enc(s) else: return BERcodec_INTEGER.enc(int(s)) @@ -273,7 +273,7 @@ class BERcodec_INTEGER(BERcodec_Object): @classmethod def enc(cls, i): s = [] - while 1: + while True: s.append(i&0xff) if -127 <= i < 0: break @@ -282,7 +282,7 @@ def enc(cls, i): i >>= 8 if not i: break - s = map(chr, s) + s = [chr(c) for c in s] s.append(BER_len_enc(len(s))) s.append(chr(cls.tag)) s.reverse() @@ -357,7 +357,7 @@ def enc(cls, oid): if len(lst) >= 2: lst[1] += 40*lst[0] del(lst[0]) - s = "".join([BER_num_enc(k) for k in lst]) + s = "".join(BER_num_enc(k) for k in lst) return chr(cls.tag)+BER_len_enc(len(s))+s @classmethod def do_dec(cls, s, context=None, safe=False): @@ -369,7 +369,7 @@ def do_dec(cls, s, context=None, safe=False): if (len(lst) > 0): lst.insert(0,lst[0]/40) lst[1] %= 40 - return cls.asn1_object(".".join([str(k) for k in lst])), t + return cls.asn1_object(".".join(str(k) for k in lst)), t class BERcodec_ENUMERATED(BERcodec_INTEGER): tag = ASN1_Class_UNIVERSAL.ENUMERATED @@ -405,8 +405,8 @@ class BERcodec_SEQUENCE(BERcodec_Object): tag = ASN1_Class_UNIVERSAL.SEQUENCE @classmethod def enc(cls, l): - if type(l) is not str: - l = "".join(map(lambda x: x.enc(cls.codec), l)) + if not isinstance(l, str): + l = "".join(x.enc(cls.codec) for x in l) return chr(cls.tag)+BER_len_enc(len(l))+l @classmethod def do_dec(cls, s, context=None, safe=False): @@ -418,7 +418,7 @@ def do_dec(cls, s, context=None, safe=False): while s: try: o,s = BERcodec_Object.dec(s, context, safe) - except BER_Decoding_Error, err: + except BER_Decoding_Error as err: err.remaining += t if err.decoded is not None: obj.append(err.decoded) diff --git a/scapy/asn1/mib.py b/scapy/asn1/mib.py index 59dc5b9617e..ed1d581db4d 100644 --- a/scapy/asn1/mib.py +++ b/scapy/asn1/mib.py @@ -90,7 +90,7 @@ def mib_register(ident, value, the_mib, unresolved): v = the_mib[v] elif v in unresolved: v = unresolved[v] - if type(v) is list: + if isinstance(v, list): resval += v else: resval.append(v) @@ -119,7 +119,7 @@ def load_mib(filenames): for k in conf.mib.iterkeys(): mib_register(k, conf.mib[k].split("."), the_mib, unresolved) - if type(filenames) is str: + if isinstance(filenames, str): filenames = [filenames] for fnames in filenames: for fname in glob(fnames): diff --git a/scapy/asn1fields.py b/scapy/asn1fields.py index 7262736ff3e..5ed6ce673dd 100644 --- a/scapy/asn1fields.py +++ b/scapy/asn1fields.py @@ -15,6 +15,7 @@ from scapy.base_classes import BasePacket from scapy.utils import binrepr from scapy import packet +from functools import reduce class ASN1F_badsequence(Exception): pass @@ -40,7 +41,7 @@ def __init__(self, name, default, context=None, self.name = name if default is None: self.default = None - elif type(default) is ASN1_NULL: + elif isinstance(default, ASN1_NULL): self.default = default else: self.default = self.ASN1_tag.asn1_object(default) @@ -127,7 +128,7 @@ def dissect(self, pkt, s): def do_copy(self, x): if hasattr(x, "copy"): return x.copy() - if type(x) is list: + if isinstance(x, list): x = x[:] for i in xrange(len(x)): if isinstance(x[i], BasePacket): @@ -170,7 +171,7 @@ def __init__(self, name, default, enum, context=None, explicit_tag=explicit_tag) i2s = self.i2s = {} s2i = self.s2i = {} - if type(enum) is list: + if isinstance(enum, list): keys = xrange(len(enum)) else: keys = enum.keys() @@ -310,7 +311,7 @@ def m2i(self, pkt, s): for obj in self.seq: try: s = obj.dissect(pkt, s) - except ASN1F_badsequence,e: + except ASN1F_badsequence as e: break if len(s) > 0: raise BER_Decoding_Error("unexpected remainder", remaining=s) @@ -444,7 +445,7 @@ def __init__(self, name, default, *args, **kwargs): else: self.choices[p.ASN1_root.network_tag] = p elif hasattr(p, "ASN1_tag"): - if type(p) is type: # should be ASN1F_field class + if isinstance(p, type): # should be ASN1F_field class self.choices[p.ASN1_tag] = p else: # should be ASN1F_PACKET instance self.choices[p.network_tag] = p @@ -471,7 +472,7 @@ def m2i(self, pkt, s): if hasattr(choice, "ASN1_root"): # we don't want to import ASN1_Packet in this module... return self.extract_packet(choice, s) - elif type(choice) is type: + elif isinstance(choice, type): #XXX find a way not to instantiate the ASN1F_field return choice(self.name, "").m2i(pkt, s) else: @@ -493,7 +494,7 @@ def randval(self): if hasattr(p, "ASN1_root"): # should be ASN1_Packet class randchoices.append(packet.fuzz(p())) elif hasattr(p, "ASN1_tag"): - if type(p) is type: # should be (basic) ASN1F_field class + if isinstance(p, type): # should be (basic) ASN1F_field class randchoices.append(p("dummy", None).randval()) else: # should be ASN1F_PACKET instance randchoices.append(p.randval()) diff --git a/scapy/automaton.py b/scapy/automaton.py index b39e08b3f11..5cf02f56f03 100644 --- a/scapy/automaton.py +++ b/scapy/automaton.py @@ -48,21 +48,21 @@ def __repr__(self): class _instance_state: def __init__(self, instance): - self.im_self = instance.im_self - self.im_func = instance.im_func - self.im_class = instance.im_class + self.__self__ = instance.__self__ + self.__func__ = instance.__func__ + self.__self__.__class__ = instance.__self__.__class__ def __getattr__(self, attr): - return getattr(self.im_func, attr) + return getattr(self.__func__, attr) def __call__(self, *args, **kargs): - return self.im_func(self.im_self, *args, **kargs) + return self.__func__(self.__self__, *args, **kargs) def breaks(self): - return self.im_self.add_breakpoints(self.im_func) + return self.__self__.add_breakpoints(self.__func__) def intercepts(self): - return self.im_self.add_interception_points(self.im_func) + return self.__self__.add_interception_points(self.__func__) def unbreaks(self): - return self.im_self.remove_breakpoints(self.im_func) + return self.__self__.remove_breakpoints(self.__func__) def unintercepts(self): - return self.im_self.remove_interception_points(self.im_func) + return self.__self__.remove_interception_points(self.__func__) ############## @@ -102,16 +102,16 @@ def __repr__(self): def state(initial=0,final=0,error=0): def deco(f,initial=initial, final=final): f.atmt_type = ATMT.STATE - f.atmt_state = f.func_name + f.atmt_state = f.__name__ f.atmt_initial = initial f.atmt_final = final f.atmt_error = error def state_wrapper(self, *args, **kargs): return ATMT.NewStateRequested(f, self, *args, **kargs) - state_wrapper.func_name = "%s_wrapper" % f.func_name + state_wrapper.__name__ = "%s_wrapper" % f.__name__ state_wrapper.atmt_type = ATMT.STATE - state_wrapper.atmt_state = f.func_name + state_wrapper.atmt_state = f.__name__ state_wrapper.atmt_initial = initial state_wrapper.atmt_final = final state_wrapper.atmt_error = error @@ -132,7 +132,7 @@ def condition(state, prio=0): def deco(f, state=state): f.atmt_type = ATMT.CONDITION f.atmt_state = state.atmt_state - f.atmt_condname = f.func_name + f.atmt_condname = f.__name__ f.atmt_prio = prio return f return deco @@ -141,7 +141,7 @@ def receive_condition(state, prio=0): def deco(f, state=state): f.atmt_type = ATMT.RECV f.atmt_state = state.atmt_state - f.atmt_condname = f.func_name + f.atmt_condname = f.__name__ f.atmt_prio = prio return f return deco @@ -150,7 +150,7 @@ def ioevent(state, name, prio=0, as_supersocket=None): def deco(f, state=state): f.atmt_type = ATMT.IOEVENT f.atmt_state = state.atmt_state - f.atmt_condname = f.func_name + f.atmt_condname = f.__name__ f.atmt_ioname = name f.atmt_prio = prio f.atmt_as_supersocket = as_supersocket @@ -162,7 +162,7 @@ def deco(f, state=state, timeout=timeout): f.atmt_type = ATMT.TIMEOUT f.atmt_state = state.atmt_state f.atmt_timeout = timeout - f.atmt_condname = f.func_name + f.atmt_condname = f.__name__ return f return deco @@ -192,7 +192,7 @@ def __init__(self, name, ioevent, automaton, proto, args, kargs): def fileno(self): return self.spa.fileno() def send(self, s): - if type(s) is not str: + if not isinstance(s, str): s = str(s) return self.spa.send(s) def recv(self, n=MTU): @@ -235,7 +235,7 @@ def __new__(cls, name, bases, dct): members[k] = v decorated = [v for v in members.itervalues() - if type(v) is types.FunctionType and hasattr(v, "atmt_type")] + if isinstance(v, types.FunctionType) and hasattr(v, "atmt_type")] for m in decorated: if m.atmt_type == ATMT.STATE: @@ -296,7 +296,7 @@ def graph(self, **kargs): s += se for st in self.states.itervalues(): - for n in st.atmt_origfunc.func_code.co_names+st.atmt_origfunc.func_code.co_consts: + for n in st.atmt_origfunc.__code__.co_names+st.atmt_origfunc.__code__.co_consts: if n in self.states: s += '\t"%s" -> "%s" [ color=green ];\n' % (st.atmt_state,n) @@ -305,31 +305,37 @@ def graph(self, **kargs): [("red",k,v) for k,v in self.recv_conditions.items()]+ [("orange",k,v) for k,v in self.ioevents.items()]): for f in v: - for n in f.func_code.co_names+f.func_code.co_consts: + for n in f.__code__.co_names+f.__code__.co_consts: if n in self.states: l = f.atmt_condname for x in self.actions[f.atmt_condname]: - l += "\\l>[%s]" % x.func_name + l += "\\l>[%s]" % x.__name__ s += '\t"%s" -> "%s" [label="%s", color=%s];\n' % (k,n,l,c) for k,v in self.timeout.iteritems(): for t,f in v: if f is None: continue - for n in f.func_code.co_names+f.func_code.co_consts: + for n in f.__code__.co_names+f.__code__.co_consts: if n in self.states: l = "%s/%.1fs" % (f.atmt_condname,t) for x in self.actions[f.atmt_condname]: - l += "\\l>[%s]" % x.func_name + l += "\\l>[%s]" % x.__name__ s += '\t"%s" -> "%s" [label="%s",color=blue];\n' % (k,n,l) s += "}\n" return do_graph(s, **kargs) -def select_objects(inputs, remain): +def select_objects(inputs, remain, customTypes=()): + """ + Select object that have checkRecv function. + inputs: objects to process + remain: timeout. If 0, return []. + customTypes: types of the objects that have the checkRecv function. + """ if WINDOWS: r = [] def look_for_select(): - for fd in inputs: - if isinstance(fd, ObjectPipe) or isinstance(fd, Automaton._IO_fdwrapper): + for fd in list(inputs): + if isinstance(fd, (ObjectPipe, Automaton._IO_fdwrapper) + customTypes): if fd.checkRecv(): r.append(fd) else: @@ -375,9 +381,9 @@ def __init__(self,rd,wr): else: raise OSError("On windows, only instances of ObjectPipe are externally available") else: - if rd is not None and type(rd) is not int: + if rd is not None and not isinstance(rd, int): rd = rd.fileno() - if wr is not None and type(wr) is not int: + if wr is not None and not isinstance(wr, int): wr = wr.fileno() self.rd = rd self.wr = wr @@ -403,7 +409,7 @@ def __init__(self,rd,wr): self.rd = rd self.wr = wr def fileno(self): - if type(self.rd) is int: + if isinstance(self.rd, int): return self.rd return self.rd.fileno() def recv(self, n=None): @@ -496,18 +502,18 @@ def __init__(self, *args, **kargs): self.ioout = {} for n in self.ionames: extfd = external_fd.get(n) - if type(extfd) is not tuple: + if not isinstance(extfd, tuple): extfd = (extfd,extfd) elif WINDOWS: raise OSError("Tuples are not allowed as external_fd on windows") ioin,ioout = extfd if ioin is None: ioin = ObjectPipe() - elif type(ioin) is not types.InstanceType: + elif not isinstance(ioin, types.InstanceType): ioin = self._IO_fdwrapper(ioin,None) if ioout is None: ioout = ObjectPipe() - elif type(ioout) is not types.InstanceType: + elif not isinstance(ioout, types.InstanceType): ioout = self._IO_fdwrapper(None,ioout) self.ioin[n] = ioin @@ -535,16 +541,16 @@ def _run_condition(self, cond, *args, **kargs): try: self.debug(5, "Trying %s [%s]" % (cond.atmt_type, cond.atmt_condname)) cond(self,*args, **kargs) - except ATMT.NewStateRequested, state_req: + except ATMT.NewStateRequested as state_req: self.debug(2, "%s [%s] taken to state [%s]" % (cond.atmt_type, cond.atmt_condname, state_req.state)) if cond.atmt_type == ATMT.RECV: if self.store_packets: self.packets.append(args[0]) for action in self.actions[cond.atmt_condname]: - self.debug(2, " + Running action [%s]" % action.func_name) + self.debug(2, " + Running action [%s]" % action.__name__) action(self, *state_req.action_args, **state_req.action_kargs) raise - except Exception,e: + except Exception as e: self.debug(2, "%s [%s] raised exception [%s]" % (cond.atmt_type, cond.atmt_condname, e)) raise else: @@ -600,10 +606,10 @@ def _do_control(self, ready, *args, **kargs): c = Message(type=_ATMT_Command.SINGLESTEP,state=state) self.cmdout.send(c) break - except StopIteration,e: + except StopIteration as e: c = Message(type=_ATMT_Command.END, result=e.args[0]) self.cmdout.send(c) - except Exception,e: + except Exception as e: exc_info = sys.exc_info() self.debug(3, "Transfering exception from tid=%i:\n%s"% (self.threadid, traceback.format_exc(exc_info))) m = Message(type=_ATMT_Command.EXCEPTION, exception=e, exc_info=exc_info) @@ -631,7 +637,7 @@ def _do_iter(self): if state_output is None: state_output = () - elif type(state_output) is not list: + elif not isinstance(state_output, list): state_output = state_output, # Then check immediate conditions @@ -655,7 +661,7 @@ def _do_iter(self): fds.append(self.listen_sock) for ioev in self.ioevents[self.state.state]: fds.append(self.ioin[ioev.atmt_ioname]) - while 1: + while True: t = time.time()-t0 if next_timeout is not None: if next_timeout <= t: @@ -688,7 +694,7 @@ def _do_iter(self): if ioevt.atmt_ioname == fd.ioname: self._run_condition(ioevt, fd, *state_output) - except ATMT.NewStateRequested,state_req: + except ATMT.NewStateRequested as state_req: self.debug(2, "switching from [%s] to [%s]" % (self.state.state,state_req.state)) self.state = state_req yield state_req diff --git a/scapy/autorun.py b/scapy/autorun.py index b64a46a4c15..29566da2ddb 100644 --- a/scapy/autorun.py +++ b/scapy/autorun.py @@ -7,7 +7,7 @@ Run commands when the Scapy interpreter starts. """ -import code,sys +import code, sys, importlib from scapy.config import conf from scapy.themes import * from scapy.error import Scapy_Exception @@ -36,13 +36,16 @@ def showtraceback(self, *args, **kargs): return code.InteractiveInterpreter.showtraceback(self, *args, **kargs) -def autorun_commands(cmds,my_globals=None,verb=0): +def autorun_commands(cmds, my_globals=None, ignore_globals=None, verb=0): sv = conf.verb import __builtin__ try: try: if my_globals is None: - my_globals = __import__("scapy.all").all.__dict__ + my_globals = importlib.import_module(".all", "scapy").__dict__ + if ignore_globals: + for ig in ignore_globals: + my_globals.pop(ig, None) conf.verb = verb interp = ScapyAutorunInterpreter(my_globals) cmd = "" @@ -50,7 +53,7 @@ def autorun_commands(cmds,my_globals=None,verb=0): cmds.append("") # ensure we finish multi-line commands cmds.reverse() __builtin__.__dict__["_"] = None - while 1: + while True: if cmd: sys.stderr.write(sys.__dict__.get("ps2","... ")) else: @@ -87,7 +90,7 @@ def flush(self): try: sys.stdout = sys.stderr = sw res = autorun_commands(cmds, **kargs) - except StopAutorun,e: + except StopAutorun as e: e.code_run = sw.s raise finally: @@ -119,7 +122,7 @@ def autorun_get_html_interactive_session(cmds, **kargs): try: conf.color_theme = HTMLTheme2() s,res = autorun_get_interactive_session(cmds, **kargs) - except StopAutorun,e: + except StopAutorun as e: e.code_run = to_html(e.code_run) raise finally: @@ -134,7 +137,7 @@ def autorun_get_latex_interactive_session(cmds, **kargs): try: conf.color_theme = LatexTheme2() s,res = autorun_get_interactive_session(cmds, **kargs) - except StopAutorun,e: + except StopAutorun as e: e.code_run = to_latex(e.code_run) raise finally: diff --git a/scapy/base_classes.py b/scapy/base_classes.py index a97e5822125..eb9976da2a4 100644 --- a/scapy/base_classes.py +++ b/scapy/base_classes.py @@ -57,7 +57,7 @@ def _parse_digit(a,netmask): if a == "*": a = (0,256) elif a.find("-") >= 0: - x,y = map(int,a.split("-")) + x, y = [int(d) for d in a.split('-')] if x > y: y = x a = (x & (0xff<>(8-netmask))))+1) @@ -71,7 +71,8 @@ def _parse_net(cls, net): if not cls.ipaddress.match(net): tmp[0]=socket.gethostbyname(tmp[0]) netmask = int(tmp[1]) - return map(lambda x,y: cls._parse_digit(x,y), tmp[0].split("."), map(lambda x,nm=netmask: x-nm, (8,16,24,32))),netmask + ret_list = [cls._parse_digit(x, y-netmask) for (x, y) in zip(tmp[0].split('.'), [8, 16, 24, 32])] + return ret_list, netmask def __init__(self, net): self.repr=net @@ -130,10 +131,10 @@ def __repr__(self): return "OID(%r)" % self.oid def __iter__(self): ii = [k[0] for k in self.cmpt] - while 1: + while True: yield self.fmt % tuple(ii) i = 0 - while 1: + while True: if i >= len(ii): raise StopIteration if ii[i] < self.cmpt[i][1]: diff --git a/scapy/config.py b/scapy/config.py index 4b93dc719fd..6c9cf8c255b 100755 --- a/scapy/config.py +++ b/scapy/config.py @@ -77,9 +77,9 @@ def __init__(self): def _is_field(f): return hasattr(f, "owners") def _recalc_layer_list(self): - self.layers = set([owner for f in self.fields for owner in f.owners]) + self.layers = {owner for f in self.fields for owner in f.owners} def add(self, *flds): - self.fields |= set([f for f in flds if self._is_field(f)]) + self.fields |= {f for f in flds if self._is_field(f)} self._recalc_layer_list() def remove(self, *flds): self.fields -= set(flds) diff --git a/scapy/contrib/HomePlugAV.py b/scapy/contrib/HomePlugAV.py index 76ebb95e467..7248d694a8a 100644 --- a/scapy/contrib/HomePlugAV.py +++ b/scapy/contrib/HomePlugAV.py @@ -1,3 +1,22 @@ +#! /usr/bin/env python + +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . + +# scapy.contrib.description = HomePlugAV Layer +# scapy.contrib.status = loads + from scapy.packet import * from scapy.fields import * from scapy.layers.l2 import Ether diff --git a/scapy/contrib/avs.py b/scapy/contrib/avs.py index 8f40aff1ec9..2d9183d6766 100644 --- a/scapy/contrib/avs.py +++ b/scapy/contrib/avs.py @@ -1,6 +1,18 @@ #! /usr/bin/env python -# http://trac.secdev.org/scapy/ticket/82 +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . # scapy.contrib.description = AVS WLAN Monitor Header # scapy.contrib.status = loads diff --git a/scapy/contrib/bgp.py b/scapy/contrib/bgp.py index 699c589e26b..e831066683d 100644 --- a/scapy/contrib/bgp.py +++ b/scapy/contrib/bgp.py @@ -1,7 +1,16 @@ # This file is part of Scapy -# See http://www.secdev.org/projects/scapy for more information -# Copyright (C) Philippe Biondi -# This program is published under a GPLv2 license +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . # scapy.contrib.description = BGP v0.1 # scapy.contrib.status = loads @@ -2016,7 +2025,7 @@ def post_build(self, p, pay): # Set default flags value ? if self.type_flags is None: # Set the standard value, if it is exists in attributes_flags. - if attributes_flags.has_key(self.type_code): + if self.type_code in attributes_flags: flags_value = attributes_flags.get(self.type_code) # Otherwise, set to optional, non-transitive. diff --git a/scapy/contrib/carp.py b/scapy/contrib/carp.py index 17fc37dfad9..9d98a086a05 100644 --- a/scapy/contrib/carp.py +++ b/scapy/contrib/carp.py @@ -1,3 +1,16 @@ +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . # scapy.contrib.description = CARP # scapy.contrib.status = loads diff --git a/scapy/contrib/cdp.py b/scapy/contrib/cdp.py index 93d1ed86850..aebc16b64d6 100644 --- a/scapy/contrib/cdp.py +++ b/scapy/contrib/cdp.py @@ -11,7 +11,8 @@ ## Arnaud Ebalard ## ## EADS/CRC security team ## ## ## -## This program is free software; you can redistribute it and/or modify it ## +## This file is part of Scapy ## +## Scapy is free software: you can redistribute it and/or modify it ## ## under the terms of the GNU General Public License version 2 as ## ## published by the Free Software Foundation; version 2. ## ## ## diff --git a/scapy/contrib/chdlc.py b/scapy/contrib/chdlc.py index 6e48376226a..610d8223d1b 100644 --- a/scapy/contrib/chdlc.py +++ b/scapy/contrib/chdlc.py @@ -1,4 +1,16 @@ -# http://trac.secdev.org/scapy/ticket/88 +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . # scapy.contrib.description = Cisco HDLC and SLARP # scapy.contrib.status = loads diff --git a/scapy/contrib/coap.py b/scapy/contrib/coap.py index aa2a1f6f719..939aa53e6be 100644 --- a/scapy/contrib/coap.py +++ b/scapy/contrib/coap.py @@ -1,3 +1,5 @@ +#! /usr/bin/env python + # This file is part of Scapy. # See http://www.secdev.org/projects/scapy for more information. # @@ -16,6 +18,9 @@ # # Copyright (C) 2016 Anmol Sarma +# scapy.contrib.description = Constrained Application Protocol (CoAP) +# scapy.contrib.status = loads + """ RFC 7252 - Constrained Application Protocol (CoAP) layer for Scapy """ diff --git a/scapy/contrib/dtp.py b/scapy/contrib/dtp.py index 9996118aa0a..208f6bacbcc 100644 --- a/scapy/contrib/dtp.py +++ b/scapy/contrib/dtp.py @@ -1,5 +1,19 @@ #!/usr/bin/env python +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . + # scapy.contrib.description = DTP # scapy.contrib.status = loads @@ -20,6 +34,7 @@ from scapy.fields import * from scapy.layers.l2 import SNAP,Dot3,LLC from scapy.sendrecv import sendp +from functools import reduce class DtpGenericTlv(Packet): name = "DTP Generic TLV" @@ -50,7 +65,7 @@ def getfield(self, pkt, s): return remain,lst def addfield(self, pkt, s, val): - return s+reduce(str.__add__, map(str, val),"") + return s + ''.join(str(v) for v in val) _DTP_TLV_CLS = { 0x0001 : "DTPDomain", diff --git a/scapy/contrib/eigrp.py b/scapy/contrib/eigrp.py index 55b48f8d4f1..b931c9d0a6e 100644 --- a/scapy/contrib/eigrp.py +++ b/scapy/contrib/eigrp.py @@ -1,5 +1,19 @@ #!/usr/bin/env python +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . + # scapy.contrib.description = EIGRP # scapy.contrib.status = loads @@ -12,16 +26,6 @@ :e-mail: lobo@c3a.de / jochen.bartl@gmail.com :license: GPL v2 - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - :TODO - Replace TLV code with a more generic solution @@ -43,6 +47,7 @@ from scapy.fields import * from scapy.layers.inet import IP from scapy.layers.inet6 import * +from functools import reduce class EigrpIPField(StrField, IPField): """ @@ -261,13 +266,13 @@ def h2i(self, pkt, x): Valid numbers are between 0 and 255. """ - if type(x) is str and x.startswith("v") and len(x) <= 8: + if isinstance(x, str) and x.startswith("v") and len(x) <= 8: major = int(x.split(".")[0][1:]) minor = int(x.split(".")[1]) return (major << 8) | minor - elif type(x) is int and 0 <= x <= 65535: + elif isinstance(x, int) and 0 <= x <= 65535: return x else: if self.default != None: @@ -431,7 +436,7 @@ def getfield(self, pkt, s): return remain,lst def addfield(self, pkt, s, val): - return s + reduce(str.__add__, map(str, val), "") + return s + ''.join(str(v) for v in val) def _EIGRPGuessPayloadClass(p, **kargs): cls = conf.raw_layer diff --git a/scapy/contrib/etherip.py b/scapy/contrib/etherip.py index e331c14671d..610897189d1 100644 --- a/scapy/contrib/etherip.py +++ b/scapy/contrib/etherip.py @@ -1,5 +1,16 @@ - -# http://trac.secdev.org/scapy/ticket/297 +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . # scapy.contrib.description = EtherIP # scapy.contrib.status = loads diff --git a/scapy/contrib/gsm_um.py b/scapy/contrib/gsm_um.py index 4d1bd33065c..7f370e17b58 100644 --- a/scapy/contrib/gsm_um.py +++ b/scapy/contrib/gsm_um.py @@ -1,23 +1,22 @@ #!/usr/bin/env python +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . + # scapy.contrib.description = PPI # scapy.contrib.status = loads -""" - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -""" - #################################################################### # This file holds the GSM UM interface implementation for Scapy # # author: Laurent Weber # @@ -50,7 +49,7 @@ def sendum(x, typeSock=0): try: - if type(x) is not str: + if not isinstance(x, str): x = str(x) if typeSock is 0: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) diff --git a/scapy/contrib/gtp.py b/scapy/contrib/gtp.py index 4fef6c023c2..8e40b17be71 100644 --- a/scapy/contrib/gtp.py +++ b/scapy/contrib/gtp.py @@ -1,198 +1,198 @@ -#! /usr/bin/env python - -## Copyright (C) 2017 Alexis Sultan -## 2017 Alessio Deiana -## 2014 Guillaume Valadon -## 2012 ffranz -## -## This program is published under a GPLv2 license - -# scapy.contrib.description = GTP -# scapy.contrib.status = loads - -import time -import logging - -from scapy.packet import * -from scapy.fields import * -from scapy.layers.inet import IP, UDP -from scapy.layers.inet6 import IP6Field -from scapy.error import warning - -# GTP Data types - -RATType = { - 1: "UTRAN", - 2: "GETRAN", - 3: "WLAN", - 4: "GAN", - 5: "HSPA" -} - -GTPmessageType = { 1: "echo_request", - 2: "echo_response", - 16: "create_pdp_context_req", - 17: "create_pdp_context_res", - 18: "update_pdp_context_req", - 19: "update_pdp_context_resp", - 20: "delete_pdp_context_req", - 21: "delete_pdp_context_res", - 26: "error_indication", - 27: "pdu_notification_req", - 255: "gtp_u_header" } - -IEType = { 1: "Cause", - 2: "IMSI", - 3: "RAI", - 4: "TLLI", - 5: "P_TMSI", - 8: "IE_ReorderingRequired", - 14: "Recovery", - 15: "SelectionMode", - 16: "TEIDI", - 17: "TEICP", - 19: "TeardownInd", - 20: "NSAPI", - 26: "ChargingChrt", - 27: "TraceReference", - 28: "TraceType", - 127: "ChargingId", - 128: "EndUserAddress", - 131: "AccessPointName", - 132: "ProtocolConfigurationOptions", - 133: "GSNAddress", - 134: "MSInternationalNumber", - 135: "QoS", - 148: "CommonFlags", - 149: "APNRestriction", - 151: "RatType", - 152: "UserLocationInformation", - 153: "MSTimeZone", - 154: "IMEI", - 181: "MSInfoChangeReportingAction", - 184: "BearerControlMode", - 191: "EvolvedAllocationRetentionPriority", - 255: "PrivateExtention"} - -CauseValues = { 0: "Request IMSI", - 1: "Request IMEI", - 2: "Request IMSI and IMEI", - 3: "No identity needed", - 4: "MS Refuses", - 5: "MS is not GPRS Responding", - 128: "Request accepted", - 129: "New PDP type due to network preference", - 130: "New PDP type due to single address bearer only", - 192: "Non-existent", - 193: "Invalid message format", - 194: "IMSI not known", - 195: "MS is GPRS Detached", - 196: "MS is not GPRS Responding", - 197: "MS Refuses", - 198: "Version not supported", - 199: "No resources available", - 200: "Service not supported", - 201: "Mandatory IE incorrect", - 202: "Mandatory IE missing", - 203: "Optional IE incorrect", - 204: "System failure", - 205: "Roaming restriction", - 206: "P-TMSI Signature mismatch", - 207: "GPRS connection suspended", - 208: "Authentication failure", - 209: "User authentication failed", - 210: "Context not found", - 211: "All dynamic PDP addresses are occupied", - 212: "No memory is available", - 213: "Reallocation failure", - 214: "Unknown mandatory extension header", - 215: "Semantic error in the TFT operation", - 216: "Syntactic error in TFT operation", - 217: "Semantic errors in packet filter(s)", - 218: "Syntactic errors in packet filter(s)", - 219: "Missing or unknown APN", - 220: "Unknown PDP address or PDP type", - 221: "PDP context without TFT already activated", - 222: "APN access denied : no subscription", - 223: "APN Restriction type incompatibility with currently active PDP Contexts", - 224: "MS MBMS Capabilities Insufficient", - 225: "Invalid Correlation : ID", - 226: "MBMS Bearer Context Superseded", - 227: "Bearer Control Mode violation", - 228: "Collision with network initiated request" } - -Selection_Mode = { 11111100: "MS or APN", - 11111101: "MS", - 11111110: "NET", - 11111111: "FutureUse" } - -TrueFalse_value = {254: "False", - 255: "True"} - - -class TBCDByteField(StrFixedLenField): - - def i2h(self, pkt, val): - return val - - def i2repr(self, pkt, x): - return repr(self.i2h(pkt,x)) - - def m2i(self, pkt, val): - ret = [] - for v in val: - byte = ord(v) - left = byte >> 4 - right = byte & 0xf - if left == 0xf: - ret += [TBCD_TO_ASCII[right]] - else: - ret += [TBCD_TO_ASCII[right], TBCD_TO_ASCII[left]] - return "".join(ret) - - def i2m(self, pkt, val): - val = str(val) - ret_string = "" - for i in xrange(0, len(val), 2): - tmp = val[i:i+2] - if len(tmp) == 2: - ret_string += chr(int(tmp[1] + tmp[0], 16)) - else: - ret_string += chr(int("F" + tmp[0], 16)) - return ret_string - - -TBCD_TO_ASCII = "0123456789*#abc" - - -class GTPHeader(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP Header" - fields_desc=[ BitField("version", 1, 3), - BitField("PT", 1, 1), - BitField("reserved", 0, 1), - BitField("E", 0, 1), - BitField("S", 1, 1), - BitField("PN", 0, 1), - ByteEnumField("gtp_type", None, GTPmessageType), - ShortField("length", None), - IntField("teid", 0) ] - - def post_build(self, p, pay): - p += pay - if self.length is None: - l = len(p)-8 - p = p[:2] + struct.pack("!H", l)+ p[4:] - return p - - def hashret(self): - return struct.pack("B", self.version) + self.payload.hashret() - - def answers(self, other): - return (isinstance(other, GTPHeader) and - self.version == other.version and - self.payload.answers(other.payload)) - +#! /usr/bin/env python + +## Copyright (C) 2017 Alexis Sultan +## 2017 Alessio Deiana +## 2014 Guillaume Valadon +## 2012 ffranz +## +## This program is published under a GPLv2 license + +# scapy.contrib.description = GTP +# scapy.contrib.status = loads + +import time +import logging + +from scapy.packet import * +from scapy.fields import * +from scapy.layers.inet import IP, UDP +from scapy.layers.inet6 import IP6Field +from scapy.error import warning + +# GTP Data types + +RATType = { + 1: "UTRAN", + 2: "GETRAN", + 3: "WLAN", + 4: "GAN", + 5: "HSPA" +} + +GTPmessageType = { 1: "echo_request", + 2: "echo_response", + 16: "create_pdp_context_req", + 17: "create_pdp_context_res", + 18: "update_pdp_context_req", + 19: "update_pdp_context_resp", + 20: "delete_pdp_context_req", + 21: "delete_pdp_context_res", + 26: "error_indication", + 27: "pdu_notification_req", + 255: "gtp_u_header" } + +IEType = { 1: "Cause", + 2: "IMSI", + 3: "RAI", + 4: "TLLI", + 5: "P_TMSI", + 8: "IE_ReorderingRequired", + 14: "Recovery", + 15: "SelectionMode", + 16: "TEIDI", + 17: "TEICP", + 19: "TeardownInd", + 20: "NSAPI", + 26: "ChargingChrt", + 27: "TraceReference", + 28: "TraceType", + 127: "ChargingId", + 128: "EndUserAddress", + 131: "AccessPointName", + 132: "ProtocolConfigurationOptions", + 133: "GSNAddress", + 134: "MSInternationalNumber", + 135: "QoS", + 148: "CommonFlags", + 149: "APNRestriction", + 151: "RatType", + 152: "UserLocationInformation", + 153: "MSTimeZone", + 154: "IMEI", + 181: "MSInfoChangeReportingAction", + 184: "BearerControlMode", + 191: "EvolvedAllocationRetentionPriority", + 255: "PrivateExtention"} + +CauseValues = { 0: "Request IMSI", + 1: "Request IMEI", + 2: "Request IMSI and IMEI", + 3: "No identity needed", + 4: "MS Refuses", + 5: "MS is not GPRS Responding", + 128: "Request accepted", + 129: "New PDP type due to network preference", + 130: "New PDP type due to single address bearer only", + 192: "Non-existent", + 193: "Invalid message format", + 194: "IMSI not known", + 195: "MS is GPRS Detached", + 196: "MS is not GPRS Responding", + 197: "MS Refuses", + 198: "Version not supported", + 199: "No resources available", + 200: "Service not supported", + 201: "Mandatory IE incorrect", + 202: "Mandatory IE missing", + 203: "Optional IE incorrect", + 204: "System failure", + 205: "Roaming restriction", + 206: "P-TMSI Signature mismatch", + 207: "GPRS connection suspended", + 208: "Authentication failure", + 209: "User authentication failed", + 210: "Context not found", + 211: "All dynamic PDP addresses are occupied", + 212: "No memory is available", + 213: "Reallocation failure", + 214: "Unknown mandatory extension header", + 215: "Semantic error in the TFT operation", + 216: "Syntactic error in TFT operation", + 217: "Semantic errors in packet filter(s)", + 218: "Syntactic errors in packet filter(s)", + 219: "Missing or unknown APN", + 220: "Unknown PDP address or PDP type", + 221: "PDP context without TFT already activated", + 222: "APN access denied : no subscription", + 223: "APN Restriction type incompatibility with currently active PDP Contexts", + 224: "MS MBMS Capabilities Insufficient", + 225: "Invalid Correlation : ID", + 226: "MBMS Bearer Context Superseded", + 227: "Bearer Control Mode violation", + 228: "Collision with network initiated request" } + +Selection_Mode = { 11111100: "MS or APN", + 11111101: "MS", + 11111110: "NET", + 11111111: "FutureUse" } + +TrueFalse_value = {254: "False", + 255: "True"} + + +class TBCDByteField(StrFixedLenField): + + def i2h(self, pkt, val): + return val + + def i2repr(self, pkt, x): + return repr(self.i2h(pkt,x)) + + def m2i(self, pkt, val): + ret = [] + for v in val: + byte = ord(v) + left = byte >> 4 + right = byte & 0xf + if left == 0xf: + ret += [TBCD_TO_ASCII[right]] + else: + ret += [TBCD_TO_ASCII[right], TBCD_TO_ASCII[left]] + return "".join(ret) + + def i2m(self, pkt, val): + val = str(val) + ret_string = "" + for i in xrange(0, len(val), 2): + tmp = val[i:i+2] + if len(tmp) == 2: + ret_string += chr(int(tmp[1] + tmp[0], 16)) + else: + ret_string += chr(int("F" + tmp[0], 16)) + return ret_string + + +TBCD_TO_ASCII = "0123456789*#abc" + + +class GTPHeader(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP Header" + fields_desc=[ BitField("version", 1, 3), + BitField("PT", 1, 1), + BitField("reserved", 0, 1), + BitField("E", 0, 1), + BitField("S", 1, 1), + BitField("PN", 0, 1), + ByteEnumField("gtp_type", None, GTPmessageType), + ShortField("length", None), + IntField("teid", 0) ] + + def post_build(self, p, pay): + p += pay + if self.length is None: + l = len(p)-8 + p = p[:2] + struct.pack("!H", l)+ p[4:] + return p + + def hashret(self): + return struct.pack("B", self.version) + self.payload.hashret() + + def answers(self, other): + return (isinstance(other, GTPHeader) and + self.version == other.version and + self.payload.answers(other.payload)) + @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 1: @@ -200,675 +200,675 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs): import gtp_v2 return gtp_v2.GTPHeader return GTPHeader - - -class GTPEchoRequest(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP Echo Request" - fields_desc = [ XBitField("seq", 0, 16), - ByteField("npdu", 0), - ByteField("next_ex", 0),] - - def hashret(self): - return struct.pack("H", self.seq) - - -class IE_Base(Packet): - - def extract_padding(self, pkt): - return "", pkt - - -class IE_Cause(IE_Base): - name = "Cause" - fields_desc = [ByteEnumField("ietype", 1, IEType), - ByteEnumField("CauseValue", None, CauseValues)] - - -class IE_IMSI(IE_Base): - name = "IMSI - Subscriber identity of the MS" - fields_desc = [ByteEnumField("ietype", 2, IEType), - TBCDByteField("imsi", str(RandNum(0, 999999999999999)), 8)] - - -class IE_Routing(IE_Base): - name = "Routing Area Identity" - fields_desc = [ ByteEnumField("ietype", 3, IEType), - TBCDByteField("MCC", "", 2), - # MNC: if the third digit of MCC is 0xf, - # then the length of MNC is 1 byte - TBCDByteField("MNC", "", 1), - ShortField("LAC", None), - ByteField("RAC", None) ] - - -class IE_ReorderingRequired(IE_Base): - name = "Recovery" - fields_desc = [ByteEnumField("ietype", 8, IEType), - ByteEnumField("reordering_required", 254, TrueFalse_value)] - - -class IE_Recovery(IE_Base): - name = "Recovery" - fields_desc = [ ByteEnumField("ietype", 14, IEType), - ByteField("restart_counter", 24) ] - - -class IE_SelectionMode(IE_Base): - # Indicates the origin of the APN in the message - name = "Selection Mode" - fields_desc = [ ByteEnumField("ietype", 15, IEType), - BitEnumField("SelectionMode", "MS or APN", - 8, Selection_Mode) ] - - -class IE_TEIDI(IE_Base): - name = "Tunnel Endpoint Identifier Data" - fields_desc = [ ByteEnumField("ietype", 16, IEType), - XIntField("TEIDI", RandInt()) ] - - -class IE_TEICP(IE_Base): - name = "Tunnel Endpoint Identifier Control Plane" - fields_desc = [ ByteEnumField("ietype", 17, IEType), - XIntField("TEICI", RandInt())] - - -class IE_Teardown(IE_Base): - name = "Teardown Indicator" - fields_desc = [ ByteEnumField("ietype", 19, IEType), - ByteEnumField("indicator", "True", TrueFalse_value) ] - - -class IE_NSAPI(IE_Base): - # Identifies a PDP context in a mobility management context specified by TEICP - name = "NSAPI" - fields_desc = [ ByteEnumField("ietype", 20, IEType), - XBitField("sparebits", 0x0000, 4), - XBitField("NSAPI", RandNum(0, 15), 4) ] - - -class IE_ChargingCharacteristics(IE_Base): - # Way of informing both the SGSN and GGSN of the rules for - name = "Charging Characteristics" - fields_desc = [ ByteEnumField("ietype", 26, IEType), - # producing charging information based on operator configured triggers. - # 0000 .... .... .... : spare - # .... 1... .... .... : normal charging - # .... .0.. .... .... : prepaid charging - # .... ..0. .... .... : flat rate charging - # .... ...0 .... .... : hot billing charging - # .... .... 0000 0000 : reserved - XBitField("Ch_ChSpare", None, 4), - XBitField("normal_charging", None, 1), - XBitField("prepaid_charging", None, 1), - XBitField("flat_rate_charging", None, 1), - XBitField("hot_billing_charging", None, 1), - XBitField("Ch_ChReserved", 0, 8) ] - -class IE_TraceReference(IE_Base): - # Identifies a record or a collection of records for a particular trace. - name = "Trace Reference" - fields_desc = [ ByteEnumField("ietype", 27, IEType), - XBitField("Trace_reference", None, 16) ] - - -class IE_TraceType(IE_Base): - # Indicates the type of the trace - name = "Trace Type" - fields_desc = [ ByteEnumField("ietype", 28, IEType), - XBitField("Trace_type", None, 16) ] - - -class IE_ChargingId(IE_Base): - name = "Charging ID" - fields_desc = [ByteEnumField("ietype", 127, IEType), - XIntField("Charging_id", RandInt())] - - -class IE_EndUserAddress(IE_Base): - # Supply protocol specific information of the external packet - name = "End User Addresss" - fields_desc = [ ByteEnumField("ietype", 128, IEType), - # data network accessed by the GGPRS subscribers. - # - Request - # 1 Type (1byte) - # 2-3 Length (2bytes) - value 2 - # 4 Spare + PDP Type Organization - # 5 PDP Type Number - # - Response - # 6-n PDP Address - ShortField("length", 2), - BitField("SPARE", 15, 4), - BitField("PDPTypeOrganization", 1, 4), - XByteField("PDPTypeNumber", None), - ConditionalField(IPField("PDPAddress", RandIP()), - lambda pkt: pkt.length > 2)] - - -class APNStrLenField(StrLenField): - # Inspired by DNSStrField - def m2i(self, pkt, s): - ret_s = "" - tmp_s = s - while tmp_s: - tmp_len = struct.unpack("!B", tmp_s[0])[0] + 1 - if tmp_len > len(tmp_s): - warning("APN prematured end of character-string (size=%i, remaining bytes=%i)" % (tmp_len, len(tmp_s))) - ret_s += tmp_s[1:tmp_len] - tmp_s = tmp_s[tmp_len:] - if len(tmp_s) : - ret_s += "." - s = ret_s - return s - def i2m(self, pkt, s): - s = "".join(map(lambda x: chr(len(x))+x, s.split("."))) - return s - - -class IE_AccessPointName(IE_Base): - # Sent by SGSN or by GGSN as defined in 3GPP TS 23.060 - name = "Access Point Name" - fields_desc = [ ByteEnumField("ietype", 131, IEType), - ShortField("length", None), - APNStrLenField("APN", "nternet", length_from=lambda x: x.length) ] - - def post_build(self, p, pay): - if self.length is None: - l = len(p)-3 - p = p[:2] + struct.pack("!B", l)+ p[3:] - return p - - -class IE_ProtocolConfigurationOptions(IE_Base): - name = "Protocol Configuration Options" - fields_desc = [ ByteEnumField("ietype", 132, IEType), - ShortField("length", 4), - StrLenField("Protocol_Configuration", "", - length_from=lambda x: x.length) ] - - -class IE_GSNAddress(IE_Base): - name = "GSN Address" - fields_desc = [ ByteEnumField("ietype", 133, IEType), - ShortField("length", 4), - IPField("address", RandIP()) ] - - -class IE_MSInternationalNumber(IE_Base): - name = "MS International Number" - fields_desc = [ ByteEnumField("ietype", 134, IEType), - ShortField("length", None), - FlagsField("flags", 0x91, 8, ["Extension","","","International Number","","","","ISDN numbering"]), - TBCDByteField("digits", "33607080910", length_from=lambda x: x.length-1) ] - - -class QoS_Profile(IE_Base): - name = "QoS profile" - fields_desc = [ByteField("qos_ei", 0), - ByteField("length", None), - XBitField("spare", 0x00, 2), - XBitField("delay_class", 0x000, 3), - XBitField("reliability_class", 0x000, 3), - XBitField("peak_troughput", 0x0000, 4), - BitField("spare", 0, 1), - XBitField("precedence_class", 0x000, 3), - XBitField("spare", 0x000, 3), - XBitField("mean_troughput", 0x00000, 5), - XBitField("traffic_class", 0x000, 3), - XBitField("delivery_order", 0x00, 2), - XBitField("delivery_of_err_sdu", 0x000, 3), - ByteField("max_sdu_size", None), - ByteField("max_bitrate_up", None), - ByteField("max_bitrate_down", None), - XBitField("redidual_ber", 0x0000, 4), - XBitField("sdu_err_ratio", 0x0000, 4), - XBitField("transfer_delay", 0x00000, 5), - XBitField("traffic_handling_prio", 0x000, 3), - ByteField("guaranteed_bit_rate_up", None), - ByteField("guaranteed_bit_rate_down", None)] - - -class IE_QoS(IE_Base): - name = "QoS" - fields_desc = [ByteEnumField("ietype", 135, IEType), - ShortField("length", None), - ByteField("allocation_retention_prioiry", 1), - - ConditionalField(XBitField("spare", 0x00, 2), - lambda pkt: pkt.length > 1), - ConditionalField(XBitField("delay_class", 0x000, 3), - lambda pkt: pkt.length > 1), - ConditionalField(XBitField("reliability_class", 0x000, 3), - lambda pkt: pkt.length > 1), - - ConditionalField(XBitField("peak_troughput", 0x0000, 4), - lambda pkt: pkt.length > 2), - ConditionalField(BitField("spare", 0, 1), - lambda pkt: pkt.length > 2), - ConditionalField(XBitField("precedence_class", 0x000, 3), - lambda pkt: pkt.length > 2), - - ConditionalField(XBitField("spare", 0x000, 3), - lambda pkt: pkt.length > 3), - ConditionalField(XBitField("mean_troughput", 0x00000, 5), - lambda pkt: pkt.length > 3), - - ConditionalField(XBitField("traffic_class", 0x000, 3), - lambda pkt: pkt.length > 4), - ConditionalField(XBitField("delivery_order", 0x00, 2), - lambda pkt: pkt.length > 4), - ConditionalField(XBitField("delivery_of_err_sdu", 0x000, 3), - lambda pkt: pkt.length > 4), - - ConditionalField(ByteField("max_sdu_size", None), - lambda pkt: pkt.length > 5), - ConditionalField(ByteField("max_bitrate_up", None), - lambda pkt: pkt.length > 6), - ConditionalField(ByteField("max_bitrate_down", None), - lambda pkt: pkt.length > 7), - - ConditionalField(XBitField("redidual_ber", 0x0000, 4), - lambda pkt: pkt.length > 8), - ConditionalField(XBitField("sdu_err_ratio", 0x0000, 4), - lambda pkt: pkt.length > 8), - ConditionalField(XBitField("transfer_delay", 0x00000, 6), - lambda pkt: pkt.length > 9), - ConditionalField(XBitField("traffic_handling_prio", - 0x000, - 2), - lambda pkt: pkt.length > 9), - - ConditionalField(ByteField("guaranteed_bit_rate_up", None), - lambda pkt: pkt.length > 10), - ConditionalField(ByteField("guaranteed_bit_rate_down", - None), - lambda pkt: pkt.length > 11), - - ConditionalField(XBitField("spare", 0x000, 3), - lambda pkt: pkt.length > 12), - ConditionalField(BitField("signaling_indication", 0, 1), - lambda pkt: pkt.length > 12), - ConditionalField(XBitField("source_stats_desc", 0x0000, 4), - lambda pkt: pkt.length > 12), - - ConditionalField(ByteField("max_bitrate_down_ext", None), - lambda pkt: pkt.length > 13), - ConditionalField(ByteField("guaranteed_bitrate_down_ext", - None), - lambda pkt: pkt.length > 14), - ConditionalField(ByteField("max_bitrate_up_ext", None), - lambda pkt: pkt.length > 15), - ConditionalField(ByteField("guaranteed_bitrate_up_ext", - None), - lambda pkt: pkt.length > 16), - ConditionalField(ByteField("max_bitrate_down_ext2", None), - lambda pkt: pkt.length > 17), - ConditionalField(ByteField("guaranteed_bitrate_down_ext2", - None), - lambda pkt: pkt.length > 18), - ConditionalField(ByteField("max_bitrate_up_ext2", None), - lambda pkt: pkt.length > 19), - ConditionalField(ByteField("guaranteed_bitrate_up_ext2", - None), - lambda pkt: pkt.length > 20)] - - -class IE_CommonFlags(IE_Base): - name = "Common Flags" - fields_desc = [ByteEnumField("ietype", 148, IEType), - ShortField("length", None), - BitField("dual_addr_bearer_fl", 0, 1), - BitField("upgrade_qos_supported", 0, 1), - BitField("nrsn", 0, 1), - BitField("no_qos_nego", 0, 1), - BitField("mbms_cnting_info", 0, 1), - BitField("ran_procedure_ready", 0, 1), - BitField("mbms_service_type", 0, 1), - BitField("prohibit_payload_compression", 0, 1)] - - -class IE_APNRestriction(IE_Base): - name = "APN Restriction" - fields_desc = [ByteEnumField("ietype", 149, IEType), - ShortField("length", 1), - ByteField("restriction_type_value", 0)] - - -class IE_RATType(IE_Base): - name = "Rat Type" - fields_desc = [ByteEnumField("ietype", 151, IEType), - ShortField("length", 1), - ByteEnumField("RAT_Type", None, RATType)] - - -class IE_UserLocationInformation(IE_Base): - name = "User Location Information" - fields_desc = [ ByteEnumField("ietype", 152, IEType), - ShortField("length", None), - ByteField("type", 1), - # Only type 1 is currently supported - TBCDByteField("MCC", "", 2), - # MNC: if the third digit of MCC is 0xf, then the length of MNC is 1 byte - TBCDByteField("MNC", "", 1), - ShortField("LAC", None), - ShortField("SAC", None) ] - - -class IE_MSTimeZone(IE_Base): - name = "MS Time Zone" - fields_desc = [ByteEnumField("ietype", 153, IEType), - ShortField("length", None), - ByteField("timezone", 0), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - XBitField("daylight_saving_time", 0x00, 2)] - - -class IE_IMEI(IE_Base): - name = "IMEI" - fields_desc = [ ByteEnumField("ietype", 154, IEType), - ShortField("length", None), - TBCDByteField("IMEI", "", length_from=lambda x: x.length) ] - - -class IE_MSInfoChangeReportingAction(IE_Base): - name = "MS Info Change Reporting Action" - fields_desc = [ByteEnumField("ietype", 181, IEType), - ShortField("length", 1), - ByteField("Action", 0)] - - -class IE_DirectTunnelFlags(IE_Base): - name = "Direct Tunnel Flags" - fields_desc = [ByteEnumField("ietype", 182, IEType), - ShortField("length", 1), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - BitField("EI", 0, 1), - BitField("GCSI", 0, 1), - BitField("DTI", 0, 1)] - - -class IE_BearerControlMode(IE_Base): - name = "Bearer Control Mode" - fields_desc = [ByteEnumField("ietype", 184, IEType), - ShortField("length", 1), - ByteField("bearer_control_mode", 0)] - - -class IE_EvolvedAllocationRetentionPriority(IE_Base): - name = "Evolved Allocation/Retention Priority" - fields_desc = [ByteEnumField("ietype", 191, IEType), - ShortField("length", 1), - BitField("Spare", 0, 1), - BitField("PCI", 0, 1), - XBitField("PL", 0x0000, 4), - BitField("Spare", 0, 1), - BitField("PVI", 0, 1)] - - -class IE_CharginGatewayAddress(IE_Base): - name = "Chargin Gateway Address" - fields_desc = [ByteEnumField("ietype", 251, IEType), - ShortField("length", 4), - ConditionalField(IPField("ipv4_address", "127.0.0.1"), - lambda - pkt: pkt.length == 4), - ConditionalField(IP6Field("ipv6_address", "::1"), lambda - pkt: pkt.length == 16)] - - -class IE_PrivateExtension(IE_Base): - name = "Private Extension" - fields_desc = [ByteEnumField("ietype", 255, IEType), - ShortField("length", 1), - ByteField("extension identifier", 0), - StrLenField("extention_value", "", - length_from=lambda x: x.length)] - - -class IE_NotImplementedTLV(Packet): - name = "IE not implemented" - fields_desc = [ ByteEnumField("ietype", 0, IEType), - ShortField("length", None), - StrLenField("data", "", length_from=lambda x: x.length) ] - def extract_padding(self, pkt): - return "",pkt - - -ietypecls = {1: IE_Cause, - 2: IE_IMSI, - 3: IE_Routing, - 8: IE_ReorderingRequired, - 14: IE_Recovery, - 15: IE_SelectionMode, - 16: IE_TEIDI, - 17: IE_TEICP, - 19: IE_Teardown, - 20: IE_NSAPI, - 26: IE_ChargingCharacteristics, - 27: IE_TraceReference, - 28: IE_TraceType, - 127: IE_ChargingId, - 128: IE_EndUserAddress, - 131: IE_AccessPointName, - 132: IE_ProtocolConfigurationOptions, - 133: IE_GSNAddress, - 134: IE_MSInternationalNumber, - 135: IE_QoS, - 148: IE_CommonFlags, - 149: IE_APNRestriction, - 151: IE_RATType, - 152: IE_UserLocationInformation, - 153: IE_MSTimeZone, - 154: IE_IMEI, - 181: IE_MSInfoChangeReportingAction, - 182: IE_DirectTunnelFlags, - 184: IE_BearerControlMode, - 191: IE_EvolvedAllocationRetentionPriority, - 251: IE_CharginGatewayAddress, - 255: IE_PrivateExtension} - - -def IE_Dispatcher(s): - """Choose the correct Information Element class.""" - - if len(s) < 1: - return Raw(s) - - # Get the IE type - ietype = ord(s[0]) - cls = ietypecls.get(ietype, Raw) - - # if ietype greater than 128 are TLVs - if cls == Raw and ietype & 128 == 128: - cls = IE_NotImplementedTLV - - return cls(s) - -class GTPEchoResponse(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP Echo Response" - fields_desc = [ XBitField("seq", 0, 16), - ByteField("npdu", 0), - ByteField("next_ex", 0), - PacketListField("IE_list", [], IE_Dispatcher) ] - - def hashret(self): - return struct.pack("H", self.seq) - - def answers(self, other): - return self.seq == other.seq - - -class GTPCreatePDPContextRequest(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP Create PDP Context Request" - fields_desc = [ ShortField("seq", RandShort()), - ByteField("npdu", 0), - ByteField("next_ex", 0), - PacketListField("IE_list", [ IE_TEIDI(), IE_NSAPI(), IE_GSNAddress(), - IE_GSNAddress(), - IE_NotImplementedTLV(ietype=135, length=15,data=RandString(15)) ], - IE_Dispatcher) ] - def hashret(self): - return struct.pack("H", self.seq) - -class GTPCreatePDPContextResponse(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP Create PDP Context Response" - fields_desc = [ ShortField("seq", RandShort()), - ByteField("npdu", 0), - ByteField("next_ex", 0), - PacketListField("IE_list", [], IE_Dispatcher) ] - - def hashret(self): - return struct.pack("H", self.seq) - - def answers(self, other): - return self.seq == other.seq - - -class GTPUpdatePDPContextRequest(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP Update PDP Context Request" - fields_desc = [ShortField("seq", RandShort()), - ByteField("npdu", 0), - ByteField("next_ex", 0), - PacketListField("IE_list", [ - IE_Cause(), - IE_Recovery(), - IE_TEIDI(), - IE_TEICP(), - IE_ChargingId(), - IE_ProtocolConfigurationOptions(), - IE_GSNAddress(), - IE_GSNAddress(), - IE_GSNAddress(), - IE_GSNAddress(), - IE_QoS(), - IE_CharginGatewayAddress(), - IE_CharginGatewayAddress(), - IE_CommonFlags(), - IE_APNRestriction(), - IE_BearerControlMode(), - IE_MSInfoChangeReportingAction(), - IE_EvolvedAllocationRetentionPriority(), - IE_PrivateExtension()], - IE_Dispatcher)] - - def hashret(self): - return struct.pack("H", self.seq) - - -class GTPUpdatePDPContextResponse(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP Update PDP Context Response" - fields_desc = [ShortField("seq", RandShort()), - ByteField("npdu", 0), - ByteField("next_ex", 0), - PacketListField("IE_list", None, IE_Dispatcher)] - - def hashret(self): - return struct.pack("H", self.seq) - - -class GTPErrorIndication(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP Error Indication" - fields_desc = [ XBitField("seq", 0, 16), - ByteField("npdu", 0), - ByteField("next_ex",0), - PacketListField("IE_list", [], IE_Dispatcher) ] - -class GTPDeletePDPContextRequest(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP Delete PDP Context Request" - fields_desc = [ XBitField("seq", 0, 16), - ByteField("npdu", 0), - ByteField("next_ex", 0), - PacketListField("IE_list", [], IE_Dispatcher) ] - -class GTPDeletePDPContextResponse(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP Delete PDP Context Response" - fields_desc = [ XBitField("seq", 0, 16), - ByteField("npdu", 0), - ByteField("next_ex",0), - PacketListField("IE_list", [], IE_Dispatcher) ] - -class GTPPDUNotificationRequest(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP PDU Notification Request" - fields_desc = [ XBitField("seq", 0, 16), - ByteField("npdu", 0), - ByteField("next_ex", 0), - PacketListField("IE_list", [ IE_IMSI(), - IE_TEICP(TEICI=RandInt()), - IE_EndUserAddress(PDPTypeNumber=0x21), - IE_AccessPointName(), - IE_GSNAddress(address="127.0.0.1"), - ], IE_Dispatcher) ] - -class GTP_U_Header(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP-U Header" - # GTP-U protocol is used to transmit T-PDUs between GSN pairs (or between an SGSN and an RNC in UMTS), - # encapsulated in G-PDUs. A G-PDU is a packet including a GTP-U header and a T-PDU. The Path Protocol - # defines the path and the GTP-U header defines the tunnel. Several tunnels may be multiplexed on a single path. - fields_desc = [ BitField("version", 1,3), - BitField("PT", 1, 1), - BitField("Reserved", 0, 1), - BitField("E", 0,1), - BitField("S", 0, 1), - BitField("PN", 0, 1), - ByteEnumField("gtp_type", None, GTPmessageType), - BitField("length", None, 16), - XBitField("TEID", 0, 32), - ConditionalField(XBitField("seq", 0, 16), lambda pkt:pkt.E==1 or pkt.S==1 or pkt.PN==1), - ConditionalField(ByteField("npdu", 0), lambda pkt:pkt.E==1 or pkt.S==1 or pkt.PN==1), - ConditionalField(ByteField("next_ex", 0), lambda pkt:pkt.E==1 or pkt.S==1 or pkt.PN==1), - ] - - def post_build(self, p, pay): - p += pay - if self.length is None: - l = len(p)-8 - p = p[:2] + struct.pack("!H", l)+ p[4:] - return p - -class GTPmorethan1500(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP More than 1500" - fields_desc = [ ByteEnumField("IE_Cause", "Cause", IEType), - BitField("IE", 1, 12000),] - -# Bind GTP-C -bind_layers(UDP, GTPHeader, dport = 2123) -bind_layers(UDP, GTPHeader, sport = 2123) -bind_layers(GTPHeader, GTPEchoRequest, gtp_type=1) -bind_layers(GTPHeader, GTPEchoResponse, gtp_type=2) -bind_layers(GTPHeader, GTPCreatePDPContextRequest, gtp_type=16) -bind_layers(GTPHeader, GTPCreatePDPContextResponse, gtp_type=17) -bind_layers(GTPHeader, GTPUpdatePDPContextRequest, gtp_type=18) -bind_layers(GTPHeader, GTPUpdatePDPContextResponse, gtp_type=19) -bind_layers(GTPHeader, GTPDeletePDPContextRequest, gtp_type=20) -bind_layers(GTPHeader, GTPDeletePDPContextResponse, gtp_type=21) -bind_layers(GTPHeader, GTPPDUNotificationRequest, gtp_type=27) - -# Bind GTP-U -bind_layers(UDP, GTP_U_Header, dport = 2152) -bind_layers(UDP, GTP_U_Header, sport = 2152) -bind_layers(GTP_U_Header, IP, gtp_type = 255) - -if __name__ == "__main__": - from scapy.all import * - interact(mydict=globals(), mybanner="GTPv1 add-on") + + +class GTPEchoRequest(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP Echo Request" + fields_desc = [ XBitField("seq", 0, 16), + ByteField("npdu", 0), + ByteField("next_ex", 0),] + + def hashret(self): + return struct.pack("H", self.seq) + + +class IE_Base(Packet): + + def extract_padding(self, pkt): + return "", pkt + + +class IE_Cause(IE_Base): + name = "Cause" + fields_desc = [ByteEnumField("ietype", 1, IEType), + ByteEnumField("CauseValue", None, CauseValues)] + + +class IE_IMSI(IE_Base): + name = "IMSI - Subscriber identity of the MS" + fields_desc = [ByteEnumField("ietype", 2, IEType), + TBCDByteField("imsi", str(RandNum(0, 999999999999999)), 8)] + + +class IE_Routing(IE_Base): + name = "Routing Area Identity" + fields_desc = [ ByteEnumField("ietype", 3, IEType), + TBCDByteField("MCC", "", 2), + # MNC: if the third digit of MCC is 0xf, + # then the length of MNC is 1 byte + TBCDByteField("MNC", "", 1), + ShortField("LAC", None), + ByteField("RAC", None) ] + + +class IE_ReorderingRequired(IE_Base): + name = "Recovery" + fields_desc = [ByteEnumField("ietype", 8, IEType), + ByteEnumField("reordering_required", 254, TrueFalse_value)] + + +class IE_Recovery(IE_Base): + name = "Recovery" + fields_desc = [ ByteEnumField("ietype", 14, IEType), + ByteField("restart_counter", 24) ] + + +class IE_SelectionMode(IE_Base): + # Indicates the origin of the APN in the message + name = "Selection Mode" + fields_desc = [ ByteEnumField("ietype", 15, IEType), + BitEnumField("SelectionMode", "MS or APN", + 8, Selection_Mode) ] + + +class IE_TEIDI(IE_Base): + name = "Tunnel Endpoint Identifier Data" + fields_desc = [ ByteEnumField("ietype", 16, IEType), + XIntField("TEIDI", RandInt()) ] + + +class IE_TEICP(IE_Base): + name = "Tunnel Endpoint Identifier Control Plane" + fields_desc = [ ByteEnumField("ietype", 17, IEType), + XIntField("TEICI", RandInt())] + + +class IE_Teardown(IE_Base): + name = "Teardown Indicator" + fields_desc = [ ByteEnumField("ietype", 19, IEType), + ByteEnumField("indicator", "True", TrueFalse_value) ] + + +class IE_NSAPI(IE_Base): + # Identifies a PDP context in a mobility management context specified by TEICP + name = "NSAPI" + fields_desc = [ ByteEnumField("ietype", 20, IEType), + XBitField("sparebits", 0x0000, 4), + XBitField("NSAPI", RandNum(0, 15), 4) ] + + +class IE_ChargingCharacteristics(IE_Base): + # Way of informing both the SGSN and GGSN of the rules for + name = "Charging Characteristics" + fields_desc = [ ByteEnumField("ietype", 26, IEType), + # producing charging information based on operator configured triggers. + # 0000 .... .... .... : spare + # .... 1... .... .... : normal charging + # .... .0.. .... .... : prepaid charging + # .... ..0. .... .... : flat rate charging + # .... ...0 .... .... : hot billing charging + # .... .... 0000 0000 : reserved + XBitField("Ch_ChSpare", None, 4), + XBitField("normal_charging", None, 1), + XBitField("prepaid_charging", None, 1), + XBitField("flat_rate_charging", None, 1), + XBitField("hot_billing_charging", None, 1), + XBitField("Ch_ChReserved", 0, 8) ] + +class IE_TraceReference(IE_Base): + # Identifies a record or a collection of records for a particular trace. + name = "Trace Reference" + fields_desc = [ ByteEnumField("ietype", 27, IEType), + XBitField("Trace_reference", None, 16) ] + + +class IE_TraceType(IE_Base): + # Indicates the type of the trace + name = "Trace Type" + fields_desc = [ ByteEnumField("ietype", 28, IEType), + XBitField("Trace_type", None, 16) ] + + +class IE_ChargingId(IE_Base): + name = "Charging ID" + fields_desc = [ByteEnumField("ietype", 127, IEType), + XIntField("Charging_id", RandInt())] + + +class IE_EndUserAddress(IE_Base): + # Supply protocol specific information of the external packet + name = "End User Addresss" + fields_desc = [ ByteEnumField("ietype", 128, IEType), + # data network accessed by the GGPRS subscribers. + # - Request + # 1 Type (1byte) + # 2-3 Length (2bytes) - value 2 + # 4 Spare + PDP Type Organization + # 5 PDP Type Number + # - Response + # 6-n PDP Address + ShortField("length", 2), + BitField("SPARE", 15, 4), + BitField("PDPTypeOrganization", 1, 4), + XByteField("PDPTypeNumber", None), + ConditionalField(IPField("PDPAddress", RandIP()), + lambda pkt: pkt.length > 2)] + + +class APNStrLenField(StrLenField): + # Inspired by DNSStrField + def m2i(self, pkt, s): + ret_s = "" + tmp_s = s + while tmp_s: + tmp_len = struct.unpack("!B", tmp_s[0])[0] + 1 + if tmp_len > len(tmp_s): + warning("APN prematured end of character-string (size=%i, remaining bytes=%i)" % (tmp_len, len(tmp_s))) + ret_s += tmp_s[1:tmp_len] + tmp_s = tmp_s[tmp_len:] + if len(tmp_s) : + ret_s += "." + s = ret_s + return s + def i2m(self, pkt, s): + s = "".join(map(lambda x: chr(len(x))+x, s.split("."))) + return s + + +class IE_AccessPointName(IE_Base): + # Sent by SGSN or by GGSN as defined in 3GPP TS 23.060 + name = "Access Point Name" + fields_desc = [ ByteEnumField("ietype", 131, IEType), + ShortField("length", None), + APNStrLenField("APN", "nternet", length_from=lambda x: x.length) ] + + def post_build(self, p, pay): + if self.length is None: + l = len(p)-3 + p = p[:2] + struct.pack("!B", l)+ p[3:] + return p + + +class IE_ProtocolConfigurationOptions(IE_Base): + name = "Protocol Configuration Options" + fields_desc = [ ByteEnumField("ietype", 132, IEType), + ShortField("length", 4), + StrLenField("Protocol_Configuration", "", + length_from=lambda x: x.length) ] + + +class IE_GSNAddress(IE_Base): + name = "GSN Address" + fields_desc = [ ByteEnumField("ietype", 133, IEType), + ShortField("length", 4), + IPField("address", RandIP()) ] + + +class IE_MSInternationalNumber(IE_Base): + name = "MS International Number" + fields_desc = [ ByteEnumField("ietype", 134, IEType), + ShortField("length", None), + FlagsField("flags", 0x91, 8, ["Extension","","","International Number","","","","ISDN numbering"]), + TBCDByteField("digits", "33607080910", length_from=lambda x: x.length-1) ] + + +class QoS_Profile(IE_Base): + name = "QoS profile" + fields_desc = [ByteField("qos_ei", 0), + ByteField("length", None), + XBitField("spare", 0x00, 2), + XBitField("delay_class", 0x000, 3), + XBitField("reliability_class", 0x000, 3), + XBitField("peak_troughput", 0x0000, 4), + BitField("spare", 0, 1), + XBitField("precedence_class", 0x000, 3), + XBitField("spare", 0x000, 3), + XBitField("mean_troughput", 0x00000, 5), + XBitField("traffic_class", 0x000, 3), + XBitField("delivery_order", 0x00, 2), + XBitField("delivery_of_err_sdu", 0x000, 3), + ByteField("max_sdu_size", None), + ByteField("max_bitrate_up", None), + ByteField("max_bitrate_down", None), + XBitField("redidual_ber", 0x0000, 4), + XBitField("sdu_err_ratio", 0x0000, 4), + XBitField("transfer_delay", 0x00000, 5), + XBitField("traffic_handling_prio", 0x000, 3), + ByteField("guaranteed_bit_rate_up", None), + ByteField("guaranteed_bit_rate_down", None)] + + +class IE_QoS(IE_Base): + name = "QoS" + fields_desc = [ByteEnumField("ietype", 135, IEType), + ShortField("length", None), + ByteField("allocation_retention_prioiry", 1), + + ConditionalField(XBitField("spare", 0x00, 2), + lambda pkt: pkt.length > 1), + ConditionalField(XBitField("delay_class", 0x000, 3), + lambda pkt: pkt.length > 1), + ConditionalField(XBitField("reliability_class", 0x000, 3), + lambda pkt: pkt.length > 1), + + ConditionalField(XBitField("peak_troughput", 0x0000, 4), + lambda pkt: pkt.length > 2), + ConditionalField(BitField("spare", 0, 1), + lambda pkt: pkt.length > 2), + ConditionalField(XBitField("precedence_class", 0x000, 3), + lambda pkt: pkt.length > 2), + + ConditionalField(XBitField("spare", 0x000, 3), + lambda pkt: pkt.length > 3), + ConditionalField(XBitField("mean_troughput", 0x00000, 5), + lambda pkt: pkt.length > 3), + + ConditionalField(XBitField("traffic_class", 0x000, 3), + lambda pkt: pkt.length > 4), + ConditionalField(XBitField("delivery_order", 0x00, 2), + lambda pkt: pkt.length > 4), + ConditionalField(XBitField("delivery_of_err_sdu", 0x000, 3), + lambda pkt: pkt.length > 4), + + ConditionalField(ByteField("max_sdu_size", None), + lambda pkt: pkt.length > 5), + ConditionalField(ByteField("max_bitrate_up", None), + lambda pkt: pkt.length > 6), + ConditionalField(ByteField("max_bitrate_down", None), + lambda pkt: pkt.length > 7), + + ConditionalField(XBitField("redidual_ber", 0x0000, 4), + lambda pkt: pkt.length > 8), + ConditionalField(XBitField("sdu_err_ratio", 0x0000, 4), + lambda pkt: pkt.length > 8), + ConditionalField(XBitField("transfer_delay", 0x00000, 6), + lambda pkt: pkt.length > 9), + ConditionalField(XBitField("traffic_handling_prio", + 0x000, + 2), + lambda pkt: pkt.length > 9), + + ConditionalField(ByteField("guaranteed_bit_rate_up", None), + lambda pkt: pkt.length > 10), + ConditionalField(ByteField("guaranteed_bit_rate_down", + None), + lambda pkt: pkt.length > 11), + + ConditionalField(XBitField("spare", 0x000, 3), + lambda pkt: pkt.length > 12), + ConditionalField(BitField("signaling_indication", 0, 1), + lambda pkt: pkt.length > 12), + ConditionalField(XBitField("source_stats_desc", 0x0000, 4), + lambda pkt: pkt.length > 12), + + ConditionalField(ByteField("max_bitrate_down_ext", None), + lambda pkt: pkt.length > 13), + ConditionalField(ByteField("guaranteed_bitrate_down_ext", + None), + lambda pkt: pkt.length > 14), + ConditionalField(ByteField("max_bitrate_up_ext", None), + lambda pkt: pkt.length > 15), + ConditionalField(ByteField("guaranteed_bitrate_up_ext", + None), + lambda pkt: pkt.length > 16), + ConditionalField(ByteField("max_bitrate_down_ext2", None), + lambda pkt: pkt.length > 17), + ConditionalField(ByteField("guaranteed_bitrate_down_ext2", + None), + lambda pkt: pkt.length > 18), + ConditionalField(ByteField("max_bitrate_up_ext2", None), + lambda pkt: pkt.length > 19), + ConditionalField(ByteField("guaranteed_bitrate_up_ext2", + None), + lambda pkt: pkt.length > 20)] + + +class IE_CommonFlags(IE_Base): + name = "Common Flags" + fields_desc = [ByteEnumField("ietype", 148, IEType), + ShortField("length", None), + BitField("dual_addr_bearer_fl", 0, 1), + BitField("upgrade_qos_supported", 0, 1), + BitField("nrsn", 0, 1), + BitField("no_qos_nego", 0, 1), + BitField("mbms_cnting_info", 0, 1), + BitField("ran_procedure_ready", 0, 1), + BitField("mbms_service_type", 0, 1), + BitField("prohibit_payload_compression", 0, 1)] + + +class IE_APNRestriction(IE_Base): + name = "APN Restriction" + fields_desc = [ByteEnumField("ietype", 149, IEType), + ShortField("length", 1), + ByteField("restriction_type_value", 0)] + + +class IE_RATType(IE_Base): + name = "Rat Type" + fields_desc = [ByteEnumField("ietype", 151, IEType), + ShortField("length", 1), + ByteEnumField("RAT_Type", None, RATType)] + + +class IE_UserLocationInformation(IE_Base): + name = "User Location Information" + fields_desc = [ ByteEnumField("ietype", 152, IEType), + ShortField("length", None), + ByteField("type", 1), + # Only type 1 is currently supported + TBCDByteField("MCC", "", 2), + # MNC: if the third digit of MCC is 0xf, then the length of MNC is 1 byte + TBCDByteField("MNC", "", 1), + ShortField("LAC", None), + ShortField("SAC", None) ] + + +class IE_MSTimeZone(IE_Base): + name = "MS Time Zone" + fields_desc = [ByteEnumField("ietype", 153, IEType), + ShortField("length", None), + ByteField("timezone", 0), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + XBitField("daylight_saving_time", 0x00, 2)] + + +class IE_IMEI(IE_Base): + name = "IMEI" + fields_desc = [ ByteEnumField("ietype", 154, IEType), + ShortField("length", None), + TBCDByteField("IMEI", "", length_from=lambda x: x.length) ] + + +class IE_MSInfoChangeReportingAction(IE_Base): + name = "MS Info Change Reporting Action" + fields_desc = [ByteEnumField("ietype", 181, IEType), + ShortField("length", 1), + ByteField("Action", 0)] + + +class IE_DirectTunnelFlags(IE_Base): + name = "Direct Tunnel Flags" + fields_desc = [ByteEnumField("ietype", 182, IEType), + ShortField("length", 1), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + BitField("EI", 0, 1), + BitField("GCSI", 0, 1), + BitField("DTI", 0, 1)] + + +class IE_BearerControlMode(IE_Base): + name = "Bearer Control Mode" + fields_desc = [ByteEnumField("ietype", 184, IEType), + ShortField("length", 1), + ByteField("bearer_control_mode", 0)] + + +class IE_EvolvedAllocationRetentionPriority(IE_Base): + name = "Evolved Allocation/Retention Priority" + fields_desc = [ByteEnumField("ietype", 191, IEType), + ShortField("length", 1), + BitField("Spare", 0, 1), + BitField("PCI", 0, 1), + XBitField("PL", 0x0000, 4), + BitField("Spare", 0, 1), + BitField("PVI", 0, 1)] + + +class IE_CharginGatewayAddress(IE_Base): + name = "Chargin Gateway Address" + fields_desc = [ByteEnumField("ietype", 251, IEType), + ShortField("length", 4), + ConditionalField(IPField("ipv4_address", "127.0.0.1"), + lambda + pkt: pkt.length == 4), + ConditionalField(IP6Field("ipv6_address", "::1"), lambda + pkt: pkt.length == 16)] + + +class IE_PrivateExtension(IE_Base): + name = "Private Extension" + fields_desc = [ByteEnumField("ietype", 255, IEType), + ShortField("length", 1), + ByteField("extension identifier", 0), + StrLenField("extention_value", "", + length_from=lambda x: x.length)] + + +class IE_NotImplementedTLV(Packet): + name = "IE not implemented" + fields_desc = [ ByteEnumField("ietype", 0, IEType), + ShortField("length", None), + StrLenField("data", "", length_from=lambda x: x.length) ] + def extract_padding(self, pkt): + return "",pkt + + +ietypecls = {1: IE_Cause, + 2: IE_IMSI, + 3: IE_Routing, + 8: IE_ReorderingRequired, + 14: IE_Recovery, + 15: IE_SelectionMode, + 16: IE_TEIDI, + 17: IE_TEICP, + 19: IE_Teardown, + 20: IE_NSAPI, + 26: IE_ChargingCharacteristics, + 27: IE_TraceReference, + 28: IE_TraceType, + 127: IE_ChargingId, + 128: IE_EndUserAddress, + 131: IE_AccessPointName, + 132: IE_ProtocolConfigurationOptions, + 133: IE_GSNAddress, + 134: IE_MSInternationalNumber, + 135: IE_QoS, + 148: IE_CommonFlags, + 149: IE_APNRestriction, + 151: IE_RATType, + 152: IE_UserLocationInformation, + 153: IE_MSTimeZone, + 154: IE_IMEI, + 181: IE_MSInfoChangeReportingAction, + 182: IE_DirectTunnelFlags, + 184: IE_BearerControlMode, + 191: IE_EvolvedAllocationRetentionPriority, + 251: IE_CharginGatewayAddress, + 255: IE_PrivateExtension} + + +def IE_Dispatcher(s): + """Choose the correct Information Element class.""" + + if len(s) < 1: + return Raw(s) + + # Get the IE type + ietype = ord(s[0]) + cls = ietypecls.get(ietype, Raw) + + # if ietype greater than 128 are TLVs + if cls == Raw and ietype & 128 == 128: + cls = IE_NotImplementedTLV + + return cls(s) + +class GTPEchoResponse(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP Echo Response" + fields_desc = [ XBitField("seq", 0, 16), + ByteField("npdu", 0), + ByteField("next_ex", 0), + PacketListField("IE_list", [], IE_Dispatcher) ] + + def hashret(self): + return struct.pack("H", self.seq) + + def answers(self, other): + return self.seq == other.seq + + +class GTPCreatePDPContextRequest(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP Create PDP Context Request" + fields_desc = [ ShortField("seq", RandShort()), + ByteField("npdu", 0), + ByteField("next_ex", 0), + PacketListField("IE_list", [ IE_TEIDI(), IE_NSAPI(), IE_GSNAddress(), + IE_GSNAddress(), + IE_NotImplementedTLV(ietype=135, length=15,data=RandString(15)) ], + IE_Dispatcher) ] + def hashret(self): + return struct.pack("H", self.seq) + +class GTPCreatePDPContextResponse(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP Create PDP Context Response" + fields_desc = [ ShortField("seq", RandShort()), + ByteField("npdu", 0), + ByteField("next_ex", 0), + PacketListField("IE_list", [], IE_Dispatcher) ] + + def hashret(self): + return struct.pack("H", self.seq) + + def answers(self, other): + return self.seq == other.seq + + +class GTPUpdatePDPContextRequest(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP Update PDP Context Request" + fields_desc = [ShortField("seq", RandShort()), + ByteField("npdu", 0), + ByteField("next_ex", 0), + PacketListField("IE_list", [ + IE_Cause(), + IE_Recovery(), + IE_TEIDI(), + IE_TEICP(), + IE_ChargingId(), + IE_ProtocolConfigurationOptions(), + IE_GSNAddress(), + IE_GSNAddress(), + IE_GSNAddress(), + IE_GSNAddress(), + IE_QoS(), + IE_CharginGatewayAddress(), + IE_CharginGatewayAddress(), + IE_CommonFlags(), + IE_APNRestriction(), + IE_BearerControlMode(), + IE_MSInfoChangeReportingAction(), + IE_EvolvedAllocationRetentionPriority(), + IE_PrivateExtension()], + IE_Dispatcher)] + + def hashret(self): + return struct.pack("H", self.seq) + + +class GTPUpdatePDPContextResponse(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP Update PDP Context Response" + fields_desc = [ShortField("seq", RandShort()), + ByteField("npdu", 0), + ByteField("next_ex", 0), + PacketListField("IE_list", None, IE_Dispatcher)] + + def hashret(self): + return struct.pack("H", self.seq) + + +class GTPErrorIndication(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP Error Indication" + fields_desc = [ XBitField("seq", 0, 16), + ByteField("npdu", 0), + ByteField("next_ex",0), + PacketListField("IE_list", [], IE_Dispatcher) ] + +class GTPDeletePDPContextRequest(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP Delete PDP Context Request" + fields_desc = [ XBitField("seq", 0, 16), + ByteField("npdu", 0), + ByteField("next_ex", 0), + PacketListField("IE_list", [], IE_Dispatcher) ] + +class GTPDeletePDPContextResponse(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP Delete PDP Context Response" + fields_desc = [ XBitField("seq", 0, 16), + ByteField("npdu", 0), + ByteField("next_ex",0), + PacketListField("IE_list", [], IE_Dispatcher) ] + +class GTPPDUNotificationRequest(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP PDU Notification Request" + fields_desc = [ XBitField("seq", 0, 16), + ByteField("npdu", 0), + ByteField("next_ex", 0), + PacketListField("IE_list", [ IE_IMSI(), + IE_TEICP(TEICI=RandInt()), + IE_EndUserAddress(PDPTypeNumber=0x21), + IE_AccessPointName(), + IE_GSNAddress(address="127.0.0.1"), + ], IE_Dispatcher) ] + +class GTP_U_Header(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP-U Header" + # GTP-U protocol is used to transmit T-PDUs between GSN pairs (or between an SGSN and an RNC in UMTS), + # encapsulated in G-PDUs. A G-PDU is a packet including a GTP-U header and a T-PDU. The Path Protocol + # defines the path and the GTP-U header defines the tunnel. Several tunnels may be multiplexed on a single path. + fields_desc = [ BitField("version", 1,3), + BitField("PT", 1, 1), + BitField("Reserved", 0, 1), + BitField("E", 0,1), + BitField("S", 0, 1), + BitField("PN", 0, 1), + ByteEnumField("gtp_type", None, GTPmessageType), + BitField("length", None, 16), + XBitField("TEID", 0, 32), + ConditionalField(XBitField("seq", 0, 16), lambda pkt:pkt.E==1 or pkt.S==1 or pkt.PN==1), + ConditionalField(ByteField("npdu", 0), lambda pkt:pkt.E==1 or pkt.S==1 or pkt.PN==1), + ConditionalField(ByteField("next_ex", 0), lambda pkt:pkt.E==1 or pkt.S==1 or pkt.PN==1), + ] + + def post_build(self, p, pay): + p += pay + if self.length is None: + l = len(p)-8 + p = p[:2] + struct.pack("!H", l)+ p[4:] + return p + +class GTPmorethan1500(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP More than 1500" + fields_desc = [ ByteEnumField("IE_Cause", "Cause", IEType), + BitField("IE", 1, 12000),] + +# Bind GTP-C +bind_layers(UDP, GTPHeader, dport = 2123) +bind_layers(UDP, GTPHeader, sport = 2123) +bind_layers(GTPHeader, GTPEchoRequest, gtp_type=1) +bind_layers(GTPHeader, GTPEchoResponse, gtp_type=2) +bind_layers(GTPHeader, GTPCreatePDPContextRequest, gtp_type=16) +bind_layers(GTPHeader, GTPCreatePDPContextResponse, gtp_type=17) +bind_layers(GTPHeader, GTPUpdatePDPContextRequest, gtp_type=18) +bind_layers(GTPHeader, GTPUpdatePDPContextResponse, gtp_type=19) +bind_layers(GTPHeader, GTPDeletePDPContextRequest, gtp_type=20) +bind_layers(GTPHeader, GTPDeletePDPContextResponse, gtp_type=21) +bind_layers(GTPHeader, GTPPDUNotificationRequest, gtp_type=27) + +# Bind GTP-U +bind_layers(UDP, GTP_U_Header, dport = 2152) +bind_layers(UDP, GTP_U_Header, sport = 2152) +bind_layers(GTP_U_Header, IP, gtp_type = 255) + +if __name__ == "__main__": + from scapy.all import * + interact(mydict=globals(), mybanner="GTPv1 add-on") diff --git a/scapy/contrib/gtp_v2.py b/scapy/contrib/gtp_v2.py index f656b12110a..b7ee9f3938c 100644 --- a/scapy/contrib/gtp_v2.py +++ b/scapy/contrib/gtp_v2.py @@ -2,8 +2,20 @@ # Copyright (C) 2017 Alessio Deiana # 2017 Alexis Sultan -## -# This program is published under a GPLv2 license + +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . # scapy.contrib.description = GTPv2 # scapy.contrib.status = loads diff --git a/scapy/contrib/http2.py b/scapy/contrib/http2.py index 7c632856a38..7b37a95961e 100644 --- a/scapy/contrib/http2.py +++ b/scapy/contrib/http2.py @@ -6,7 +6,8 @@ ## ## ## Copyright (C) 2016 Florian Maury ## ## ## -## This program is free software; you can redistribute it and/or modify it ## +## This file is part of Scapy ## +## Scapy is free software: you can redistribute it and/or modify it ## ## under the terms of the GNU General Public License version 2 as ## ## published by the Free Software Foundation. ## ## ## @@ -192,7 +193,7 @@ def __init__(self, name, default, size): @return None @raise AssertionError """ - assert(isinstance(default, types.NoneType) or (isinstance(default, (int, long)) and default >= 0)) + assert(default is None or (isinstance(default, (int, long)) and default >= 0)) assert(0 < size <= 8) super(AbstractUVarIntField, self).__init__(name, default) self.size = size @@ -334,7 +335,7 @@ def any2i(self, pkt, x): @return int|None: the converted value. @raise AssertionError """ - if isinstance(x, types.NoneType): + if isinstance(x, type(None)): return x if isinstance(x, (int, long)): assert(x >= 0) @@ -502,7 +503,7 @@ def h2i(self, pkt, x): @raise AssertionError """ ret = super(UVarIntField, self).h2i(pkt, x) - assert(not isinstance(ret, types.NoneType) and ret >= 0) + assert(not isinstance(ret, type(None)) and ret >= 0) return ret def i2h(self, pkt, x): @@ -515,7 +516,7 @@ def i2h(self, pkt, x): @raise AssertionError """ ret = super(UVarIntField, self).i2h(pkt, x) - assert(not isinstance(ret, types.NoneType) and ret >= 0) + assert(not isinstance(ret, type(None)) and ret >= 0) return ret def any2i(self, pkt, x): @@ -528,7 +529,7 @@ def any2i(self, pkt, x): @raise AssertionError """ ret = super(UVarIntField, self).any2i(pkt, x) - assert(not isinstance(ret, types.NoneType) and ret >= 0) + assert(not isinstance(ret, type(None)) and ret >= 0) return ret def i2repr(self, pkt, x): @@ -1038,9 +1039,9 @@ def huffman_decode(cls, i, ibl): assert(i >= 0) assert(ibl >= 0) - if isinstance(cls.static_huffman_tree, types.NoneType): + if isinstance(cls.static_huffman_tree, type(None)): cls.huffman_compute_decode_tree() - assert(not isinstance(cls.static_huffman_tree, types.NoneType)) + assert(not isinstance(cls.static_huffman_tree, type(None))) s = [] j = 0 @@ -1057,7 +1058,7 @@ def huffman_decode(cls, i, ibl): if isinstance(elmt, HuffmanNode): interrupted = True cur = elmt - if isinstance(cur, types.NoneType): + if isinstance(cur, type(None)): raise AssertionError() elif isinstance(elmt, EOS): raise InvalidEncodingException('Huffman decoder met the full EOS symbol') @@ -2236,7 +2237,7 @@ def __init__(self, dynamic_table_max_size=4096, dynamic_table_cap_size=4096): @param int dynamic_table_cap_size: the maximum-maximum size of the dynamic entry table in bytes @raises AssertionError """ - if isinstance(type(self)._static_entries_last_idx, types.NoneType): + if isinstance(type(self)._static_entries_last_idx, type(None)): type(self).init_static_table() assert dynamic_table_max_size <= dynamic_table_cap_size, \ @@ -2409,7 +2410,7 @@ def __len__(self): # type: () -> int """ __len__ returns the summed length of all dynamic entries """ - return sum([len(x) for x in self._dynamic_table]) + return sum(len(x) for x in self._dynamic_table) def gen_txt_repr(self, hdrs, register=True): # type: (Union[H2Frame, List[HPackHeaders]], Optional[bool]) -> str diff --git a/scapy/contrib/icmp_extensions.py b/scapy/contrib/icmp_extensions.py index 3dcaf8d2bcc..44ba75e9ace 100644 --- a/scapy/contrib/icmp_extensions.py +++ b/scapy/contrib/icmp_extensions.py @@ -1,3 +1,22 @@ +#! /usr/bin/env python + +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . + +# scapy.contrib.description = ICMP Extensions +# scapy.contrib.status = loads + import scapy from scapy.packet import Packet, bind_layers from scapy.fields import * diff --git a/scapy/contrib/igmp.py b/scapy/contrib/igmp.py index 705e0de5f9c..a59dcfeb603 100644 --- a/scapy/contrib/igmp.py +++ b/scapy/contrib/igmp.py @@ -1,5 +1,19 @@ #! /usr/bin/env python +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . + # scapy.contrib.description = IGMP/IGMPv2 # scapy.contrib.status = loads diff --git a/scapy/contrib/igmpv3.py b/scapy/contrib/igmpv3.py index e7037291989..7c8aec2549f 100644 --- a/scapy/contrib/igmpv3.py +++ b/scapy/contrib/igmpv3.py @@ -1,6 +1,18 @@ #! /usr/bin/env python -# http://trac.secdev.org/scapy/ticket/31 +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . # scapy.contrib.description = IGMPv3 # scapy.contrib.status = loads diff --git a/scapy/contrib/ikev2.py b/scapy/contrib/ikev2.py index 34d21da75c9..c28b1aee84e 100644 --- a/scapy/contrib/ikev2.py +++ b/scapy/contrib/ikev2.py @@ -1,6 +1,18 @@ #!/usr/bin/env python -# http://trac.secdev.org/scapy/ticket/353 +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . # scapy.contrib.description = IKEv2 # scapy.contrib.status = loads diff --git a/scapy/contrib/isis.py b/scapy/contrib/isis.py index 3b7122e30b3..cb709e1dec9 100644 --- a/scapy/contrib/isis.py +++ b/scapy/contrib/isis.py @@ -1,3 +1,17 @@ +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . + # scapy.contrib.description = ISIS # scapy.contrib.status = loads @@ -122,7 +136,7 @@ def m2i(self, pkt, x): return self.to_id(x) def any2i(self, pkt, x): - if type(x) is str and len(x) == self.length: + if isinstance(x, str) and len(x) == self.length: return self.m2i(pkt, x) return x diff --git a/scapy/contrib/ldp.py b/scapy/contrib/ldp.py index b27b3969916..12019aaf6b6 100644 --- a/scapy/contrib/ldp.py +++ b/scapy/contrib/ldp.py @@ -79,7 +79,7 @@ def m2i(self, pkt, x): x=x[4+nbroctets:] return list def i2m(self, pkt, x): - if type(x) is str: + if isinstance(x, str): return x s = b"\x01\x00" l = 0 @@ -109,7 +109,7 @@ class LabelTLVField(StrField): def m2i(self, pkt, x): return struct.unpack("!I",x[4:8])[0] def i2m(self, pkt, x): - if type(x) is str: + if isinstance(x, str): return x s = b"\x02\x00\x00\x04" s += struct.pack("!I",x) @@ -137,7 +137,7 @@ def m2i(self, pkt, x): list.append(inet_ntoa(add)) return list def i2m(self, pkt, x): - if type(x) is str: + if isinstance(x, str): return x l=2+len(x)*4 s = b"\x01\x01"+struct.pack("!H",l)+b"\x00\x01" @@ -167,7 +167,7 @@ def m2i(self, pkt, x): l.append( struct.unpack("!H", x[12:14])[0] ) return l def i2m(self, pkt, x): - if type(x) is str: + if isinstance(x, str): return x s = b"\x03\x00" + struct.pack("!H",10) statuscode = 0 @@ -205,7 +205,7 @@ def m2i(self, pkt, x): list.append(v) return list def i2m(self, pkt, x): - if type(x) is str: + if isinstance(x, str): return x s = b"\x04\x00\x00\x04" s += struct.pack("!H",x[0]) @@ -236,7 +236,7 @@ def m2i(self, pkt, x): l.append( struct.unpack("!H",x[16:18])[0] ) return l def i2m(self, pkt, x): - if type(x) is str: + if isinstance(x, str): return x s = b"\x05\x00\x00\x0E\x00\x01" s += struct.pack("!H",x[0]) diff --git a/scapy/contrib/modbus.py b/scapy/contrib/modbus.py index a6be7ff50fe..55640711894 100644 --- a/scapy/contrib/modbus.py +++ b/scapy/contrib/modbus.py @@ -14,6 +14,9 @@ # You should have received a copy of the GNU General Public License # along with Scapy. If not, see . +# scapy.contrib.description = ModBus Protocol +# scapy.contrib.status = loads + # Copyright (C) 2016 Arthur Gervais, Ken LE PRADO, Sébastien Mainand from scapy.packet import * diff --git a/scapy/contrib/mpls.py b/scapy/contrib/mpls.py index 6af1d4ac146..732cf2a11fb 100644 --- a/scapy/contrib/mpls.py +++ b/scapy/contrib/mpls.py @@ -1,4 +1,16 @@ -# http://trac.secdev.org/scapy/ticket/31 +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . # scapy.contrib.description = MPLS # scapy.contrib.status = loads @@ -29,3 +41,4 @@ def guess_payload_class(self, payload): bind_layers(Ether, MPLS, type=0x8847) bind_layers(GRE, MPLS, proto=0x8847) +bind_layers(MPLS, MPLS, s=0) diff --git a/scapy/contrib/mqtt.uts b/scapy/contrib/mqtt.uts index 17d92c2d3b9..0b3f456eede 100644 --- a/scapy/contrib/mqtt.uts +++ b/scapy/contrib/mqtt.uts @@ -1,110 +1,110 @@ -# MQTT layer unit tests -# Copyright (C) Santiago Hernandez Ramos -# -# Type the following command to launch start the tests: -# $ test/run_tests -P "load_contrib('mqtt')" -t scapy/contrib/mqtt.uts - -+ Syntax check -= Import the MQTT layer -from scapy.contrib.mqtt import * - - -+ MQTT protocol test - -= MQTTPublish, packet instanciation -p = MQTT()/MQTTPublish(topic='test1',value='test2') -assert(p.type == 3) -assert(p.topic == 'test1') -assert(p.value == 'test2') -assert(p.len == None) -assert(p.length == None) - -= Fixed header and MQTTPublish, packet dissection -s = b'0\n\x00\x04testtest' -publish = MQTT(s) -assert(publish.type == 3) -assert(publish.QOS == 0) -assert(publish.DUP == 0) -assert(publish.RETAIN == 0) -assert(publish.len == 10) -assert(publish[MQTTPublish].length == 4) -assert(publish[MQTTPublish].topic == 'test') -assert(publish[MQTTPublish].value == 'test') - - -= MQTTConnect, packet instanciation -c = MQTT()/MQTTConnect(clientIdlen=5, clientId='newid') -assert(c.type == 1) -assert(c.clientId == 'newid') -assert(c.clientIdlen == 5) - -= MQTTConnect, packet dissection -s = b'\x10\x1f\x00\x06MQIsdp\x03\x02\x00<\x00\x11mosqpub/1440-kali' -connect = MQTT(s) -assert(connect.length == 6) -assert(connect.protoname == 'MQIsdp') -assert(connect.protolevel == 3) -assert(connect.usernameflag == 0) -assert(connect.passwordflag == 0) -assert(connect.willretainflag == 0) -assert(connect.willQOSflag == 0) -assert(connect.willflag == 0) -assert(connect.cleansess == 1) -assert(connect.reserved == 0) -assert(connect.klive == 60) -assert(connect.clientIdlen == 17) -assert(connect.clientId == 'mosqpub/1440-kali') - - -=MQTTConnack, packet instanciation -ck = MQTT()/MQTTConnack(sessPresentFlag=1,retcode=0) -assert(ck.type == 2) -assert(ck.sessPresentFlag == 1) -assert(ck.retcode == 0) - -= MQTTConnack, packet dissection -s = b' \x02\x00\x00' -connack = MQTT(s) -assert(connack.sessPresentFlag == 0) -assert(connack.retcode == 0) - - -= MQTTSubscribe, packet instanciation -sb = MQTT()/MQTTSubscribe(msgid=1,topic='newtopic',QOS=0,length=0) -assert(sb.type == 8) -assert(sb.msgid == 1) -assert(sb.topic == 'newtopic') -assert(sb.length == 0) -assert(sb[MQTTSubscribe].QOS == 0) - -= MQTTSubscribe, packet dissection -s = b'\x82\t\x00\x01\x00\x04test\x00' -subscribe = MQTT(s) -assert(subscribe.msgid == 1) -assert(subscribe.length == 4) -assert(subscribe.topic == 'test') -assert(subscribe.QOS == 1) - - -= MQTTSuback, packet instanciation -sk = MQTT()/MQTTSuback(msgid=1, retcode=0) -assert(sk.type == 9) -assert(sk.msgid == 1) -assert(sk.retcode == 0) - -= MQTTSuback, packet dissection -s = b'\x90\x03\x00\x01\x00' -suback = MQTT(s) -assert(suback.msgid == 1) -assert(suback.retcode == 0) - - -= MQTTPubrec, packet instanciation -pc = MQTT()/MQTTPubrec(msgid=1) -assert(pc.type == 5) -assert(pc.msgid == 1) - -= MQTTPubrec packet dissection -s = b'P\x02\x00\x01' -pubrec = MQTT(s) -assert(pubrec.msgid == 1) +# MQTT layer unit tests +# Copyright (C) Santiago Hernandez Ramos +# +# Type the following command to launch start the tests: +# $ test/run_tests -P "load_contrib('mqtt')" -t scapy/contrib/mqtt.uts + ++ Syntax check += Import the MQTT layer +from scapy.contrib.mqtt import * + + ++ MQTT protocol test + += MQTTPublish, packet instanciation +p = MQTT()/MQTTPublish(topic='test1',value='test2') +assert(p.type == 3) +assert(p.topic == 'test1') +assert(p.value == 'test2') +assert(p.len == None) +assert(p.length == None) + += Fixed header and MQTTPublish, packet dissection +s = b'0\n\x00\x04testtest' +publish = MQTT(s) +assert(publish.type == 3) +assert(publish.QOS == 0) +assert(publish.DUP == 0) +assert(publish.RETAIN == 0) +assert(publish.len == 10) +assert(publish[MQTTPublish].length == 4) +assert(publish[MQTTPublish].topic == 'test') +assert(publish[MQTTPublish].value == 'test') + + += MQTTConnect, packet instanciation +c = MQTT()/MQTTConnect(clientIdlen=5, clientId='newid') +assert(c.type == 1) +assert(c.clientId == 'newid') +assert(c.clientIdlen == 5) + += MQTTConnect, packet dissection +s = b'\x10\x1f\x00\x06MQIsdp\x03\x02\x00<\x00\x11mosqpub/1440-kali' +connect = MQTT(s) +assert(connect.length == 6) +assert(connect.protoname == 'MQIsdp') +assert(connect.protolevel == 3) +assert(connect.usernameflag == 0) +assert(connect.passwordflag == 0) +assert(connect.willretainflag == 0) +assert(connect.willQOSflag == 0) +assert(connect.willflag == 0) +assert(connect.cleansess == 1) +assert(connect.reserved == 0) +assert(connect.klive == 60) +assert(connect.clientIdlen == 17) +assert(connect.clientId == 'mosqpub/1440-kali') + + +=MQTTConnack, packet instanciation +ck = MQTT()/MQTTConnack(sessPresentFlag=1,retcode=0) +assert(ck.type == 2) +assert(ck.sessPresentFlag == 1) +assert(ck.retcode == 0) + += MQTTConnack, packet dissection +s = b' \x02\x00\x00' +connack = MQTT(s) +assert(connack.sessPresentFlag == 0) +assert(connack.retcode == 0) + + += MQTTSubscribe, packet instanciation +sb = MQTT()/MQTTSubscribe(msgid=1,topic='newtopic',QOS=0,length=0) +assert(sb.type == 8) +assert(sb.msgid == 1) +assert(sb.topic == 'newtopic') +assert(sb.length == 0) +assert(sb[MQTTSubscribe].QOS == 0) + += MQTTSubscribe, packet dissection +s = b'\x82\t\x00\x01\x00\x04test\x00' +subscribe = MQTT(s) +assert(subscribe.msgid == 1) +assert(subscribe.length == 4) +assert(subscribe.topic == 'test') +assert(subscribe.QOS == 1) + + += MQTTSuback, packet instanciation +sk = MQTT()/MQTTSuback(msgid=1, retcode=0) +assert(sk.type == 9) +assert(sk.msgid == 1) +assert(sk.retcode == 0) + += MQTTSuback, packet dissection +s = b'\x90\x03\x00\x01\x00' +suback = MQTT(s) +assert(suback.msgid == 1) +assert(suback.retcode == 0) + + += MQTTPubrec, packet instanciation +pc = MQTT()/MQTTPubrec(msgid=1) +assert(pc.type == 5) +assert(pc.msgid == 1) + += MQTTPubrec packet dissection +s = b'P\x02\x00\x01' +pubrec = MQTT(s) +assert(pubrec.msgid == 1) diff --git a/scapy/contrib/nsh.py b/scapy/contrib/nsh.py index 42c1f3a8d86..86abe6e8e1a 100644 --- a/scapy/contrib/nsh.py +++ b/scapy/contrib/nsh.py @@ -1,6 +1,20 @@ -#! /usr/bin/env python -# scapy.contrib.description = nsh +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . + +# scapy.contrib.description = NSH Protocol # scapy.contrib.status = loads + from scapy.all import bind_layers from scapy.fields import BitField, ByteField, ByteEnumField from scapy.fields import ShortField, X3BytesField, XIntField diff --git a/scapy/contrib/openflow.py b/scapy/contrib/openflow.py index 62c0f031d6d..0809ebe9c5d 100755 --- a/scapy/contrib/openflow.py +++ b/scapy/contrib/openflow.py @@ -8,7 +8,7 @@ ## Based on OpenFlow v1.0.1 ## Specifications can be retrieved from https://www.opennetworking.org/ -# scapy.contrib.description = openflow v1.0 +# scapy.contrib.description = Openflow v1.0 # scapy.contrib.status = loads import struct diff --git a/scapy/contrib/openflow3.py b/scapy/contrib/openflow3.py index df8ed5aab9e..0d8a6e6d7bf 100755 --- a/scapy/contrib/openflow3.py +++ b/scapy/contrib/openflow3.py @@ -8,7 +8,7 @@ ## Based on OpenFlow v1.3.4 ## Specifications can be retrieved from https://www.opennetworking.org/ -# scapy.contrib.description = openflow v1.3 +# scapy.contrib.description = Openflow v1.3 # scapy.contrib.status = loads import struct diff --git a/scapy/contrib/ospf.py b/scapy/contrib/ospf.py index 15b2d5e9a22..8b316ca55e9 100644 --- a/scapy/contrib/ospf.py +++ b/scapy/contrib/ospf.py @@ -3,6 +3,20 @@ # scapy.contrib.description = OSPF # scapy.contrib.status = loads +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . + """ OSPF extension for Scapy @@ -11,16 +25,6 @@ Copyright (c) 2008 Dirk Loss : mail dirk-loss de Copyright (c) 2010 Jochen Bartl : jochen.bartl gmail com - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. """ diff --git a/scapy/contrib/ppi.py b/scapy/contrib/ppi.py index 07fa6f13b1b..13945a33fae 100644 --- a/scapy/contrib/ppi.py +++ b/scapy/contrib/ppi.py @@ -1,86 +1,97 @@ -## This file is (hopefully) part of Scapy -## See http://www.secdev.org/projects/scapy for more informations -## -## This program is published under a GPLv2 license - -# scapy.contrib.description = PPI -# scapy.contrib.status = loads - - -""" -PPI (Per-Packet Information). -""" -import logging,struct -from scapy.config import conf -from scapy.packet import * -from scapy.fields import * -from scapy.layers.l2 import Ether -from scapy.layers.dot11 import Dot11 - -# Dictionary to map the TLV type to the class name of a sub-packet -_ppi_types = {} -def addPPIType(id, value): - _ppi_types[id] = value -def getPPIType(id, default="default"): - return _ppi_types.get(id, _ppi_types.get(default, None)) - - -# Default PPI Field Header -class PPIGenericFldHdr(Packet): - name = "PPI Field Header" - fields_desc = [ LEShortField('pfh_type', 0), - FieldLenField('pfh_length', None, length_of="value", fmt='= 4: - t,pfh_len = struct.unpack(" pfh_len): - out.payload.payload = conf.padding_layer(p[pfh_len:]) - elif (len(p) > pfh_len): - out.payload = conf.padding_layer(p[pfh_len:]) - - else: - out = conf.raw_layer(p, **kargs) - return out - - - - -class PPI(Packet): - name = "PPI Packet Header" - fields_desc = [ ByteField('pph_version', 0), - ByteField('pph_flags', 0), - FieldLenField('pph_len', None, length_of="PPIFieldHeaders", fmt=". + +# author: + +# scapy.contrib.description = PPI +# scapy.contrib.status = loads + + +""" +PPI (Per-Packet Information). +""" +import logging,struct +from scapy.config import conf +from scapy.packet import * +from scapy.fields import * +from scapy.layers.l2 import Ether +from scapy.layers.dot11 import Dot11 + +# Dictionary to map the TLV type to the class name of a sub-packet +_ppi_types = {} +def addPPIType(id, value): + _ppi_types[id] = value +def getPPIType(id, default="default"): + return _ppi_types.get(id, _ppi_types.get(default, None)) + + +# Default PPI Field Header +class PPIGenericFldHdr(Packet): + name = "PPI Field Header" + fields_desc = [ LEShortField('pfh_type', 0), + FieldLenField('pfh_length', None, length_of="value", fmt='= 4: + t,pfh_len = struct.unpack(" pfh_len): + out.payload.payload = conf.padding_layer(p[pfh_len:]) + elif (len(p) > pfh_len): + out.payload = conf.padding_layer(p[pfh_len:]) + + else: + out = conf.raw_layer(p, **kargs) + return out + + + + +class PPI(Packet): + name = "PPI Packet Header" + fields_desc = [ ByteField('pph_version', 0), + ByteField('pph_flags', 0), + FieldLenField('pph_len', None, length_of="PPIFieldHeaders", fmt=" -## This program is published under a GPLv2 license - -# scapy.contrib.description = PPI CACE -# scapy.contrib.status = loads - -""" -CACE PPI types -""" -import logging,struct -from scapy.config import conf -from scapy.packet import * -from scapy.fields import * -from scapy.layers.l2 import Ether -from scapy.layers.dot11 import Dot11 -from scapy.contrib.ppi import * - -PPI_DOT11COMMON = 2 -PPI_DOT11NMAC = 3 -PPI_DOT11NMACPHY = 4 -PPI_SPECTRUMMAP = 5 -PPI_PROCESSINFO = 6 -PPI_CAPTUREINFO = 7 -PPI_AGGREGATION = 8 -PPI_DOT3 = 9 - -# PPI 802.11 Common Field Header Fields -class dBmByteField(Field): - def __init__(self, name, default): - Field.__init__(self, name, default, "b") - def i2repr(self, pkt, val): - if (val != None): - val = "%4d dBm" % val - return val - -class PPITSFTField(LELongField): - def i2h(self, pkt, val): - flags = 0 - if (pkt): - flags = pkt.getfieldval("Pkt_Flags") - if not flags: - flags = 0 - if (flags & 0x02): - scale = 1e-3 - else: - scale = 1e-6 - tout = scale * float(val) - return tout - def h2i(self, pkt, val): - scale = 1e6 - if pkt: - flags = pkt.getfieldval("Pkt_Flags") - if flags: - if (flags & 0x02): - scale = 1e3 - tout = int((scale * val) + 0.5) - return tout - -_PPIDot11CommonChFlags = ['','','','','Turbo','CCK','OFDM','2GHz','5GHz', - 'PassiveOnly','Dynamic CCK-OFDM','GSFK'] - -_PPIDot11CommonPktFlags = ['FCS','TSFT_ms','FCS_Invalid','PHY_Error'] - -# PPI 802.11 Common Field Header -class Dot11Common(Packet): - name = "PPI 802.11-Common" - fields_desc = [ LEShortField('pfh_type',PPI_DOT11COMMON), - LEShortField('pfh_length', 20), - PPITSFTField('TSF_Timer', 0), - FlagsField('Pkt_Flags',0, -16, _PPIDot11CommonPktFlags), - LEShortField('Rate',0), - LEShortField('Ch_Freq',0), - FlagsField('Ch_Flags', 0, -16, _PPIDot11CommonChFlags), - ByteField('FHSS_Hop',0), - ByteField('FHSS_Pat',0), - dBmByteField('Antsignal',-128), - dBmByteField('Antnoise',-128)] - - def extract_padding(self, p): - return "",p -#Hopefully other CACE defined types will be added here. - -#Add the dot11common layer to the PPI array -addPPIType(PPI_DOT11COMMON, Dot11Common) - +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . + +# author: + +# scapy.contrib.description = PPI CACE +# scapy.contrib.status = loads + +""" +CACE PPI types +""" +import logging,struct +from scapy.config import conf +from scapy.packet import * +from scapy.fields import * +from scapy.layers.l2 import Ether +from scapy.layers.dot11 import Dot11 +from scapy.contrib.ppi import * + +PPI_DOT11COMMON = 2 +PPI_DOT11NMAC = 3 +PPI_DOT11NMACPHY = 4 +PPI_SPECTRUMMAP = 5 +PPI_PROCESSINFO = 6 +PPI_CAPTUREINFO = 7 +PPI_AGGREGATION = 8 +PPI_DOT3 = 9 + +# PPI 802.11 Common Field Header Fields +class dBmByteField(Field): + def __init__(self, name, default): + Field.__init__(self, name, default, "b") + def i2repr(self, pkt, val): + if (val != None): + val = "%4d dBm" % val + return val + +class PPITSFTField(LELongField): + def i2h(self, pkt, val): + flags = 0 + if (pkt): + flags = pkt.getfieldval("Pkt_Flags") + if not flags: + flags = 0 + if (flags & 0x02): + scale = 1e-3 + else: + scale = 1e-6 + tout = scale * float(val) + return tout + def h2i(self, pkt, val): + scale = 1e6 + if pkt: + flags = pkt.getfieldval("Pkt_Flags") + if flags: + if (flags & 0x02): + scale = 1e3 + tout = int((scale * val) + 0.5) + return tout + +_PPIDot11CommonChFlags = ['','','','','Turbo','CCK','OFDM','2GHz','5GHz', + 'PassiveOnly','Dynamic CCK-OFDM','GSFK'] + +_PPIDot11CommonPktFlags = ['FCS','TSFT_ms','FCS_Invalid','PHY_Error'] + +# PPI 802.11 Common Field Header +class Dot11Common(Packet): + name = "PPI 802.11-Common" + fields_desc = [ LEShortField('pfh_type',PPI_DOT11COMMON), + LEShortField('pfh_length', 20), + PPITSFTField('TSF_Timer', 0), + FlagsField('Pkt_Flags',0, -16, _PPIDot11CommonPktFlags), + LEShortField('Rate',0), + LEShortField('Ch_Freq',0), + FlagsField('Ch_Flags', 0, -16, _PPIDot11CommonChFlags), + ByteField('FHSS_Hop',0), + ByteField('FHSS_Pat',0), + dBmByteField('Antsignal',-128), + dBmByteField('Antnoise',-128)] + + def extract_padding(self, p): + return "",p +#Hopefully other CACE defined types will be added here. + +#Add the dot11common layer to the PPI array +addPPIType(PPI_DOT11COMMON, Dot11Common) + diff --git a/scapy/contrib/ppi_geotag.py b/scapy/contrib/ppi_geotag.py index 60a84571977..23fe38b0cc8 100644 --- a/scapy/contrib/ppi_geotag.py +++ b/scapy/contrib/ppi_geotag.py @@ -1,448 +1,459 @@ -## This file is (hopefully) part of Scapy -## See http://www.secdev.org/projects/scapy for more informations -## -## This program is published under a GPLv2 license - -# scapy.contrib.description = PPI GEOLOCATION -# scapy.contrib.status = loads - - -""" -PPI-GEOLOCATION tags -""" -import struct, time -from scapy.packet import * -from scapy.fields import * -from scapy.contrib.ppi import PPIGenericFldHdr,addPPIType -from scapy.error import warning - -CURR_GEOTAG_VER = 2 #Major revision of specification - -PPI_GPS = 30002 -PPI_VECTOR = 30003 -PPI_SENSOR = 30004 -PPI_ANTENNA = 30005 -#The FixedX_Y Fields are used to store fixed point numbers in a variety of fields in the GEOLOCATION-TAGS specification -class Fixed3_6Field(LEIntField): - def i2h(self, pkt, x): - if x is not None: - if (x < 0): - warning("Fixed3_6: Internal value too negative: %d" % x) - x = 0 - elif (x > 999999999): - warning("Fixed3_6: Internal value too positive: %d" % x) - x = 999999999 - x = x * 1e-6 - return x - def h2i(self, pkt, x): - if x is not None: - if (x <= -0.5e-6): - warning("Fixed3_6: Input value too negative: %.7f" % x) - x = 0 - elif (x >= 999.9999995): - warning("Fixed3_6: Input value too positive: %.7f" % x) - x = 999.999999 - x = int(round(x * 1e6)) - return x - def i2m(self, pkt, x): - """Convert internal value to machine value""" - if x is None: - #Try to return zero if undefined - x = self.h2i(pkt, 0) - return x - - def i2repr(self,pkt,x): - if x is None: - y=0 - else: - y=self.i2h(pkt,x) - return "%3.6f"%(y) -class Fixed3_7Field(LEIntField): - def i2h(self, pkt, x): - if x is not None: - if (x < 0): - warning("Fixed3_7: Internal value too negative: %d" % x) - x = 0 - elif (x > 3600000000): - warning("Fixed3_7: Internal value too positive: %d" % x) - x = 3600000000 - x = (x - 1800000000) * 1e-7 - return x - def h2i(self, pkt, x): - if x is not None: - if (x <= -180.00000005): - warning("Fixed3_7: Input value too negative: %.8f" % x) - x = -180.0 - elif (x >= 180.00000005): - warning("Fixed3_7: Input value too positive: %.8f" % x) - x = 180.0 - x = int(round((x + 180.0) * 1e7)) - return x - def i2m(self, pkt, x): - """Convert internal value to machine value""" - if x is None: - #Try to return zero if undefined - x = self.h2i(pkt, 0) - return x - def i2repr(self,pkt,x): - if x is None: - y=0 - else: - y=self.i2h(pkt,x) - return "%3.7f"%(y) - -class Fixed6_4Field(LEIntField): - def i2h(self, pkt, x): - if x is not None: - if (x < 0): - warning("Fixed6_4: Internal value too negative: %d" % x) - x = 0 - elif (x > 3600000000): - warning("Fixed6_4: Internal value too positive: %d" % x) - x = 3600000000 - x = (x - 1800000000) * 1e-4 - return x - def h2i(self, pkt, x): - if x is not None: - if (x <= -180000.00005): - warning("Fixed6_4: Input value too negative: %.5f" % x) - x = -180000.0 - elif (x >= 180000.00005): - warning("Fixed6_4: Input value too positive: %.5f" % x) - x = 180000.0 - x = int(round((x + 180000.0) * 1e4)) - return x - def i2m(self, pkt, x): - """Convert internal value to machine value""" - if x is None: - #Try to return zero if undefined - x = self.h2i(pkt, 0) - return x - def i2repr(self,pkt,x): - if x is None: - y=0 - else: - y=self.i2h(pkt,x) - return "%6.4f"%(y) -#The GPS timestamps fractional time counter is stored in a 32-bit unsigned ns counter. -#The ept field is as well, -class NSCounter_Field(LEIntField): - def i2h(self, pkt, x): #converts nano-seconds to seconds for output - if x is not None: - if (x < 0): - warning("NSCounter_Field: Internal value too negative: %d" % x) - x = 0 - elif (x >= 2**32): - warning("NSCounter_Field: Internal value too positive: %d" % x) - x = 2**32-1 - x = (x / 1e9) - return x - def h2i(self, pkt, x): #converts input in seconds into nano-seconds for storage - if x is not None: - if (x < 0): - warning("NSCounter_Field: Input value too negative: %.10f" % x) - x = 0 - elif (x >= (2**32) / 1e9): - warning("NSCounter_Field: Input value too positive: %.10f" % x) - x = (2**32-1) / 1e9 - x = int(round((x * 1e9))) - return x - def i2repr(self,pkt,x): - if x is None: - y=0 - else: - y=self.i2h(pkt,x) - return "%1.9f"%(y) - -class LETimeField(UTCTimeField,LEIntField): - __slots__ = ["epoch", "delta", "strf"] - def __init__(self, name, default, epoch=None, strf="%a, %d %b %Y %H:%M:%S +0000"): - LEIntField.__init__(self, name, default) - UTCTimeField.__init__(self, name, default, epoch=epoch, strf=strf) - -class SignedByteField(Field): - def __init__(self, name, default): - Field.__init__(self, name, default, "b") - def randval(self): - return RandSByte() - -class XLEShortField(LEShortField,XShortField): - def i2repr(self, pkt, x): - return XShortField.i2repr(self, pkt, x) - -class XLEIntField(LEIntField,XIntField): - def i2repr(self, pkt, x): - return XIntField.i2repr(self, pkt, x) - -class GPSTime_Field(LETimeField): - def __init__(self, name, default): - return LETimeField.__init__(self, name, default, strf="%a, %d %b %Y %H:%M:%S UTC") - -class VectorFlags_Field(XLEIntField): - """Represents te VectorFlags field. Handles the RelativeTo:sub-field""" - _fwdstr = "DefinesForward" - _resmask = 0xfffffff8 - _relmask = 0x6 - _relnames = ["RelativeToForward", "RelativeToEarth", "RelativeToCurrent", "RelativeToReserved"] - _relvals = [0x00, 0x02, 0x04, 0x06] - def i2repr(self, pkt, x): - if x is None: - return str(x) - r = [] - if (x & 0x1): - r.append(self._fwdstr) - i = (x & self._relmask) >> 1 - r.append(self._relnames[i]) - i = x & self._resmask - if (i): - r.append("ReservedBits:%08X" % i) - sout = "+".join(r) - return sout - def any2i(self, pkt, x): - if type(x) is str: - r = x.split("+") - y = 0 - for value in r: - if (value == self._fwdstr): - y |= 0x1 - elif (value in self._relnames): - i = self._relnames.index(value) - y &= (~self._relmask) - y |= self._relvals[i] - else: - #logging.warning("Unknown VectorFlags Argument: %s" % value) - pass - else: - y = x - #print "any2i: %s --> %s" % (str(x), str(y)) - return y - -class HCSIFlagsField(FlagsField): - """ A FlagsField where each bit/flag turns a conditional field on or off. - If the value is None when building a packet, i2m() will check the value of - every field in self.names. If the field's value is not None, the corresponding - flag will be set. """ - def i2m(self, pkt, val): - if val is None: - val = 0 - if (pkt): - for i, name in enumerate(self.names): - value = pkt.getfieldval(name) - if value is not None: - val |= 1 << i - return val - -class HCSINullField(StrFixedLenField): - def __init__(self, name, default): - return StrFixedLenField.__init__(self, name, default, length=0) - -class HCSIDescField(StrFixedLenField): - def __init__(self, name, default): - return StrFixedLenField.__init__(self, name, default, length=32) - -class HCSIAppField(StrFixedLenField): - def __init__(self, name, default): - return StrFixedLenField.__init__(self, name, default, length=60) - -def _FlagsList(myfields): - flags = ["Reserved%02d" % i for i in xrange(32)] - for i, value in myfields.iteritems(): - flags[i] = value - return flags - -# Define all geolocation-tag flags lists -_hcsi_gps_flags = _FlagsList({0:"No Fix Available", 1:"GPS", 2:"Differential GPS", - 3:"Pulse Per Second", 4:"Real Time Kinematic", - 5:"Float Real Time Kinematic", 6:"Estimated (Dead Reckoning)", - 7:"Manual Input", 8:"Simulation"}) - -#_hcsi_vector_flags = _FlagsList({0:"ForwardFrame", 1:"RotationsAbsoluteXYZ", 5:"OffsetFromGPS_XYZ"}) -#This has been replaced with the VectorFlags_Field class, in order to handle the RelativeTo:subfield - -_hcsi_vector_char_flags = _FlagsList({0:"Antenna", 1:"Direction of Travel", - 2:"Front of Vehicle", 3:"Angle of Arrival", 4:"Transmitter Position", - 8:"GPS Derived", 9:"INS Derived", 10:"Compass Derived", - 11:"Acclerometer Derived", 12:"Human Derived"}) - -_hcsi_antenna_flags = _FlagsList({ 1:"Horizontal Polarization", 2:"Vertical Polarization", - 3:"Circular Polarization Left", 4:"Circular Polarization Right", - 16:"Electronically Steerable", 17:"Mechanically Steerable"}) - -""" HCSI PPI Fields are similar to RadioTap. A mask field called "present" specifies if each field -is present. All other fields are conditional. When dissecting a packet, each field is present if -"present" has the corresponding bit set. When building a packet, if "present" is None, the mask is -set to include every field that does not have a value of None. Otherwise, if the mask field is -not None, only the fields specified by "present" will be added to the packet. - -To build each Packet type, build a list of the fields normally, excluding the present bitmask field. -The code will then construct conditional versions of each field and add the present field. -See GPS_Fields as an example. """ - -# Conditional test for all HCSI Fields -def _HCSITest(pkt, ibit, name): - if pkt.present is None: - return (pkt.getfieldval(name) is not None) - return pkt.present & ibit - -# Wrap optional fields in ConditionalField, add HCSIFlagsField -def _HCSIBuildFields(fields): - names = [f.name for f in fields] - cond_fields = [HCSIFlagsField('present', None, -len(names), names)] - for i, name in enumerate(names): - ibit = 1 << i - seval = "lambda pkt:_HCSITest(pkt,%s,'%s')" % (ibit, name) - test = eval(seval) - cond_fields.append(ConditionalField(fields[i], test)) - return cond_fields - -class HCSIPacket(Packet): - name = "PPI HCSI" - fields_desc = [ LEShortField('pfh_type', None), - LEShortField('pfh_length', None), - ByteField('geotag_ver', CURR_GEOTAG_VER), - ByteField('geotag_pad', 0), - LEShortField('geotag_len', None)] - def post_build(self, p, pay): - if self.pfh_length is None: - l = len(p) - 4 - sl = struct.pack('. + +# author: + +# scapy.contrib.description = PPI GEOLOCATION +# scapy.contrib.status = loads + + +""" +PPI-GEOLOCATION tags +""" +import struct, time +from scapy.packet import * +from scapy.fields import * +from scapy.contrib.ppi import PPIGenericFldHdr,addPPIType +from scapy.error import warning + +CURR_GEOTAG_VER = 2 #Major revision of specification + +PPI_GPS = 30002 +PPI_VECTOR = 30003 +PPI_SENSOR = 30004 +PPI_ANTENNA = 30005 +#The FixedX_Y Fields are used to store fixed point numbers in a variety of fields in the GEOLOCATION-TAGS specification +class Fixed3_6Field(LEIntField): + def i2h(self, pkt, x): + if x is not None: + if (x < 0): + warning("Fixed3_6: Internal value too negative: %d" % x) + x = 0 + elif (x > 999999999): + warning("Fixed3_6: Internal value too positive: %d" % x) + x = 999999999 + x = x * 1e-6 + return x + def h2i(self, pkt, x): + if x is not None: + if (x <= -0.5e-6): + warning("Fixed3_6: Input value too negative: %.7f" % x) + x = 0 + elif (x >= 999.9999995): + warning("Fixed3_6: Input value too positive: %.7f" % x) + x = 999.999999 + x = int(round(x * 1e6)) + return x + def i2m(self, pkt, x): + """Convert internal value to machine value""" + if x is None: + #Try to return zero if undefined + x = self.h2i(pkt, 0) + return x + + def i2repr(self,pkt,x): + if x is None: + y=0 + else: + y=self.i2h(pkt,x) + return "%3.6f"%(y) +class Fixed3_7Field(LEIntField): + def i2h(self, pkt, x): + if x is not None: + if (x < 0): + warning("Fixed3_7: Internal value too negative: %d" % x) + x = 0 + elif (x > 3600000000): + warning("Fixed3_7: Internal value too positive: %d" % x) + x = 3600000000 + x = (x - 1800000000) * 1e-7 + return x + def h2i(self, pkt, x): + if x is not None: + if (x <= -180.00000005): + warning("Fixed3_7: Input value too negative: %.8f" % x) + x = -180.0 + elif (x >= 180.00000005): + warning("Fixed3_7: Input value too positive: %.8f" % x) + x = 180.0 + x = int(round((x + 180.0) * 1e7)) + return x + def i2m(self, pkt, x): + """Convert internal value to machine value""" + if x is None: + #Try to return zero if undefined + x = self.h2i(pkt, 0) + return x + def i2repr(self,pkt,x): + if x is None: + y=0 + else: + y=self.i2h(pkt,x) + return "%3.7f"%(y) + +class Fixed6_4Field(LEIntField): + def i2h(self, pkt, x): + if x is not None: + if (x < 0): + warning("Fixed6_4: Internal value too negative: %d" % x) + x = 0 + elif (x > 3600000000): + warning("Fixed6_4: Internal value too positive: %d" % x) + x = 3600000000 + x = (x - 1800000000) * 1e-4 + return x + def h2i(self, pkt, x): + if x is not None: + if (x <= -180000.00005): + warning("Fixed6_4: Input value too negative: %.5f" % x) + x = -180000.0 + elif (x >= 180000.00005): + warning("Fixed6_4: Input value too positive: %.5f" % x) + x = 180000.0 + x = int(round((x + 180000.0) * 1e4)) + return x + def i2m(self, pkt, x): + """Convert internal value to machine value""" + if x is None: + #Try to return zero if undefined + x = self.h2i(pkt, 0) + return x + def i2repr(self,pkt,x): + if x is None: + y=0 + else: + y=self.i2h(pkt,x) + return "%6.4f"%(y) +#The GPS timestamps fractional time counter is stored in a 32-bit unsigned ns counter. +#The ept field is as well, +class NSCounter_Field(LEIntField): + def i2h(self, pkt, x): #converts nano-seconds to seconds for output + if x is not None: + if (x < 0): + warning("NSCounter_Field: Internal value too negative: %d" % x) + x = 0 + elif (x >= 2**32): + warning("NSCounter_Field: Internal value too positive: %d" % x) + x = 2**32-1 + x = (x / 1e9) + return x + def h2i(self, pkt, x): #converts input in seconds into nano-seconds for storage + if x is not None: + if (x < 0): + warning("NSCounter_Field: Input value too negative: %.10f" % x) + x = 0 + elif (x >= (2**32) / 1e9): + warning("NSCounter_Field: Input value too positive: %.10f" % x) + x = (2**32-1) / 1e9 + x = int(round((x * 1e9))) + return x + def i2repr(self,pkt,x): + if x is None: + y=0 + else: + y=self.i2h(pkt,x) + return "%1.9f"%(y) + +class LETimeField(UTCTimeField,LEIntField): + __slots__ = ["epoch", "delta", "strf"] + def __init__(self, name, default, epoch=None, strf="%a, %d %b %Y %H:%M:%S +0000"): + LEIntField.__init__(self, name, default) + UTCTimeField.__init__(self, name, default, epoch=epoch, strf=strf) + +class SignedByteField(Field): + def __init__(self, name, default): + Field.__init__(self, name, default, "b") + def randval(self): + return RandSByte() + +class XLEShortField(LEShortField,XShortField): + def i2repr(self, pkt, x): + return XShortField.i2repr(self, pkt, x) + +class XLEIntField(LEIntField,XIntField): + def i2repr(self, pkt, x): + return XIntField.i2repr(self, pkt, x) + +class GPSTime_Field(LETimeField): + def __init__(self, name, default): + return LETimeField.__init__(self, name, default, strf="%a, %d %b %Y %H:%M:%S UTC") + +class VectorFlags_Field(XLEIntField): + """Represents te VectorFlags field. Handles the RelativeTo:sub-field""" + _fwdstr = "DefinesForward" + _resmask = 0xfffffff8 + _relmask = 0x6 + _relnames = ["RelativeToForward", "RelativeToEarth", "RelativeToCurrent", "RelativeToReserved"] + _relvals = [0x00, 0x02, 0x04, 0x06] + def i2repr(self, pkt, x): + if x is None: + return str(x) + r = [] + if (x & 0x1): + r.append(self._fwdstr) + i = (x & self._relmask) >> 1 + r.append(self._relnames[i]) + i = x & self._resmask + if (i): + r.append("ReservedBits:%08X" % i) + sout = "+".join(r) + return sout + def any2i(self, pkt, x): + if isinstance(x, str): + r = x.split("+") + y = 0 + for value in r: + if (value == self._fwdstr): + y |= 0x1 + elif (value in self._relnames): + i = self._relnames.index(value) + y &= (~self._relmask) + y |= self._relvals[i] + else: + #logging.warning("Unknown VectorFlags Argument: %s" % value) + pass + else: + y = x + #print "any2i: %s --> %s" % (str(x), str(y)) + return y + +class HCSIFlagsField(FlagsField): + """ A FlagsField where each bit/flag turns a conditional field on or off. + If the value is None when building a packet, i2m() will check the value of + every field in self.names. If the field's value is not None, the corresponding + flag will be set. """ + def i2m(self, pkt, val): + if val is None: + val = 0 + if (pkt): + for i, name in enumerate(self.names): + value = pkt.getfieldval(name) + if value is not None: + val |= 1 << i + return val + +class HCSINullField(StrFixedLenField): + def __init__(self, name, default): + return StrFixedLenField.__init__(self, name, default, length=0) + +class HCSIDescField(StrFixedLenField): + def __init__(self, name, default): + return StrFixedLenField.__init__(self, name, default, length=32) + +class HCSIAppField(StrFixedLenField): + def __init__(self, name, default): + return StrFixedLenField.__init__(self, name, default, length=60) + +def _FlagsList(myfields): + flags = ["Reserved%02d" % i for i in xrange(32)] + for i, value in myfields.iteritems(): + flags[i] = value + return flags + +# Define all geolocation-tag flags lists +_hcsi_gps_flags = _FlagsList({0:"No Fix Available", 1:"GPS", 2:"Differential GPS", + 3:"Pulse Per Second", 4:"Real Time Kinematic", + 5:"Float Real Time Kinematic", 6:"Estimated (Dead Reckoning)", + 7:"Manual Input", 8:"Simulation"}) + +#_hcsi_vector_flags = _FlagsList({0:"ForwardFrame", 1:"RotationsAbsoluteXYZ", 5:"OffsetFromGPS_XYZ"}) +#This has been replaced with the VectorFlags_Field class, in order to handle the RelativeTo:subfield + +_hcsi_vector_char_flags = _FlagsList({0:"Antenna", 1:"Direction of Travel", + 2:"Front of Vehicle", 3:"Angle of Arrival", 4:"Transmitter Position", + 8:"GPS Derived", 9:"INS Derived", 10:"Compass Derived", + 11:"Acclerometer Derived", 12:"Human Derived"}) + +_hcsi_antenna_flags = _FlagsList({ 1:"Horizontal Polarization", 2:"Vertical Polarization", + 3:"Circular Polarization Left", 4:"Circular Polarization Right", + 16:"Electronically Steerable", 17:"Mechanically Steerable"}) + +""" HCSI PPI Fields are similar to RadioTap. A mask field called "present" specifies if each field +is present. All other fields are conditional. When dissecting a packet, each field is present if +"present" has the corresponding bit set. When building a packet, if "present" is None, the mask is +set to include every field that does not have a value of None. Otherwise, if the mask field is +not None, only the fields specified by "present" will be added to the packet. + +To build each Packet type, build a list of the fields normally, excluding the present bitmask field. +The code will then construct conditional versions of each field and add the present field. +See GPS_Fields as an example. """ + +# Conditional test for all HCSI Fields +def _HCSITest(pkt, ibit, name): + if pkt.present is None: + return (pkt.getfieldval(name) is not None) + return pkt.present & ibit + +# Wrap optional fields in ConditionalField, add HCSIFlagsField +def _HCSIBuildFields(fields): + names = [f.name for f in fields] + cond_fields = [HCSIFlagsField('present', None, -len(names), names)] + for i, name in enumerate(names): + ibit = 1 << i + seval = "lambda pkt:_HCSITest(pkt,%s,'%s')" % (ibit, name) + test = eval(seval) + cond_fields.append(ConditionalField(fields[i], test)) + return cond_fields + +class HCSIPacket(Packet): + name = "PPI HCSI" + fields_desc = [ LEShortField('pfh_type', None), + LEShortField('pfh_length', None), + ByteField('geotag_ver', CURR_GEOTAG_VER), + ByteField('geotag_pad', 0), + LEShortField('geotag_len', None)] + def post_build(self, p, pay): + if self.pfh_length is None: + l = len(p) - 4 + sl = struct.pack('. # scapy.contrib.description = RIPng # scapy.contrib.status = loads diff --git a/scapy/contrib/rsvp.py b/scapy/contrib/rsvp.py index e2b1247e311..3908546c5b9 100644 --- a/scapy/contrib/rsvp.py +++ b/scapy/contrib/rsvp.py @@ -1,188 +1,200 @@ -## RSVP layer - -# http://trac.secdev.org/scapy/ticket/197 - -# scapy.contrib.description = RSVP -# scapy.contrib.status = loads - -from scapy.packet import * -from scapy.fields import * -from scapy.layers.inet import IP - -rsvpmsgtypes = { 0x01 : "Path", - 0x02 : "Reservation request", - 0x03 : "Path error", - 0x04 : "Reservation request error", - 0x05 : "Path teardown", - 0x06 : "Reservation teardown", - 0x07 : "Reservation request acknowledgment" -} - -class RSVP(Packet): - name = "RSVP" - fields_desc = [ BitField("Version",1,4), - BitField("Flags",1,4), - ByteEnumField("Class",0x01, rsvpmsgtypes), - XShortField("chksum", None), - ByteField("TTL",1), - XByteField("dataofs", 0), - ShortField("Length",None)] - def post_build(self, p, pay): - p += pay - if self.Length is None: - l = len(p) - p = p[:6]+chr((l>>8)&0xff)+chr(l&0xff)+p[8:] - if self.chksum is None: - ck = checksum(p) - p = p[:2]+chr(ck>>8)+chr(ck&0xff)+p[4:] - return p - -rsvptypes = { 0x01 : "Session", - 0x03 : "HOP", - 0x04 : "INTEGRITY", - 0x05 : "TIME_VALUES", - 0x06 : "ERROR_SPEC", - 0x07 : "SCOPE", - 0x08 : "STYLE", - 0x09 : "FLOWSPEC", - 0x0A : "FILTER_SPEC", - 0x0B : "SENDER_TEMPLATE", - 0x0C : "SENDER_TSPEC", - 0x0D : "ADSPEC", - 0x0E : "POLICY_DATA", - 0x0F : "RESV_CONFIRM", - 0x10 : "RSVP_LABEL", - 0x11 : "HOP_COUNT", - 0x12 : "STRICT_SOURCE_ROUTE", - 0x13 : "LABEL_REQUEST", - 0x14 : "EXPLICIT_ROUTE", - 0x15 : "ROUTE_RECORD", - 0x16 : "HELLO", - 0x17 : "MESSAGE_ID", - 0x18 : "MESSAGE_ID_ACK", - 0x19 : "MESSAGE_ID_LIST", - 0x1E : "DIAGNOSTIC", - 0x1F : "ROUTE", - 0x20 : "DIAG_RESPONSE", - 0x21 : "DIAG_SELECT", - 0x22 : "RECOVERY_LABEL", - 0x23 : "UPSTREAM_LABEL", - 0x24 : "LABEL_SET", - 0x25 : "PROTECTION", - 0x26 : "PRIMARY PATH ROUTE", - 0x2A : "DSBM IP ADDRESS", - 0x2B : "SBM_PRIORITY", - 0x2C : "DSBM TIMER INTERVALS", - 0x2D : "SBM_INFO", - 0x32 : "S2L_SUB_LSP", - 0x3F : "DETOUR", - 0x40 : "CHALLENGE", - 0x41 : "DIFF-SERV", - 0x42 : "CLASSTYPE", - 0x43 : "LSP_REQUIRED_ATTRIBUTES", - 0x80 : "NODE_CHAR", - 0x81 : "SUGGESTED_LABEL", - 0x82 : "ACCEPTABLE_LABEL_SET", - 0x83 : "RESTART_CA", - 0x84 : "SESSION-OF-INTEREST", - 0x85 : "LINK_CAPABILITY", - 0x86 : "Capability Object", - 0xA1 : "RSVP_HOP_L2", - 0xA2 : "LAN_NHOP_L2", - 0xA3 : "LAN_NHOP_L3", - 0xA4 : "LAN_LOOPBACK", - 0xA5 : "TCLASS", - 0xC0 : "TUNNEL", - 0xC1 : "LSP_TUNNEL_INTERFACE_ID", - 0xC2 : "USER_ERROR_SPEC", - 0xC3 : "NOTIFY_REQUEST", - 0xC4 : "ADMIN-STATUS", - 0xC5 : "LSP_ATTRIBUTES", - 0xC6 : "ALARM_SPEC", - 0xC7 : "ASSOCIATION", - 0xC8 : "SECONDARY_EXPLICIT_ROUTE", - 0xC9 : "SECONDARY_RECORD_ROUTE", - 0xCD : "FAST_REROUTE", - 0xCF : "SESSION_ATTRIBUTE", - 0xE1 : "DCLASS", - 0xE2 : "PACKETCABLE EXTENSIONS", - 0xE3 : "ATM_SERVICECLASS", - 0xE4 : "CALL_OPS (ASON)", - 0xE5 : "GENERALIZED_UNI", - 0xE6 : "CALL_ID", - 0xE7 : "3GPP2_Object", - 0xE8 : "EXCLUDE_ROUTE" -} - -class RSVP_Object(Packet): - name = "RSVP_Object" - fields_desc = [ ShortField("Length",4), - ByteEnumField("Class",0x01, rsvptypes), - ByteField("C-Type",1)] - def guess_payload_class(self, payload): - if self.Class == 0x03: - return RSVP_HOP - elif self.Class == 0x05: - return RSVP_Time - elif self.Class == 0x0c: - return RSVP_SenderTSPEC - elif self.Class == 0x13: - return RSVP_LabelReq - elif self.Class == 0xCF: - return RSVP_SessionAttrb - else: - return RSVP_Data - - - -class RSVP_Data(Packet): - name = "Data" - fields_desc = [StrLenField("Data","",length_from= lambda pkt:pkt.underlayer.Length - 4)] - def default_payload_class(self, payload): - return RSVP_Object - -class RSVP_HOP(Packet): - name = "HOP" - fields_desc = [ IPField("neighbor","0.0.0.0"), - BitField("inface",1,32)] - def default_payload_class(self, payload): - return RSVP_Object - -class RSVP_Time(Packet): - name = "Time Val" - fields_desc = [ BitField("refresh",1,32)] - def default_payload_class(self, payload): - return RSVP_Object - -class RSVP_SenderTSPEC(Packet): - name = "Sender_TSPEC" - fields_desc = [ ByteField("Msg_Format",0), - ByteField("reserve",0), - ShortField("Data_Length",4), - ByteField("Srv_hdr",1), - ByteField("reserve2",0), - ShortField("Srv_Length",4), - StrLenField("Tokens","",length_from= lambda pkt:pkt.underlayer.Length - 12) ] - def default_payload_class(self, payload): - return RSVP_Object - -class RSVP_LabelReq(Packet): - name = "Lable Req" - fields_desc = [ ShortField("reserve",1), - ShortField("L3PID",1)] - def default_payload_class(self, payload): - return RSVP_Object - -class RSVP_SessionAttrb(Packet): - name = "Session_Attribute" - fields_desc = [ ByteField("Setup_priority",1), - ByteField("Hold_priority",1), - ByteField("flags",1), - ByteField("Name_length",1), - StrLenField("Name","",length_from= lambda pkt:pkt.underlayer.Length - 8), - ] - def default_payload_class(self, payload): - return RSVP_Object - -bind_layers( IP, RSVP, { "proto" : 46} ) -bind_layers( RSVP, RSVP_Object, {}) +## RSVP layer + +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . + +# scapy.contrib.description = RSVP +# scapy.contrib.status = loads + +from scapy.packet import * +from scapy.fields import * +from scapy.layers.inet import IP + +rsvpmsgtypes = { 0x01 : "Path", + 0x02 : "Reservation request", + 0x03 : "Path error", + 0x04 : "Reservation request error", + 0x05 : "Path teardown", + 0x06 : "Reservation teardown", + 0x07 : "Reservation request acknowledgment" +} + +class RSVP(Packet): + name = "RSVP" + fields_desc = [ BitField("Version",1,4), + BitField("Flags",1,4), + ByteEnumField("Class",0x01, rsvpmsgtypes), + XShortField("chksum", None), + ByteField("TTL",1), + XByteField("dataofs", 0), + ShortField("Length",None)] + def post_build(self, p, pay): + p += pay + if self.Length is None: + l = len(p) + p = p[:6]+chr((l>>8)&0xff)+chr(l&0xff)+p[8:] + if self.chksum is None: + ck = checksum(p) + p = p[:2]+chr(ck>>8)+chr(ck&0xff)+p[4:] + return p + +rsvptypes = { 0x01 : "Session", + 0x03 : "HOP", + 0x04 : "INTEGRITY", + 0x05 : "TIME_VALUES", + 0x06 : "ERROR_SPEC", + 0x07 : "SCOPE", + 0x08 : "STYLE", + 0x09 : "FLOWSPEC", + 0x0A : "FILTER_SPEC", + 0x0B : "SENDER_TEMPLATE", + 0x0C : "SENDER_TSPEC", + 0x0D : "ADSPEC", + 0x0E : "POLICY_DATA", + 0x0F : "RESV_CONFIRM", + 0x10 : "RSVP_LABEL", + 0x11 : "HOP_COUNT", + 0x12 : "STRICT_SOURCE_ROUTE", + 0x13 : "LABEL_REQUEST", + 0x14 : "EXPLICIT_ROUTE", + 0x15 : "ROUTE_RECORD", + 0x16 : "HELLO", + 0x17 : "MESSAGE_ID", + 0x18 : "MESSAGE_ID_ACK", + 0x19 : "MESSAGE_ID_LIST", + 0x1E : "DIAGNOSTIC", + 0x1F : "ROUTE", + 0x20 : "DIAG_RESPONSE", + 0x21 : "DIAG_SELECT", + 0x22 : "RECOVERY_LABEL", + 0x23 : "UPSTREAM_LABEL", + 0x24 : "LABEL_SET", + 0x25 : "PROTECTION", + 0x26 : "PRIMARY PATH ROUTE", + 0x2A : "DSBM IP ADDRESS", + 0x2B : "SBM_PRIORITY", + 0x2C : "DSBM TIMER INTERVALS", + 0x2D : "SBM_INFO", + 0x32 : "S2L_SUB_LSP", + 0x3F : "DETOUR", + 0x40 : "CHALLENGE", + 0x41 : "DIFF-SERV", + 0x42 : "CLASSTYPE", + 0x43 : "LSP_REQUIRED_ATTRIBUTES", + 0x80 : "NODE_CHAR", + 0x81 : "SUGGESTED_LABEL", + 0x82 : "ACCEPTABLE_LABEL_SET", + 0x83 : "RESTART_CA", + 0x84 : "SESSION-OF-INTEREST", + 0x85 : "LINK_CAPABILITY", + 0x86 : "Capability Object", + 0xA1 : "RSVP_HOP_L2", + 0xA2 : "LAN_NHOP_L2", + 0xA3 : "LAN_NHOP_L3", + 0xA4 : "LAN_LOOPBACK", + 0xA5 : "TCLASS", + 0xC0 : "TUNNEL", + 0xC1 : "LSP_TUNNEL_INTERFACE_ID", + 0xC2 : "USER_ERROR_SPEC", + 0xC3 : "NOTIFY_REQUEST", + 0xC4 : "ADMIN-STATUS", + 0xC5 : "LSP_ATTRIBUTES", + 0xC6 : "ALARM_SPEC", + 0xC7 : "ASSOCIATION", + 0xC8 : "SECONDARY_EXPLICIT_ROUTE", + 0xC9 : "SECONDARY_RECORD_ROUTE", + 0xCD : "FAST_REROUTE", + 0xCF : "SESSION_ATTRIBUTE", + 0xE1 : "DCLASS", + 0xE2 : "PACKETCABLE EXTENSIONS", + 0xE3 : "ATM_SERVICECLASS", + 0xE4 : "CALL_OPS (ASON)", + 0xE5 : "GENERALIZED_UNI", + 0xE6 : "CALL_ID", + 0xE7 : "3GPP2_Object", + 0xE8 : "EXCLUDE_ROUTE" +} + +class RSVP_Object(Packet): + name = "RSVP_Object" + fields_desc = [ ShortField("Length",4), + ByteEnumField("Class",0x01, rsvptypes), + ByteField("C-Type",1)] + def guess_payload_class(self, payload): + if self.Class == 0x03: + return RSVP_HOP + elif self.Class == 0x05: + return RSVP_Time + elif self.Class == 0x0c: + return RSVP_SenderTSPEC + elif self.Class == 0x13: + return RSVP_LabelReq + elif self.Class == 0xCF: + return RSVP_SessionAttrb + else: + return RSVP_Data + + + +class RSVP_Data(Packet): + name = "Data" + fields_desc = [StrLenField("Data","",length_from= lambda pkt:pkt.underlayer.Length - 4)] + def default_payload_class(self, payload): + return RSVP_Object + +class RSVP_HOP(Packet): + name = "HOP" + fields_desc = [ IPField("neighbor","0.0.0.0"), + BitField("inface",1,32)] + def default_payload_class(self, payload): + return RSVP_Object + +class RSVP_Time(Packet): + name = "Time Val" + fields_desc = [ BitField("refresh",1,32)] + def default_payload_class(self, payload): + return RSVP_Object + +class RSVP_SenderTSPEC(Packet): + name = "Sender_TSPEC" + fields_desc = [ ByteField("Msg_Format",0), + ByteField("reserve",0), + ShortField("Data_Length",4), + ByteField("Srv_hdr",1), + ByteField("reserve2",0), + ShortField("Srv_Length",4), + StrLenField("Tokens","",length_from= lambda pkt:pkt.underlayer.Length - 12) ] + def default_payload_class(self, payload): + return RSVP_Object + +class RSVP_LabelReq(Packet): + name = "Lable Req" + fields_desc = [ ShortField("reserve",1), + ShortField("L3PID",1)] + def default_payload_class(self, payload): + return RSVP_Object + +class RSVP_SessionAttrb(Packet): + name = "Session_Attribute" + fields_desc = [ ByteField("Setup_priority",1), + ByteField("Hold_priority",1), + ByteField("flags",1), + ByteField("Name_length",1), + StrLenField("Name","",length_from= lambda pkt:pkt.underlayer.Length - 8), + ] + def default_payload_class(self, payload): + return RSVP_Object + +bind_layers( IP, RSVP, { "proto" : 46} ) +bind_layers( RSVP, RSVP_Object, {}) diff --git a/scapy/contrib/send.py b/scapy/contrib/send.py index 676158a4373..af9620b059f 100644 --- a/scapy/contrib/send.py +++ b/scapy/contrib/send.py @@ -1,11 +1,24 @@ #! /usr/bin/env python +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . + ## Copyright (C) 2009 Adline Stephane ## -## This program is published under a GPLv2 license # Partial support of RFC3971 -# scapy.contrib.description = SEND +# scapy.contrib.description = SEND (ICMPv6) # scapy.contrib.status = loads import socket @@ -25,13 +38,13 @@ class HashField(Field): def __init__(self, name, default): Field.__init__(self, name, default, "16s") def h2i(self, pkt, x): - if type(x) is str: + if isinstance(x, str): try: x = in6_ptop(x) except socket.error: x = Net6(x) - elif type(x) is list: - x = map(Net6, x) + elif isinstance(x, list): + x = [Net6(e) for e in x] return x def i2m(self, pkt, x): return inet_pton(socket.AF_INET6, x) diff --git a/scapy/contrib/skinny.py b/scapy/contrib/skinny.py index 215602db9f9..e21979e361c 100644 --- a/scapy/contrib/skinny.py +++ b/scapy/contrib/skinny.py @@ -11,7 +11,8 @@ ## Copyright (C) 2006 Nicolas Bareil ## ## EADS/CRC security team ## ## ## -## This program is free software; you can redistribute it and/or modify it ## +## This file is part of Scapy ## +## Scapy is free software: you can redistribute it and/or modify ## ## under the terms of the GNU General Public License version 2 as ## ## published by the Free Software Foundation; version 2. ## ## ## @@ -207,13 +208,13 @@ def m2i(self, pkt, s): return (year, month, day, hour, min, sec) def i2m(self, pkt, val): - if type(val) is str: + if isinstance(val, str): val = self.h2i(pkt, val) l= val[:2] + (0,) + val[2:7] + (0,) return struct.pack('<8I', *l) def i2h(self, pkt, x): - if type(x) is str: + if isinstance(x, str): return x else: return time.ctime(time.mktime(x+(0,0,0))) @@ -223,7 +224,7 @@ def i2repr(self, pkt, x): def h2i(self, pkt, s): t = () - if type(s) is str: + if isinstance(s, str): t = time.strptime(s) t = t[:2] + t[2:-3] else: diff --git a/scapy/contrib/spbm.py b/scapy/contrib/spbm.py index 44ae942d324..56559db2ca0 100644 --- a/scapy/contrib/spbm.py +++ b/scapy/contrib/spbm.py @@ -1,22 +1,40 @@ +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . + # IEEE 802.1aq - Shorest Path Bridging Mac-in-mac (SPBM): # Ethernet based link state protocol that enables Layer 2 Unicast, Layer 2 Multicast, Layer 3 Unicast, and Layer 3 Multicast virtualized services # https://en.wikipedia.org/wiki/IEEE_802.1aq # Modeled after the scapy VXLAN contribution -# -############################################################# -# Example SPB Frame Creation -# -# Note the outer Dot1Q Ethertype marking (0x88e7) -############################################################# -# backboneEther = Ether(dst='00:bb:00:00:90:00', src='00:bb:00:00:40:00', type=0x8100) -# backboneDot1Q = Dot1Q(vlan=4051,type=0x88e7) -# backboneServiceID = SPBM(prio=1,isid=20011) -# customerEther = Ether(dst='00:1b:4f:5e:ca:00',src='00:00:00:00:00:01',type=0x8100) -# customerDot1Q = Dot1Q(prio=1,vlan=11,type=0x0800) -# customerIP = IP(src='10.100.11.10',dst='10.100.12.10',id=0x0629,len=106) -# customerUDP = UDP(sport=1024,dport=1025,chksum=0,len=86) -# -# spb_example = backboneEther/backboneDot1Q/backboneServiceID/customerEther/customerDot1Q/customerIP/customerUDP/"Payload" + +# scapy.contrib.description = SBPM +# scapy.contrib.status = loads + +""" + Example SPB Frame Creation + + Note the outer Dot1Q Ethertype marking (0x88e7) + + backboneEther = Ether(dst='00:bb:00:00:90:00', src='00:bb:00:00:40:00', type=0x8100) + backboneDot1Q = Dot1Q(vlan=4051,type=0x88e7) + backboneServiceID = SPBM(prio=1,isid=20011) + customerEther = Ether(dst='00:1b:4f:5e:ca:00',src='00:00:00:00:00:01',type=0x8100) + customerDot1Q = Dot1Q(prio=1,vlan=11,type=0x0800) + customerIP = IP(src='10.100.11.10',dst='10.100.12.10',id=0x0629,len=106) + customerUDP = UDP(sport=1024,dport=1025,chksum=0,len=86) + + spb_example = backboneEther/backboneDot1Q/backboneServiceID/customerEther/customerDot1Q/customerIP/customerUDP/"Payload" +""" from scapy.packet import Packet, bind_layers from scapy.fields import * diff --git a/scapy/contrib/ubberlogger.py b/scapy/contrib/ubberlogger.py index 1c01db2f600..b25556ec09d 100644 --- a/scapy/contrib/ubberlogger.py +++ b/scapy/contrib/ubberlogger.py @@ -1,8 +1,21 @@ +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . + # Author: Sylvain SARMEJEANNE -# http://trac.secdev.org/scapy/ticket/1 # scapy.contrib.description = Ubberlogger dissectors -# scapy.contrib.status = untested +# scapy.contrib.status = loads from scapy.packet import * from scapy.fields import * diff --git a/scapy/contrib/vqp.py b/scapy/contrib/vqp.py index 9328cea45b5..fbe8dadb068 100644 --- a/scapy/contrib/vqp.py +++ b/scapy/contrib/vqp.py @@ -1,5 +1,16 @@ - -# http://trac.secdev.org/scapy/ticket/147 +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . # scapy.contrib.description = VLAN Query Protocol # scapy.contrib.status = loads diff --git a/scapy/contrib/vtp.py b/scapy/contrib/vtp.py index 8c6c8d01d5b..98a7a97e7a5 100644 --- a/scapy/contrib/vtp.py +++ b/scapy/contrib/vtp.py @@ -1,4 +1,16 @@ -#!/usr/bin/env python +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . # scapy.contrib.description = VLAN Trunking Protocol (VTP) # scapy.contrib.status = loads diff --git a/scapy/contrib/wpa_eapol.py b/scapy/contrib/wpa_eapol.py index 084eedd827a..da6b2113027 100644 --- a/scapy/contrib/wpa_eapol.py +++ b/scapy/contrib/wpa_eapol.py @@ -1,5 +1,16 @@ - -# http://trac.secdev.org/scapy/ticket/104 +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see . # scapy.contrib.description = WPA EAPOL dissector # scapy.contrib.status = loads diff --git a/scapy/dadict.py b/scapy/dadict.py index c6cf847794c..67cb8515e7d 100644 --- a/scapy/dadict.py +++ b/scapy/dadict.py @@ -35,7 +35,7 @@ def __getitem__(self, attr): def __setitem__(self, attr, val): return setattr(self, self.fixname(attr), val) def __iter__(self): - return iter(map(lambda (x,y):y,filter(lambda (x,y):x and x[0]!="_", self.__dict__.items()))) + return iter(map(lambda x_y1: x_y1[1],filter(lambda x_y: x_y[0] and x_y[0][0]!="_", self.__dict__.items()))) def _show(self): for k in self.__dict__.keys(): if k and k[0] != "_": diff --git a/scapy/data.py b/scapy/data.py index 33712533b70..33224223078 100644 --- a/scapy/data.py +++ b/scapy/data.py @@ -77,7 +77,7 @@ def load_protocols(filename): if len(lt) < 2 or not lt[0]: continue dct[lt[0]] = int(lt[1]) - except Exception,e: + except Exception as e: log_loading.info("Couldn't parse file [%s]: line [%r] (%s)" % (filename,l,e)) except IOError: log_loading.info("Can't open %s file" % filename) @@ -100,10 +100,10 @@ def load_ethertypes(filename): if len(lt) < 2 or not lt[0]: continue dct[lt[0]] = int(lt[1], 16) - except Exception,e: + except Exception as e: log_loading.info("Couldn't parse file [%s]: line [%r] (%s)" % (filename,l,e)) f.close() - except IOError,msg: + except IOError as msg: pass return dct @@ -128,7 +128,7 @@ def load_services(filename): tdct[lt[0]] = int(lt[1].split('/')[0]) elif lt[1].endswith("/udp"): udct[lt[0]] = int(lt[1].split('/')[0]) - except Exception,e: + except Exception as e: log_loading.warning("Couldn't file [%s]: line [%r] (%s)" % (filename,l,e)) f.close() except IOError: @@ -152,7 +152,7 @@ def _resolve_MAC(self, mac): return ":".join([self[oui][0]]+ mac.split(":")[3:]) return mac def __repr__(self): - return "\n".join(["<%s %s, %s>" % (i[0], i[1][0], i[1][1]) for i in self.__dict__.items()]) + return "\n".join("<%s %s, %s>" % (i[0], i[1][0], i[1][1]) for i in self.__dict__.items()) @@ -171,7 +171,7 @@ def load_manuf(filename): else: lng = l[i+2:] manufdb[oui] = shrt, lng - except Exception,e: + except Exception as e: log_loading.warning("Couldn't parse one line from [%s] [%r] (%s)" % (filename, l, e)) except IOError: log_loading.warning("Couldn't open [%s] file" % filename) diff --git a/scapy/fields.py b/scapy/fields.py index 7e2c4e2ab94..da2e4c9867a 100644 --- a/scapy/fields.py +++ b/scapy/fields.py @@ -78,7 +78,7 @@ def getfield(self, pkt, s): def do_copy(self, x): if hasattr(x, "copy"): return x.copy() - if type(x) is list: + if isinstance(x, list): x = x[:] for i in xrange(len(x)): if isinstance(x[i], BasePacket): @@ -208,7 +208,7 @@ def i2m(self, pkt, x): def m2i(self, pkt, x): return str2mac(x) def any2i(self, pkt, x): - if type(x) is str and len(x) is 6: + if isinstance(x, str) and len(x) is 6: x = self.m2i(pkt, x) return x def i2repr(self, pkt, x): @@ -230,7 +230,7 @@ def h2i(self, pkt, x): inet_aton(x) except socket.error: x = Net(x) - elif type(x) is list: + elif isinstance(x, list): x = [self.h2i(pkt, n) for n in x] return x def resolve(self, x): @@ -380,7 +380,7 @@ def i2len(self, pkt, i): def i2m(self, pkt, x): if x is None: x = "" - elif type(x) is not str: + elif not isinstance(x, str): x=str(x) return x def addfield(self, pkt, s, val): @@ -440,12 +440,12 @@ def __init__(self, name, default, cls, count_from=None, length_from=None): def any2i(self, pkt, x): - if type(x) is not list: + if not isinstance(x, list): return [x] else: return x def i2count(self, pkt, val): - if type(val) is list: + if isinstance(val, list): return len(val) return 1 def i2len(self, pkt, val): @@ -489,7 +489,7 @@ def getfield(self, pkt, s): lst.append(p) return remain+ret,lst def addfield(self, pkt, s, val): - return s+"".join(map(str, val)) + return s + "".join(str(v) for v in val) class StrFixedLenField(StrField): @@ -500,7 +500,7 @@ def __init__(self, name, default, length=None, length_from=None): if length is not None: self.length_from = lambda pkt,length=length: length def i2repr(self, pkt, v): - if type(v) is str: + if isinstance(v, str): v = v.rstrip(b"\0") return repr(v) def getfield(self, pkt, s): @@ -539,7 +539,7 @@ def i2m(self, pkt, x): x = "" x += " "*(l) x = x[:l] - x = "".join(map(lambda x: chr(0x41+(ord(x)>>4))+chr(0x41+(ord(x)&0xf)), x)) + x = "".join(chr(0x41 + ord(b)>>4) + chr(0x41 + ord(b)&0xf) for b in x) x = " "+x return x def m2i(self, pkt, x): @@ -607,7 +607,7 @@ def __init__(self, name, default, field, length_from=None, count_from=None): self.length_from = length_from def i2count(self, pkt, val): - if type(val) is list: + if isinstance(val, list): return len(val) return 1 def i2len(self, pkt, val): @@ -618,10 +618,10 @@ def i2m(self, pkt, val): val = [] return val def any2i(self, pkt, x): - if type(x) is not list: + if not isinstance(x, list): return [self.field.any2i(pkt, x)] else: - return map(lambda e, pkt=pkt: self.field.any2i(pkt, e), x) + return [self.field.any2i(pkt, e) for e in x] def i2repr(self, pkt, x): res = [] for v in x: @@ -730,7 +730,7 @@ def reverse(self, val): def addfield(self, pkt, s, val): val = self.i2m(pkt, val) - if type(s) is tuple: + if isinstance(s, tuple): s,bitsdone,v = s else: bitsdone = 0 @@ -749,7 +749,7 @@ def addfield(self, pkt, s, val): else: return s def getfield(self, pkt, s): - if type(s) is tuple: + if isinstance(s, tuple): s,bn = s else: bn = 0 @@ -795,7 +795,7 @@ def __init__(self, name, default, size, length_of=None, count_of=None, adjust=la self.count_of = count_of self.adjust = adjust def i2m(self, pkt, x): - return FieldLenField.i2m.im_func(self, pkt, x) + return FieldLenField.i2m.__func__(self, pkt, x) class XBitField(BitField): @@ -830,11 +830,11 @@ def __init__(self, name, default, enum, fmt = "H"): s2i = self.s2i = {} self.i2s_cb = None self.s2i_cb = None - if type(enum) is list: + if isinstance(enum, list): keys = range(len(enum)) else: keys = enum.keys() - if any(type(x) is str for x in keys): + if any(isinstance(x, str) for x in keys): i2s, s2i = s2i, i2s for k in keys: i2s[k] = enum[k] @@ -842,7 +842,7 @@ def __init__(self, name, default, enum, fmt = "H"): Field.__init__(self, name, default, fmt) def any2i_one(self, pkt, x): - if type(x) is str: + if isinstance(x, str): try: x = self.s2i[x] except TypeError: @@ -862,14 +862,14 @@ def i2repr_one(self, pkt, x): return repr(x) def any2i(self, pkt, x): - if type(x) is list: - return map(lambda z,pkt=pkt:self.any2i_one(pkt,z), x) + if isinstance(x, list): + return [self.any2i_one(pkt, z) for z in x] else: return self.any2i_one(pkt,x) def i2repr(self, pkt, x): - if type(x) is list: - return map(lambda z,pkt=pkt:self.i2repr_one(pkt,z), x) + if isinstance(x, list): + return [self.i2repr_one(pkt, z) for z in x] else: return self.i2repr_one(pkt,x) @@ -957,7 +957,7 @@ def __init__(self, name, default, enum, depends_on, fmt = "H"): self.s2i_all[v] = k Field.__init__(self, name, default, fmt) def any2i_one(self, pkt, x): - if type (x) is str: + if isinstance(x, str): v = self.depends_on(pkt) if v in self.s2i_multi: s2i = self.s2i_multi[v] @@ -1151,7 +1151,7 @@ def any2i(self, pkt, x): else: v = self.depends_on(pkt) if v is not None: - assert self.names.has_key(v), 'invalid dependency' + assert v in self.names, 'invalid dependency' these_names = self.names[v] s = set() for i in x: @@ -1204,7 +1204,7 @@ def m2i(self, pkt, x): def i2repr(self, pkt, x): v = self.depends_on(pkt) - if self.names.has_key(v): + if v in self.names: these_names = self.names[v] else: these_names = {} diff --git a/scapy/layers/all.py b/scapy/layers/all.py index f23fae1c3d0..a8523385bfb 100644 --- a/scapy/layers/all.py +++ b/scapy/layers/all.py @@ -7,15 +7,25 @@ All layers. Configurable with conf.load_layers. """ +import __builtin__ from scapy.config import conf from scapy.error import log_loading -import logging +import logging, importlib +ignored = list(__builtin__.__dict__.keys()) + ["sys"] log = logging.getLogger("scapy.loading") __all__ = [] + +def _validate_local(x): + """Returns whether or not a variable should be imported. + Will return False for any default modules (sys), or if + they are detected as private vars (starting with a _)""" + global ignored + return x[0] != "_" and not x in ignored + def _import_star(m): - mod = __import__(m, globals(), locals()) + mod = importlib.import_module("." + m, "scapy.layers") if '__all__' in mod.__dict__: # only import the exported symbols in __all__ for name in mod.__dict__['__all__']: @@ -24,7 +34,7 @@ def _import_star(m): else: # import all the non-private symbols for name, sym in mod.__dict__.iteritems(): - if name[0] != '_': + if _validate_local(name): __all__.append(name) globals()[name] = sym @@ -33,6 +43,6 @@ def _import_star(m): try: if _l != "tls": _import_star(_l) - except Exception,e: + except Exception as e: log.warning("can't import layer %s: %s" % (_l,e)) diff --git a/scapy/layers/bluetooth.py b/scapy/layers/bluetooth.py index e17aac08352..cb845062cea 100644 --- a/scapy/layers/bluetooth.py +++ b/scapy/layers/bluetooth.py @@ -44,7 +44,7 @@ def i2m(self, pkt, x): def m2i(self, pkt, x): return str2mac(x[::-1]) def any2i(self, pkt, x): - if type(x) is str and len(x) is 6: + if isinstance(x, str) and len(x) is 6: x = self.m2i(pkt, x) return x def i2repr(self, pkt, x): diff --git a/scapy/layers/dhcp.py b/scapy/layers/dhcp.py index 96094066867..f17191d616a 100644 --- a/scapy/layers/dhcp.py +++ b/scapy/layers/dhcp.py @@ -145,7 +145,7 @@ def answers(self, other): DHCPRevOptions = {} for k,v in DHCPOptions.iteritems(): - if type(v) is str: + if isinstance(v, str): n = v v = None else: @@ -173,7 +173,7 @@ def _fix(self): op = [] for k in xrange(self.size): o = random.choice(self._opts) - if type(o) is str: + if isinstance(o, str): op.append((o,self.rndstr*1)) else: op.append((o.name, o.randval()._fix())) @@ -185,8 +185,8 @@ class DHCPOptionsField(StrField): def i2repr(self,pkt,x): s = [] for v in x: - if type(v) is tuple and len(v) >= 2: - if DHCPRevOptions.has_key(v[0]) and isinstance(DHCPRevOptions[v[0]][1],Field): + if isinstance(v, tuple) and len(v) >= 2: + if v[0] in DHCPRevOptions and isinstance(DHCPRevOptions[v[0]][1],Field): f = DHCPRevOptions[v[0]][1] vv = ",".join(f.i2repr(pkt,val) for val in v[1:]) else: @@ -214,7 +214,7 @@ def m2i(self, pkt, x): if len(x) < 2 or len(x) < ord(x[1])+2: opt.append(x) break - elif DHCPOptions.has_key(o): + elif o in DHCPOptions: f = DHCPOptions[o] if isinstance(f, str): @@ -242,17 +242,17 @@ def m2i(self, pkt, x): x = x[olen+2:] return opt def i2m(self, pkt, x): - if type(x) is str: + if isinstance(x, str): return x s = "" for o in x: - if type(o) is tuple and len(o) >= 2: + if isinstance(o, tuple) and len(o) >= 2: name = o[0] lval = o[1:] if isinstance(name, int): onum, oval = name, "".join(lval) - elif DHCPRevOptions.has_key(name): + elif name in DHCPRevOptions: onum, f = DHCPRevOptions[name] if f is not None: lval = [f.addfield(pkt,"",f.any2i(pkt,val)) for val in lval] @@ -265,12 +265,12 @@ def i2m(self, pkt, x): s += chr(len(oval)) s += oval - elif (type(o) is str and DHCPRevOptions.has_key(o) and + elif (isinstance(o, str) and o in DHCPRevOptions and DHCPRevOptions[o][1] == None): s += chr(DHCPRevOptions[o][0]) - elif type(o) is int: + elif isinstance(o, int): s += chr(o)+b"\0" - elif type(o) is str: + elif isinstance(o, str): s += o else: warning("Malformed option %s" % o) @@ -336,8 +336,8 @@ def print_reply(self, req, reply): def make_reply(self, req): mac = req.src - if type(self.pool) is list: - if not self.leases.has_key(mac): + if isinstance(self.pool, list): + if mac not in self.leases: self.leases[mac] = self.pool.pop() ip = self.leases[mac] else: @@ -361,7 +361,7 @@ def make_reply(self, req): if DHCP in req: dhcp_options = [(op[0],{1:2,3:5}.get(op[1],op[1])) for op in req[DHCP].options - if type(op) is tuple and op[0] == "message-type"] + if isinstance(op, tuple) and op[0] == "message-type"] dhcp_options += [("server_id",self.gw), ("domain", self.domain), ("router", self.gw), diff --git a/scapy/layers/dhcp6.py b/scapy/layers/dhcp6.py index f40f0caad97..7887a8d3c7d 100644 --- a/scapy/layers/dhcp6.py +++ b/scapy/layers/dhcp6.py @@ -319,7 +319,7 @@ class _IANAOptField(PacketListField): def i2len(self, pkt, z): if z is None or z == []: return 0 - return sum(map(lambda x: len(str(x)) ,z)) + return sum(len(str(x)) for x in z) def getfield(self, pkt, s): l = self.length_from(pkt) @@ -378,7 +378,7 @@ def any2i(self, pkt, x): def i2repr(self, pkt, x): s = [] for y in self.i2h(pkt, x): - if dhcp6opts.has_key(y): + if y in dhcp6opts: s.append(dhcp6opts[y]) else: s.append("%d" % y) @@ -395,7 +395,7 @@ def m2i(self, pkt, x): return r def i2m(self, pkt, x): - return "".join(map(lambda y: struct.pack("!H", y), x)) + return "".join(struct.pack('!H', y) for y in x) # A client may include an ORO in a solicit, Request, Renew, Rebind, # Confirm or Information-request @@ -547,7 +547,7 @@ class _UserClassDataField(PacketListField): def i2len(self, pkt, z): if z is None or z == []: return 0 - return sum(map(lambda x: len(str(x)) ,z)) + return sum(len(str(x)) for x in z) def getfield(self, pkt, s): l = self.length_from(pkt) @@ -747,7 +747,7 @@ def m2i(self, pkt, x): def i2m(self, pkt, x): if not x: return "" - tmp = "".join(map(lambda z: chr(len(z))+z, x.split('.'))) + tmp = "".join(chr(len(z)) + z for z in x.split('.')) return tmp class DHCP6OptNISDomain(_DHCP6OptGuessPayload): #RFC3898 @@ -1267,11 +1267,11 @@ def parse_options(self, dns="2001:500::1035", domain="localdomain, local", def norm_list(val, param_name): if val is None: return None - if type(val) is list: + if isinstance(val, list): return val - elif type(val) is str: + elif isinstance(val, str): l = val.split(',') - return map(lambda x: x.strip(), l) + return [x.strip() for x in l] else: print "Bad '%s' parameter provided." % param_name self.usage() @@ -1307,8 +1307,7 @@ def norm_list(val, param_name): if self.debug: print "\n[+] List of active DHCPv6 options:" - opts = self.dhcpv6_options.keys() - opts.sort() + opts = sorted(self.dhcpv6_options.keys()) for i in opts: print " %d: %s" % (i, repr(self.dhcpv6_options[i])) @@ -1337,7 +1336,7 @@ def norm_list(val, param_name): # Mac Address rawmac = get_if_raw_hwaddr(iface)[1] - mac = ":".join(map(lambda x: "%.02x" % ord(x), list(rawmac))) + mac = ":".join("%.02x" % ord(x) for x in rawmac) self.duid = DUID_LLT(timeval = timeval, lladdr = mac) @@ -1409,7 +1408,7 @@ def is_request(self, p): return False # provided server DUID must match ours duid = p[DHCP6OptServerId].duid - if (type(duid) != type(self.duid)): + if not isinstance(duid, type(self.duid)): return False if str(duid) != str(self.duid): return False @@ -1447,12 +1446,10 @@ def is_request(self, p): elif isinstance(it, DHCP6OptIA_TA): l = it.iataopts - opsaddr = filter(lambda x: isinstance(x, DHCP6OptIAAddress),l) - a=map(lambda x: x.addr, opsaddr) - addrs += a + addrs += [x.addr for x in l if isinstance(x, DHCP6OptIAAddress)] it = it.payload - addrs = map(lambda x: bo + x + n, addrs) + addrs = [bo + x + n for x in addrs] if debug: msg = r + "[DEBUG]" + n + " Received " + g + "Decline" + n msg += " from " + bo + src + vendor + " for " @@ -1476,7 +1473,7 @@ def is_request(self, p): elif p.msgtype == 11: # Information-Request if DHCP6OptServerId in p: duid = p[DHCP6OptServerId].duid - if (type(duid) != type(self.duid)): + if not isinstance(duid, type(self.duid)): return False if str(duid) != str(self.duid): return False diff --git a/scapy/layers/dns.py b/scapy/layers/dns.py index cd116d48e71..2080e4adeda 100644 --- a/scapy/layers/dns.py +++ b/scapy/layers/dns.py @@ -17,6 +17,7 @@ from scapy.layers.inet import IP, DestIPField, UDP, TCP from scapy.layers.inet6 import DestIP6Field from scapy.error import warning +from functools import reduce class DNSStrField(StrField): @@ -29,8 +30,8 @@ def i2m(self, pkt, x): if x == ".": return b"\x00" - x = [k[:63] for k in x.split(".")] # Truncate chunks that cannot be encoded (more than 63 bytes..) - x = map(lambda y: chr(len(y))+y, x) + # Truncate chunks that cannot be encoded (more than 63 bytes..) + x = "".join(chr(len(y)) + y for y in (k[:63] for k in x.split("."))) x = "".join(x) if x[-1] != b"\x00": x += b"\x00" @@ -42,7 +43,7 @@ def getfield(self, pkt, s): if ord(s[0]) == 0: return s[1:], "." - while 1: + while True: l = ord(s[0]) s = s[1:] if not l: @@ -82,7 +83,7 @@ def DNSgetstr(s,p): name = "" q = 0 jpath = [p] - while 1: + while True: if p >= len(s): warning("DNS RR prematured end (ofs=%i, len=%i)"%(p,len(s))) break @@ -139,7 +140,7 @@ def decodeRR(self, name, s, p): rr.rrname = name return rr,p def getfield(self, pkt, s): - if type(s) is tuple : + if isinstance(s, tuple) : s,p = s else: p = 0 @@ -201,7 +202,7 @@ def i2m(self, pkt, s): if s: s = inet_aton(s) elif pkt.type in [2, 3, 4, 5, 12]: # NS, MD, MF, CNAME, PTR - s = "".join(map(lambda x: chr(len(x))+x, s.split("."))) + s = "".join(chr(len(x)) + x for x in s.split('.')) if ord(s[-1]): s += b"\x00" elif pkt.type == 16: # TXT @@ -365,7 +366,7 @@ class DNSRROPT(Packet): class TimeField(IntField): def any2i(self, pkt, x): - if type(x) == str: + if isinstance(x, str): import time, calendar t = time.strptime(x, "%Y%m%d%H%M%S") return int(calendar.timegm(t)) @@ -428,11 +429,9 @@ def RRlist2bitmap(lst): import math bitmap = "" - lst = list(set(lst)) - lst.sort() + lst = sorted(set(lst)) - lst = filter(lambda x: x <= 65535, lst) - lst = map(lambda x: abs(x), lst) + lst = [abs(x) for x in lst if x <= 65535] # number of window blocks max_window_blocks = int(math.ceil(lst[-1] / 256.)) @@ -443,8 +442,7 @@ def RRlist2bitmap(lst): for wb in xrange(min_window_blocks, max_window_blocks+1): # First, filter out RR not encoded in the current window block # i.e. keep everything between 256*wb <= 256*(wb+1) - rrlist = filter(lambda x: 256 * wb <= x < 256 * (wb + 1), lst) - rrlist.sort() + rrlist = sorted(filter(lambda x: 256 * wb <= x < 256 * (wb + 1), lst)) if rrlist == []: continue @@ -465,11 +463,10 @@ def RRlist2bitmap(lst): v = 0 # Remove out of range Resource Records tmp_rrlist = filter(lambda x: 256 * wb + 8 * tmp <= x < 256 * wb + 8 * tmp + 8, rrlist) - if not tmp_rrlist == []: + if tmp_rrlist: # 1. rescale to fit into 8 bits - tmp_rrlist = map(lambda x: (x-256*wb)-(tmp*8), tmp_rrlist) # 2. x gives the bit position ; compute the corresponding value - tmp_rrlist = map(lambda x: 2**(7-x) , tmp_rrlist) + tmp_rrlist = [2 ** (7 - (x - 256 * wb) + (tmp * 8)) for x in tmp_rrlist] # 3. sum everything v = reduce(lambda x,y: x+y, tmp_rrlist) bitmap += struct.pack("B", v) @@ -479,7 +476,7 @@ def RRlist2bitmap(lst): class RRlistField(StrField): def h2i(self, pkt, x): - if type(x) == list: + if isinstance(x, list): return RRlist2bitmap(x) return x diff --git a/scapy/layers/dot11.py b/scapy/layers/dot11.py index 1d4a1b1218e..7f7caff3460 100644 --- a/scapy/layers/dot11.py +++ b/scapy/layers/dot11.py @@ -509,7 +509,7 @@ def __init__(self, res=None, name="Dot11List", stats=None): PacketList.__init__(self, res, name, stats) def toEthernet(self): - data = map(lambda x:x.getlayer(Dot11), filter(lambda x : x.haslayer(Dot11) and x.type == 2, self.res)) + data = [x[Dot11] for x in self.res if Dot11 in x and x.type == 2] r2 = [] for p in data: q = p.copy() diff --git a/scapy/layers/inet.py b/scapy/layers/inet.py index 146b42ea7e4..f969dc5e9d5 100644 --- a/scapy/layers/inet.py +++ b/scapy/layers/inet.py @@ -44,8 +44,7 @@ def whois(self): else: os.system("whois %s" % self.src) def ottl(self): - t = [32,64,128,255]+[self.ttl] - t.sort() + t = sorted([32,64,128,255]+[self.ttl]) return t[t.index(self.ttl)+1] def hops(self): return self.ottl() - self.ttl @@ -269,7 +268,7 @@ def m2i(self, pkt, x): warning("Malformed TCP option (announced length is %i)" % olen) olen = 2 oval = x[2:olen] - if TCPOptions[0].has_key(onum): + if onum in TCPOptions[0]: oname, ofmt = TCPOptions[0][onum] if onum == 5: #SAck ofmt += "%iI" % (len(oval)/4) @@ -286,20 +285,20 @@ def m2i(self, pkt, x): def i2m(self, pkt, x): opt = "" for oname,oval in x: - if type(oname) is str: + if isinstance(oname, str): if oname == "NOP": opt += b"\x01" continue elif oname == "EOL": opt += b"\x00" continue - elif TCPOptions[1].has_key(oname): + elif oname in TCPOptions[1]: onum = TCPOptions[1][oname] ofmt = TCPOptions[0][onum][1] if onum == 5: #SAck ofmt += "%iI" % len(oval) - if ofmt is not None and (type(oval) is not str or "s" in ofmt): - if type(oval) is not tuple: + if ofmt is not None and (not isinstance(oval, str) or "s" in ofmt): + if not isinstance(oval, tuple): oval = (oval,) oval = struct.pack(ofmt, *oval) else: @@ -307,7 +306,7 @@ def i2m(self, pkt, x): continue else: onum = oname - if type(oval) is not str: + if not isinstance(oval, str): warning("option [%i] is not string."%onum) continue opt += chr(onum)+chr(2+len(oval))+oval @@ -327,7 +326,7 @@ def i2repr(self, pkt, val): hour, min = divmod(min, 60) return "%d:%d:%d.%d" %(hour, min, sec, int(milli)) def any2i(self, pkt, val): - if type(val) is str: + if isinstance(val, str): hmsms = self.re_hmsm.match(val) if hmsms: h,_,m,_,s,_,ms = hmsms = hmsms.groups() @@ -1004,7 +1003,7 @@ def _packetlist_timeskew_graph(self, ip, **kargs): """Tries to graph the timeskew between the timestamps and real time for a given ip""" # Filter TCP segments which source address is 'ip' - res = map(lambda x: self._elt2pkt(x), self.res) + res = [self._elt2pkt(x) for x in self.res] b = filter(lambda x:x.haslayer(IP) and x.getlayer(IP).src == ip and x.haslayer(TCP), res) # Build a list of tuples (creation_time, replied_timestamp) @@ -1034,7 +1033,7 @@ def _wrap_data(ts_tuple, wrap_seconds=2000): return X, Y - data = map(_wrap_data, c) + data = [_wrap_data(e) for e in c] # Mimic the default gnuplot output if kargs == {}: @@ -1063,9 +1062,9 @@ def __init__(self, res=None, name="Traceroute", stats=None): self.nloc = None def show(self): - return self.make_table(lambda (s,r): (s.sprintf("%IP.dst%:{TCP:tcp%ir,TCP.dport%}{UDP:udp%ir,UDP.dport%}{ICMP:ICMP}"), - s.ttl, - r.sprintf("%-15s,IP.src% {TCP:%TCP.flags%}{ICMP:%ir,ICMP.type%}"))) + return self.make_table(lambda s_r: (s_r[0].sprintf("%IP.dst%:{TCP:tcp%ir,TCP.dport%}{UDP:udp%ir,UDP.dport%}{ICMP:ICMP}"), + s_r[0].ttl, + s_r[1].sprintf("%-15s,IP.src% {TCP:%TCP.flags%}{ICMP:%ir,ICMP.type%}"))) def get_trace(self): @@ -1159,7 +1158,7 @@ def action(self): start = ip.pos movcenter=None - while 1: + while True: visual.rate(50) if visual.scene.kb.keys: k = visual.scene.kb.getkey() @@ -1235,7 +1234,7 @@ def world_trace(self, **kargs): trace_id = (s.src,s.dst,s.proto,0) trace = rt.get(trace_id,{}) if not r.haslayer(ICMP) or r.type != 11: - if ports_done.has_key(trace_id): + if trace_id in ports_done: continue ports_done[trace_id] = None trace[s.ttl] = r.src @@ -1333,9 +1332,9 @@ def make_graph(self,ASres=None,padding=0): trace = rt[rtk] max_trace = max(trace) for n in xrange(min(trace), max_trace): - if not trace.has_key(n): + if n not in trace: trace[n] = unknown_label.next() - if not ports_done.has_key(rtk): + if rtk not in ports_done: if rtk[2] == 1: #ICMP bh = "%s %i/icmp" % (rtk[1],rtk[3]) elif rtk[2] == 6: #TCP @@ -1421,7 +1420,7 @@ def make_graph(self,ASres=None,padding=0): for rtk in rt: - s += "#---[%s\n" % `rtk` + s += "#---[%s\n" % repr(rtk) s += '\t\tedge [color="#%s%s%s"];\n' % forecolorlist.next() trace = rt[rtk] maxtrace = max(trace) @@ -1642,10 +1641,10 @@ def IPID_count(lst, funcID=lambda x:x[1].id, funcpres=lambda x:x[1].summary()): lst: a list of packets funcID: a function that returns IP id values funcpres: a function used to summarize packets""" - idlst = map(funcID, lst) + idlst = [funcID(e) for e in lst] idlst.sort() - classes = [idlst[0]]+map(lambda x:x[1],filter(lambda (x,y): abs(x-y)>50, map(lambda x,y: (x,y),idlst[:-1], idlst[1:]))) - lst = map(lambda x:(funcID(x), funcpres(x)), lst) + classes = [idlst[0]] + [x[1] for x in zip(idlst[:-1], idlst[1:]) if abs(x[0] - x[1]) > 50] + lst = [(funcID(x), funcpres(x)) for x in lst] lst.sort() print "Probably %i classes:" % len(classes), classes for id,pr in lst: @@ -1662,7 +1661,7 @@ def fragleak(target,sport=123, dport=123, timeout=0.2, onlyasc=0): intr=0 found={} try: - while 1: + while True: try: if not intr: s.send(pkt) @@ -1708,7 +1707,7 @@ def fragleak(target,sport=123, dport=123, timeout=0.2, onlyasc=0): def fragleak2(target, timeout=0.4, onlyasc=0): found={} try: - while 1: + while True: p = sr1(IP(dst=target, options=b"\x00"*40, proto=200)/"XXXXYYYYYYYYYYYY",timeout=timeout,verbose=0) if not p: continue diff --git a/scapy/layers/inet6.py b/scapy/layers/inet6.py index 20afedf8308..c35468f5815 100644 --- a/scapy/layers/inet6.py +++ b/scapy/layers/inet6.py @@ -166,7 +166,7 @@ def m8(i): tuple = filter(lambda x: m8(x), xrange(8, 129)) a = in6_and(self.net, self.mask) - tmp = map(lambda x: x, struct.unpack('16B', a)) + tmp = [x for x in struct.unpack("16B", a)] def parse_digit(a, netmask): netmask = min(8,max(netmask,0)) @@ -208,13 +208,13 @@ class IP6Field(Field): def __init__(self, name, default): Field.__init__(self, name, default, "16s") def h2i(self, pkt, x): - if type(x) is str: + if isinstance(x, str): try: x = in6_ptop(x) except socket.error: x = Net6(x) - elif type(x) is list: - x = map(Net6, x) + elif isinstance(x, list): + x = [Net6(a) for a in x] return x def i2m(self, pkt, x): return inet_pton(socket.AF_INET6, x) @@ -225,7 +225,7 @@ def any2i(self, pkt, x): def i2repr(self, pkt, x): if x is None: return self.i2h(pkt,x) - elif not isinstance(x, Net6) and not type(x) is list: + elif not isinstance(x, Net6) and not isinstance(x, list): if in6_isaddrTeredo(x): # print Teredo info server, flag, maddr, mport = teredoAddrExtractInfo(x) return "%s [Teredo srv: %s cli: %s:%s]" % (self.i2h(pkt, x), server, maddr,mport) @@ -317,7 +317,7 @@ def i2len(self, pkt, i): return 16*len(i) def i2count(self, pkt, i): - if type(i) is list: + if isinstance(i, list): return len(i) return 0 @@ -828,7 +828,7 @@ def i2len(self, pkt, i): return l def i2count(self, pkt, i): - if type(i) is list: + if isinstance(i, list): return len(i) return 0 @@ -851,7 +851,7 @@ def getfield(self, pkt, s): c -= 1 o = ord(x[0]) # Option type cls = self.cls - if _hbhoptcls.has_key(o): + if o in _hbhoptcls: cls = _hbhoptcls[o] try: op = cls(x) @@ -1915,8 +1915,8 @@ def conditionalTrailingDot(z): return z return z+b'\x00' # Build the encode names - tmp = map(lambda y: map((lambda z: chr(len(z))+z), y.split('.')), x) - ret_string = "".join(map(lambda x: conditionalTrailingDot("".join(x)), tmp)) + tmp = [[chr(len(z)) + z for z in y.split('.')] for y in x] + ret_string = "".join(conditionalTrailingDot("".join(x)) for x in tmp) # In padded mode, add some \x00 bytes if self.padded and not len(ret_string) % self.padded_unit == 0: @@ -2149,7 +2149,7 @@ def names2dnsrepr(x): !!! At the moment, compression is not implemented !!! """ - if type(x) is str: + if isinstance(x, str): if x and x[-1] == b'\x00': # stupid heuristic return x x = [x] @@ -2159,7 +2159,7 @@ def names2dnsrepr(x): termin = b"\x00" if n.count('.') == 0: # single-component gets one more termin += b'\x00' - n = "".join(map(lambda y: chr(len(y))+y, n.split("."))) + termin + n = "".join(chr(len(y)) + y for y in n.split('.')) + termin res.append(n) return "".join(res) @@ -2206,7 +2206,7 @@ def i2h(self, pkt, x): return val def h2i(self, pkt, x): - if x is tuple and type(x[0]) is int: + if x is tuple and isinstance(x[0], int): return x val = None @@ -2262,7 +2262,7 @@ def getfield(self, pkt, s): return "", (1, s) def addfield(self, pkt, s, val): - if ((type(val) is tuple and val[1] is None) or + if ((isinstance(val, tuple) and val[1] is None) or val is None): val = (1, "") t = val[0] @@ -2360,7 +2360,7 @@ def h2i(self, pkt, x): # overridden through 'qtype' in pkt # No user hint, let's use 'qtype' value for that purpose - if type(x) is not tuple: + if not isinstance(x, tuple): if pkt is not None: qtype = getattr(pkt, "qtype") else: @@ -2370,26 +2370,26 @@ def h2i(self, pkt, x): # From that point on, x is the value (second element of the tuple) if qtype == 2: # DNS name - if type(x) is str: # listify the string + if isinstance(x, str): # listify the string x = [x] - if type(x) is list and x and type(x[0]) is not int: # ttl was omitted : use 0 + if isinstance(x, list) and x and not isinstance(x[0], int): # ttl was omitted : use 0 x = [0] + x ttl = x[0] names = x[1:] return (2, [ttl, names2dnsrepr(names)]) elif qtype in [3, 4]: # IPv4 or IPv6 addr - if type(x) is str: + if isinstance(x, str): x = [x] # User directly provided an IP, instead of list # List elements are not tuples, user probably # omitted ttl value : we will use 0 instead def addttl(x): - if type(x) is str: + if isinstance(x, str): return (0, x) return x - return (qtype, map(addttl, x)) + return (qtype, [addttl(d) for d in x]) return (qtype, x) @@ -2402,9 +2402,9 @@ def addfield(self, pkt, s, val): ttl,dnsstr = tmp return s+ struct.pack("!I", ttl) + dnsstr elif t == 3: - return s + "".join(map(lambda (x,y): struct.pack("!I", x)+inet_pton(socket.AF_INET6, y), tmp)) + return s + "".join(map(lambda x_y1: struct.pack("!I", x_y1[0])+inet_pton(socket.AF_INET6, x_y1[1]), tmp)) elif t == 4: - return s + "".join(map(lambda (x,y): struct.pack("!I", x)+inet_pton(socket.AF_INET, y), tmp)) + return s + "".join(map(lambda x_y2: struct.pack("!I", x_y2[0])+inet_pton(socket.AF_INET, x_y2[1]), tmp)) else: return s + tmp @@ -2450,14 +2450,14 @@ def i2repr(self, pkt, x): if x is None: return "[]" - if type(x) is tuple and len(x) == 2: + if isinstance(x, tuple) and len(x) == 2: t, val = x if t == 2: # DNS names ttl,l = val l = dnsrepr2names(l) return "ttl:%d %s" % (ttl, ", ".join(l)) elif t == 3 or t == 4: - return "[ %s ]" % (", ".join(map(lambda (x,y): "(%d, %s)" % (x, y), val))) + return "[ %s ]" % (", ".join(map(lambda x_y: "(%d, %s)" % (x_y[0], x_y[1]), val))) return repr(val) return repr(x) # XXX should not happen @@ -2877,7 +2877,7 @@ def m2i(self, pkt, x): while x: o = ord(x[0]) # Option type cls = self.cls - if moboptcls.has_key(o): + if o in moboptcls: cls = moboptcls[o] try: op = cls(x) @@ -3125,9 +3125,9 @@ def _resolve_one(self, ip): class TracerouteResult6(TracerouteResult): __slots__ = [] def show(self): - return self.make_table(lambda (s,r): (s.sprintf("%-42s,IPv6.dst%:{TCP:tcp%TCP.dport%}{UDP:udp%UDP.dport%}{ICMPv6EchoRequest:IER}"), # TODO: ICMPv6 ! - s.hlim, - r.sprintf("%-42s,IPv6.src% {TCP:%TCP.flags%}"+ + return self.make_table(lambda s_r: (s_r[0].sprintf("%-42s,IPv6.dst%:{TCP:tcp%TCP.dport%}{UDP:udp%UDP.dport%}{ICMPv6EchoRequest:IER}"), # TODO: ICMPv6 ! + s_r[0].hlim, + s_r[1].sprintf("%-42s,IPv6.src% {TCP:%TCP.flags%}"+ "{ICMPv6DestUnreach:%ir,type%}{ICMPv6PacketTooBig:%ir,type%}"+ "{ICMPv6TimeExceeded:%ir,type%}{ICMPv6ParamProblem:%ir,type%}"+ "{ICMPv6EchoReply:%ir,type%}"))) diff --git a/scapy/layers/isakmp.py b/scapy/layers/isakmp.py index 74d97781965..a18d5231f54 100644 --- a/scapy/layers/isakmp.py +++ b/scapy/layers/isakmp.py @@ -15,6 +15,7 @@ from scapy.layers.inet import IP,UDP from scapy.sendrecv import sr from scapy.error import warning +from functools import reduce # see http://www.iana.org/assignments/ipsec-registry for details @@ -101,7 +102,8 @@ class ISAKMPTransformSetField(StrLenField): islist=1 - def type2num(self, (typ,val)): + def type2num(self, type_val_tuple): + typ, val = type_val_tuple type_val,enc_dict,tlv = ISAKMPTransformTypes.get(typ, (typ,{},0)) val = enc_dict.get(val, val) s = "" @@ -124,7 +126,7 @@ def num2type(self, typ, enc): def i2m(self, pkt, i): if i is None: return "" - i = map(self.type2num, i) + i = [self.type2num(e) for e in i] return "".join(i) def m2i(self, pkt, m): # I try to ensure that we don't read off the end of our packet based diff --git a/scapy/layers/l2.py b/scapy/layers/l2.py index 1f60256615c..1e7aa7ed764 100644 --- a/scapy/layers/l2.py +++ b/scapy/layers/l2.py @@ -59,7 +59,7 @@ def getmacbyip(ip, chainCC=0): if isinstance(ip,Net): ip = iter(ip).next() ip = inet_ntoa(inet_aton(ip)) - tmp = map(ord, inet_aton(ip)) + tmp = [ord(e) for e in inet_aton(ip)] if (tmp[0] & 0xf0) == 0xe0: # mcast @ return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1]&0x7f,tmp[2],tmp[3]) iff,a,gw = conf.route.route(ip) @@ -1169,7 +1169,7 @@ def arpcachepoison(target, victim, interval=60): tmac = getmacbyip(target) p = Ether(dst=tmac)/ARP(op="who-has", psrc=victim, pdst=target) try: - while 1: + while True: sendp(p, iface_hint=target) if conf.verb > 1: os.write(1,".") @@ -1262,7 +1262,7 @@ def make_reply(self, req): ether = req.getlayer(Ether) arp = req.getlayer(ARP) - if self.optsend.has_key('iface'): + if 'iface' in self.optsend: iff = self.optsend.get('iface') else: iff,a,gw = conf.route.route(arp.psrc) @@ -1284,7 +1284,7 @@ def make_reply(self, req): return resp def send_reply(self, reply): - if self.optsend.has_key('iface'): + if 'iface' in self.optsend: self.send_function(reply, **self.optsend) else: self.send_function(reply, iface=self.iff, **self.optsend) @@ -1297,7 +1297,7 @@ def print_reply(self, req, reply): def etherleak(target, **kargs): """Exploit Etherleak flaw""" return srpflood(Ether()/ARP(pdst=target), - prn=lambda (s,r): conf.padding_layer in r and hexstr(r[conf.padding_layer].load), + prn=lambda s_r: conf.padding_layer in s_r[1] and hexstr(s_r[1][conf.padding_layer].load), filter="arp", **kargs) diff --git a/scapy/layers/radius.py b/scapy/layers/radius.py index 4d93bcff41d..1038974efd7 100644 --- a/scapy/layers/radius.py +++ b/scapy/layers/radius.py @@ -9,139 +9,1199 @@ """ import struct -from scapy.packet import * -from scapy.fields import * -from scapy.layers.inet import * +import logging +from scapy.packet import Packet, bind_layers +from scapy.fields import ByteField, ByteEnumField, IntField, StrLenField,\ + XStrLenField, XStrFixedLenField, FieldLenField, PacketField,\ + PacketListField, IPField, MultiEnumField +from scapy.layers.inet import UDP +from scapy.layers.l2 import EAP +from scapy.config import conf +from scapy.error import Scapy_Exception + + +g_log_loading = logging.getLogger("scapy.logging") + +_crypto_loading_failure_message = \ + "Could not import python-cryptography."\ + "Computations for the \"authenticator\" field (RADIUS packets) and"\ + "\"Message-Authenticator\" attribute value field are disabled." + +if conf.crypto_valid: + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives import hashes, hmac +else: + g_log_loading.info(_crypto_loading_failure_message) + + +# https://www.iana.org/assignments/radius-types/radius-types.xhtml +_radius_attribute_types = { + 1: "User-Name", + 2: "User-Password", + 3: "CHAP-Password", + 4: "NAS-IP-Address", + 5: "NAS-Port", + 6: "Service-Type", + 7: "Framed-Protocol", + 8: "Framed-IP-Address", + 9: "Framed-IP-Netmask", + 10: "Framed-Routing", + 11: "Filter-Id", + 12: "Framed-MTU", + 13: "Framed-Compression", + 14: "Login-IP-Host", + 15: "Login-Service", + 16: "Login-TCP-Port", + 17: "Unassigned", + 18: "Reply-Message", + 19: "Callback-Number", + 20: "Callback-Id", + 21: "Unassigned", + 22: "Framed-Route", + 23: "Framed-IPX-Network", + 24: "State", + 25: "Class", + 26: "Vendor-Specific", + 27: "Session-Timeout", + 28: "Idle-Timeout", + 29: "Termination-Action", + 30: "Called-Station-Id", + 31: "Calling-Station-Id", + 32: "NAS-Identifier", + 33: "Proxy-State", + 34: "Login-LAT-Service", + 35: "Login-LAT-Node", + 36: "Login-LAT-Group", + 37: "Framed-AppleTalk-Link", + 38: "Framed-AppleTalk-Network", + 39: "Framed-AppleTalk-Zone", + 40: "Acct-Status-Type", + 41: "Acct-Delay-Time", + 42: "Acct-Input-Octets", + 43: "Acct-Output-Octets", + 44: "Acct-Session-Id", + 45: "Acct-Authentic", + 46: "Acct-Session-Time", + 47: "Acct-Input-Packets", + 48: "Acct-Output-Packets", + 49: "Acct-Terminate-Cause", + 50: "Acct-Multi-Session-Id", + 51: "Acct-Link-Count", + 52: "Acct-Input-Gigawords", + 53: "Acct-Output-Gigawords", + 54: "Unassigned", + 55: "Event-Timestamp", + 56: "Egress-VLANID", + 57: "Ingress-Filters", + 58: "Egress-VLAN-Name", + 59: "User-Priority-Table", + 60: "CHAP-Challenge", + 61: "NAS-Port-Type", + 62: "Port-Limit", + 63: "Login-LAT-Port", + 64: "Tunnel-Type", + 65: "Tunnel-Medium-Type", + 66: "Tunnel-Client-Endpoint", + 67: "Tunnel-Server-Endpoint", + 68: "Acct-Tunnel-Connection", + 69: "Tunnel-Password", + 70: "ARAP-Password", + 71: "ARAP-Features", + 72: "ARAP-Zone-Access", + 73: "ARAP-Security", + 74: "ARAP-Security-Data", + 75: "Password-Retry", + 76: "Prompt", + 77: "Connect-Info", + 78: "Configuration-Token", + 79: "EAP-Message", + 80: "Message-Authenticator", + 81: "Tunnel-Private-Group-ID", + 82: "Tunnel-Assignment-ID", + 83: "Tunnel-Preference", + 84: "ARAP-Challenge-Response", + 85: "Acct-Interim-Interval", + 86: "Acct-Tunnel-Packets-Lost", + 87: "NAS-Port-Id", + 88: "Framed-Pool", + 89: "CUI", + 90: "Tunnel-Client-Auth-ID", + 91: "Tunnel-Server-Auth-ID", + 92: "NAS-Filter-Rule", + 93: "Unassigned", + 94: "Originating-Line-Info", + 95: "NAS-IPv6-Address", + 96: "Framed-Interface-Id", + 97: "Framed-IPv6-Prefix", + 98: "Login-IPv6-Host", + 99: "Framed-IPv6-Route", + 100: "Framed-IPv6-Pool", + 101: "Error-Cause", + 102: "EAP-Key-Name", + 103: "Digest-Response", + 104: "Digest-Realm", + 105: "Digest-Nonce", + 106: "Digest-Response-Auth", + 107: "Digest-Nextnonce", + 108: "Digest-Method", + 109: "Digest-URI", + 110: "Digest-Qop", + 111: "Digest-Algorithm", + 112: "Digest-Entity-Body-Hash", + 113: "Digest-CNonce", + 114: "Digest-Nonce-Count", + 115: "Digest-Username", + 116: "Digest-Opaque", + 117: "Digest-Auth-Param", + 118: "Digest-AKA-Auts", + 119: "Digest-Domain", + 120: "Digest-Stale", + 121: "Digest-HA1", + 122: "SIP-AOR", + 123: "Delegated-IPv6-Prefix", + 124: "MIP6-Feature-Vector", + 125: "MIP6-Home-Link-Prefix", + 126: "Operator-Name", + 127: "Location-Information", + 128: "Location-Data", + 129: "Basic-Location-Policy-Rules", + 130: "Extended-Location-Policy-Rules", + 131: "Location-Capable", + 132: "Requested-Location-Info", + 133: "Framed-Management-Protocol", + 134: "Management-Transport-Protection", + 135: "Management-Policy-Id", + 136: "Management-Privilege-Level", + 137: "PKM-SS-Cert", + 138: "PKM-CA-Cert", + 139: "PKM-Config-Settings", + 140: "PKM-Cryptosuite-List", + 141: "PKM-SAID", + 142: "PKM-SA-Descriptor", + 143: "PKM-Auth-Key", + 144: "DS-Lite-Tunnel-Name", + 145: "Mobile-Node-Identifier", + 146: "Service-Selection", + 147: "PMIP6-Home-LMA-IPv6-Address", + 148: "PMIP6-Visited-LMA-IPv6-Address", + 149: "PMIP6-Home-LMA-IPv4-Address", + 150: "PMIP6-Visited-LMA-IPv4-Address", + 151: "PMIP6-Home-HN-Prefix", + 152: "PMIP6-Visited-HN-Prefix", + 153: "PMIP6-Home-Interface-ID", + 154: "PMIP6-Visited-Interface-ID", + 155: "PMIP6-Home-IPv4-HoA", + 156: "PMIP6-Visited-IPv4-HoA", + 157: "PMIP6-Home-DHCP4-Server-Address", + 158: "PMIP6-Visited-DHCP4-Server-Address", + 159: "PMIP6-Home-DHCP6-Server-Address", + 160: "PMIP6-Visited-DHCP6-Server-Address", + 161: "PMIP6-Home-IPv4-Gateway", + 162: "PMIP6-Visited-IPv4-Gateway", + 163: "EAP-Lower-Layer", + 164: "GSS-Acceptor-Service-Name", + 165: "GSS-Acceptor-Host-Name", + 166: "GSS-Acceptor-Service-Specifics", + 167: "GSS-Acceptor-Realm-Name", + 168: "Framed-IPv6-Address", + 169: "DNS-Server-IPv6-Address", + 170: "Route-IPv6-Information", + 171: "Delegated-IPv6-Prefix-Pool", + 172: "Stateful-IPv6-Address-Pool", + 173: "IPv6-6rd-Configuration", + 174: "Allowed-Called-Station-Id", + 175: "EAP-Peer-Id", + 176: "EAP-Server-Id", + 177: "Mobility-Domain-Id", + 178: "Preauth-Timeout", + 179: "Network-Id-Name", + 180: "EAPoL-Announcement", + 181: "WLAN-HESSID", + 182: "WLAN-Venue-Info", + 183: "WLAN-Venue-Language", + 184: "WLAN-Venue-Name", + 185: "WLAN-Reason-Code", + 186: "WLAN-Pairwise-Cipher", + 187: "WLAN-Group-Cipher", + 188: "WLAN-AKM-Suite", + 189: "WLAN-Group-Mgmt-Cipher", + 190: "WLAN-RF-Band", + 191: "Unassigned", +} + + +class RadiusAttribute(Packet): + """ + Implements a RADIUS attribute (RFC 2865). Every specific RADIUS attribute + class should inherit from this one. + """ -class RadiusAttribute(Packet): name = "Radius Attribute" fields_desc = [ - ByteEnumField("type",1,{ 1:"User-Name", - 2:"User-Password", - 3:"CHAP-Password", - 4:"NAS-IP-Address", - 5:"NAS-Port", - 6:"Service-Type", - 7:"Framed-Protocol", - 8:"Framed-IP-Address", - 9:"Framed-IP-Netmask", - 10:"Framed-Routing", - 11:"Filter-Id", - 12:"Framed-MTU", - 13:"Framed-Compression", - 14:"Login-IP-Host", - 15:"Login-Service", - 16:"Login-TCP-Port", - 17:"(unassigned)", - 18:"Reply-Message", - 19:"Callback-Number", - 20:"Callback-Id", - 21:"(unassigned)", - 22:"Framed-Route", - 23:"Framed-IPX-Network", - 24:"State", - 25:"Class", - 26:"Vendor-Specific", - 27:"Session-Timeout", - 28:"Idle-Timeout", - 29:"Termination-Action", - 30:"Called-Station-Id", - 31:"Calling-Station-Id", - 32:"NAS-Identifier", - 33:"Proxy-State", - 34:"Login-LAT-Service", - 35:"Login-LAT-Node", - 36:"Login-LAT-Group", - 37:"Framed-AppleTalk-Link", - 38:"Framed-AppleTalk-Network", - 39:"Framed-AppleTalk-Zone", - 40:"Acct-Status-Type", - 41:"Acct-Delay-Time", - 42:"Acct-Input-Octets", - 43:"Acct-Output-Octets", - 44:"Acct-Session-Id", - 45:"Acct-Authentic", - 46:"Acct-Session-Time", - 47:"Acct-Input-Packets", - 48:"Acct-Output-Packets", - 49:"Acct-Terminate-Cause", - 50:"Acct-Multi-Session-Id", - 51:"Acct-Link-Count", - 60:"CHAP-Challenge", - 61:"NAS-Port-Type", - 62:"Port-Limit", - 63:"Login-LAT-Port", - 70:"ARAP-Password", - 75:"Password-Retry", - 79:"EAP-Message", - 80:"Message-Authenticator", - 94:"Originating-Line-Info", - 101:"Error-Cause" - }), - FieldLenField("len", None, "value", "B", adjust=lambda pkt,x:len(pkt.value)+2), - StrLenField("value", "" , length_from=lambda pkt:pkt.len-2),] + ByteEnumField("type", 1, _radius_attribute_types), + FieldLenField("len", None, "value", "B", + adjust=lambda pkt, x: len(pkt.value) + 2), + StrLenField("value", "", length_from=lambda pkt: pkt.len - 2) + ] + + registered_attributes = {} + + @classmethod + def register_variant(cls): + """ + Registers the RADIUS attributes defined in this module. + """ + + if hasattr(cls, "val"): + cls.registered_attributes[cls.val] = cls + else: + cls.registered_attributes[cls.type.default] = cls + + @classmethod + def dispatch_hook(cls, _pkt=None, *args, **kargs): + """ + Returns the right RadiusAttribute class for the given data. + """ + + if _pkt: + attr_type = ord(_pkt[0]) + return cls.registered_attributes.get(attr_type, cls) + return cls + + def haslayer(self, cls): + if cls == RadiusAttribute: + for attr_class in RadiusAttribute.registered_attributes.values(): + if isinstance(self, attr_class): + return True + elif cls in RadiusAttribute.registered_attributes.values() and isinstance(self, cls): + return True + return False + + def getlayer(self, cls, nb=1, _track=None): + layer = None + if cls == RadiusAttribute: + for attr_class in RadiusAttribute.registered_attributes.values(): + if isinstance(self, attr_class): + layer = self + break + else: + layer = Packet.getlayer(self, cls, nb, _track) + return layer + def post_build(self, p, pay): - l = self.len - if l is None: - l = len(p) - p = p[:1]+struct.pack("!B", l)+p[2:] + length = self.len + if length is None: + length = len(p) + p = p[:1] + struct.pack("!B", length) + p[2:] return p - - def extract_padding(self, pay): - return "",pay + + +class _SpecificRadiusAttr(RadiusAttribute): + """ + Class from which every "specific" RADIUS attribute defined in this module + inherits. + """ + + __slots__ = ["val"] + + def __init__(self, _pkt="", post_transform=None, _internal=0, _underlayer=None, **fields): + super(_SpecificRadiusAttr, self).__init__( + _pkt, + post_transform, + _internal, + _underlayer + ) + self.fields["type"] = self.val + name_parts = self.__class__.__name__.split('RadiusAttr_') + if len(name_parts) < 2: + raise Scapy_Exception( + "Invalid class name: {}".format(self.__class__.__name__) + ) + self.name = name_parts[1].replace('_', '-') + + +# +# RADIUS attributes which values are 4 bytes integers +# + +class _RadiusAttrIntValue(_SpecificRadiusAttr): + """ + Implements a RADIUS attribute which value field is 4 bytes long integer. + """ + + fields_desc = [ + ByteEnumField("type", 5, _radius_attribute_types), + ByteField("len", 6), + IntField("value", 0) + ] + + +class RadiusAttr_NAS_Port(_RadiusAttrIntValue): + """RFC 2865""" + val = 5 + + +class RadiusAttr_Framed_MTU(_RadiusAttrIntValue): + """RFC 2865""" + val = 12 + + +class RadiusAttr_Login_TCP_Port(_RadiusAttrIntValue): + """RFC 2865""" + val = 16 + + +class RadiusAttr_Session_Timeout(_RadiusAttrIntValue): + """RFC 2865""" + val = 27 + + +class RadiusAttr_Idle_Timeout(_RadiusAttrIntValue): + """RFC 2865""" + val = 28 + + +class RadiusAttr_Framed_AppleTalk_Link(_RadiusAttrIntValue): + """RFC 2865""" + val = 37 + + +class RadiusAttr_Framed_AppleTalk_Network(_RadiusAttrIntValue): + """RFC 2865""" + val = 38 + + +class RadiusAttr_Acct_Delay_Time(_RadiusAttrIntValue): + """RFC 2866""" + val = 41 + + +class RadiusAttr_Acct_Input_Octets(_RadiusAttrIntValue): + """RFC 2866""" + val = 42 + + +class RadiusAttr_Acct_Output_Octets(_RadiusAttrIntValue): + """RFC 2866""" + val = 43 + + +class RadiusAttr_Acct_Session_Time(_RadiusAttrIntValue): + """RFC 2866""" + val = 46 + + +class RadiusAttr_Acct_Input_Packets(_RadiusAttrIntValue): + """RFC 2866""" + val = 47 + + +class RadiusAttr_Acct_Output_Packets(_RadiusAttrIntValue): + """RFC 2866""" + val = 48 + + +class RadiusAttr_Acct_Link_Count(_RadiusAttrIntValue): + """RFC 2866""" + val = 51 + + +class RadiusAttr_Acct_Input_Gigawords(_RadiusAttrIntValue): + """RFC 2869""" + val = 52 + + +class RadiusAttr_Acct_Output_Gigawords(_RadiusAttrIntValue): + """RFC 2869""" + val = 53 + + +class RadiusAttr_Egress_VLANID(_RadiusAttrIntValue): + """RFC 4675""" + val = 56 + + +class RadiusAttr_Port_Limit(_RadiusAttrIntValue): + """RFC 2865""" + val = 62 + + +class RadiusAttr_ARAP_Security(_RadiusAttrIntValue): + """RFC 2869""" + val = 73 + + +class RadiusAttr_Password_Retry(_RadiusAttrIntValue): + """RFC 2869""" + val = 75 + + +class RadiusAttr_Tunnel_Preference(_RadiusAttrIntValue): + """RFC 2868""" + val = 83 + + +class RadiusAttr_Acct_Interim_Interval(_RadiusAttrIntValue): + """RFC 2869""" + val = 85 + + +class RadiusAttr_Acct_Tunnel_Packets_Lost(_RadiusAttrIntValue): + """RFC 2867""" + val = 86 + + +class RadiusAttr_Management_Privilege_Level(_RadiusAttrIntValue): + """RFC 5607""" + val = 136 + + +class RadiusAttr_Mobility_Domain_Id(_RadiusAttrIntValue): + """RFC 7268""" + val = 177 + + +class RadiusAttr_Preauth_Timeout(_RadiusAttrIntValue): + """RFC 7268""" + val = 178 + + +class RadiusAttr_WLAN_Venue_Info(_RadiusAttrIntValue): + """RFC 7268""" + val = 182 + + +class RadiusAttr_WLAN_Reason_Code(_RadiusAttrIntValue): + """RFC 7268""" + val = 185 + + +class RadiusAttr_WLAN_Pairwise_Cipher(_RadiusAttrIntValue): + """RFC 7268""" + val = 186 + + +class RadiusAttr_WLAN_Group_Cipher(_RadiusAttrIntValue): + """RFC 7268""" + val = 187 + + +class RadiusAttr_WLAN_AKM_Suite(_RadiusAttrIntValue): + """RFC 7268""" + val = 188 + + +class RadiusAttr_WLAN_Group_Mgmt_Cipher(_RadiusAttrIntValue): + """RFC 7268""" + val = 189 + + +class RadiusAttr_WLAN_RF_Band(_RadiusAttrIntValue): + """RFC 7268""" + val = 190 + + +# +# RADIUS attributes which values are string (displayed as hex) +# + +class _RadiusAttrHexStringVal(_SpecificRadiusAttr): + """ + Implements a RADIUS attribute which value field is a string that will be + as a hex string. + """ + + __slots__ = ["val"] + + def __init__(self, _pkt="", post_transform=None, _internal=0, _underlayer=None, **fields): + super(_RadiusAttrHexStringVal, self).__init__( + _pkt, + post_transform, + _internal, + _underlayer + ) + self.fields["type"] = self.val + name_parts = self.__class__.__name__.split('RadiusAttr_') + if len(name_parts) < 2: + raise Scapy_Exception( + "Invalid class name: {}".format(self.__class__.__name__) + ) + self.name = name_parts[1].replace('_', '-') + + fields_desc = [ + ByteEnumField("type", 24, _radius_attribute_types), + FieldLenField( + "len", + None, + "value", + "B", + adjust=lambda p, x: len(p.value) + 2 + ), + XStrLenField("value", "", length_from=lambda p: p.len - 2 if p.len else 0) + ] + + +class RadiusAttr_State(_RadiusAttrHexStringVal): + """RFC 2865""" + val = 24 + + +class RadiusAttr_Message_Authenticator(_RadiusAttrHexStringVal): + """RFC 2869""" + val = 80 + + fields_desc = [ + ByteEnumField("type", 24, _radius_attribute_types), + FieldLenField( + "len", + 18, + "value", + "B", + ), + XStrFixedLenField("value", "\x00" * 16, length=16) + ] + + @staticmethod + def compute_message_authenticator( + radius_packet, + packed_req_authenticator, + shared_secret + ): + """ + Computes the "Message-Authenticator" of a given RADIUS packet. + """ + + if not conf.crypto_valid: + g_log_loading.info(_crypto_loading_failure_message) + return None + + packed_hdr = struct.pack("!B", radius_packet.code) + packed_hdr += struct.pack("!B", radius_packet.id) + packed_hdr += struct.pack("!H", radius_packet.len) + packed_attrs = '' + for index in range(0, len(radius_packet.attributes)): + packed_attrs = packed_attrs + str(radius_packet.attributes[index]) + + hmac_ = hmac.HMAC( + shared_secret, + hashes.MD5(), + backend=default_backend() + ) + packed_data = packed_hdr + packed_req_authenticator + packed_attrs + hmac_.update(packed_data) + return hmac_.finalize() + + +# +# RADIUS attributes which values are IPv4 prefixes +# + +class _RadiusAttrIPv4AddrVal(RadiusAttribute): + """ + Implements a RADIUS attribute which value field is an IPv4 address. + """ + + __slots__ = ["val"] + + fields_desc = [ + ByteEnumField("type", 4, _radius_attribute_types), + ByteField("len", 6), + IPField("value", "0.0.0.0") + ] + + +class RadiusAttr_NAS_IP_Address(_RadiusAttrIPv4AddrVal): + """RFC 2865""" + val = 4 + + +class RadiusAttr_Framed_IP_Address(_RadiusAttrIPv4AddrVal): + """RFC 2865""" + val = 8 + + +class RadiusAttr_Framed_IP_Netmask(_RadiusAttrIPv4AddrVal): + """RFC 2865""" + val = 9 + + +class RadiusAttr_Login_IP_Host(_RadiusAttrIPv4AddrVal): + """RFC 2865""" + val = 14 + + +class RadiusAttr_Framed_IPX_Network(_RadiusAttrIPv4AddrVal): + """RFC 2865""" + val = 23 + + +class RadiusAttr_PMIP6_Home_LMA_IPv4_Address(_RadiusAttrIPv4AddrVal): + """RFC 6572""" + val = 149 + + +class RadiusAttr_PMIP6_Visited_LMA_IPv4_Address(_RadiusAttrIPv4AddrVal): + """RFC 6572""" + val = 150 + + +class RadiusAttr_PMIP6_Home_DHCP4_Server_Address(_RadiusAttrIPv4AddrVal): + """RFC 6572""" + val = 157 + + +class RadiusAttr_PMIP6_Visited_DHCP4_Server_Address(_RadiusAttrIPv4AddrVal): + """RFC 6572""" + val = 158 + + +class RadiusAttr_PMIP6_Home_IPv4_Gateway(_RadiusAttrIPv4AddrVal): + """RFC 6572""" + val = 161 + + +class RadiusAttr_PMIP6_Visited_IPv4_Gateway(_RadiusAttrIPv4AddrVal): + """RFC 6572""" + val = 162 + + +# See IANA registry "RADIUS Types" +_radius_attrs_values = { + # Service-Type + 6: + { + 1: "Login", + 2: "Framed", + 3: "Callback Login", + 4: "Callback Framed", + 5: "Outbound", + 6: "Administrative", + 7: "NAS Prompt", + 8: "Authenticate Only", + 9: "Callback NAS Prompt", + 10: "Call Check", + 11: "Callback Administrative", + 12: "Voice", + 13: "Fax", + 14: "Modem Relay", + 15: "IAPP-Register", + 16: "IAPP-AP-Check", + 17: "Authorize Only", + 18: "Framed-Management", + 19: "Additional-Authorization" + }, + + # Framed-Protocol + 7: + { + 1: "PPP", + 2: "SLIP", + 3: "AppleTalk Remote Access Protocol (ARAP)", + 4: "Gandalf proprietary SingleLink/MultiLink protocol", + 5: "Xylogics proprietary IPX/SLIP", + 6: "X.75 Synchronous", + 7: "GPRS PDP Context" + }, + + # Framed-Routing + 10: + { + 0: "None", + 1: "Send routing packets", + 2: "Listen for routing packets", + 3: "Send and Listen" + }, + + # Framed-Compression + 13: + { + 0: "None", + 1: "VJ TCP/IP header compression", + 2: "IPX header compression", + 3: "Stac-LZS compression" + }, + + # Login-Service + 15: + { + 0: "Telnet", + 1: "Rlogin", + 2: "TCP Clear", + 3: "PortMaster (proprietary)", + 4: "LAT", + 5: "X25-PAD", + 6: "X25-T3POS", + 7: "Unassigned", + 8: "TCP Clear Quiet (suppresses any NAS-generated connect string)" + }, + + # Termination-Action + 29: + { + 0: "Default", + 1: "RADIUS-Request" + }, + + # Acct-Status-Type + 40: + { + 1: "Start", + 2: "Stop", + 3: "Interim-Update", + 4: "Unassigned", + 5: "Unassigned", + 6: "Unassigned", + 7: "Accounting-On", + 8: "Accounting-Off", + 9: "Tunnel-Start", + 10: "Tunnel-Stop", + 11: "Tunnel-Reject", + 12: "Tunnel-Link-Start", + 13: "Tunnel-Link-Stop", + 14: "Tunnel-Link-Reject", + 15: "Failed" + }, + + # Acct-Authentic + 45: + { + 1: "RADIUS", + 2: "Local", + 3: "Remote", + 4: "Diameter" + }, + + # Acct-Terminate-Cause + 49: + { + 1: "User Request", + 2: "Lost Carrier", + 3: "Lost Service", + 4: "Idle Timeout", + 5: "Session Timeout", + 6: "Admin Reset", + 7: "Admin Reboot", + 8: "Port Error", + 9: "NAS Error", + 10: "NAS Request", + 11: "NAS Reboot", + 12: "Port Unneeded", + 13: "Port Preempted", + 14: "Port Suspended", + 15: "Service Unavailable", + 16: "Callback", + 17: "User Error", + 18: "Host Request", + 19: "Supplicant Restart", + 20: "Reauthentication Failure", + 21: "Port Reinitialized", + 22: "Port Administratively Disabled", + 23: "Lost Power", + }, + + # NAS-Port-Type + 61: + { + 0: "Async", + 1: "Sync", + 2: "ISDN Sync", + 3: "ISDN Async V.120", + 4: "ISDN Async V.110", + 5: "Virtual", + 6: "PIAFS", + 7: "HDLC Clear Channel", + 8: "X.25", + 9: "X.75", + 10: "G.3 Fax", + 11: "SDSL - Symmetric DSL", + 12: "ADSL-CAP - Asymmetric DSL, Carrierless Amplitude Phase Modulation", + 13: "ADSL-DMT - Asymmetric DSL, Discrete Multi-Tone", + 14: "IDSL - ISDN Digital Subscriber Line", + 15: "Ethernet", + 16: "xDSL - Digital Subscriber Line of unknown type", + 17: "Cable", + 18: "Wireles - Other", + 19: "Wireless - IEEE 802.11", + 20: "Token-Ring", + 21: "FDDI", + 22: "Wireless - CDMA2000", + 23: "Wireless - UMTS", + 24: "Wireless - 1X-EV", + 25: "IAPP", + 26: "FTTP - Fiber to the Premises", + 27: "Wireless - IEEE 802.16", + 28: "Wireless - IEEE 802.20", + 29: "Wireless - IEEE 802.22", + 30: "PPPoA - PPP over ATM", + 31: "PPPoEoA - PPP over Ethernet over ATM", + 32: "PPPoEoE - PPP over Ethernet over Ethernet", + 33: "PPPoEoVLAN - PPP over Ethernet over VLAN", + 34: "PPPoEoQinQ - PPP over Ethernet over IEEE 802.1QinQ", + 35: "xPON - Passive Optical Network", + 36: "Wireless - XGP", + 37: "WiMAX Pre-Release 8 IWK Function", + 38: "WIMAX-WIFI-IWK: WiMAX WIFI Interworking", + 39: "WIMAX-SFF: Signaling Forwarding Function for LTE/3GPP2", + 40: "WIMAX-HA-LMA: WiMAX HA and or LMA function", + 41: "WIMAX-DHCP: WIMAX DCHP service", + 42: "WIMAX-LBS: WiMAX location based service", + 43: "WIMAX-WVS: WiMAX voice service" + }, + + # Tunnel-Type + 64: + { + 1: "Point-to-Point Tunneling Protocol (PPTP)", + 2: "Layer Two Forwarding (L2F)", + 3: "Layer Two Tunneling Protocol (L2TP)", + 4: "Ascend Tunnel Management Protocol (ATMP)", + 5: "Virtual Tunneling Protocol (VTP)", + 6: "IP Authentication Header in the Tunnel-mode (AH)", + 7: "IP-in-IP Encapsulation (IP-IP)", + 8: "Minimal IP-in-IP Encapsulation (MIN-IP-IP)", + 9: "IP Encapsulating Security Payload in the Tunnel-mode (ESP)", + 10: "Generic Route Encapsulation (GRE)", + 11: "Bay Dial Virtual Services (DVS)", + 12: "IP-in-IP Tunneling", + 13: "Virtual LANs (VLAN)" + }, + + # Tunnel-Medium-Type + 65: + { + 1: "IPv4 (IP version 4)", + 2: "IPv6 (IP version 6)", + 3: "NSAP", + 4: "HDLC (8-bit multidrop)", + 5: "BBN 1822", + 6: "802", + 7: "E.163 (POTS)", + 8: "E.164 (SMDS, Frame Relay, ATM)", + 9: "F.69 (Telex)", + 10: "X.121 (X.25, Frame Relay)", + 11: "IPX", + 12: "Appletalk", + 13: "Decnet IV", + 14: "Banyan Vine", + 15: "E.164 with NSAP format subaddress" + }, + + # ARAP-Zone-Access + 72: + { + 1: "Only allow access to default zone", + 2: "Use zone filter inclusively", + 3: "Not used", + 4: "Use zone filter exclusively" + }, + + # Prompt + 76: + { + 0: "No Echo", + 1: "Echo" + }, + + # Error-Cause Attribute + 101: + { + 201: "Residual Session Context Removed", + 202: "Invalid EAP Packet (Ignored)", + 401: "Unsupported Attribute", + 402: "Missing Attribute", + 403: "NAS Identification Mismatch", + 404: "Invalid Request", + 405: "Unsupported Service", + 406: "Unsupported Extension", + 407: "Invalid Attribute Value", + 501: "Administratively Prohibited", + 502: "Request Not Routable (Proxy)", + 503: "Session Context Not Found", + 504: "Session Context Not Removable", + 505: "Other Proxy Processing Error", + 506: "Resources Unavailable", + 507: "Request Initiated", + 508: "Multiple Session Selection Unsupported", + 509: "Location-Info-Required", + 601: "Response Too Big" + }, + + # Operator Namespace Identifier - Attribute 126 + 126: + { + 0x30: "TADIG", + 0x31: "REALM", + 0x32: "E212", + 0x33: "ICC", + 0xFF: "Reserved" + }, + + # Basic-Location-Policy-Rules + 129: + { + 0: "Retransmission allowed", + }, + + # Location-Capable + 131: + { + 1: "CIVIC_LOCATION", + 2: "GEO_LOCATION", + 4: "USERS_LOCATION", + 8: "NAS_LOCATION" + }, + + # Framed-Management-Protocol + 133: + { + 1: "SNMP", + 2: "Web-based", + 3: "NETCONF", + 4: "FTP", + 5: "TFTP", + 6: "SFTP", + 7: "RCP", + 8: "SCP" + }, + + # Management-Transport-Protection + 134: + { + 1: "No-Protection", + 2: "Integrity-Protection", + 3: "Integrity-Confidentiality-Protection", + }, +} + + +class _RadiusAttrIntEnumVal(_SpecificRadiusAttr): + """ + Implements a RADIUS attribute which value field is 4 bytes long integer. + """ + + __slots__ = ["val"] + + fields_desc = [ + ByteEnumField("type", 6, _radius_attribute_types), + ByteField("len", 6), + MultiEnumField( + "value", + 0, + _radius_attrs_values, + depends_on=lambda p: p.type, + fmt="I" + ) + ] + + +class RadiusAttr_Service_Type(_RadiusAttrIntEnumVal): + """RFC 2865""" + val = 6 + + +class RadiusAttr_Framed_Protocol(_RadiusAttrIntEnumVal): + """RFC 2865""" + val = 7 + + +class RadiusAttr_NAS_Port_Type(_RadiusAttrIntEnumVal): + """RFC 2865""" + val = 61 + + +class _EAPPacketField(PacketField): + + """ + Handles EAP-Message attribute value (the actual EAP packet). + """ + + def m2i(self, pkt, m): + ret = None + eap_packet_len = struct.unpack("!H", m[2:4])[0] + if eap_packet_len < 254: + # If the EAP packet has not been fragmented, build a Scapy EAP + # packet from the data. + ret = EAP(m) + else: + ret = conf.raw_layer(m) + return ret + + +class RadiusAttr_EAP_Message(RadiusAttribute): + """ + Implements the "EAP-Message" attribute (RFC 3579). + """ + + name = "EAP-Message" + fields_desc = [ + ByteEnumField("type", 79, _radius_attribute_types), + FieldLenField( + "len", + None, + "value", + "B", + adjust=lambda pkt, x: len(pkt.value) + 2 + ), + _EAPPacketField("value", "", EAP) + ] + + +class RadiusAttr_Vendor_Specific(RadiusAttribute): + """ + Implements the "Vendor-Specific" attribute, as described in RFC 2865. + """ + + name = "Vendor-Specific" + fields_desc = [ + ByteEnumField("type", 26, _radius_attribute_types), + FieldLenField( + "len", + None, + "value", + "B", + adjust=lambda pkt, x: len(pkt.value) + 8 + ), + IntField("vendor_id", 0), + ByteField("vendor_type", 0), + FieldLenField( + "vendor_len", + None, + "value", + "B", + adjust=lambda p, x: len(p.value) + 2 + ), + StrLenField("value", "", length_from=lambda p: p.vendor_len - 2) + ] + + +class _RADIUSAttrPacketListField(PacketListField): + """ + PacketListField handling a list of RADIUS attributes. + """ + + def getfield(self, pkt, s): + lst = [] + length = None + ret = "" + + if self.length_from is not None: + length = self.length_from(pkt) + + if length is not None: + remain, ret = s[:length], s[length:] + + while remain: + attr_len = struct.unpack("!B", remain[1])[0] + current = remain[:attr_len] + remain = remain[attr_len:] + packet = self.m2i(pkt, current) + lst.append(packet) + + return remain + ret, lst + + +# See IANA RADIUS Packet Type Codes registry +_packet_codes = { + 1: "Access-Request", + 2: "Access-Accept", + 3: "Access-Reject", + 4: "Accounting-Request", + 5: "Accounting-Response", + 6: "Accounting-Status (now Interim Accounting)", + 7: "Password-Request", + 8: "Password-Ack", + 9: "Password-Reject", + 10: "Accounting-Message", + 11: "Access-Challenge", + 12: "Status-Server (experimental)", + 13: "Status-Client (experimental)", + 21: "Resource-Free-Request", + 22: "Resource-Free-Response", + 23: "Resource-Query-Request", + 24: "Resource-Query-Response", + 25: "Alternate-Resource-Reclaim-Request", + 26: "NAS-Reboot-Request", + 27: "NAS-Reboot-Response", + 28: "Reserved", + 29: "Next-Passcode", + 30: "New-Pin", + 31: "Terminate-Session", + 32: "Password-Expired", + 33: "Event-Request", + 34: "Event-Response", + 40: "Disconnect-Request", + 41: "Disconnect-ACK", + 42: "Disconnect-NAK", + 43: "CoA-Request", + 44: "CoA-ACK", + 45: "CoA-NAK", + 50: "IP-Address-Allocate", + 51: "IP-Address-Release", + 52: "Protocol-Error", + 250: "Experimental Use", + 251: "Experimental Use", + 252: "Experimental Use", + 253: "Experimental Use", + 254: "Reserved", + 255: "Reserved" +} class Radius(Packet): - name = "Radius" - fields_desc = [ ByteEnumField("code", 1, {1: "Access-Request", - 2: "Access-Accept", - 3: "Access-Reject", - 4: "Accounting-Request", - 5: "Accounting-Accept", - 6: "Accounting-Status", - 7: "Password-Request", - 8: "Password-Ack", - 9: "Password-Reject", - 10: "Accounting-Message", - 11: "Access-Challenge", - 12: "Status-Server", - 13: "Status-Client", - 21: "Resource-Free-Request", - 22: "Resource-Free-Response", - 23: "Resource-Query-Request", - 24: "Resource-Query-Response", - 25: "Alternate-Resource-Reclaim-Request", - 26: "NAS-Reboot-Request", - 27: "NAS-Reboot-Response", - 29: "Next-Passcode", - 30: "New-Pin", - 31: "Terminate-Session", - 32: "Password-Expired", - 33: "Event-Request", - 34: "Event-Response", - 40: "Disconnect-Request", - 41: "Disconnect-ACK", - 42: "Disconnect-NAK", - 43: "CoA-Request", - 44: "CoA-ACK", - 45: "CoA-NAK", - 50: "IP-Address-Allocate", - 51: "IP-Address-Release", - 253: "Experimental-use", - 254: "Reserved", - 255: "Reserved"} ), - ByteField("id", 0), - FieldLenField("len", None, "attributes", "H" , adjust=lambda pkt,x:len(pkt.attributes)+20), - StrFixedLenField("authenticator","",16), - PacketListField("attributes", [], RadiusAttribute, length_from=lambda pkt:pkt.len-20) ] + """ + Implements a RADIUS packet (RFC 2865). + """ + + name = "RADIUS" + fields_desc = [ + ByteEnumField("code", 1, _packet_codes), + ByteField("id", 0), + FieldLenField( + "len", + None, + "attributes", + "H", + adjust=lambda pkt, x: len(pkt.attributes) + 20 + ), + XStrFixedLenField("authenticator", "", 16), + _RADIUSAttrPacketListField( + "attributes", + [], + RadiusAttribute, + length_from=lambda pkt: pkt.len - 20 + ) + ] + + def compute_authenticator(self, packed_request_auth, shared_secret): + """ + Computes the authenticator field (RFC 2865 - Section 3) + """ + + if not conf.crypto_valid: + g_log_loading.info(_crypto_loading_failure_message) + return None + + packed_hdr = struct.pack("!B", self.code) + packed_hdr += struct.pack("!B", self.id) + packed_hdr += struct.pack("!H", self.len) + packed_attrs = '' + for index in range(0, len(self.attributes)): + packed_attrs = packed_attrs + str(self.attributes[index]) + packed_data = packed_hdr + packed_request_auth + packed_attrs +\ + shared_secret + + digest = hashes.Hash(hashes.MD5(), backend=default_backend()) + digest.update(packed_data) + return digest.finalize() + def post_build(self, p, pay): p += pay - l = self.len - if l is None: - l = len(p) - p = p[:2]+struct.pack("!H",l)+p[4:] + length = self.len + if length is None: + length = len(p) + p = p[:2] + struct.pack("!H", length) + p[4:] return p diff --git a/scapy/layers/sctp.py b/scapy/layers/sctp.py index 94b3f4b398c..3799a1698e9 100644 --- a/scapy/layers/sctp.py +++ b/scapy/layers/sctp.py @@ -470,13 +470,13 @@ def __init__(self, name, default): def i2m(self, pkt, x): if x is None: return b"\0\0\0\0" - sta, end = map(int, x.split(":")) + sta, end = [int(e) for e in x.split(':')] args = tuple([">HH", sta, end]) return struct.pack(*args) def m2i(self, pkt, x): return "%d:%d"%(struct.unpack(">HH", x)) def any2i(self, pkt, x): - if type(x) is tuple and len(x) == 2: + if isinstance(x, tuple) and len(x) == 2: return "%d:%d"%(x) return x diff --git a/scapy/layers/snmp.py b/scapy/layers/snmp.py index e602e20bef2..cb2dc0b734d 100644 --- a/scapy/layers/snmp.py +++ b/scapy/layers/snmp.py @@ -244,7 +244,7 @@ def answers(self, other): def snmpwalk(dst, oid="1", community="public"): try: - while 1: + while True: r = sr1(IP(dst=dst)/UDP(sport=RandShort())/SNMP(community=community, PDU=SNMPnext(varbindlist=[SNMPvarbind(oid=oid)])),timeout=2, chainCC=1, verbose=0, retry=2) if ICMP in r: print repr(r) diff --git a/scapy/layers/tls/cert.py b/scapy/layers/tls/cert.py index 13f23675377..47296a0a590 100644 --- a/scapy/layers/tls/cert.py +++ b/scapy/layers/tls/cert.py @@ -187,7 +187,7 @@ def __call__(cls, key_path=None): return obj # This deals with the rare RSA 'kx export' call. - if type(key_path) is tuple: + if isinstance(key_path, tuple): obj = type.__call__(cls) obj.__class__ = PubKeyRSA obj.frmt = "tuple" @@ -671,7 +671,7 @@ def remainingDays(self, now=None): """ if now is None: now = time.localtime() - elif type(now) is str: + elif isinstance(now, str): try: if '/' in now: now = time.strptime(now, '%m/%d/%y') @@ -706,11 +706,9 @@ def isRevoked(self, crl_list): if (self.authorityKeyID is not None and c.authorityKeyID is not None and self.authorityKeyID == c.authorityKeyID): - return self.serial in map(lambda x: x[0], - c.revoked_cert_serials) + return self.serial in (x[0] for x in c.revoked_cert_serials) elif self.issuer == c.issuer: - return self.serial in map(lambda x: x[0], - c.revoked_cert_serials) + return self.serial in (x[0] for x in c.revoked_cert_serials) return False def export(self, filename, fmt="DER"): diff --git a/scapy/layers/tls/crypto/cipher_aead.py b/scapy/layers/tls/crypto/cipher_aead.py index dd759bb71f9..b2e755976c9 100644 --- a/scapy/layers/tls/crypto/cipher_aead.py +++ b/scapy/layers/tls/crypto/cipher_aead.py @@ -68,7 +68,7 @@ def __init__(self, key=None, salt=None, nonce_explicit=None): self.ready["nonce_explicit"] = False nonce_explicit = 0 - if type(nonce_explicit) is str: + if isinstance(nonce_explicit, str): nonce_explicit = pkcs_os2ip(nonce_explicit) # we use super() in order to avoid any deadlock with __setattr__ @@ -92,7 +92,7 @@ def __setattr__(self, name, val): self._cipher.mode._initialization_vector = iv self.ready["salt"] = True elif name == "nonce_explicit": - if type(val) is str: + if isinstance(val, str): val = pkcs_os2ip(val) iv = self.salt + pkcs_i2osp(val, self.nonce_explicit_len) if self._cipher is not None: diff --git a/scapy/layers/tls/crypto/pkcs1.py b/scapy/layers/tls/crypto/pkcs1.py index eee8f52ac20..81273877ee4 100644 --- a/scapy/layers/tls/crypto/pkcs1.py +++ b/scapy/layers/tls/crypto/pkcs1.py @@ -15,6 +15,7 @@ import math, random, struct from scapy.config import conf, crypto_validator +from functools import reduce if conf.crypto_valid: from cryptography.exceptions import InvalidSignature from cryptography.hazmat.backends import default_backend @@ -163,7 +164,7 @@ def pkcs_mgf1(mgfSeed, maskLen, h): """ # steps are those of Appendix B.2.1 - if not _hashFuncParams.has_key(h): + if h not in _hashFuncParams: warning("pkcs_mgf1: invalid hash (%s) provided" % h) return None hLen = _hashFuncParams[h][0] @@ -220,7 +221,7 @@ def pkcs_emsa_pss_encode(M, emBits, h, mgf, sLen): rem = 8*emLen - emBits - 8*l # additionnal bits andMask = l*b'\x00' if rem: - j = chr(reduce(lambda x,y: x+y, map(lambda x: 1< 12: sid = sid[:11] + "..." res.append((src, dst, sid)) - colwidth = map(lambda x: max(map(lambda y: len(y), x)), - apply(zip, res)) + colwidth = map(lambda x: max(map(lambda y: len(y), x)), apply(zip, res)) fmt = " ".join(map(lambda x: "%%-%ds"%x, colwidth)) return "\n".join(map(lambda x: fmt % x, res)) diff --git a/scapy/layers/x509.py b/scapy/layers/x509.py index ba713dfb501..eb1e64d3e07 100644 --- a/scapy/layers/x509.py +++ b/scapy/layers/x509.py @@ -648,7 +648,7 @@ def dissect(self, pkt, s): if not self.flexible_tag and len(s) > 0: err_msg = "extension sequence length issue" raise BER_Decoding_Error(err_msg, remaining=s) - except ASN1F_badsequence,e: + except ASN1F_badsequence as e: raise Exception("could not parse extensions") return remain diff --git a/scapy/main.py b/scapy/main.py index 1b857f14045..ea0d441bcbd 100644 --- a/scapy/main.py +++ b/scapy/main.py @@ -11,8 +11,10 @@ import glob import types import gzip +import importlib import cPickle import __builtin__ +ignored = list(__builtin__.__dict__.keys()) from scapy.error import * @@ -29,12 +31,18 @@ def _probe_config_file(cf): def _read_config_file(cf): log_loading.debug("Loading config file [%s]" % cf) try: - execfile(cf) - except IOError,e: + exec(compile(open(cf).read(), cf, 'exec')) + except IOError as e: log_loading.warning("Cannot read config file [%s] [%s]" % (cf,e)) - except Exception,e: + except Exception as e: log_loading.exception("Error during evaluation of config file [%s]" % cf) +def _validate_local(x): + """Returns whether or not a variable should be imported. + Will return False for any default modules (sys), or if + they are detected as private vars (starting with a _)""" + global ignored + return x[0] != "_" and not x in ignored DEFAULT_PRESTART_FILE = _probe_config_file(".scapy_prestart.py") DEFAULT_STARTUP_FILE = _probe_config_file(".scapy_startup.py") @@ -58,7 +66,7 @@ def _usage(): def _load(module): try: - mod = __import__(module,globals(),locals(),".") + mod = importlib.import_module(module) if '__all__' in mod.__dict__: # import listed symbols for name in mod.__dict__['__all__']: @@ -66,9 +74,9 @@ def _load(module): else: # only import non-private symbols for name, sym in mod.__dict__.iteritems(): - if name[0] != '_': + if _validate_local(name): __builtin__.__dict__[name] = sym - except Exception,e: + except Exception as e: log_interactive.error(e) def load_module(name): @@ -79,7 +87,7 @@ def load_layer(name): def load_contrib(name): try: - __import__("scapy.contrib." + name) + importlib.import_module("scapy.contrib." + name) _load("scapy.contrib." + name) except ImportError: # if layer not found in contrib, try in layers @@ -91,7 +99,7 @@ def list_contrib(name=None): elif "*" not in name and "?" not in name and not name.endswith(".py"): name += ".py" name = os.path.join(os.path.dirname(__file__), "contrib", name) - for f in glob.glob(name): + for f in sorted(glob.glob(name)): mod = os.path.basename(f) if mod.startswith("__"): continue @@ -130,11 +138,11 @@ def save_session(fname=None, session=None, pickleProto=-1): to_be_saved = session.copy() - if to_be_saved.has_key("__builtins__"): + if "__builtins__" in to_be_saved: del(to_be_saved["__builtins__"]) for k in to_be_saved.keys(): - if type(to_be_saved[k]) in [types.TypeType, types.ClassType, types.ModuleType]: + if type(to_be_saved[k]) in [type, type, types.ModuleType]: log_interactive.error("[%s] (%s) can't be saved." % (k, type(to_be_saved[k]))) del(to_be_saved[k]) @@ -180,11 +188,11 @@ def init_session(session_name, mydict=None): global session global globkeys - scapy_builtins = __import__("all",globals(),locals(),".").__dict__ + scapy_builtins = importlib.import_module(".all", "scapy").__dict__ for name, sym in scapy_builtins.iteritems(): - if name [0] != '_': + if _validate_local(name): __builtin__.__dict__[name] = sym - globkeys = scapy_builtins.keys() + globkeys = list(scapy_builtins.keys()) globkeys.append("scapy_session") scapy_builtins=None # XXX replace with "with" statement if mydict is not None: @@ -236,7 +244,7 @@ def scapy_write_history_file(readline): if conf.histfile: try: readline.write_history_file(conf.histfile) - except IOError,e: + except IOError as e: try: warning("Could not write history to [%s]\n\t (%s)" % (conf.histfile,e)) tmp = utils.get_temp_file(keep=True) @@ -345,7 +353,7 @@ def attr_matches(self, text): raise getopt.GetoptError("Too many parameters : [%s]" % " ".join(opts[1])) - except getopt.GetoptError, msg: + except getopt.GetoptError as msg: log_loading.error(msg) sys.exit(1) @@ -373,7 +381,7 @@ def attr_matches(self, text): try: import IPython IPYTHON=True - except ImportError, e: + except ImportError as e: log_loading.warning("IPython not available. Using standard Python shell instead.") IPYTHON=False @@ -385,7 +393,7 @@ def attr_matches(self, text): args = [''] # IPython command line args (will be seen as sys.argv) ipshell = IPython.Shell.IPShellEmbed(args, banner = banner) ipshell(local_ns=session) - except AttributeError, e: + except AttributeError as e: pass # In the IPython cookbook, see 'Updating-code-for-use-with-IPython-0.11-and-later' diff --git a/scapy/modules/p0f.py b/scapy/modules/p0f.py index 499aea69587..39ce6190519 100644 --- a/scapy/modules/p0f.py +++ b/scapy/modules/p0f.py @@ -69,7 +69,7 @@ def a2i(x): if x.isdigit(): return int(x) return x - li = map(a2i, l[1:4]) + li = [a2i(e) for e in l[1:4]] #if li[0] not in self.ttl_range: # self.ttl_range.append(li[0]) # self.ttl_range.sort() @@ -173,7 +173,7 @@ def packet2p0f(pkt): if ilen > 0: qqP = True else: - if type(option[0]) is str: + if isinstance(option[0], str): ooo += "?%i," % TCPOptions[1][option[0]] else: ooo += "?%i," % option[0] @@ -530,7 +530,9 @@ def addresult(res): # XXX are the packets also seen twice on non Linux systems ? count=14 pl = sniff(iface=iface, filter='tcp and port ' + str(port), count = count, timeout=3) - map(addresult, map(packet2p0f, pl)) + for pkt in pl: + for elt in packet2p0f(pkt): + addresult(elt) os.waitpid(pid,0) elif pid < 0: log_runtime.error("fork error") diff --git a/scapy/modules/queso.py b/scapy/modules/queso.py index 9c38f42735e..aba6c248fd1 100644 --- a/scapy/modules/queso.py +++ b/scapy/modules/queso.py @@ -56,7 +56,7 @@ def lazy_init(self): res = l[2:].split() res[-1] = quesoTCPflags(res[-1]) res = " ".join(res) - if not p.has_key(res): + if res not in p: p[res] = {} p = p[res] if p is not None: @@ -100,7 +100,7 @@ def queso_search(sig): while sig: s = sig.pop() p = p[s] - if p.has_key(""): + if "" in p: ret.append(p[""]) except KeyError: pass diff --git a/scapy/packet.py b/scapy/packet.py index 6bc1db5ce23..588d9fbf02e 100644 --- a/scapy/packet.py +++ b/scapy/packet.py @@ -123,7 +123,7 @@ def __init__(self, _pkt="", post_transform=None, _internal=0, _underlayer=None, self.dissection_done(self) for f, v in fields.iteritems(): self.fields[f] = self.get_field(f).any2i(self, v) - if type(post_transform) is list: + if isinstance(post_transform, list): self.post_transforms = post_transform elif post_transform is None: self.post_transforms = [] @@ -169,10 +169,10 @@ def add_payload(self, payload): self.payload = payload payload.add_underlayer(self) for t in self.aliastypes: - if payload.overload_fields.has_key(t): + if t in payload.overload_fields: self.overloaded_fields = payload.overload_fields[t] break - elif type(payload) is str: + elif isinstance(payload, str): self.payload = conf.raw_layer(load=payload) else: raise TypeError("payload must be either 'Packet' or 'str', not [%s]" % repr(payload)) @@ -229,7 +229,7 @@ def __getattr__(self, attr): return v def setfieldval(self, attr, val): - if self.default_fields.has_key(attr): + if attr in self.default_fields: fld = self.get_field(attr) if fld is None: any2i = lambda x,y: y @@ -255,12 +255,12 @@ def __setattr__(self, attr, val): return object.__setattr__(self, attr, val) def delfieldval(self, attr): - if self.fields.has_key(attr): + if attr in self.fields: del(self.fields[attr]) self.explicit = 0 # in case a default value must be explicited self.raw_packet_cache = None self.raw_packet_cache_fields = None - elif self.default_fields.has_key(attr): + elif attr in self.default_fields: pass elif attr == "payload": self.remove_payload() @@ -315,19 +315,19 @@ def __div__(self, other): cloneB = other.copy() cloneA.add_payload(cloneB) return cloneA - elif type(other) is str: + elif isinstance(other, str): return self/conf.raw_layer(load=other) else: return other.__rdiv__(self) __truediv__ = __div__ def __rdiv__(self, other): - if type(other) is str: + if isinstance(other, str): return conf.raw_layer(load=other)/self else: raise TypeError __rtruediv__ = __rdiv__ def __mul__(self, other): - if type(other) is int: + if isinstance(other, int): return [self]*other else: raise TypeError @@ -431,7 +431,7 @@ def do_build_ps(self): if isinstance(f, ConditionalField) and not f._evalcond(self): continue p = f.addfield(self, p, self.getfieldval(f.name) ) - if type(p) is str: + if isinstance(p, str): r = p[len(q):] q = p else: @@ -805,7 +805,7 @@ def __gt__(self, other): """True if other is an answer from self (self ==> other).""" if isinstance(other, Packet): return other < self - elif type(other) is str: + elif isinstance(other, str): return 1 else: raise TypeError((self, other)) @@ -813,7 +813,7 @@ def __lt__(self, other): """True if self is an answer from other (other ==> self).""" if isinstance(other, Packet): return self.answers(other) - elif type(other) is str: + elif isinstance(other, str): return 1 else: raise TypeError((self, other)) @@ -858,10 +858,10 @@ def haslayer(self, cls): return self.payload.haslayer(cls) def getlayer(self, cls, nb=1, _track=None): """Return the nb^th layer that is an instance of cls.""" - if type(cls) is int: + if isinstance(cls, int): nb = cls+1 cls = None - if type(cls) is str and "." in cls: + if isinstance(cls, str) and "." in cls: ccls,fld = cls.split(".",1) else: ccls,fld = cls,None @@ -895,7 +895,7 @@ def firstlayer(self): return q def __getitem__(self, cls): - if type(cls) is slice: + if isinstance(cls, slice): lname = cls.start if cls.stop: ret = self.getlayer(cls.start, cls.stop) @@ -907,9 +907,9 @@ def __getitem__(self, cls): lname=cls ret = self.getlayer(cls) if ret is None: - if type(lname) is Packet_metaclass: + if isinstance(lname, Packet_metaclass): lname = lname.__name__ - elif type(lname) is not str: + elif not isinstance(lname, str): lname = repr(lname) raise IndexError("Layer [%s] not found" % lname) return ret @@ -967,7 +967,7 @@ def _show_or_dump(self, dump=False, indent=3, lvl="", label_lvl="", first_call=T ncol = ct.field_name vcol = ct.field_value fvalue = self.getfieldval(f.name) - if isinstance(fvalue, Packet) or (f.islist and f.holds_packets and type(fvalue) is list): + if isinstance(fvalue, Packet) or (f.islist and f.holds_packets and isinstance(fvalue, list)): s += "%s \\%-10s\\\n" % (label_lvl+lvl, ncol(f.name)) fvalue_gen = SetGen(fvalue,_iterpacket=0) for fvalue in fvalue_gen: @@ -977,7 +977,7 @@ def _show_or_dump(self, dump=False, indent=3, lvl="", label_lvl="", first_call=T ncol(f.name), ct.punct("="),) reprval = f.i2repr(self,fvalue) - if type(reprval) is str: + if isinstance(reprval, str): reprval = reprval.replace("\n", "\n"+" "*(len(label_lvl) +len(lvl) +len(f.name) @@ -1135,7 +1135,7 @@ def _do_summary(self): ret = "" if not found or self.__class__ in needed: ret = self.mysummary() - if type(ret) is tuple: + if isinstance(ret, tuple): ret,n = ret needed += n if ret or needed: @@ -1180,7 +1180,7 @@ def command(self): fld = self.get_field(fn) if isinstance(fv, Packet): fv = fv.command() - elif fld.islist and fld.holds_packets and type(fv) is list: + elif fld.islist and fld.holds_packets and isinstance(fv, list): fv = "[%s]" % ",".join( map(Packet.command, fv)) elif isinstance(fld, FlagsField): fv = int(fv) @@ -1337,7 +1337,8 @@ def bind_layers(lower, upper, __fval=None, **fval): def split_bottom_up(lower, upper, __fval=None, **fval): if __fval is not None: fval.update(__fval) - def do_filter((f,u),upper=upper,fval=fval): + def do_filter(xxx_todo_changeme,upper=upper,fval=fval): + (f,u) = xxx_todo_changeme if u != upper: return True for k in fval: diff --git a/scapy/pipetool.py b/scapy/pipetool.py index e13ed09cbd0..5f86d73d60f 100644 --- a/scapy/pipetool.py +++ b/scapy/pipetool.py @@ -5,16 +5,21 @@ ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license -import os, thread, select +import os import subprocess import itertools import collections import time import Queue -import scapy.utils +from threading import Lock, Thread +from scapy.automaton import Message, select_objects +from scapy.consts import WINDOWS from scapy.error import log_interactive, warning from scapy.config import conf +from scapy.utils import get_temp_file, do_graph + +import scapy.arch class PipeEngine: pipes = {} @@ -39,8 +44,9 @@ def __init__(self, *pipes): self.active_drains = set() self.active_sinks = set() self._add_pipes(*pipes) - self.thread_lock = thread.allocate_lock() - self.command_lock = thread.allocate_lock() + self.thread_lock = Lock() + self.command_lock = Lock() + self.__fd_queue = [] self.__fdr,self.__fdw = os.pipe() self.threadid = None def __getattr__(self, attr): @@ -55,6 +61,22 @@ def f(*args, **kargs): return f raise AttributeError(attr) + def checkRecv(self): + """As select.select is not available, we check if there + is some data to read by using a list that stores pointers.""" + return len(self.__fd_queue) > 0 + + def fileno(self): + return self.__fdr + + def _read_cmd(self): + self.__fd_queue.pop() + return os.read(self.__fdr,1) + + def _write_cmd(self, _cmd): + os.write(self.__fdw, _cmd) + self.__fd_queue.append("X") + def add_one_pipe(self, pipe): self.active_pipes.add(pipe) if isinstance(pipe, Source): @@ -90,15 +112,15 @@ def run(self): for p in self.active_pipes: p.start() sources = self.active_sources - sources.add(self.__fdr) + sources.add(self) exhausted = set([]) RUN=True STOP_IF_EXHAUSTED = False while RUN and (not STOP_IF_EXHAUSTED or len(sources) > 1): - fds,fdo,fde=select.select(sources,[],[]) + fds = select_objects(sources, 2, customTypes=(AutoSource, PipeEngine)) for fd in fds: - if fd is self.__fdr: - cmd = os.read(self.__fdr,1) + if fd is self: + cmd = self._read_cmd() if cmd == "X": RUN=False break @@ -106,13 +128,13 @@ def run(self): STOP_IF_EXHAUSTED = True elif cmd == "A": sources = self.active_sources-exhausted - sources.add(self.__fdr) + sources.add(self) else: warning("Unknown internal pipe engine command: %r. Ignoring." % cmd) elif fd in sources: try: fd.deliver() - except Exception,e: + except Exception as e: log_interactive.exception("piping from %s failed: %s" % (fd.name, e)) else: if fd.exhausted(): @@ -130,7 +152,9 @@ def run(self): def start(self): if self.thread_lock.acquire(0): - self.threadid = thread.start_new_thread(self.run,()) + _t = Thread(target=self.run) + _t.start() + self.threadid = _t.ident else: warning("Pipe engine already running") def wait_and_stop(self): @@ -139,7 +163,7 @@ def stop(self, _cmd="X"): try: with self.command_lock: if self.threadid is not None: - os.write(self.__fdw, _cmd) + self._write_cmd(_cmd) while not self.thread_lock.acquire(0): time.sleep(0.01) # interruptible wait for thread to terminate self.thread_lock.release() # (not using .join() because it needs 'threading' module) @@ -154,7 +178,7 @@ def add(self, *pipes): if self.threadid is not None: for p in pipes: p.start() - os.write(self.__fdw, "A") + self._write_cmd("A") def graph(self,**kargs): g=['digraph "pipe" {',"\tnode [shape=rectangle];",] @@ -177,7 +201,7 @@ def graph(self,**kargs): g.append('\t"%i" -> "%i";' % (id(p), id(q))) g.append('}') graph = "\n".join(g) - scapy.utils.do_graph(graph, **kargs) + do_graph(graph, **kargs) class _ConnectorLogic(object): @@ -237,7 +261,7 @@ def _send(self, msg): def _high_send(self, msg): for s in self.high_sinks: s.high_push(msg) - def _trigger(self, msg): + def _trigger(self, msg=None): for s in self.trigger_sinks: s.on_trigger(msg) @@ -286,13 +310,14 @@ def __init__(self, name=None): Pipe.__init__(self, name=name) self.is_exhausted = False def _read_message(self): - from scapy.automaton import Message return Message() def deliver(self): msg = self._read_message self._send(msg) def fileno(self): return None + def checkRecv(self): + return False def exhausted(self): return self.is_exhausted def start(self): @@ -335,6 +360,8 @@ def __init__(self, name=None): self._queue = collections.deque() def fileno(self): return self.__fdr + def checkRecv(self): + return len(self._queue) > 0 def _gen_data(self, msg): self._queue.append((msg,False)) self._wake_up() @@ -363,7 +390,7 @@ def generate(self): pass def start(self): self.RUN = True - thread.start_new_thread(self.generate,()) + Thread(target=self.generate).start() def stop(self): self.RUN = False @@ -393,14 +420,15 @@ class RawConsoleSink(Sink): def __init__(self, name=None, newlines=True): Sink.__init__(self, name=name) self.newlines = newlines + self._write_pipe = 1 def push(self, msg): if self.newlines: msg += "\n" - os.write(1, str(msg)) + os.write(self._write_pipe, str(msg)) def high_push(self, msg): if self.newlines: msg += "\n" - os.write(1, str(msg)) + os.write(self._write_pipe, str(msg)) class CLIFeeder(AutoSource): """Send messages from python command line @@ -470,8 +498,19 @@ def __init__(self, name=None, keepterm=True, newlines=True, openearly=True): self.opened = False if self.openearly: self.start() - - def start(self): + def _start_windows(self): + if not self.opened: + self.opened = True + self.__f = get_temp_file() + self.name = "Scapy" if self.name is None else self.name + # Start a powershell in a new window and print the PID + cmd = "$app = Start-Process PowerShell -ArgumentList '-command &{$host.ui.RawUI.WindowTitle=\\\"%s\\\";Get-Content \\\"%s\\\" -wait}' -passthru; echo $app.Id" % (self.name, self.__f.replace("\\", "\\\\")) + _p = subprocess.Popen([conf.prog.powershell, cmd], stdout=subprocess.PIPE) + _output, _stderr = _p.communicate() + # This is the process PID + self.__p = int(_output) + print("PID:" + str(self.__p)) + def _start_unix(self): if not self.opened: self.opened = True self.__r,self.__w = os.pipe() @@ -481,19 +520,43 @@ def start(self): if self.keepterm: cmd.append("-hold") cmd.extend(["-e", "cat 0<&%i" % self.__r]) - self.__p = subprocess.Popen(cmd) + self.__p = subprocess.Popen(cmd, shell=True, executable="/bin/bash") os.close(self.__r) - def stop(self): + def start(self): + if WINDOWS: + return self._start_windows() + else: + return self._start_unix() + def _stop_windows(self): + if not self.keepterm: + self.opened = False + # Recipe to kill process with PID + # http://code.activestate.com/recipes/347462-terminating-a-subprocess-on-windows/ + import ctypes + PROCESS_TERMINATE = 1 + handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, self.__p) + ctypes.windll.kernel32.TerminateProcess(handle, -1) + ctypes.windll.kernel32.CloseHandle(handle) + def _stop_unix(self): if not self.keepterm: self.opened = False os.close(self.__w) self.__p.kill() self.__p.wait() + def stop(self): + if WINDOWS: + return self._stop_windows() + else: + return self._stop_unix() def _print(self, s): if self.newlines: s+="\n" - os.write(self.__w, s) - + if WINDOWS: + self.__w = open(self.__f, "a") + self.__w.write(s) + self.__w.close() + else: + os.write(self.__w, s) def push(self, msg): self._print(str(msg)) def high_push(self, msg): @@ -564,27 +627,3 @@ def push(self, msg): pass def high_push(self, msg): self._send(msg) - - -def _testmain(): - s = PeriodicSource("hello", 1, name="src") - d1 = Drain(name="d1") - c = ConsoleSink(name="c") - tf = TransformDrain(lambda x:"Got %r" % x) - t = TermSink(name="t", keepterm=False) - - s > d1 > c - d1 > tf > t - - p = PipeEngine(s) - - p.graph(type="png",target="> /tmp/pipe.png") - - p.start() - print p.threadid - time.sleep(5) - p.stop() - - -if __name__ == "__main__": - _testmain() diff --git a/scapy/plist.py b/scapy/plist.py index 7aed92175a9..a56434920a9 100644 --- a/scapy/plist.py +++ b/scapy/plist.py @@ -16,6 +16,7 @@ from scapy.utils import do_graph,hexdump,make_table,make_lined_table,make_tex_table,get_temp_file from scapy.consts import plt, MATPLOTLIB_INLINED, MATPLOTLIB_DEFAULT_PLOT_KARGS +from functools import reduce ############# @@ -77,7 +78,7 @@ def __getitem__(self, item): if isinstance(item,type) and issubclass(item,BasePacket): return self.__class__(filter(lambda x: item in self._elt2pkt(x),self.res), name="%s from %s"%(item.__name__,self.listname)) - if type(item) is slice: + if isinstance(item, slice): return self.__class__(self.res.__getitem__(item), name = "mod %s" % self.listname) return self.res.__getitem__(item) @@ -379,24 +380,24 @@ def minmax(x): gr += "# src nodes\n" for s in sl: n,l = sl[s]; n = 1+float(n-mins)/(maxs-mins) - gr += '"src.%s" [label = "%s", shape=box, fillcolor="#FF0000", style=filled, fixedsize=1, height=%.2f,width=%.2f];\n' % (`s`,`s`,n,n) + gr += '"src.%s" [label = "%s", shape=box, fillcolor="#FF0000", style=filled, fixedsize=1, height=%.2f,width=%.2f];\n' % (repr(s),repr(s),n,n) gr += "# event nodes\n" for e in el: n,l = el[e]; n = n = 1+float(n-mine)/(maxe-mine) - gr += '"evt.%s" [label = "%s", shape=circle, fillcolor="#00FFFF", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (`e`,`e`,n,n) + gr += '"evt.%s" [label = "%s", shape=circle, fillcolor="#00FFFF", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (repr(e),repr(e),n,n) for d in dl: n = dl[d]; n = n = 1+float(n-mind)/(maxd-mind) - gr += '"dst.%s" [label = "%s", shape=triangle, fillcolor="#0000ff", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (`d`,`d`,n,n) + gr += '"dst.%s" [label = "%s", shape=triangle, fillcolor="#0000ff", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (repr(d),repr(d),n,n) gr += "###\n" for s in sl: n,l = sl[s] for e in l: - gr += ' "src.%s" -> "evt.%s";\n' % (`s`,`e`) + gr += ' "src.%s" -> "evt.%s";\n' % (repr(s),repr(e)) for e in el: n,l = el[e] for d in l: - gr += ' "evt.%s" -> "dst.%s";\n' % (`e`,`d`) + gr += ' "evt.%s" -> "dst.%s";\n' % (repr(e),repr(d)) gr += "}" return do_graph(gr, **kargs) @@ -509,7 +510,7 @@ def replace(self, *args, **kargs): """ delete_checksums = kargs.get("delete_checksums",False) x=PacketList(name="Replaced %s" % self.listname) - if type(args[0]) is not tuple: + if not isinstance(args[0], tuple): args = (args,) for p in self.res: p = self._elt2pkt(p) diff --git a/scapy/route.py b/scapy/route.py index df15b12b1d0..0195548d05f 100644 --- a/scapy/route.py +++ b/scapy/route.py @@ -128,7 +128,7 @@ def ifadd(self, iff, addr): def route(self,dest,verbose=None): - if type(dest) is list and dest: + if isinstance(dest, list) and dest: dest = dest[0] if dest in self.cache: return self.cache[dest] @@ -137,7 +137,7 @@ def route(self,dest,verbose=None): # Transform "192.168.*.1-5" to one IP of the set dst = dest.split("/")[0] dst = dst.replace("*","0") - while 1: + while True: l = dst.find("-") if l < 0: break diff --git a/scapy/scapypipes.py b/scapy/scapypipes.py index 4f882d28781..b1cbc5b6d01 100644 --- a/scapy/scapypipes.py +++ b/scapy/scapypipes.py @@ -4,6 +4,7 @@ ## This program is published under a GPLv2 license import socket +import Queue from scapy.pipetool import Source,Drain,Sink from scapy.config import conf from scapy.utils import PcapReader, PcapWriter @@ -173,7 +174,7 @@ def deliver(self): class TCPListenPipe(TCPConnectPipe): """TCP listen on [addr:]port and use first connection as source and sink ; send peer address to high output - +-------------+ + +------^------+ >>-| +-[peer]-|->> | / | >-|-[addr:port]-|-> @@ -182,21 +183,34 @@ class TCPListenPipe(TCPConnectPipe): def __init__(self, addr="", port=0, name=None): TCPConnectPipe.__init__(self, addr, port, name) self.connected = False + self.q = Queue.Queue() def start(self): self.connected = False self.fd = socket.socket() self.fd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.fd.bind((self.addr,self.port)) self.fd.listen(1) + def push(self, msg): + if self.connected: + self.fd.send(msg) + else: + self.q.put(msg) def deliver(self): if self.connected: self._send(self.fd.recv(65536)) else: fd,frm = self.fd.accept() - self._high_send(repr(frm)) + self._high_send(frm) self.fd.close() self.fd = fd self.connected = True + self._trigger(frm) + while True: + try: + self.fd.send(self.q.get(block=False)) + except Queue.Empty: + break + class TriggeredMessage(Drain): """Send a preloaded message when triggered and trigger in chain @@ -235,3 +249,83 @@ def high_push(self, msg): if v: self._trigger(v) self._high_send(msg) + +class TriggeredValve(Drain): + """Let messages alternatively pass or not, changing on trigger + +------^------+ + >>-|-[pass/stop]-|->> + | | | + >-|-[pass/stop]-|-> + +------^------+ +""" + def __init__(self, start_state=True, name=None): + Drain.__init__(self, name=name) + self.opened = start_state + def push(self, msg): + if self.opened: + self._send(msg) + def high_push(self, msg): + if self.opened: + self._send(msg) + def on_trigger(self, msg): + self.opened ^= True + self._trigger(msg) + +class TriggeredQueueingValve(Drain): + """Let messages alternatively pass or queued, changing on trigger + +------^-------+ + >>-|-[pass/queue]-|->> + | | | + >-|-[pass/queue]-|-> + +------^-------+ +""" + def __init__(self, start_state=True, name=None): + Drain.__init__(self, name=name) + self.opened = start_state + self.q = Queue.Queue() + def start(self): + self.q = Queue.Queue() + def push(self, msg): + if self.opened: + self._send(msg) + else: + self.q.put((True,msg)) + def high_push(self, msg): + if self.opened: + self._send(msg) + else: + self.hq.put((False,msg)) + def on_trigger(self, msg): + self.opened ^= True + self._trigger(msg) + while True: + try: + low,msg = self.q.get(block=False) + except Queue.Empty: + break + else: + if low: + self._send(msg) + else: + self._high_send(msg) + +class TriggeredSwitch(Drain): + """Let messages alternatively high or low, changing on trigger + +------^------+ + >>-|-\ | /-|->> + | [up/down] | + >-|-/ | \-|-> + +------^------+ +""" + def __init__(self, start_state=True, name=None): + Drain.__init__(self, name=name) + self.low = start_state + def push(self, msg): + if self.low: + self._send(msg) + else: + self._high_send(msg) + high_push = push + def on_trigger(self, msg): + self.low ^= True + self._trigger(msg) diff --git a/scapy/sendrecv.py b/scapy/sendrecv.py index 1271b1303e8..1d0de06eb0d 100644 --- a/scapy/sendrecv.py +++ b/scapy/sendrecv.py @@ -122,7 +122,7 @@ def sndrcv(pks, pkt, timeout = None, inter = 0, verbose=None, chainCC=0, retry=0 inmask = [rdpipe,pks] try: try: - while 1: + while True: if stoptime: remaintime = stoptime-time.time() if remaintime <= 0: @@ -226,7 +226,7 @@ def sndrcv(pks, pkt, timeout = None, inter = 0, verbose=None, chainCC=0, retry=0 def __gen_send(s, x, inter=0, loop=0, count=None, verbose=None, realtime=None, return_packets=False, *args, **kargs): - if type(x) is str: + if isinstance(x, str): x = conf.raw_layer(load=x) if not isinstance(x, Gen): x = SetGen(x) @@ -269,20 +269,27 @@ def __gen_send(s, x, inter=0, loop=0, count=None, verbose=None, realtime=None, r return sent_packets @conf.commands.register -def send(x, inter=0, loop=0, count=None, verbose=None, realtime=None, return_packets=False, *args, **kargs): +def send(x, inter=0, loop=0, count=None, verbose=None, realtime=None, return_packets=False, socket=None, + *args, **kargs): """Send packets at layer 3 -send(packets, [inter=0], [loop=0], [verbose=conf.verb]) -> None""" - return __gen_send(conf.L3socket(*args, **kargs), x, inter=inter, loop=loop, count=count,verbose=verbose, +send(packets, [inter=0], [loop=0], [count=None], [verbose=conf.verb], [realtime=None], [return_packets=False], + [socket=None]) -> None""" + if socket is None: + socket = conf.L3socket(*args, **kargs) + return __gen_send(socket, x, inter=inter, loop=loop, count=count,verbose=verbose, realtime=realtime, return_packets=return_packets) @conf.commands.register def sendp(x, inter=0, loop=0, iface=None, iface_hint=None, count=None, verbose=None, realtime=None, - return_packets=False, *args, **kargs): + return_packets=False, socket=None, *args, **kargs): """Send packets at layer 2 -sendp(packets, [inter=0], [loop=0], [verbose=conf.verb]) -> None""" - if iface is None and iface_hint is not None: +sendp(packets, [inter=0], [loop=0], [iface=None], [iface_hint=None], [count=None], [verbose=conf.verb], + [realtime=None], [return_packets=False], [socket=None]) -> None""" + if iface is None and iface_hint is not None and socket is None: iface = conf.route.route(iface_hint)[0] - return __gen_send(conf.L2socket(iface=iface, *args, **kargs), x, inter=inter, loop=loop, count=count, + if socket is None: + socket = conf.L2socket(iface=iface, *args, **kargs) + return __gen_send(socket, x, inter=inter, loop=loop, count=count, verbose=verbose, realtime=realtime, return_packets=return_packets) @conf.commands.register @@ -318,7 +325,7 @@ def sendpfast(x, pps=None, mbps=None, realtime=None, loop=0, file_cache=False, i subprocess.check_call(argv) except KeyboardInterrupt: log_interactive.info("Interrupted by user") - except Exception,e: + except Exception as e: log_interactive.error("while trying to exec [%s]: %s" % (argv[0],e)) finally: os.unlink(f) @@ -338,7 +345,7 @@ def sr(x, promisc=None, filter=None, iface=None, nofilter=0, *args,**kargs): multi: whether to accept multiple answers for the same stimulus filter: provide a BPF filter iface: listen answers only on the given interface""" - if not kargs.has_key("timeout"): + if "timeout" not in kargs: kargs["timeout"] = -1 s = conf.L3socket(promisc=promisc, filter=filter, iface=iface, nofilter=nofilter) a,b=sndrcv(s,x,*args,**kargs) @@ -356,7 +363,7 @@ def sr1(x, promisc=None, filter=None, iface=None, nofilter=0, *args,**kargs): multi: whether to accept multiple answers for the same stimulus filter: provide a BPF filter iface: listen answers only on the given interface""" - if not kargs.has_key("timeout"): + if "timeout" not in kargs: kargs["timeout"] = -1 s=conf.L3socket(promisc=promisc, filter=filter, nofilter=nofilter, iface=iface) a,b=sndrcv(s,x,*args,**kargs) @@ -377,7 +384,7 @@ def srp(x, promisc=None, iface=None, iface_hint=None, filter=None, nofilter=0, t multi: whether to accept multiple answers for the same stimulus filter: provide a BPF filter iface: work only on the given interface""" - if not kargs.has_key("timeout"): + if "timeout" not in kargs: kargs["timeout"] = -1 if iface is None and iface_hint is not None: iface = conf.route.route(iface_hint)[0] @@ -397,7 +404,7 @@ def srp1(*args,**kargs): multi: whether to accept multiple answers for the same stimulus filter: provide a BPF filter iface: work only on the given interface""" - if not kargs.has_key("timeout"): + if "timeout" not in kargs: kargs["timeout"] = -1 a,b=srp(*args,**kargs) if len(a) > 0: @@ -417,7 +424,7 @@ def __sr_loop(srfunc, pkts, prn=lambda x:x[1].summary(), prnfail=lambda x:x.summ if timeout is None: timeout = min(2*inter, 5) try: - while 1: + while True: parity ^= 1 col = [ct.even,ct.odd][parity] if count is not None: @@ -469,7 +476,7 @@ def srploop(pkts, *args, **kargs): return __sr_loop(srp, pkts, *args, **kargs) -def sndrcvflood(pks, pkt, prn=lambda (s,r):r.summary(), chainCC=0, store=1, unique=0): +def sndrcvflood(pks, pkt, prn=lambda s_r:s_r[1].summary(), chainCC=0, store=1, unique=0): if not isinstance(pkt, Gen): pkt = SetGen(pkt) tobesent = [p for p in pkt] @@ -485,7 +492,7 @@ def sndrcvflood(pks, pkt, prn=lambda (s,r):r.summary(), chainCC=0, store=1, uniq hsent[h] = [i] def send_in_loop(tobesent): - while 1: + while True: for p in tobesent: yield p @@ -494,7 +501,7 @@ def send_in_loop(tobesent): ssock = rsock = pks.fileno() try: - while 1: + while True: if conf.use_bpf: from scapy.arch.bpf.supersocket import bpf_select readyr = bpf_select([rsock]) @@ -597,7 +604,7 @@ def sniff(count=0, store=1, offline=None, prn=None, lfilter=None, if offline is None: if L2socket is None: L2socket = conf.L2listen - if type(iface) is list: + if isinstance(iface, list): for i in iface: s = L2socket(type=ETH_P_ALL, iface=i, *arg, **karg) label[s] = i diff --git a/scapy/supersocket.py b/scapy/supersocket.py index 2a2c1107eaa..5bd0f626ff3 100644 --- a/scapy/supersocket.py +++ b/scapy/supersocket.py @@ -106,7 +106,7 @@ def send(self, x): sx = str(x) x.sent_time = time.time() self.outs.sendto(sx,(x.dst,0)) - except socket.error,msg: + except socket.error as msg: log_runtime.error(msg) class SimpleSocket(SuperSocket): diff --git a/scapy/themes.py b/scapy/themes.py index c7d2a1ff5b7..bf7ae4760d3 100644 --- a/scapy/themes.py +++ b/scapy/themes.py @@ -31,7 +31,7 @@ class Color: def create_styler(fmt=None, before="", after="", fmt2="%s"): def do_style(val, fmt=fmt, before=before, after=after, fmt2=fmt2): if fmt is None: - if type(val) is not str: + if not isinstance(val, str): val = str(val) else: val = fmt % val diff --git a/scapy/tools/UTscapy.py b/scapy/tools/UTscapy.py index 63fe42a526c..b96aea13b32 100755 --- a/scapy/tools/UTscapy.py +++ b/scapy/tools/UTscapy.py @@ -7,7 +7,7 @@ Unit testing infrastructure for Scapy """ -import sys, getopt, imp, glob +import sys, getopt, imp, glob, importlib import bz2, base64, os.path, time, traceback, zlib, sha from scapy.consts import WINDOWS @@ -355,24 +355,24 @@ def remove_empty_testsets(test_campaign): #### RUN CAMPAIGN ##### -def run_campaign(test_campaign, get_interactive_session, verb=3): +def run_campaign(test_campaign, get_interactive_session, verb=3, ignore_globals=None): if WINDOWS: # Add a route to 127.0.0.1 and ::1 from scapy.arch.windows import route_add_loopback route_add_loopback() passed=failed=0 if test_campaign.preexec: - test_campaign.preexec_output = get_interactive_session(test_campaign.preexec.strip())[0] + test_campaign.preexec_output = get_interactive_session(test_campaign.preexec.strip(), ignore_globals=ignore_globals)[0] for testset in test_campaign: for t in testset: - t.output,res = get_interactive_session(t.test.strip()) + t.output,res = get_interactive_session(t.test.strip(), ignore_globals=ignore_globals) the_res = False try: if res is None or res: the_res= True - except Exception,msg: + except Exception as msg: t.output+="UTscapy: Error during result interpretation:\n" - t.output+="".join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback,)) + t.output+="".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2],)) if the_res: t.res = True res = "passed" @@ -607,7 +607,7 @@ def usage(): #### MAIN #### def execute_campaign(TESTFILE, OUTPUTFILE, PREEXEC, NUM, KW_OK, KW_KO, DUMP, - FORMAT, VERB, ONLYFAILED, CRC, autorun_func, pos_begin=0): + FORMAT, VERB, ONLYFAILED, CRC, autorun_func, pos_begin=0, ignore_globals=None): # Parse test file test_campaign = parse_campaign_file(TESTFILE) @@ -637,7 +637,7 @@ def execute_campaign(TESTFILE, OUTPUTFILE, PREEXEC, NUM, KW_OK, KW_KO, DUMP, # Run tests test_campaign.output_file = OUTPUTFILE - result = run_campaign(test_campaign, autorun_func[FORMAT], verb=VERB) + result = run_campaign(test_campaign, autorun_func[FORMAT], verb=VERB, ignore_globals=None) # Shrink passed if ONLYFAILED: @@ -672,6 +672,7 @@ def resolve_testfiles(TESTFILES): def main(argv): import __builtin__ + ignore_globals = list(__builtin__.__dict__.keys()) + ["sys"] # Parse arguments @@ -713,7 +714,7 @@ def main(argv): elif opt == "-f": try: FORMAT = Format.from_string(optarg) - except KeyError,msg: + except KeyError as msg: raise getopt.GetoptError("Unknown output format %s" % msg) elif opt == "-t": TESTFILES.append(optarg) @@ -738,7 +739,7 @@ def main(argv): KW_KO = [data.kw_ko] try: FORMAT = Format.from_string(data.format) - except KeyError,msg: + except KeyError as msg: raise getopt.GetoptError("Unknown output format %s" % msg) TESTFILES = resolve_testfiles(TESTFILES) elif opt == "-o": @@ -751,7 +752,7 @@ def main(argv): try: NUM.append(int(v)) except ValueError: - v1, v2 = map(int, v.split("-", 1)) + v1, v2 = [int(e) for e in v.split('-', 1)] NUM.extend(xrange(v1, v2 + 1)) elif opt == "-m": MODULES.append(optarg) @@ -764,17 +765,17 @@ def main(argv): print >>sys.stderr, "### Booting scapy..." try: from scapy import all as scapy - except ImportError,e: + except ImportError as e: raise getopt.GetoptError("cannot import [%s]: %s" % (SCAPY,e)) for m in MODULES: try: mod = import_module(m) __builtin__.__dict__.update(mod.__dict__) - except ImportError,e: + except ImportError as e: raise getopt.GetoptError("cannot import [%s]: %s" % (m,e)) - except getopt.GetoptError,msg: + except getopt.GetoptError as msg: print >>sys.stderr,"ERROR:",msg raise SystemExit @@ -815,7 +816,7 @@ def main(argv): output, result, campaign = execute_campaign(open(TESTFILE), OUTPUTFILE, PREEXEC, NUM, KW_OK, KW_KO, DUMP, FORMAT, VERB, ONLYFAILED, - CRC, autorun_func, pos_begin) + CRC, autorun_func, pos_begin, ignore_globals) runned_campaigns.append(campaign) pos_begin = campaign.end_pos if UNIQUE: diff --git a/scapy/tools/check_asdis.py b/scapy/tools/check_asdis.py index 2c1efa4c38d..4be9ef1bb36 100755 --- a/scapy/tools/check_asdis.py +++ b/scapy/tools/check_asdis.py @@ -39,7 +39,7 @@ def main(argv): if PCAP_IN is None: raise getopt.GetoptError("Missing pcap file (-i)") - except getopt.GetoptError,e: + except getopt.GetoptError as e: print >>sys.stderr,"ERROR: %s" % e raise SystemExit @@ -72,7 +72,7 @@ def main(argv): p2 = str(p2d) except KeyboardInterrupt: raise - except Exception,e: + except Exception as e: print "Dissection error on packet %i" % i failed += 1 else: diff --git a/scapy/utils.py b/scapy/utils.py index 7dd8f9fb04e..d24a2523ad7 100644 --- a/scapy/utils.py +++ b/scapy/utils.py @@ -56,9 +56,9 @@ def sane(x): def lhex(x): if type(x) in (int,long): return hex(x) - elif type(x) is tuple: + elif isinstance(x, tuple): return "(%s)" % ", ".join(map(lhex, x)) - elif type(x) is list: + elif isinstance(x, list): return "[%s]" % ", ".join(map(lhex, x)) else: return x @@ -137,7 +137,7 @@ def chexdump(x, dump=False): :returns: a String only if dump=True """ x = str(x) - s = str(", ".join(map(lambda x: "%#04x"%ord(x), x))) + s = str(", ".join("%#04x" % ord(x) for x in x)) if dump: return s else: @@ -147,14 +147,14 @@ def chexdump(x, dump=False): def hexstr(x, onlyasc=0, onlyhex=0): s = [] if not onlyasc: - s.append(" ".join(map(lambda x:"%02x"%ord(x), x))) + s.append(" ".join("%02x" % ord(b) for b in x)) if not onlyhex: s.append(sane(x)) return " ".join(s) def repr_hex(s): """ Convert provided bitstring to a simple string of hex digits """ - return "".join(map(lambda x: "%02x" % ord(x),s)) + return "".join("%02x" % ord(x) for x in s) @conf.commands.register def hexdiff(x,y): @@ -339,7 +339,7 @@ def fletcher16_checkbytes(binbuf, offset): def mac2str(mac): - return "".join(map(lambda x: chr(int(x,16)), mac.split(":"))) + return "".join(chr(int(x, 16)) for x in mac.split(':')) def str2mac(s): return ("%02x:"*6)[:-1] % tuple(map(ord, s)) @@ -348,15 +348,13 @@ def randstring(l): """ Returns a random string of length l (l >= 0) """ - tmp = map(lambda x: struct.pack("B", random.randrange(0, 256, 1)), [""]*l) - return "".join(tmp) + return b"".join(struct.pack('B', random.randint(0, 255)) for _ in xrange(l)) def zerofree_randstring(l): """ Returns a random string of length l (l >= 0) without zero in it. """ - tmp = map(lambda x: struct.pack("B", random.randrange(1, 256, 1)), [""]*l) - return "".join(tmp) + return b"".join(struct.pack('B', random.randint(1, 255)) for _ in xrange(l)) def strxor(s1, s2): """ @@ -438,7 +436,10 @@ def do_graph(graph,prog=None,format=None,target=None,type=None,string=None,optio format = "-T %s" % format w,r = os.popen2("%s %s %s %s" % (prog,options or "", format or "", target)) w.write(graph) - w.close() + try: + w.close() + except IOError: + pass if start_viewer: # Workaround for file not found error: We wait until tempfile is written. waiting_start = time.time() @@ -482,7 +483,7 @@ def colgen(*lstcol,**kargs): if len(lstcol) < 2: lstcol *= 2 trans = kargs.get("trans", lambda x,y,z: (x,y,z)) - while 1: + while True: for i in xrange(len(lstcol)): for j in xrange(len(lstcol)): for k in xrange(len(lstcol)): @@ -524,7 +525,7 @@ class Enum_metaclass(type): def __new__(cls, name, bases, dct): rdict={} for k,v in dct.iteritems(): - if type(v) is int: + if isinstance(v, int): v = cls.element_class(k,v) dct[k] = v rdict[v] = k @@ -1018,7 +1019,7 @@ def write(self, pkt): written to the dumpfile """ - if type(pkt) is str: + if isinstance(pkt, str): if not self.header_present: self._write_header(pkt) self._write_packet(pkt) @@ -1103,7 +1104,7 @@ def _write_packet(self, packet): def import_hexcap(): p = "" try: - while 1: + while True: l = raw_input().strip() try: p += re_extract_hexcap.match(l).groups()[2] @@ -1282,7 +1283,7 @@ def pretty_routes(rtlst, header, sortBy=0): # Append tag rtlst = header + rtlst # Detect column's width - colwidth = map(lambda x: max(map(lambda y: len(y), x)), apply(zip, rtlst)) + colwidth = map(lambda x: max(map(lambda y: len(y), x)), zip(*rtlst)) # Make text fit in box (if exist) # TODO: find a better and more precise way of doing this. That's currently working but very complicated width = get_terminal_width() @@ -1304,7 +1305,7 @@ def _crop(x, width): return _r rtlst = [tuple([_crop(rtlst[j][i], colwidth[i]) for i in range(0, len(rtlst[j]))]) for j in range(0, len(rtlst))] # Recalculate column's width - colwidth = map(lambda x: max(map(lambda y: len(y), x)), apply(zip, rtlst)) + colwidth = map(lambda x: max(map(lambda y: len(y), x)), zip(*rtlst)) fmt = _space.join(map(lambda x: "%%-%ds"%x, colwidth)) rt = "\n".join(map(lambda x: fmt % x, rtlst)) return rt @@ -1317,7 +1318,7 @@ def __make_table(yfmtfunc, fmtfunc, endline, list, fxyz, sortx=None, sorty=None, vyf = {} l = 0 for e in list: - xx,yy,zz = map(str, fxyz(e)) + xx, yy, zz = [str(s) for s in fxyz(e)] l = max(len(yy),l) vx[xx] = max(vx.get(xx,0), len(xx), len(zz)) vy[yy] = None @@ -1348,7 +1349,7 @@ def __make_table(yfmtfunc, fmtfunc, endline, list, fxyz, sortx=None, sorty=None, if seplinefunc: - sepline = seplinefunc(l, map(lambda x:vx[x],vxk)) + sepline = seplinefunc(l, [vx[x] for x in vxk]) print sepline fmt = yfmtfunc(l) @@ -1372,7 +1373,7 @@ def make_table(*args, **kargs): def make_lined_table(*args, **kargs): __make_table(lambda l:"%%-%is |" % l, lambda l:"%%-%is |" % l, "", - seplinefunc=lambda a,x:"+".join(map(lambda y:"-"*(y+2), [a-1]+x+[-2])), + seplinefunc=lambda a,x:"+".join('-'*(y+2) for y in [a-1]+x+[-2]), *args, **kargs) def make_tex_table(*args, **kargs): diff --git a/scapy/utils6.py b/scapy/utils6.py index 99292911dfd..ace1db2ea55 100644 --- a/scapy/utils6.py +++ b/scapy/utils6.py @@ -19,6 +19,7 @@ from scapy.pton_ntop import * from scapy.volatile import RandMAC from scapy.error import warning +from functools import reduce def construct_source_candidate_set(addr, plen, laddr, loiface): @@ -66,7 +67,7 @@ def cset_sort(x,y): cset = filter(lambda x: x[1] == IPV6_ADDR_SITELOCAL, laddr) elif addr == '::' and plen == 0: cset = filter(lambda x: x[1] == IPV6_ADDR_GLOBAL, laddr) - cset = map(lambda x: x[0], cset) + cset = [x[0] for x in cset] cset.sort(cmp=cset_sort) # Sort with global addresses first return cset @@ -222,7 +223,7 @@ def in6_ifaceidtomac(ifaceid): # TODO: finish commenting function behavior first = struct.pack("B", ((first & 0xFD) | ulbit)) oui = first + ifaceid[1:3] end = ifaceid[5:] - l = map(lambda x: "%.02x" % struct.unpack("B", x)[0], list(oui+end)) + l = ["%.02x" % struct.unpack('B', x)[0] for x in list(oui + end)] return ":".join(l) def in6_addrtomac(addr): @@ -289,7 +290,7 @@ def in6_getLinkScopedMcastAddr(addr, grpid=None, scope=2): if grpid is None: grpid = b'\x00\x00\x00\x00' else: - if type(grpid) is str: + if isinstance(grpid, str): if len(grpid) == 8: try: grpid = int(grpid, 16) & 0xffffffff @@ -523,10 +524,9 @@ def _in6_bitops(a1, a2, operator=0): fop = [ lambda x,y: x | y, lambda x,y: x & y, lambda x,y: x ^ y - ] + ] ret = map(fop[operator%len(fop)], a1, a2) - t = ''.join(map(lambda x: struct.pack('I', x), ret)) - return t + return ''.join(struct.pack('I', x) for x in ret) def in6_or(a1, a2): """ @@ -567,7 +567,7 @@ def in6_cidr2mask(m): t.append(max(0, 2**32 - 2**(32-min(32, m)))) m -= 32 - return ''.join(map(lambda x: struct.pack('!I', x), t)) + return ''.join(struct.pack('!I', x) for x in t) def in6_getnsma(a): """ @@ -588,7 +588,7 @@ def in6_getnsmac(a): # return multicast Ethernet address associated with multica a = struct.unpack('16B', a)[-4:] mac = '33:33:' - mac += ':'.join(map(lambda x: '%.2x' %x, a)) + mac += ':'.join("%.2x" %x for x in a) return mac def in6_getha(prefix): diff --git a/scapy/volatile.py b/scapy/volatile.py index 230470bc9ea..73892a72778 100644 --- a/scapy/volatile.py +++ b/scapy/volatile.py @@ -75,7 +75,7 @@ def __getattr__(self, attr): elif attr == "__cmp__": x = self._fix() def cmp2(y,x=x): - if type(x) != type(y): + if not isinstance(x, type(y)): return -1 return x.__cmp__(y) return cmp2 @@ -341,8 +341,8 @@ def _fix(self): if i == "*": oid.append(str(self.idnum)) elif i == "**": - oid += map(str, [self.idnum for i in xrange(1+self.depth)]) - elif type(i) is tuple: + oid += [str(self.idnum) for i in xrange(1 + self.depth)] + elif isinstance(i, tuple): oid.append(str(random.randrange(*i))) else: oid.append(i) @@ -375,7 +375,7 @@ def choice_expand(s): #XXX does not support special sets like (ex ':alnum:') s = s[:p-1]+rng+s[p+1:] res = m+s if invert: - res = "".join([chr(x) for x in xrange(256) if chr(x) not in res]) + res = "".join(chr(x) for x in xrange(256) if chr(x) not in res) return res @staticmethod @@ -383,7 +383,7 @@ def stack_fix(lst, index): r = "" mul = 1 for e in lst: - if type(e) is list: + if isinstance(e, list): if mul != 1: mul = mul-1 r += RandRegExp.stack_fix(e[1:]*mul, index) @@ -394,7 +394,7 @@ def stack_fix(lst, index): index[i] = f r += f mul = 1 - elif type(e) is tuple: + elif isinstance(e, tuple): kind,val = e if kind == "cite": r += index[val-1] @@ -433,7 +433,7 @@ def _fix(self): elif c == '|': p = current[0] ch = p[-1] - if type(ch) is not tuple: + if not isinstance(ch, tuple): ch = ("choice",[current]) p[-1] = ch else: @@ -441,7 +441,7 @@ def _fix(self): current = [p] elif c == ')': ch = current[0][-1] - if type(ch) is tuple: + if isinstance(ch, tuple): ch[1].append(current) index.append(current) current = current[0] @@ -515,10 +515,10 @@ def make_power_of_two(end): end = -end sign = -1 end_n = int(math.log(end)/math.log(2))+1 - return set([sign*2**i for i in xrange(end_n)]) + return {sign*2**i for i in xrange(end_n)} def __init__(self, mn, mx): - sing = set([0, mn, mx, int((mn+mx)/2)]) + sing = {0, mn, mx, int((mn+mx)/2)} sing |= self.make_power_of_two(mn) sing |= self.make_power_of_two(mx) for i in sing.copy(): @@ -630,7 +630,7 @@ def __init__(self, *args): pool = [] for p in args: w = 1 - if type(p) is tuple: + if isinstance(p, tuple): p,w = p pool += [p]*w self._pool = pool diff --git a/test/mock_windows.uts b/test/mock_windows.uts index ce7391c5c1e..b7357456a12 100644 --- a/test/mock_windows.uts +++ b/test/mock_windows.uts @@ -197,6 +197,8 @@ for i in ps_read_routes: assert _correct +conf.prog._reload() + = show_interfaces from scapy.arch import show_interfaces @@ -223,3 +225,20 @@ assert test_show_interfaces() from scapy.config import conf assert dev_from_pcapname(conf.iface.pcap_name).guid == conf.iface.guid + += test pcap_service_status + +status = pcap_service_status() +status +assert status[0] in ["npcap", "npf"] +assert status[2] == True + += test pcap_service_stop + +pcap_service_stop() +assert pcap_service_status()[2] == False + += test pcap_service_start + +pcap_service_start() +assert pcap_service_status()[2] == True \ No newline at end of file diff --git a/test/pipetool.uts b/test/pipetool.uts new file mode 100644 index 00000000000..5b0a7103bab --- /dev/null +++ b/test/pipetool.uts @@ -0,0 +1,219 @@ +######################## +% Pipetool related tests +######################## + ++ Basic tests + += Test default test case + +s = PeriodicSource("hello", 1, name="src") +d1 = Drain(name="d1") +c = ConsoleSink(name="c") +tf = TransformDrain(lambda x:"Got %r" % x) +t = TermSink(name="t", keepterm=False) +s > d1 > c +d1 > tf > t + +p = PipeEngine(s) +p.graph(type="png",target="> /tmp/pipe.png") +p.start() +time.sleep(3) +p.stop() + += Test add_pipe + +s = AutoSource() +p = PipeEngine(s) +p.add(Pipe()) +assert len(p.active_pipes) == 2 + +x = p.spawn_Pipe() +assert len(p.active_pipes) == 3 +assert isinstance(x, Pipe) + += Test exhausted source + +s = AutoSource() +s._gen_data("hello") +s.is_exhausted = True +d1 = Drain(name="d1") +c = ConsoleSink(name="c") +s > d1 > c + +p = PipeEngine(s) +p.start() +time.sleep(1) +p.wait_and_stop() + += Test add_pipe on running instance + +test_val = None + +class TestSink(Sink): + def push(self, msg): + global test_val + test_val = msg + +p = PipeEngine() +p.start() + +s = AutoSource() +s._gen_data("hello") +s.is_exhausted = True + +d1 = Drain(name="d1") +c = TestSink(name="c") +s > d1 > c + +p.add(s) +time.sleep(1) +p.wait_and_stop() +assert test_val == "hello" + += Test Operators + +s = AutoSource() +p = PipeEngine(s) +assert p == p +assert not p < p +assert not p > p + +a = AutoSource() +b = AutoSource() +a >> b +assert len(a.high_sinks) == 1 +assert len(a.high_sources) == 0 +assert len(b.high_sinks) == 0 +assert len(b.high_sources) == 1 +a +b + +a = AutoSource() +b = AutoSource() +a << b +assert len(a.high_sinks) == 0 +assert len(a.high_sources) == 1 +assert len(b.high_sinks) == 1 +assert len(b.high_sources) == 0 +a +b + +a = AutoSource() +b = AutoSource() +a == b +assert len(a.sinks) == 1 +assert len(a.sources) == 1 +assert len(b.sinks) == 1 +assert len(b.sources) == 1 + +a = AutoSource() +b = AutoSource() +a//b +assert len(a.high_sinks) == 1 +assert len(a.high_sources) == 1 +assert len(b.high_sinks) == 1 +assert len(b.high_sources) == 1 + +a = AutoSource() +b = AutoSource() +a^b +assert len(b.trigger_sources) == 1 +assert len(a.trigger_sinks) == 1 + += Test doc + +s = AutoSource() +p = PipeEngine(s) +p.list_pipes() +p.list_pipes_detailed() + += Test RawConsoleSink with CLIFeeder + +p = PipeEngine() +p.start() + +s = CLIFeeder() +s.send("hello") +s.is_exhausted = True + +r, w = os.pipe() + +d1 = Drain(name="d1") +c = RawConsoleSink(name="c") +c._write_pipe = w +s > d1 > c + +p.add(s) +time.sleep(1) +p.wait_and_stop() +assert os.read(r, 20) == "hello\n" + += Test QueueSink with CLIFeeder + +p = PipeEngine() +p.start() + +s = CLIFeeder() +s.send("hello") +s.is_exhausted = True + +d1 = Drain(name="d1") +c = QueueSink(name="c") +s > d1 > c + +p.add(s) +time.sleep(1) +p.wait_and_stop() +assert c.recv() == "hello" + += Test UpDrain + +test_val = None + +class TestSink(Sink): + def high_push(self, msg): + global test_val + test_val = msg + +p = PipeEngine() +p.start() + +s = CLIFeeder() +s.send("hello") +s.is_exhausted = True + +d1 = UpDrain(name="d1") +c = TestSink(name="c") +s > d1 +d1 >> c + +p.add(s) +time.sleep(1) +p.wait_and_stop() +assert test_val == "hello" + += Test DownDrain + +test_val = None + +class TestSink(Sink): + def push(self, msg): + global test_val + test_val = msg + +p = PipeEngine() +p.start() + +s = CLIHighFeeder() +s.send("hello") +s.is_exhausted = True + +d1 = DownDrain(name="d1") +c = TestSink(name="c") +s >> d1 +d1 > c + +p.add(s) +time.sleep(1) +p.wait_and_stop() +assert test_val == "hello" diff --git a/test/regression.uts b/test/regression.uts index bf50c24b0ca..843088abaef 100644 --- a/test/regression.uts +++ b/test/regression.uts @@ -7547,16 +7547,177 @@ RIPEntry in p and RIPAuth in p and p[RIPAuth].password.startswith("scapy") ############ ############ -+ Radius tests ++ RADIUS tests -= Radius - build += IP/UDP/RADIUS - Build s = str(IP()/UDP(sport=1812)/Radius(authenticator="scapy")/RadiusAttribute(value="scapy")) s == b'E\x00\x007\x00\x01\x00\x00@\x11|\xb3\x7f\x00\x00\x01\x7f\x00\x00\x01\x07\x14\x07\x15\x00#U\xb2\x01\x00\x00\x1bscapy\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x07scapy' -= Radius - dissection += IP/UDP/RADIUS - Dissection p = IP(s) Radius in p and len(p[Radius].attributes) == 1 and p[Radius].attributes[0].value == "scapy" += RADIUS - Access-Request - Dissection (1) +s = b'\x01\xae\x01\x17>k\xd4\xc4\x19V\x0b*1\x99\xc8D\xea\xc2\x94Z\x01\x06leap\x06\x06\x00\x00\x00\x02\x1a\x1b\x00\x00\x00\t\x01\x15service-type=Framed\x0c\x06\x00\x00#\xee\x1e\x13AC-7E-8A-4E-E2-92\x1f\x1300-26-73-9E-0F-D3O\x0b\x02\x01\x00\t\x01leapP\x12U\xbc\x12\xcdM\x00\xf8\xdb4\xf1\x18r\xca_\x8c\xf6f\x02\x1a1\x00\x00\x00\t\x01+audit-session-id=0AC8090E0000001A0354CA00\x1a\x14\x00\x00\x00\t\x01\x0emethod=dot1x\x08\x06\xc0\xa8\n\xb9\x04\x06\xc0\xa8\n\x80\x1a\x1d\x00\x00\x00\t\x02\x17GigabitEthernet1/0/18W\x17GigabitEthernet1/0/18=\x06\x00\x00\x00\x0f\x05\x06\x00\x00\xc3\xc6' +radius_packet = Radius(s) +assert(radius_packet.id == 174) +assert(radius_packet.len == 279) +assert(radius_packet.authenticator == b'>k\xd4\xc4\x19V\x0b*1\x99\xc8D\xea\xc2\x94Z') +assert(len(radius_packet.attributes) == 17) +assert(radius_packet.attributes[0].type == 1) +assert(type(radius_packet.attributes[0]) == RadiusAttribute) +assert(radius_packet.attributes[0].len == 6) +assert(radius_packet.attributes[0].value == "leap") +assert(radius_packet.attributes[1].type == 6) +assert(type(radius_packet.attributes[1]) == RadiusAttr_Service_Type) +assert(radius_packet.attributes[1].len == 6) +assert(radius_packet.attributes[1].value == 2) +assert(radius_packet.attributes[2].type == 26) +assert(type(radius_packet.attributes[2]) == RadiusAttr_Vendor_Specific) +assert(radius_packet.attributes[2].len == 27) +assert(radius_packet.attributes[2].vendor_id == 9) +assert(radius_packet.attributes[2].vendor_type == 1) +assert(radius_packet.attributes[2].vendor_len == 21) +assert(radius_packet.attributes[2].value == "service-type=Framed") +assert(radius_packet.attributes[6].type == 79) +assert(type(radius_packet.attributes[6]) == RadiusAttr_EAP_Message) +assert(radius_packet.attributes[6].len == 11) +assert(radius_packet.attributes[6].value.haslayer(EAP)) +assert(radius_packet.attributes[6].value[EAP].code == 2) +assert(radius_packet.attributes[6].value[EAP].id == 1) +assert(radius_packet.attributes[6].value[EAP].len == 9) +assert(radius_packet.attributes[6].value[EAP].type == 1) +assert(hasattr(radius_packet.attributes[6].value[EAP], "identity")) +assert(radius_packet.attributes[6].value[EAP].identity == "leap") +assert(radius_packet.attributes[7].type == 80) +assert(type(radius_packet.attributes[7]) == RadiusAttr_Message_Authenticator) +assert(radius_packet.attributes[7].len == 18) +assert(radius_packet.attributes[7].value == b'U\xbc\x12\xcdM\x00\xf8\xdb4\xf1\x18r\xca_\x8c\xf6') +assert(radius_packet.attributes[11].type == 8) +assert(type(radius_packet.attributes[11]) == RadiusAttr_Framed_IP_Address) +assert(radius_packet.attributes[11].len == 6) +assert(radius_packet.attributes[11].value == '192.168.10.185') +assert(radius_packet.attributes[16].type == 5) +assert(type(radius_packet.attributes[16]) == RadiusAttr_NAS_Port) +assert(radius_packet.attributes[16].len == 6) +assert(radius_packet.attributes[16].value == 50118) + += RADIUS - Access-Challenge - Dissection (2) +s = b'\x0b\xae\x00[\xc7\xae\xfc6\xa1=\xb5\x99&^\xdf=\xe9\x00\xa6\xe8\x12\rHello, leapO\x16\x01\x02\x00\x14\x11\x01\x00\x08\xb8\xc4\x1a4\x97x\xd3\x82leapP\x12\xd3\x12\x17\xa6\x0c.\x94\x85\x03]t\xd1\xdb\xd0\x13\x8c\x18\x12iQs\xf7iSb@k\x9d,\xa0\x99\x8ehO' +radius_packet = Radius(s) +assert(radius_packet.id == 174) +assert(radius_packet.len == 91) +assert(radius_packet.authenticator == b'\xc7\xae\xfc6\xa1=\xb5\x99&^\xdf=\xe9\x00\xa6\xe8') +assert(len(radius_packet.attributes) == 4) +assert(radius_packet.attributes[0].type == 18) +assert(type(radius_packet.attributes[0]) == RadiusAttribute) +assert(radius_packet.attributes[0].len == 13) +assert(radius_packet.attributes[0].value == "Hello, leap") +assert(radius_packet.attributes[1].type == 79) +assert(type(radius_packet.attributes[1]) == RadiusAttr_EAP_Message) +assert(radius_packet.attributes[1].len == 22) +assert(radius_packet.attributes[1][EAP].code == 1) +assert(radius_packet.attributes[1][EAP].id == 2) +assert(radius_packet.attributes[1][EAP].len == 20) +assert(radius_packet.attributes[1][EAP].type == 17) +assert(radius_packet.attributes[2].type == 80) +assert(type(radius_packet.attributes[2]) == RadiusAttr_Message_Authenticator) +assert(radius_packet.attributes[2].len == 18) +assert(radius_packet.attributes[2].value == b'\xd3\x12\x17\xa6\x0c.\x94\x85\x03]t\xd1\xdb\xd0\x13\x8c') +assert(radius_packet.attributes[3].type == 24) +assert(type(radius_packet.attributes[3]) == RadiusAttr_State) +assert(radius_packet.attributes[3].len == 18) +assert(radius_packet.attributes[3].value == b'iQs\xf7iSb@k\x9d,\xa0\x99\x8ehO') + += RADIUS - Access-Request - Dissection (3) +s = b'\x01\xaf\x01DC\xbe!J\x08\xdf\xcf\x9f\x00v~,\xfb\x8e`\xc8\x01\x06leap\x06\x06\x00\x00\x00\x02\x1a\x1b\x00\x00\x00\t\x01\x15service-type=Framed\x0c\x06\x00\x00#\xee\x1e\x13AC-7E-8A-4E-E2-92\x1f\x1300-26-73-9E-0F-D3O&\x02\x02\x00$\x11\x01\x00\x18\rE\xc9\x92\xf6\x9ae\x04\xa2\x06\x13\x8f\x0b#\xf1\xc56\x8eU\xd9\x89\xe5\xa1)leapP\x12|\x1c\x9d[dv\x9c\x19\x96\xc6\xec\xb82\x8f\n f\x02\x1a1\x00\x00\x00\t\x01+audit-session-id=0AC8090E0000001A0354CA00\x1a\x14\x00\x00\x00\t\x01\x0emethod=dot1x\x08\x06\xc0\xa8\n\xb9\x04\x06\xc0\xa8\n\x80\x1a\x1d\x00\x00\x00\t\x02\x17GigabitEthernet1/0/18W\x17GigabitEthernet1/0/18=\x06\x00\x00\x00\x0f\x05\x06\x00\x00\xc3\xc6\x18\x12iQs\xf7iSb@k\x9d,\xa0\x99\x8ehO' +radius_packet = Radius(s) +assert(radius_packet.id == 175) +assert(radius_packet.len == 324) +assert(radius_packet.authenticator == 'C\xbe!J\x08\xdf\xcf\x9f\x00v~,\xfb\x8e`\xc8') +assert(len(radius_packet.attributes) == 18) +assert(radius_packet.attributes[0].type == 1) +assert(type(radius_packet.attributes[0]) == RadiusAttribute) +assert(radius_packet.attributes[0].len == 6) +assert(radius_packet.attributes[0].value == "leap") +assert(radius_packet.attributes[1].type == 6) +assert(type(radius_packet.attributes[1]) == RadiusAttr_Service_Type) +assert(radius_packet.attributes[1].len == 6) +assert(radius_packet.attributes[1].value == 2) +assert(radius_packet.attributes[2].type == 26) +assert(type(radius_packet.attributes[2]) == RadiusAttr_Vendor_Specific) +assert(radius_packet.attributes[2].len == 27) +assert(radius_packet.attributes[2].vendor_id == 9) +assert(radius_packet.attributes[2].vendor_type == 1) +assert(radius_packet.attributes[2].vendor_len == 21) +assert(radius_packet.attributes[2].value == "service-type=Framed") +assert(radius_packet.attributes[6].type == 79) +assert(type(radius_packet.attributes[6]) == RadiusAttr_EAP_Message) +assert(radius_packet.attributes[6].len == 38) +assert(radius_packet.attributes[6].value.haslayer(EAP)) +assert(radius_packet.attributes[6].value[EAP].code == 2) +assert(radius_packet.attributes[6].value[EAP].id == 2) +assert(radius_packet.attributes[6].value[EAP].len == 36) +assert(radius_packet.attributes[6].value[EAP].type == 17) +assert(radius_packet.attributes[7].type == 80) +assert(type(radius_packet.attributes[7]) == RadiusAttr_Message_Authenticator) +assert(radius_packet.attributes[7].len == 18) +assert(radius_packet.attributes[7].value == b'|\x1c\x9d[dv\x9c\x19\x96\xc6\xec\xb82\x8f\n ') +assert(radius_packet.attributes[11].type == 8) +assert(type(radius_packet.attributes[11]) == RadiusAttr_Framed_IP_Address) +assert(radius_packet.attributes[11].len == 6) +assert(radius_packet.attributes[11].value == '192.168.10.185') +assert(radius_packet.attributes[16].type == 5) +assert(type(radius_packet.attributes[16]) == RadiusAttr_NAS_Port) +assert(radius_packet.attributes[16].len == 6) +assert(radius_packet.attributes[16].value == 50118) +assert(radius_packet.attributes[17].type == 24) +assert(type(radius_packet.attributes[17]) == RadiusAttr_State) +assert(radius_packet.attributes[17].len == 18) +assert(radius_packet.attributes[17].value == b'iQs\xf7iSb@k\x9d,\xa0\x99\x8ehO') + += RADIUS - Access-Challenge - Dissection (4) +s = b'\x0b\xaf\x00K\x82 \x95=\xfd\x80\x05 -l}\xab)\xa5kU\x12\rHello, leapO\x06\x03\x03\x00\x04P\x12l0\xb9\x8d\xca\xfc!\xf3\xa7\x08\x80\xe1\xf6}\x84\xff\x18\x12iQs\xf7hRb@k\x9d,\xa0\x99\x8ehO' +radius_packet = Radius(s) +assert(radius_packet.id == 175) +assert(radius_packet.len == 75) +assert(radius_packet.authenticator == b'\x82 \x95=\xfd\x80\x05 -l}\xab)\xa5kU') +assert(len(radius_packet.attributes) == 4) +assert(radius_packet.attributes[0].type == 18) +assert(type(radius_packet.attributes[0]) == RadiusAttribute) +assert(radius_packet.attributes[0].len == 13) +assert(radius_packet.attributes[0].value == "Hello, leap") +assert(radius_packet.attributes[1].type == 79) +assert(type(radius_packet.attributes[1]) == RadiusAttr_EAP_Message) +assert(radius_packet.attributes[1].len == 6) +assert(radius_packet.attributes[1][EAP].code == 3) +assert(radius_packet.attributes[1][EAP].id == 3) +assert(radius_packet.attributes[1][EAP].len == 4) +assert(radius_packet.attributes[2].type == 80) +assert(type(radius_packet.attributes[2]) == RadiusAttr_Message_Authenticator) +assert(radius_packet.attributes[2].len == 18) +assert(radius_packet.attributes[2].value == b'l0\xb9\x8d\xca\xfc!\xf3\xa7\x08\x80\xe1\xf6}\x84\xff') +assert(radius_packet.attributes[3].type == 24) +assert(type(radius_packet.attributes[3]) == RadiusAttr_State) +assert(radius_packet.attributes[3].len == 18) +assert(radius_packet.attributes[3].value == b'iQs\xf7hRb@k\x9d,\xa0\x99\x8ehO') + += RADIUS - Response Authenticator computation +~ crypto +s = b'\x01\xae\x01\x17>k\xd4\xc4\x19V\x0b*1\x99\xc8D\xea\xc2\x94Z\x01\x06leap\x06\x06\x00\x00\x00\x02\x1a\x1b\x00\x00\x00\t\x01\x15service-type=Framed\x0c\x06\x00\x00#\xee\x1e\x13AC-7E-8A-4E-E2-92\x1f\x1300-26-73-9E-0F-D3O\x0b\x02\x01\x00\t\x01leapP\x12U\xbc\x12\xcdM\x00\xf8\xdb4\xf1\x18r\xca_\x8c\xf6f\x02\x1a1\x00\x00\x00\t\x01+audit-session-id=0AC8090E0000001A0354CA00\x1a\x14\x00\x00\x00\t\x01\x0emethod=dot1x\x08\x06\xc0\xa8\n\xb9\x04\x06\xc0\xa8\n\x80\x1a\x1d\x00\x00\x00\t\x02\x17GigabitEthernet1/0/18W\x17GigabitEthernet1/0/18=\x06\x00\x00\x00\x0f\x05\x06\x00\x00\xc3\xc6' +access_request = Radius(s) +s = b'\x0b\xae\x00[\xc7\xae\xfc6\xa1=\xb5\x99&^\xdf=\xe9\x00\xa6\xe8\x12\rHello, leapO\x16\x01\x02\x00\x14\x11\x01\x00\x08\xb8\xc4\x1a4\x97x\xd3\x82leapP\x12\xd3\x12\x17\xa6\x0c.\x94\x85\x03]t\xd1\xdb\xd0\x13\x8c\x18\x12iQs\xf7iSb@k\x9d,\xa0\x99\x8ehO' +access_challenge = Radius(s) +access_challenge.compute_authenticator(access_request.authenticator, "radiuskey") == access_challenge.authenticator + += RADIUS - Layers (1) +radius_attr = RadiusAttr_EAP_Message(value = EAP()) +assert(RadiusAttr_EAP_Message in radius_attr) +assert(RadiusAttribute in radius_attr) +type(radius_attr[RadiusAttribute]) +assert(type(radius_attr[RadiusAttribute]) == RadiusAttr_EAP_Message) +assert(EAP in radius_attr.value) + ############ ############ @@ -8492,3 +8653,20 @@ class Test(Packet): pkt = Test(str(Test(Values=[0, 0, 0, 0, 1, 1, 1, 1]))) assert(pkt.BitCount == 8) assert(pkt.ByteCount == 1) + +############ +############ ++ MPLS tests + += MPLS - build/dissection +from scapy.contrib.mpls import MPLS +p1 = MPLS()/IP()/UDP() +assert(p1[MPLS].s == 1) +p2 = MPLS()/MPLS()/IP()/UDP() +assert(p2[MPLS].s == 0) + +p1[MPLS] +p1[IP] +p2[MPLS] +p2[MPLS:1] +p2[IP] diff --git a/test/run_tests.bat b/test/run_tests.bat index 8c4200d867f..fce8e76ec21 100644 --- a/test/run_tests.bat +++ b/test/run_tests.bat @@ -1,10 +1,10 @@ -@echo off -title UTscapy - All tests -set MYDIR=%cd%\.. -set PYTHONPATH=%MYDIR% -if [%1]==[] ( - python "%MYDIR%\scapy\tools\UTscapy.py" -c configs\\windows2.utsc -T bpf.uts -o scapy_regression_test_%date:~6,4%_%date:~3,2%_%date:~0,2%.html -) else ( - python "%MYDIR%\scapy\tools\UTscapy.py" %@ -) -PAUSE +@echo off +title UTscapy - All tests +set MYDIR=%cd%\.. +set PYTHONPATH=%MYDIR% +if [%1]==[] ( + python "%MYDIR%\scapy\tools\UTscapy.py" -c configs\\windows2.utsc -T bpf.uts -o scapy_regression_test_%date:~6,4%_%date:~3,2%_%date:~0,2%.html +) else ( + python "%MYDIR%\scapy\tools\UTscapy.py" %@ +) +PAUSE