diff --git a/.github/workflows/preflight_check.yaml b/.github/workflows/preflight_check.yaml index 3368218..c9f52e3 100644 --- a/.github/workflows/preflight_check.yaml +++ b/.github/workflows/preflight_check.yaml @@ -6,18 +6,18 @@ on: - '**' pull_request: branches: - - main + - '**' jobs: lint: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: matrix: - python-version: [3.6, 3.7, 3.8] + python-version: ["3.8", "3.9", "3.10"] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies @@ -25,20 +25,23 @@ jobs: python -m pip install --upgrade pip pip install black isort flake8 - name: Format checker with psf/black - run: black --check -l 79 . + uses: psf/black@stable + with: + options: "--check -l 79 --exclude docs/" + version: "24.3.0" - name: Format checker with isort run: isort --check-only -m 3 -l 79 --profile=black . - name: Lint with flake8 run: flake8 --exclude test,docs,examples . test: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: matrix: - python-version: [2.7, 3.5, 3.6, 3.7, 3.8] + python-version: ["3.8", "3.9", "3.10"] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Setup Environment @@ -58,16 +61,16 @@ jobs: COVERALLS_FLAG_NAME: ${{ matrix.python-version }} COVERALLS_PARALLEL: true run: | - coveralls + coveralls --service=github coveralls: name: Finish Coveralls needs: test - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 container: python:3-slim steps: - name: Finished run: | pip3 install --upgrade coveralls - coveralls --finish + coveralls --finish --service=github env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bf80633..ab2e020 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,23 +1,34 @@ exclude: ^(test/|.tox/|docs) repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.3.0 - hooks: - - id: check-yaml - - id: end-of-file-fixer - - id: trailing-whitespace -- repo: https://github.com/psf/black - rev: 20.8b1 - hooks: - - id: black - args: [--line-length=79] - files: ^libnmap -- repo: https://github.com/pre-commit/mirrors-isort - rev: v5.6.4 - hooks: - - id: isort - args: [--multi-line=3, --line-length=79, --profile=black] -- repo: https://gitlab.com/pycqa/flake8 - rev: 3.8.4 - hooks: - - id: flake8 +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v2.3.0 + hooks: + - id: check-yaml + - id: end-of-file-fixer + - id: trailing-whitespace +- repo: https://github.com/psf/black + rev: 24.3.0 + hooks: + - id: black + args: [--line-length=79] + files: ^libnmap +- repo: https://github.com/pre-commit/mirrors-isort + rev: v5.6.4 + hooks: + - id: isort + args: [--multi-line=3, --line-length=79, --profile=black] +- repo: https://gitlab.com/pycqa/flake8 + rev: 3.8.4 + hooks: + - id: flake8 + exclude: ^libnmap/(test/|docs/|examples/) +- repo: local + hooks: + - id: pytest-check + name: pytest-check + stages: [pre-commit] + types: [python] + entry: pytest --cov=libnmap/ --ignore=libnmap/test/test_backend_plugin_factory.py + language: system + pass_filenames: false + always_run: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 824e7d2..d3fd9ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). (or tries to...) +## [v0.7.3] 2022-09-01 + +### Fixed + +- Linting and coveralls issues + +### Security + +- Fix for security issue on arguments injections - [CVE-2022-30284](https://nvd.nist.gov/vuln/detail/CVE-2022-30284) + ## [v0.7.2] 2020-12-16 ### Added @@ -142,7 +152,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added NmapReport.endtimestr - Added and tested cElementTree support (performance) -### Fixed +### Fixed - Fixed bug when NmapReport.summary is empty @@ -199,10 +209,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added stop() to terminate nmap scan running in background -### Fixed +### Fixed - Bug corrected in missing data from nmap scan output - + ## [v0.3.1] - 17/06/2013 ### Changed diff --git a/CODEOWNERS b/CODEOWNERS index 7b644ee..78c6fef 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1 @@ -* @savon-noir \ No newline at end of file +* @savon-noir diff --git a/LICENCE b/LICENCE index 92138ca..067f271 100644 --- a/LICENCE +++ b/LICENCE @@ -10,4 +10,4 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file + limitations under the License. diff --git a/NOTICE b/NOTICE index 88e053c..615671d 100644 --- a/NOTICE +++ b/NOTICE @@ -1,4 +1,4 @@ python-libnmap Copyright 2020 Ronald Bister -This product includes software developed by Ronald Bister \ No newline at end of file +This product includes software developed by Ronald Bister diff --git a/README.rst b/README.rst index 023726f..d4ab112 100644 --- a/README.rst +++ b/README.rst @@ -115,21 +115,22 @@ You can install libnmap via pip: ronald@brouette:~$ pip install python-libnmap -or via git and dist utils (à l’ancienne): +or via git and pip: .. code:: bash ronald@brouette:~$ git clone https://github.com/savon-noir/python-libnmap.git ronald@brouette:~$ cd python-libnmap - ronald@brouette:~$ python setup.py install + ronald@brouette:~$ pip install . -or via git and pip: +or via git and dist utils (à l’ancienne/deprecated): .. code:: bash ronald@brouette:~$ git clone https://github.com/savon-noir/python-libnmap.git ronald@brouette:~$ cd python-libnmap - ronald@brouette:~$ pip install . + ronald@brouette:~$ python setup.py install + Examples -------- diff --git a/TODO b/TODO index 6aa4c65..bf03075 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -0.7.2: clean-up blacked code and pylint it +0.7.2: clean-up blacked code and pylint it 0.7.2: add unittest for defusedxml to fix billionlaugh and external entities security issues 0.7.2: Change License from CC-BY to Apache 2.0 0.7.2: Enabled defusedxml support as preferred option for parsing () @@ -10,7 +10,7 @@ release: - changelog date not respecting KACL specs - check https://github.com/anton-yurchenko/git-release -- https://github.com/sean0x42/markdown-extract +- https://github.com/sean0x42/markdown-extract Contribution file: - specify where version needs to be set before adding tag to commit diff --git a/config/database.yml b/config/database.yml index 7a28ee5..5c7a0f7 100644 --- a/config/database.yml +++ b/config/database.yml @@ -4,7 +4,6 @@ sqlite: timeout: 500 mysql: adapter: mysql2 - database: poulet + database: poulet username: encoding: utf8 - diff --git a/docs/diff.rst b/docs/diff.rst index 658c3f9..e9950d9 100644 --- a/docs/diff.rst +++ b/docs/diff.rst @@ -17,7 +17,7 @@ Those methods return a python set() of keys which have been changed/added/remove object to another. The keys of each objects could be found in the implementation of the get_dict() methods of the compared objects. -The example below is a heavy version of going through all nested objects to see waht has changed after a diff:: +The example below is a heavy version of going through all nested objects to see what has changed after a diff:: #!/usr/bin/env python diff --git a/docs/index.rst b/docs/index.rst index 7e89213..7226bbf 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -21,7 +21,7 @@ libnmap is a python toolkit for manipulating nmap. It currently offers the follo - plugins: enables you to support datastores for your scan results directly in the "NmapReport" object from report module - mongodb: only plugin implemented so far, ultra basic, for POC purpose only - - sqlalchemy: Allow to store/retreive NmapReport to sqlite/mysql/... all engine supported by sqlalchemy + - sqlalchemy: Allow to store/retrieve NmapReport to sqlite/mysql/... all engine supported by sqlalchemy - rabbitMQ : todo - couchdb: todo - elastic search: todo diff --git a/docs/parser.rst b/docs/parser.rst index c0a1a70..09bc5d2 100644 --- a/docs/parser.rst +++ b/docs/parser.rst @@ -63,7 +63,7 @@ Using libnmap.parser module NmapParser parse the whole data and returns nmap objects usable via their documented API. -The NmapParser should never be instanciated and only the following methods should be called: +The NmapParser should never be instantiated and only the following methods should be called: - NmapParser.parse(string) - NmapParser.parse_fromfile(file_path) diff --git a/libnmap/objects/host.py b/libnmap/objects/host.py index 9425e2e..dba1653 100644 --- a/libnmap/objects/host.py +++ b/libnmap/objects/host.py @@ -38,6 +38,7 @@ def __init__( self._status = status if status is not None else {} self._services = services if services is not None else [] self._extras = extras if extras is not None else {} + self._extraports = self._extras.get("extraports", None) self._osfingerprinted = False self.os = None if "os" in self._extras: @@ -462,34 +463,14 @@ def id(self): return self.address @property - def extraports_state(self): + def extraports(self): """ - dictionnary containing state and amount of extra ports scanned - for which a common state, usually, closed was discovered. + Returns a list of extraport dict with + with struct { count: "123", state: "filtered, extrareasons: [{}] } - :return: dict with keys 'state' and 'count' or None + :return: list of extraport dict """ - _xtrports = self._extras.get("extraports", None) - - if _xtrports is None: - return None - - return {"state": _xtrports["state"], "count": _xtrports["count"]} - - @property - def extraports_reasons(self): - """ - dictionnary containing reasons why extra ports scanned - for which a common state, usually, closed was discovered. - - :return: array of dict containing keys 'state' and 'count' or None - """ - r = self._extras.get("extraports", {}) - - if r is None: - return None - - return r.get("reasons", None) + return self._extraports def get_dict(self): """ diff --git a/libnmap/objects/os.py b/libnmap/objects/os.py index 912c32e..2d2e109 100644 --- a/libnmap/objects/os.py +++ b/libnmap/objects/os.py @@ -89,7 +89,6 @@ def __init__(self, osmatch_dict): pass def add_osclass(self, osclass_obj): - """ Add a NmapOSClass object to the OSMatch object. This method is useful to implement compatibility with older versions of NMAP @@ -269,7 +268,7 @@ def __repr__(self): class NmapOSFingerprint(object): """ NmapOSFingerprint is a easier API for using os fingerprinting. - Data for OS fingerprint ( tag) is instanciated from + Data for OS fingerprint ( tag) is instantiated from a NmapOSFingerprint which is accessible in NmapHost via NmapHost.os """ diff --git a/libnmap/objects/report.py b/libnmap/objects/report.py index cd9a556..3a18ed6 100644 --- a/libnmap/objects/report.py +++ b/libnmap/objects/report.py @@ -254,7 +254,7 @@ def elapsed(self): @property def hosts_up(self): """ - Accessor returning the numer of host detected + Accessor returning the number of host detected as 'up' during the scan. :return: integer (0 >= or -1) @@ -270,7 +270,7 @@ def hosts_up(self): @property def hosts_down(self): """ - Accessor returning the numer of host detected + Accessor returning the number of host detected as 'down' during the scan. :return: integer (0 >= or -1) @@ -411,6 +411,11 @@ def __ne__(self, other): return rval def __repr__(self): + """ + Returns a string-based representation of the report + + :return: string + """ return "{0}: started at {1} hosts up {2}/{3}".format( self.__class__.__name__, self.started, diff --git a/libnmap/parser.py b/libnmap/parser.py index 21f6a12..e657d1c 100644 --- a/libnmap/parser.py +++ b/libnmap/parser.py @@ -34,7 +34,9 @@ def parse(cls, nmap_data=None, data_type="XML", incomplete=False): :param incomplete: enable you to parse interrupted nmap scans \ and/or incomplete nmap xml blocks by adding a at \ - the end of the scan. + the end of the scan. Be aware that this flag does not work for \ + already valid XML files, because adding an XML tag will \ + invalidate the XML. :type incomplete: boolean As of today, only XML parsing is supported. @@ -305,6 +307,7 @@ def _parse_xml_host(cls, scanhost_data): "tcpsequence", "ipidsequence", "tcptssequence", + "trace", "times", ] for xh in xelement: @@ -326,6 +329,9 @@ def _parse_xml_host(cls, scanhost_data): elif xh.tag == "hostscript": _host_scripts = cls.__parse_host_scripts(xh) _host_extras.update({"hostscript": _host_scripts}) + elif xh.tag == "trace": + _trace = cls.__parse_trace(xh) + _host_extras.update({"trace": _trace}) elif xh.tag in extra_tags: _host_extras[xh.tag] = cls.__format_attributes(xh) # else: @@ -379,17 +385,14 @@ def _parse_xml_ports(cls, scanports_data): xelement = cls.__format_element(scanports_data) - rdict = {"ports": [], "extraports": None} + rdict = {"ports": [], "extraports": []} for xservice in xelement: if xservice.tag == "port": nport = cls._parse_xml_port(xservice) rdict["ports"].append(nport) elif xservice.tag == "extraports": extraports = cls.__parse_extraports(xservice) - rdict["extraports"] = extraports - # else: - # print "struct port unknown attr: %s value: %s" % - # (h.tag, h.get(h.tag)) + rdict["extraports"].append(extraports) return rdict @classmethod @@ -466,20 +469,18 @@ def __parse_extraports(cls, extraports_data): :param extraports_data: XML data for extraports :type extraports_data: xml.ElementTree.Element or a string - :return: python dict with following keys: state, count, reason + :return: python dict with following keys: state, count, reasons """ - rdict = {"state": "", "count": "", "reasons": []} + rdict = {"state": "", "count": "", "extrareasons": []} xelement = cls.__format_element(extraports_data) extraports_dict = cls.__format_attributes(xelement) - if "state" in extraports_dict: - rdict["state"] = extraports_dict - if "count" in extraports_dict: - rdict["count"] = extraports_dict + rdict["state"] = extraports_dict.get("state", None) + rdict["count"] = extraports_dict.get("count", None) for xelt in xelement: if xelt.tag == "extrareasons": extrareasons_dict = cls.__format_attributes(xelt) - rdict["reasons"].append(extrareasons_dict) + rdict["extrareasons"].append(extrareasons_dict) return rdict @classmethod @@ -680,6 +681,39 @@ def __parse_runstats(cls, scanrunstats_data): return rdict + @classmethod + def __parse_trace(cls, scantrace_data): + """ + Private method parsing a portion of a nmap scan result. + Receives a XML tag. + + :param scantrace_data: XML tag from a nmap scan + :type scantrace_data: xml.ElementTree.Element or a string + + :return: python dict representing the XML trace tag + """ + + xelement = cls.__format_element(scantrace_data) + _trace_attrs = cls.__format_attributes(xelement) + + rdict = {} + + if "proto" in _trace_attrs: + rdict["proto"] = _trace_attrs["proto"] + + if "port" in _trace_attrs: + rdict["port"] = _trace_attrs["port"] + + rdict["hops"] = [] + for xmltag in xelement: + if xmltag.tag in ["hop"]: + rdict["hops"].append(cls.__format_attributes(xmltag)) + else: + exmsg = "Unexcepted node in : {0}".format(xmltag.tag) + raise NmapParserException(exmsg) + + return rdict + @staticmethod def __format_element(elt_data): """ diff --git a/libnmap/plugins/backendplugin.py b/libnmap/plugins/backendplugin.py index cfbf393..0a7c9a5 100644 --- a/libnmap/plugins/backendplugin.py +++ b/libnmap/plugins/backendplugin.py @@ -30,7 +30,7 @@ def delete(self, id): def get(self, id): """ - retreive a NmapReport from the backend + retrieve a NmapReport from the backend :param id: str :return: NmapReport """ diff --git a/libnmap/plugins/es.py b/libnmap/plugins/es.py index 688a3d2..8db8623 100644 --- a/libnmap/plugins/es.py +++ b/libnmap/plugins/es.py @@ -48,7 +48,7 @@ def delete(self, id): def get(self, id): """ - retreive a NmapReport from the backend + retrieve a NmapReport from the backend :param id: str :return: NmapReport """ diff --git a/libnmap/plugins/mongodb.py b/libnmap/plugins/mongodb.py index 1e707f3..80bfe1a 100644 --- a/libnmap/plugins/mongodb.py +++ b/libnmap/plugins/mongodb.py @@ -15,7 +15,7 @@ class NmapMongodbPlugin(NmapBackendPlugin): Implementation is made using pymongo Object of this class must be create via the BackendPluginFactory.create(**url) where url is a named dict like - {'plugin_name': "mongodb"} this dict may reeive all the param + {'plugin_name': "mongodb"} this dict may receive all the param MongoClient() support """ diff --git a/libnmap/plugins/sql.py b/libnmap/plugins/sql.py index dc0ede4..95eb36f 100644 --- a/libnmap/plugins/sql.py +++ b/libnmap/plugins/sql.py @@ -77,7 +77,7 @@ def __init__(self, **kwargs): - create all the necessary obj to discuss with the DB - create all the mapping(ORM) - todo : suport the : sqlalchemy.engine_from_config + todo : support the : sqlalchemy.engine_from_config :param **kwargs: :raises: ValueError if no url is given, @@ -121,7 +121,7 @@ def insert(self, nmap_report): def get(self, report_id=None): """ - retreive a NmapReport from the backend + retrieve a NmapReport from the backend :param id: str diff --git a/libnmap/process.py b/libnmap/process.py index 639a7f1..a2825cc 100644 --- a/libnmap/process.py +++ b/libnmap/process.py @@ -4,6 +4,7 @@ import os import platform import shlex +import string import subprocess import warnings from threading import Thread @@ -19,10 +20,9 @@ class NmapTask(object): - """ NmapTask is a internal class used by process. Each time nmap - starts a new task during the scan, a new class will be instanciated. + starts a new task during the scan, a new class will be instantiated. Classes examples are: "Ping Scan", "NSE script", "DNS Resolve",.. To each class an estimated time to complete is assigned and updated at least every second within the NmapProcess. @@ -45,7 +45,6 @@ def __init__(self, name, starttime=0, extrainfo=""): class NmapProcess(Thread): - """ NmapProcess is a class which wraps around the nmap executable. @@ -129,6 +128,9 @@ def __init__( "Supplied target list should be either a string or a list" ) + for target in self.__nmap_targets: + self.__validate_target(target) + self._nmap_options = set(options.split()) if safe_mode and not self._nmap_options.isdisjoint(unsafe_opts): raise Exception( @@ -215,7 +217,7 @@ def _ensure_user_exists(self, username=""): def sudo_run(self, run_as="root"): """ Public method enabling the library's user to run the scan with - priviledges via sudo. The sudo configuration should be set manually + privileges via sudo. The sudo configuration should be set manually on the local system otherwise sudo will prompt for a password. This method alters the command line by prefixing the sudo command to nmap and will then call self.run() @@ -245,7 +247,7 @@ def sudo_run(self, run_as="root"): def sudo_run_background(self, run_as="root"): """ Public method enabling the library's user to run in background a - nmap scan with priviledges via sudo. + nmap scan with privileges via sudo. The sudo configuration should be set manually on the local system otherwise sudo will prompt for a password. This method alters the command line by prefixing the sudo command to @@ -480,6 +482,41 @@ def __build_windows_cmdline(self): cmdline += self.__nmap_targets # already a list return cmdline + @staticmethod + def __validate_target(target): + """ + Check if a provided target is valid. This function was created + in order to address CVE-2022-30284 + + See https://nmap.org/book/man-target-specification.html for all the + ways targets can be specified + + This function verifies the following: + + - matches the user specified target against a list of allowed chars + - check if dashes are used at the start or at the end of target + + FQDN can contain dashes anywhere except at the beginning or end + This check also fixes/prevents CVE-2022-30284, which depends on being + able to pass options such as --script as a target + + :return: False if target contains forbidden characters + """ + allowed_characters = frozenset( + string.ascii_letters + string.digits + "-.:/% " + ) + if not set(target).issubset(allowed_characters): + raise Exception( + "Target '{}' contains invalid characters".format(target) + ) + elif target.startswith("-") or target.endswith("-"): + raise Exception( + "Target '{}' cannot begin or end with a dash ('-')".format( + target + ) + ) + return True + @property def command(self): """ diff --git a/libnmap/test/files/1_host_ping.xml b/libnmap/test/files/1_host_ping.xml index 92fde18..0a0b797 100644 --- a/libnmap/test/files/1_host_ping.xml +++ b/libnmap/test/files/1_host_ping.xml @@ -16,4 +16,4 @@ - \ No newline at end of file + diff --git a/libnmap/test/files/2_hosts.json b/libnmap/test/files/2_hosts.json index f7099ea..985f293 100644 --- a/libnmap/test/files/2_hosts.json +++ b/libnmap/test/files/2_hosts.json @@ -1 +1 @@ -{"__NmapReport__": {"_nmaprun": {"scanner": "nmap", "args": "nmap -sS -vv -oX 2_hosts.xml localhost scanme.nmap.org", "start": "1361737906", "startstr": "Sun Feb 24 21:31:46 2013", "version": "5.51", "xmloutputversion": "1.03"}, "_scaninfo": {"type": "syn", "protocol": "tcp", "numservices": "1000", "services": "1,3-4,6-7,9,13,17,19-26,30,32-33,37,42-43,49,53,70,79-85,88-90,99-100,106,109-111,113,119,125,135,139,143-144,146,161,163,179,199,211-212,222,254-256,259,264,280,301,306,311,340,366,389,406-407,416-417,425,427,443-445,458,464-465,481,497,500,512-515,524,541,543-545,548,554-555,563,587,593,616-617,625,631,636,646,648,666-668,683,687,691,700,705,711,714,720,722,726,749,765,777,783,787,800-801,808,843,873,880,888,898,900-903,911-912,981,987,990,992-993,995,999-1002,1007,1009-1011,1021-1100,1102,1104-1108,1110-1114,1117,1119,1121-1124,1126,1130-1132,1137-1138,1141,1145,1147-1149,1151-1152,1154,1163-1166,1169,1174-1175,1183,1185-1187,1192,1198-1199,1201,1213,1216-1218,1233-1234,1236,1244,1247-1248,1259,1271-1272,1277,1287,1296,1300-1301,1309-1311,1322,1328,1334,1352,1417,1433-1434,1443,1455,1461,1494,1500-1501,1503,1521,1524,1533,1556,1580,1583,1594,1600,1641,1658,1666,1687-1688,1700,1717-1721,1723,1755,1761,1782-1783,1801,1805,1812,1839-1840,1862-1864,1875,1900,1914,1935,1947,1971-1972,1974,1984,1998-2010,2013,2020-2022,2030,2033-2035,2038,2040-2043,2045-2049,2065,2068,2099-2100,2103,2105-2107,2111,2119,2121,2126,2135,2144,2160-2161,2170,2179,2190-2191,2196,2200,2222,2251,2260,2288,2301,2323,2366,2381-2383,2393-2394,2399,2401,2492,2500,2522,2525,2557,2601-2602,2604-2605,2607-2608,2638,2701-2702,2710,2717-2718,2725,2800,2809,2811,2869,2875,2909-2910,2920,2967-2968,2998,3000-3001,3003,3005-3007,3011,3013,3017,3030-3031,3052,3071,3077,3128,3168,3211,3221,3260-3261,3268-3269,3283,3300-3301,3306,3322-3325,3333,3351,3367,3369-3372,3389-3390,3404,3476,3493,3517,3527,3546,3551,3580,3659,3689-3690,3703,3737,3766,3784,3800-3801,3809,3814,3826-3828,3851,3869,3871,3878,3880,3889,3905,3914,3918,3920,3945,3971,3986,3995,3998,4000-4006,4045,4111,4125-4126,4129,4224,4242,4279,4321,4343,4443-4446,4449,4550,4567,4662,4848,4899-4900,4998,5000-5004,5009,5030,5033,5050-5051,5054,5060-5061,5080,5087,5100-5102,5120,5190,5200,5214,5221-5222,5225-5226,5269,5280,5298,5357,5405,5414,5431-5432,5440,5500,5510,5544,5550,5555,5560,5566,5631,5633,5666,5678-5679,5718,5730,5800-5802,5810-5811,5815,5822,5825,5850,5859,5862,5877,5900-5904,5906-5907,5910-5911,5915,5922,5925,5950,5952,5959-5963,5987-5989,5998-6007,6009,6025,6059,6100-6101,6106,6112,6123,6129,6156,6346,6389,6502,6510,6543,6547,6565-6567,6580,6646,6666-6669,6689,6692,6699,6779,6788-6789,6792,6839,6881,6901,6969,7000-7002,7004,7007,7019,7025,7070,7100,7103,7106,7200-7201,7402,7435,7443,7496,7512,7625,7627,7676,7741,7777-7778,7800,7911,7920-7921,7937-7938,7999-8002,8007-8011,8021-8022,8031,8042,8045,8080-8090,8093,8099-8100,8180-8181,8192-8194,8200,8222,8254,8290-8292,8300,8333,8383,8400,8402,8443,8500,8600,8649,8651-8652,8654,8701,8800,8873,8888,8899,8994,9000-9003,9009-9011,9040,9050,9071,9080-9081,9090-9091,9099-9103,9110-9111,9200,9207,9220,9290,9415,9418,9485,9500,9502-9503,9535,9575,9593-9595,9618,9666,9876-9878,9898,9900,9917,9929,9943-9944,9968,9998-10004,10009-10010,10012,10024-10025,10082,10180,10215,10243,10566,10616-10617,10621,10626,10628-10629,10778,11110-11111,11967,12000,12174,12265,12345,13456,13722,13782-13783,14000,14238,14441-14442,15000,15002-15004,15660,15742,16000-16001,16012,16016,16018,16080,16113,16992-16993,17877,17988,18040,18101,18988,19101,19283,19315,19350,19780,19801,19842,20000,20005,20031,20221-20222,20828,21571,22939,23502,24444,24800,25734-25735,26214,27000,27352-27353,27355-27356,27715,28201,30000,30718,30951,31038,31337,32768-32785,33354,33899,34571-34573,35500,38292,40193,40911,41511,42510,44176,44442-44443,44501,45100,48080,49152-49161,49163,49165,49167,49175-49176,49400,49999-50003,50006,50300,50389,50500,50636,50800,51103,51493,52673,52822,52848,52869,54045,54328,55055-55056,55555,55600,56737-56738,57294,57797,58080,60020,60443,61532,61900,62078,63331,64623,64680,65000,65129,65389"}, "_hosts": [{"__NmapHost__": {"_starttime": "1361737906", "_endtime": "1361737906", "_hostnames": ["localhost", "localhost"], "_status": {"state": "up", "reason": "localhost-response"}, "_services": [{"__NmapService__": {"_portid": 22, "_protocol": "tcp", "_state": {"state": "open", "reason": "syn-ack", "reason_ttl": "64"}, "_service": {"name": "ssh", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "syn-ack", "_reason_ip": "", "_reason_ttl": "64", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}, {"__NmapService__": {"_portid": 25, "_protocol": "tcp", "_state": {"state": "open", "reason": "syn-ack", "reason_ttl": "64"}, "_service": {"name": "smtp", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "syn-ack", "_reason_ip": "", "_reason_ttl": "64", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}, {"__NmapService__": {"_portid": 111, "_protocol": "tcp", "_state": {"state": "open", "reason": "syn-ack", "reason_ttl": "64"}, "_service": {"name": "rpcbind", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "syn-ack", "_reason_ip": "", "_reason_ttl": "64", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}, {"__NmapService__": {"_portid": 631, "_protocol": "tcp", "_state": {"state": "open", "reason": "syn-ack", "reason_ttl": "64"}, "_service": {"name": "ipp", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "syn-ack", "_reason_ip": "", "_reason_ttl": "64", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}, {"__NmapService__": {"_portid": 3306, "_protocol": "tcp", "_state": {"state": "open", "reason": "syn-ack", "reason_ttl": "64"}, "_service": {"name": "mysql", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "syn-ack", "_reason_ip": "", "_reason_ttl": "64", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}], "_extras": {"extraports": {"state": {"state": "closed", "count": "995"}, "count": {"state": "closed", "count": "995"}, "reasons": [{"reason": "resets", "count": "995"}]}, "times": {"srtt": "7", "rttvar": "0", "to": "100000"}}, "_osfingerprinted": false, "os": {"__NmapOSFingerprint__": {"_NmapOSFingerprint__osmatches": [], "_NmapOSFingerprint__ports_used": [], "_NmapOSFingerprint__fingerprints": []}}, "_ipv4_addr": "127.0.0.1", "_ipv6_addr": null, "_mac_addr": null, "_vendor": null, "_main_address": "127.0.0.1", "_address": [{"addr": "127.0.0.1", "addrtype": "ipv4"}]}}, {"__NmapHost__": {"_starttime": "1361737906", "_endtime": "1361738040", "_hostnames": ["scanme.nmap.org", "scanme.nmap.org"], "_status": {"state": "up", "reason": "echo-reply"}, "_services": [{"__NmapService__": {"_portid": 22, "_protocol": "tcp", "_state": {"state": "open", "reason": "syn-ack", "reason_ttl": "53"}, "_service": {"name": "ssh", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "syn-ack", "_reason_ip": "", "_reason_ttl": "53", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}, {"__NmapService__": {"_portid": 25, "_protocol": "tcp", "_state": {"state": "filtered", "reason": "admin-prohibited", "reason_ttl": "253", "reason_ip": "109.133.192.1"}, "_service": {"name": "smtp", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "admin-prohibited", "_reason_ip": "109.133.192.1", "_reason_ttl": "253", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}, {"__NmapService__": {"_portid": 80, "_protocol": "tcp", "_state": {"state": "open", "reason": "syn-ack", "reason_ttl": "51"}, "_service": {"name": "http", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "syn-ack", "_reason_ip": "", "_reason_ttl": "51", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}, {"__NmapService__": {"_portid": 9929, "_protocol": "tcp", "_state": {"state": "open", "reason": "syn-ack", "reason_ttl": "53"}, "_service": {"name": "nping-echo", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "syn-ack", "_reason_ip": "", "_reason_ttl": "53", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}], "_extras": {"extraports": {"state": {"state": "closed", "count": "996"}, "count": {"state": "closed", "count": "996"}, "reasons": [{"reason": "resets", "count": "996"}]}, "times": {"srtt": "177425", "rttvar": "1981", "to": "185349"}}, "_osfingerprinted": false, "os": {"__NmapOSFingerprint__": {"_NmapOSFingerprint__osmatches": [], "_NmapOSFingerprint__ports_used": [], "_NmapOSFingerprint__fingerprints": []}}, "_ipv4_addr": "74.207.244.221", "_ipv6_addr": null, "_mac_addr": null, "_vendor": null, "_main_address": "74.207.244.221", "_address": [{"addr": "74.207.244.221", "addrtype": "ipv4"}]}}], "_runstats": {"finished": {"time": "1361738040", "timestr": "Sun Feb 24 21:34:00 2013", "elapsed": "134.36", "summary": "Nmap done at Sun Feb 24 21:34:00 2013; 2 IP addresses (2 hosts up) scanned in 134.36 seconds", "exit": "success"}, "hosts": {"up": "2", "down": "0", "total": "2"}}}} \ No newline at end of file +{"__NmapReport__": {"_nmaprun": {"scanner": "nmap", "args": "nmap -sS -vv -oX 2_hosts.xml localhost scanme.nmap.org", "start": "1361737906", "startstr": "Sun Feb 24 21:31:46 2013", "version": "5.51", "xmloutputversion": "1.03"}, "_scaninfo": {"type": "syn", "protocol": "tcp", "numservices": "1000", "services": "1,3-4,6-7,9,13,17,19-26,30,32-33,37,42-43,49,53,70,79-85,88-90,99-100,106,109-111,113,119,125,135,139,143-144,146,161,163,179,199,211-212,222,254-256,259,264,280,301,306,311,340,366,389,406-407,416-417,425,427,443-445,458,464-465,481,497,500,512-515,524,541,543-545,548,554-555,563,587,593,616-617,625,631,636,646,648,666-668,683,687,691,700,705,711,714,720,722,726,749,765,777,783,787,800-801,808,843,873,880,888,898,900-903,911-912,981,987,990,992-993,995,999-1002,1007,1009-1011,1021-1100,1102,1104-1108,1110-1114,1117,1119,1121-1124,1126,1130-1132,1137-1138,1141,1145,1147-1149,1151-1152,1154,1163-1166,1169,1174-1175,1183,1185-1187,1192,1198-1199,1201,1213,1216-1218,1233-1234,1236,1244,1247-1248,1259,1271-1272,1277,1287,1296,1300-1301,1309-1311,1322,1328,1334,1352,1417,1433-1434,1443,1455,1461,1494,1500-1501,1503,1521,1524,1533,1556,1580,1583,1594,1600,1641,1658,1666,1687-1688,1700,1717-1721,1723,1755,1761,1782-1783,1801,1805,1812,1839-1840,1862-1864,1875,1900,1914,1935,1947,1971-1972,1974,1984,1998-2010,2013,2020-2022,2030,2033-2035,2038,2040-2043,2045-2049,2065,2068,2099-2100,2103,2105-2107,2111,2119,2121,2126,2135,2144,2160-2161,2170,2179,2190-2191,2196,2200,2222,2251,2260,2288,2301,2323,2366,2381-2383,2393-2394,2399,2401,2492,2500,2522,2525,2557,2601-2602,2604-2605,2607-2608,2638,2701-2702,2710,2717-2718,2725,2800,2809,2811,2869,2875,2909-2910,2920,2967-2968,2998,3000-3001,3003,3005-3007,3011,3013,3017,3030-3031,3052,3071,3077,3128,3168,3211,3221,3260-3261,3268-3269,3283,3300-3301,3306,3322-3325,3333,3351,3367,3369-3372,3389-3390,3404,3476,3493,3517,3527,3546,3551,3580,3659,3689-3690,3703,3737,3766,3784,3800-3801,3809,3814,3826-3828,3851,3869,3871,3878,3880,3889,3905,3914,3918,3920,3945,3971,3986,3995,3998,4000-4006,4045,4111,4125-4126,4129,4224,4242,4279,4321,4343,4443-4446,4449,4550,4567,4662,4848,4899-4900,4998,5000-5004,5009,5030,5033,5050-5051,5054,5060-5061,5080,5087,5100-5102,5120,5190,5200,5214,5221-5222,5225-5226,5269,5280,5298,5357,5405,5414,5431-5432,5440,5500,5510,5544,5550,5555,5560,5566,5631,5633,5666,5678-5679,5718,5730,5800-5802,5810-5811,5815,5822,5825,5850,5859,5862,5877,5900-5904,5906-5907,5910-5911,5915,5922,5925,5950,5952,5959-5963,5987-5989,5998-6007,6009,6025,6059,6100-6101,6106,6112,6123,6129,6156,6346,6389,6502,6510,6543,6547,6565-6567,6580,6646,6666-6669,6689,6692,6699,6779,6788-6789,6792,6839,6881,6901,6969,7000-7002,7004,7007,7019,7025,7070,7100,7103,7106,7200-7201,7402,7435,7443,7496,7512,7625,7627,7676,7741,7777-7778,7800,7911,7920-7921,7937-7938,7999-8002,8007-8011,8021-8022,8031,8042,8045,8080-8090,8093,8099-8100,8180-8181,8192-8194,8200,8222,8254,8290-8292,8300,8333,8383,8400,8402,8443,8500,8600,8649,8651-8652,8654,8701,8800,8873,8888,8899,8994,9000-9003,9009-9011,9040,9050,9071,9080-9081,9090-9091,9099-9103,9110-9111,9200,9207,9220,9290,9415,9418,9485,9500,9502-9503,9535,9575,9593-9595,9618,9666,9876-9878,9898,9900,9917,9929,9943-9944,9968,9998-10004,10009-10010,10012,10024-10025,10082,10180,10215,10243,10566,10616-10617,10621,10626,10628-10629,10778,11110-11111,11967,12000,12174,12265,12345,13456,13722,13782-13783,14000,14238,14441-14442,15000,15002-15004,15660,15742,16000-16001,16012,16016,16018,16080,16113,16992-16993,17877,17988,18040,18101,18988,19101,19283,19315,19350,19780,19801,19842,20000,20005,20031,20221-20222,20828,21571,22939,23502,24444,24800,25734-25735,26214,27000,27352-27353,27355-27356,27715,28201,30000,30718,30951,31038,31337,32768-32785,33354,33899,34571-34573,35500,38292,40193,40911,41511,42510,44176,44442-44443,44501,45100,48080,49152-49161,49163,49165,49167,49175-49176,49400,49999-50003,50006,50300,50389,50500,50636,50800,51103,51493,52673,52822,52848,52869,54045,54328,55055-55056,55555,55600,56737-56738,57294,57797,58080,60020,60443,61532,61900,62078,63331,64623,64680,65000,65129,65389"}, "_hosts": [{"__NmapHost__": {"_starttime": "1361737906", "_endtime": "1361737906", "_hostnames": ["localhost", "localhost"], "_status": {"state": "up", "reason": "localhost-response"}, "_services": [{"__NmapService__": {"_portid": 22, "_protocol": "tcp", "_state": {"state": "open", "reason": "syn-ack", "reason_ttl": "64"}, "_service": {"name": "ssh", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "syn-ack", "_reason_ip": "", "_reason_ttl": "64", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}, {"__NmapService__": {"_portid": 25, "_protocol": "tcp", "_state": {"state": "open", "reason": "syn-ack", "reason_ttl": "64"}, "_service": {"name": "smtp", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "syn-ack", "_reason_ip": "", "_reason_ttl": "64", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}, {"__NmapService__": {"_portid": 111, "_protocol": "tcp", "_state": {"state": "open", "reason": "syn-ack", "reason_ttl": "64"}, "_service": {"name": "rpcbind", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "syn-ack", "_reason_ip": "", "_reason_ttl": "64", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}, {"__NmapService__": {"_portid": 631, "_protocol": "tcp", "_state": {"state": "open", "reason": "syn-ack", "reason_ttl": "64"}, "_service": {"name": "ipp", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "syn-ack", "_reason_ip": "", "_reason_ttl": "64", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}, {"__NmapService__": {"_portid": 3306, "_protocol": "tcp", "_state": {"state": "open", "reason": "syn-ack", "reason_ttl": "64"}, "_service": {"name": "mysql", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "syn-ack", "_reason_ip": "", "_reason_ttl": "64", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}], "_extras": {"extraports": [{"state": "closed", "count": "995", "extrareasons": [{"reason": "resets", "count": "995"}]}], "times": {"srtt": "7", "rttvar": "0", "to": "100000"}}, "_extraports": [{"state": "closed", "count": "995", "extrareasons": [{"reason": "resets", "count": "995"}]}], "_osfingerprinted": false, "os": {"__NmapOSFingerprint__": {"_NmapOSFingerprint__osmatches": [], "_NmapOSFingerprint__ports_used": [], "_NmapOSFingerprint__fingerprints": []}}, "_ipv4_addr": "127.0.0.1", "_ipv6_addr": null, "_mac_addr": null, "_vendor": null, "_main_address": "127.0.0.1", "_address": [{"addr": "127.0.0.1", "addrtype": "ipv4"}]}}, {"__NmapHost__": {"_starttime": "1361737906", "_endtime": "1361738040", "_hostnames": ["scanme.nmap.org", "scanme.nmap.org"], "_status": {"state": "up", "reason": "echo-reply"}, "_services": [{"__NmapService__": {"_portid": 22, "_protocol": "tcp", "_state": {"state": "open", "reason": "syn-ack", "reason_ttl": "53"}, "_service": {"name": "ssh", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "syn-ack", "_reason_ip": "", "_reason_ttl": "53", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}, {"__NmapService__": {"_portid": 25, "_protocol": "tcp", "_state": {"state": "filtered", "reason": "admin-prohibited", "reason_ttl": "253", "reason_ip": "109.133.192.1"}, "_service": {"name": "smtp", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "admin-prohibited", "_reason_ip": "109.133.192.1", "_reason_ttl": "253", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}, {"__NmapService__": {"_portid": 80, "_protocol": "tcp", "_state": {"state": "open", "reason": "syn-ack", "reason_ttl": "51"}, "_service": {"name": "http", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "syn-ack", "_reason_ip": "", "_reason_ttl": "51", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}, {"__NmapService__": {"_portid": 9929, "_protocol": "tcp", "_state": {"state": "open", "reason": "syn-ack", "reason_ttl": "53"}, "_service": {"name": "nping-echo", "method": "table", "conf": "3", "cpelist": []}, "_cpelist": [], "_owner": "", "_reason": "syn-ack", "_reason_ip": "", "_reason_ttl": "53", "_servicefp": "", "_tunnel": "", "_service_extras": {"scripts": []}}}], "_extras": {"extraports": [{"state": "closed", "count": "996", "extrareasons": [{"reason": "resets", "count": "996"}]}], "times": {"srtt": "177425", "rttvar": "1981", "to": "185349"}}, "_extraports": [{"state": "closed", "count": "996", "extrareasons": [{"reason": "resets", "count": "996"}]}], "_osfingerprinted": false, "os": {"__NmapOSFingerprint__": {"_NmapOSFingerprint__osmatches": [], "_NmapOSFingerprint__ports_used": [], "_NmapOSFingerprint__fingerprints": []}}, "_ipv4_addr": "74.207.244.221", "_ipv6_addr": null, "_mac_addr": null, "_vendor": null, "_main_address": "74.207.244.221", "_address": [{"addr": "74.207.244.221", "addrtype": "ipv4"}]}}], "_runstats": {"finished": {"time": "1361738040", "timestr": "Sun Feb 24 21:34:00 2013", "elapsed": "134.36", "summary": "Nmap done at Sun Feb 24 21:34:00 2013; 2 IP addresses (2 hosts up) scanned in 134.36 seconds", "exit": "success"}, "hosts": {"up": "2", "down": "0", "total": "2"}}}} diff --git a/libnmap/test/files/defused_et_included.xml b/libnmap/test/files/defused_et_included.xml index 82e04b6..59472a0 100644 --- a/libnmap/test/files/defused_et_included.xml +++ b/libnmap/test/files/defused_et_included.xml @@ -3,4 +3,4 @@ text texttail - \ No newline at end of file + diff --git a/libnmap/test/files/defused_et_local_includer.xml b/libnmap/test/files/defused_et_local_includer.xml index d063ae6..6e90be8 100644 --- a/libnmap/test/files/defused_et_local_includer.xml +++ b/libnmap/test/files/defused_et_local_includer.xml @@ -2,4 +2,4 @@ ]> - \ No newline at end of file + diff --git a/libnmap/test/files/diff_1_host_ping_mac_changed.xml b/libnmap/test/files/diff_1_host_ping_mac_changed.xml index 91d0429..be92c66 100644 --- a/libnmap/test/files/diff_1_host_ping_mac_changed.xml +++ b/libnmap/test/files/diff_1_host_ping_mac_changed.xml @@ -16,4 +16,4 @@ - \ No newline at end of file + diff --git a/libnmap/test/files/dionaea_scan.xml b/libnmap/test/files/dionaea_scan.xml index f891430..14e3b26 100644 --- a/libnmap/test/files/dionaea_scan.xml +++ b/libnmap/test/files/dionaea_scan.xml @@ -342,4 +342,4 @@ - \ No newline at end of file + diff --git a/libnmap/test/files/extra_ports.xml b/libnmap/test/files/extra_ports.xml new file mode 100644 index 0000000..26b650a --- /dev/null +++ b/libnmap/test/files/extra_ports.xml @@ -0,0 +1,350 @@ + + + + + + + + + + + + +cpe:/a:mysql:mysql:5.7.16 + + +cpe:/a:memcached:memcached:1.4.25 + + + + + + + + diff --git a/libnmap/test/files/test_osclass.xml b/libnmap/test/files/test_osclass.xml index bcfd9c6..68850bb 100644 --- a/libnmap/test/files/test_osclass.xml +++ b/libnmap/test/files/test_osclass.xml @@ -43,4 +43,4 @@ - \ No newline at end of file + diff --git a/libnmap/test/test_extraports.py b/libnmap/test/test_extraports.py new file mode 100644 index 0000000..c52a17a --- /dev/null +++ b/libnmap/test/test_extraports.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os +import unittest + +from libnmap.parser import NmapParser, NmapParserException + + +class TestExtraPorts(unittest.TestCase): + def setUp(self): + fdir = os.path.dirname(os.path.realpath(__file__)) + _extrareasons = [ + {"reason": "filtered", "count": "3"}, + {"reason": "resets", "count": "7"}, + ] + self.flist = [ + { + "path": "%s/%s" % (fdir, "files/extra_ports.xml"), + "extrareasons": _extrareasons, + } + ] + + def test_extraports(self): + for fentry in self.flist: + rep1 = NmapParser.parse_fromfile(fentry["path"]) + ep_list = rep1.hosts[0].extraports + self.assertEqual(len(ep_list), 2) + self.assertEqual(ep_list[0]["count"], "65509") + self.assertEqual(ep_list[0]["state"], "closed") + self.assertEqual(len(ep_list[0]["extrareasons"]), 1) + self.assertEqual(ep_list[1]["count"], "10") + self.assertEqual(len(ep_list[1]["extrareasons"]), 2) + self.assertEqual( + ep_list[1]["extrareasons"], fentry["extrareasons"] + ) + + +if __name__ == "__main__": + test_suite = [ + "test_extraports", + ] + suite = unittest.TestSuite(map(TestExtraPorts, test_suite)) + test_result = unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/libnmap/test/test_host.py b/libnmap/test/test_host.py index d192f32..0dff34d 100644 --- a/libnmap/test/test_host.py +++ b/libnmap/test/test_host.py @@ -181,25 +181,6 @@ def test_host_api(self): self.assertEqual(len(h2.get_open_ports()), 3) self.assertEqual(h2.get_service(22, "tcp").state, "open") - def test_extra_ports(self): - h1 = NmapParser.parse(host1) - h2 = NmapParser.parse(host2) - - self.assertEqual( - h1.extraports_state["state"], - {"count": "995", "state": "WILLY_WONCKA"}, - ) - self.assertEqual( - h1.extraports_reasons, [{"reason": "conn-refused", "count": "995"}] - ) - - self.assertEqual( - h2.extraports_state["state"], {"count": "995", "state": "closed"} - ) - self.assertEqual( - h2.extraports_reasons, [{"reason": "conn-refused", "count": "995"}] - ) - def test_diff_host(self): h1 = NmapParser.parse(host1) h2 = NmapParser.parse(host2) diff --git a/libnmap/test/test_process.py b/libnmap/test/test_process.py index 4345493..b2f3297 100644 --- a/libnmap/test/test_process.py +++ b/libnmap/test/test_process.py @@ -19,19 +19,26 @@ def setUp(self): self._assertRaisesRegex = self.assertRaisesRegexp self.fdir = os.path.dirname(os.path.realpath(__file__)) - def test_check_targets(self): - invalid_target_tests = [{"a": "bba"}, 5] + def test_check_valid_targets(self): valid_target_tests = [ {"value": "127.0.0.1, 1.1.1.1, 2.20.202", "size": 3}, {"value": ["127.0.0.1", "1.1.1.1", "2.20.202.2"], "size": 3}, {"value": [" 127.0.0.1", " 1.1.1.1"], "size": 2}, {"value": " 127.0.0.1, 1.1.1.1 , a", "size": 3}, + {"value": ["192.168.10.0/24", "192.168.0-255.1-254"], "size": 2}, + {"value": ["fe80::a8bb:ccff:fedd:eeff%eth0"], "size": 1}, + {"value": ["my-domain.com", "my-num3r1c-domain.com"], "size": 2}, ] for vtarget in valid_target_tests: nmapobj = NmapProcess(targets=vtarget["value"], options="-sP") self.assertEqual(vtarget["size"], len(nmapobj.targets)) - for vtarget in invalid_target_tests: + def test_check_invalid_targets(self): + invalid_target_type_tests = [{"a": "bba"}, 5] + invalid_target_character_tests = ["1.1.1.1$", "invalid_domain.com"] + invalid_target_dash_tests = ["-invalid-target", "--option"] + + for vtarget in invalid_target_type_tests: self._assertRaisesRegex( Exception, "Supplied target list should be either a string or a list", @@ -40,6 +47,24 @@ def test_check_targets(self): options="-sP", ) + for vtarget in invalid_target_character_tests: + self._assertRaisesRegex( + Exception, + "contains invalid characters", + NmapProcess, + targets=vtarget, + options="-sP", + ) + + for vtarget in invalid_target_dash_tests: + self._assertRaisesRegex( + Exception, + "cannot begin or end with a dash", + NmapProcess, + targets=vtarget, + options="-sP", + ) + def test_nmap_options(self): invalid_options = ["--iflist"] diff --git a/requirements-dev.txt b/requirements-dev.txt index aaeebb6..cb383eb 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,6 +1,6 @@ -black==20.8b1 -defusedxml==0.6.0 -isort==5.6.4 +black==24.3.0 +defusedxml==0.7.1 +isort==6.0.0 pre-commit pytest pytest-cov diff --git a/setup.py b/setup.py index 9668371..1ff64c0 100644 --- a/setup.py +++ b/setup.py @@ -1,12 +1,21 @@ # -*- coding: utf-8 -*- -from distutils.core import setup +import sys -with open("README.rst", encoding="utf-8") as rfile: - long_description = rfile.read() +try: + from setuptools import setup +except ImportError: + from distutils.core import setup + +if sys.version_info >= (3, 0): + with open("README.rst", encoding="utf-8") as rfile: + long_description = rfile.read() +else: # if encoding not compatible with python2 + with open("README.rst") as rfile: + long_description = rfile.read() setup( name="python-libnmap", - version="0.7.2", + version="0.7.3", author="Ronald Bister", author_email="mini.pelle@gmail.com", packages=["libnmap", "libnmap.plugins", "libnmap.objects"], @@ -33,6 +42,8 @@ "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Topic :: System :: Networking", ], ) diff --git a/tox.ini b/tox.ini index 45ba18a..f86d9d3 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ envlist = py27, py32, py38, flake8, pycodestyle, formatting, defusedxml, coveral [testenv] deps=pytest pytest-cov -commands=pytest --cov --cov-report term-missing --ignore=libnmap/test/test_backend_plugin_factory.py --ignore=libnmap/test/test_defusedxml.py +commands=pytest --cov --cov-report term-missing --ignore=libnmap/test/test_backend_plugin_factory.py --ignore=libnmap/test/test_defusedxml.py [testenv:defusedxml] deps=pytest @@ -29,7 +29,7 @@ deps = pycodestyle commands = pycodestyle --exclude test,docs,examples,.tox . - + [testenv:formatting] deps = #black==20.8b1