lanscape 1.2.8a3__tar.gz → 1.2.9a2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of lanscape might be problematic. Click here for more details.
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/MANIFEST.in +1 -0
- {lanscape-1.2.8a3/src/lanscape.egg-info → lanscape-1.2.9a2}/PKG-INFO +2 -10
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/README.md +0 -8
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/pyproject.toml +1 -1
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/libraries/app_scope.py +12 -1
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/libraries/ip_parser.py +1 -1
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/libraries/mac_lookup.py +1 -2
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/libraries/net_tools.py +9 -1
- lanscape-1.2.9a2/src/lanscape/libraries/service_scan.py +51 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/libraries/subnet_scan.py +62 -27
- lanscape-1.2.9a2/src/lanscape/resources/services/definitions.jsonc +456 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/tests/test_library.py +1 -1
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/blueprints/api/scan.py +3 -1
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/blueprints/web/routes.py +1 -1
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/js/main.js +5 -1
- {lanscape-1.2.8a3 → lanscape-1.2.9a2/src/lanscape.egg-info}/PKG-INFO +2 -10
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape.egg-info/SOURCES.txt +2 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/LICENSE +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/setup.cfg +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/__init__.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/__main__.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/libraries/decorators.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/libraries/errors.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/libraries/logger.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/libraries/port_manager.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/libraries/runtime_args.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/libraries/version_manager.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/resources/mac_addresses/convert_csv.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/resources/mac_addresses/mac_db.json +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/resources/ports/convert_csv.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/resources/ports/full.json +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/resources/ports/large.json +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/resources/ports/medium.json +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/resources/ports/small.json +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/tests/__init__.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/tests/_helpers.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/tests/test_api.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/tests/test_env.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/app.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/blueprints/__init__.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/blueprints/api/__init__.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/blueprints/api/port.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/blueprints/api/tools.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/blueprints/web/__init__.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/main.py +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/css/style.css +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/img/ico/android-chrome-192x192.png +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/img/ico/android-chrome-512x512.png +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/img/ico/apple-touch-icon.png +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/img/ico/favicon-16x16.png +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/img/ico/favicon-32x32.png +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/img/ico/favicon.ico +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/img/ico/site.webmanifest +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/js/core.js +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/js/layout-sizing.js +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/js/quietReload.js +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/js/shutdown-server.js +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/js/subnet-info.js +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/js/subnet-selector.js +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/lanscape.webmanifest +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/templates/base.html +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/templates/core/head.html +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/templates/core/scripts.html +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/templates/error.html +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/templates/info.html +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/templates/main.html +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/templates/scan/export.html +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/templates/scan/ip-table-row.html +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/templates/scan/ip-table.html +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/templates/scan/overview.html +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/templates/scan/scan-error.html +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/templates/scan.html +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/templates/shutdown.html +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape.egg-info/dependency_links.txt +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape.egg-info/requires.txt +0 -0
- {lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: lanscape
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.9a2
|
|
4
4
|
Summary: A python based local network scanner
|
|
5
5
|
Author-email: Michael Dennis <michael@dipduo.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/mdennis281/py-lanscape
|
|
@@ -55,14 +55,6 @@ can sometimes require admin-level permissions to retrieve accurate results.
|
|
|
55
55
|
This is a missing dependency related to the ARP lookup. This is handled in the code, but you would get marginally faster/better results with this installed: [npcap download](https://npcap.com/#download)
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
### Unable to start webview client. Try --nogui (Linux)
|
|
59
|
-
Linux and QT (GUI package) dont seem to play well with each other very well. If you really want the gui (`python -m lanscape --nogui` is almost as good) I had success on ubuntu desktop by running these:
|
|
60
|
-
```sh
|
|
61
|
-
sudo apt install libcairo2-dev libxt-dev libgirepository1.0-dev
|
|
62
|
-
pip install pycairo PyGObject qtpy PyQt5 PyQtWebEngine
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
|
|
66
58
|
### Something else
|
|
67
59
|
Feel free to submit a github issue detailing your experience.
|
|
68
60
|
|
|
@@ -34,14 +34,6 @@ can sometimes require admin-level permissions to retrieve accurate results.
|
|
|
34
34
|
This is a missing dependency related to the ARP lookup. This is handled in the code, but you would get marginally faster/better results with this installed: [npcap download](https://npcap.com/#download)
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
### Unable to start webview client. Try --nogui (Linux)
|
|
38
|
-
Linux and QT (GUI package) dont seem to play well with each other very well. If you really want the gui (`python -m lanscape --nogui` is almost as good) I had success on ubuntu desktop by running these:
|
|
39
|
-
```sh
|
|
40
|
-
sudo apt install libcairo2-dev libxt-dev libgirepository1.0-dev
|
|
41
|
-
pip install pycairo PyGObject qtpy PyQt5 PyQtWebEngine
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
|
|
45
37
|
### Something else
|
|
46
38
|
Feel free to submit a github issue detailing your experience.
|
|
47
39
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
import
|
|
2
|
+
import json
|
|
3
3
|
import sys
|
|
4
|
+
import re
|
|
4
5
|
|
|
5
6
|
class ResourceManager:
|
|
6
7
|
"""
|
|
@@ -17,6 +18,16 @@ class ResourceManager:
|
|
|
17
18
|
with open(self.asset_dir / asset_name, 'r') as f:
|
|
18
19
|
return f.read()
|
|
19
20
|
|
|
21
|
+
def get_json(self, asset_name: str):
|
|
22
|
+
return json.loads(self.get(asset_name))
|
|
23
|
+
|
|
24
|
+
def get_jsonc(self, asset_name: str):
|
|
25
|
+
" Get JSON content with comments removed "
|
|
26
|
+
content = self.get(asset_name)
|
|
27
|
+
cleaned_content = re.sub(r'//.*', '', content)
|
|
28
|
+
return json.loads(cleaned_content)
|
|
29
|
+
|
|
30
|
+
|
|
20
31
|
def update(self, asset_name: str, content: str):
|
|
21
32
|
with open(self.asset_dir / asset_name, 'w') as f:
|
|
22
33
|
f.write(content)
|
|
@@ -28,7 +28,7 @@ def parse_ip_input(ip_input):
|
|
|
28
28
|
|
|
29
29
|
# If no CIDR or range, assume a single IP
|
|
30
30
|
else:
|
|
31
|
-
ip_ranges.append(ipaddress.IPv4Address(entry
|
|
31
|
+
ip_ranges.append(ipaddress.IPv4Address(entry))
|
|
32
32
|
if len(ip_ranges) > MAX_IPS_ALLOWED:
|
|
33
33
|
raise SubnetTooLargeError(ip_input)
|
|
34
34
|
return ip_ranges
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import re
|
|
2
|
-
import json
|
|
3
2
|
import logging
|
|
4
3
|
import platform
|
|
5
4
|
import subprocess
|
|
@@ -7,7 +6,7 @@ from typing import List
|
|
|
7
6
|
|
|
8
7
|
from .app_scope import ResourceManager
|
|
9
8
|
|
|
10
|
-
DB =
|
|
9
|
+
DB = ResourceManager('mac_addresses').get_json('mac_db.json')
|
|
11
10
|
|
|
12
11
|
log = logging.getLogger('MacLookup')
|
|
13
12
|
|
|
@@ -8,9 +8,10 @@ import ipaddress
|
|
|
8
8
|
import traceback
|
|
9
9
|
import subprocess
|
|
10
10
|
from time import sleep
|
|
11
|
-
from typing import List
|
|
11
|
+
from typing import List, Dict
|
|
12
12
|
from scapy.all import ARP, Ether, srp
|
|
13
13
|
|
|
14
|
+
from .service_scan import scan_service
|
|
14
15
|
from .mac_lookup import lookup_mac, get_macs
|
|
15
16
|
from .ip_parser import get_address_count, MAX_IPS_ALLOWED
|
|
16
17
|
|
|
@@ -73,6 +74,7 @@ class Device(IPAlive):
|
|
|
73
74
|
self.manufacturer: str = None
|
|
74
75
|
self.ports: List[int] = []
|
|
75
76
|
self.stage: str = 'found'
|
|
77
|
+
self.services: Dict[str,List[int]] = {}
|
|
76
78
|
self.log = logging.getLogger('Device')
|
|
77
79
|
|
|
78
80
|
def get_metadata(self):
|
|
@@ -100,6 +102,12 @@ class Device(IPAlive):
|
|
|
100
102
|
return True
|
|
101
103
|
return False
|
|
102
104
|
|
|
105
|
+
def scan_service(self,port:int):
|
|
106
|
+
service = scan_service(self.ip,port)
|
|
107
|
+
service_ports = self.services.get(service,[])
|
|
108
|
+
service_ports.append(port)
|
|
109
|
+
self.services[service] = service_ports
|
|
110
|
+
|
|
103
111
|
def get_mac(self):
|
|
104
112
|
if not self.macs:
|
|
105
113
|
self.macs = self._get_mac_addresses()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
import traceback
|
|
4
|
+
from .app_scope import ResourceManager
|
|
5
|
+
|
|
6
|
+
log = logging.getLogger('ServiceScan')
|
|
7
|
+
SERVICES = ResourceManager('services').get_jsonc('definitions.jsonc')
|
|
8
|
+
|
|
9
|
+
# skip printer ports because they cause blank pages to be printed
|
|
10
|
+
PRINTER_PORTS = [9100, 631]
|
|
11
|
+
|
|
12
|
+
def scan_service(ip: str, port: int, timeout=10) -> str:
|
|
13
|
+
"""
|
|
14
|
+
Synchronous function that attempts to identify the service running on a given port.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
async def _async_scan_service(ip: str, port: int, timeout) -> str:
|
|
18
|
+
if port in PRINTER_PORTS:
|
|
19
|
+
return "Printer"
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
# Add a timeout to prevent hanging
|
|
23
|
+
reader, writer = await asyncio.wait_for(asyncio.open_connection(ip, port), timeout=5)
|
|
24
|
+
|
|
25
|
+
# Send a probe appropriate for common services
|
|
26
|
+
probe = "GET / HTTP/1.1\r\nHost: {}\r\n\r\n".format(ip).encode("utf-8")
|
|
27
|
+
writer.write(probe)
|
|
28
|
+
await writer.drain()
|
|
29
|
+
|
|
30
|
+
# Receive the response with a timeout
|
|
31
|
+
response = await asyncio.wait_for(reader.read(1024), timeout=timeout)
|
|
32
|
+
writer.close()
|
|
33
|
+
await writer.wait_closed()
|
|
34
|
+
|
|
35
|
+
# Analyze the response to identify the service
|
|
36
|
+
response_str = response.decode("utf-8", errors="ignore")
|
|
37
|
+
for service, hints in SERVICES.items():
|
|
38
|
+
if any(hint.lower() in response_str.lower() for hint in hints):
|
|
39
|
+
return service
|
|
40
|
+
except asyncio.TimeoutError:
|
|
41
|
+
log.warning(f"Timeout scanning {ip}:{port}")
|
|
42
|
+
except Exception as e:
|
|
43
|
+
log.error(f"Error scanning {ip}:{port}: {str(e)}")
|
|
44
|
+
log.debug(traceback.format_exc())
|
|
45
|
+
return "Unknown"
|
|
46
|
+
|
|
47
|
+
# Use asyncio.run to execute the asynchronous logic synchronously
|
|
48
|
+
return asyncio.run(_async_scan_service(ip, port,timeout=timeout))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
@@ -27,7 +27,37 @@ TCNT_DEVICE_ISALIVE = 256
|
|
|
27
27
|
class ScanConfig:
|
|
28
28
|
subnet: str
|
|
29
29
|
port_list: str
|
|
30
|
-
|
|
30
|
+
t_multiplier: float = 1.0
|
|
31
|
+
t_cnt_port_scan: int = 10
|
|
32
|
+
t_cnt_port_test: int = 128
|
|
33
|
+
t_cnt_isalive: int = 256
|
|
34
|
+
|
|
35
|
+
task_scan_ports: bool = True
|
|
36
|
+
# below wont run if above false
|
|
37
|
+
task_scan_port_services: bool = True
|
|
38
|
+
|
|
39
|
+
def t_cnt(self, id: str) -> int:
|
|
40
|
+
return int(int(getattr(self, f't_cnt_{id}')) * float(self.t_multiplier))
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def from_dict(data: dict) -> 'ScanConfig':
|
|
44
|
+
return ScanConfig(
|
|
45
|
+
subnet = data['subnet'],
|
|
46
|
+
port_list = data['port_list'],
|
|
47
|
+
t_multiplier = data.get('parallelism',1.0),
|
|
48
|
+
t_cnt_port_scan = data.get('t_cnt_port_scan',10),
|
|
49
|
+
t_cnt_port_test = data.get('t_cnt_port_test',128),
|
|
50
|
+
t_cnt_isalive = data.get('t_cnt_isalive',256),
|
|
51
|
+
task_scan_ports = data.get('task_scan_ports',True),
|
|
52
|
+
task_scan_port_services = data.get('task_scan_port_services',True)
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
def get_ports(self) -> List[int]:
|
|
56
|
+
return PortManager().get_port_list(self.port_list).keys()
|
|
57
|
+
|
|
58
|
+
def parse_subnet(self) -> List[ipaddress.IPv4Network]:
|
|
59
|
+
return parse_ip_input(self.subnet)
|
|
60
|
+
|
|
31
61
|
|
|
32
62
|
|
|
33
63
|
|
|
@@ -36,12 +66,13 @@ class SubnetScanner:
|
|
|
36
66
|
self,
|
|
37
67
|
config: ScanConfig
|
|
38
68
|
):
|
|
39
|
-
self.
|
|
40
|
-
self.
|
|
41
|
-
self.ports:
|
|
69
|
+
self.cfg = config
|
|
70
|
+
self.subnet = config.parse_subnet()
|
|
71
|
+
self.ports: List[int] = config.get_ports()
|
|
42
72
|
self.running = False
|
|
43
|
-
self.parallelism: float = float(config.parallelism)
|
|
44
73
|
self.subnet_str = config.subnet
|
|
74
|
+
|
|
75
|
+
|
|
45
76
|
self.job_stats = JobStats()
|
|
46
77
|
self.uid = str(uuid.uuid4())
|
|
47
78
|
self.results = ScannerResults(self)
|
|
@@ -58,7 +89,7 @@ class SubnetScanner:
|
|
|
58
89
|
"""
|
|
59
90
|
self._set_stage('scanning devices')
|
|
60
91
|
self.running = True
|
|
61
|
-
with ThreadPoolExecutor(max_workers=self.
|
|
92
|
+
with ThreadPoolExecutor(max_workers=self.cfg.t_cnt('isalive')) as executor:
|
|
62
93
|
futures = {executor.submit(self._get_host_details, str(ip)): str(ip) for ip in self.subnet}
|
|
63
94
|
for future in futures:
|
|
64
95
|
ip = futures[future]
|
|
@@ -73,7 +104,8 @@ class SubnetScanner:
|
|
|
73
104
|
|
|
74
105
|
|
|
75
106
|
self._set_stage('testing ports')
|
|
76
|
-
self.
|
|
107
|
+
if self.cfg.task_scan_ports:
|
|
108
|
+
self._scan_network_ports()
|
|
77
109
|
self.running = False
|
|
78
110
|
self._set_stage('complete')
|
|
79
111
|
|
|
@@ -104,7 +136,7 @@ class SubnetScanner:
|
|
|
104
136
|
remaining_isalive_sec = (self.results.devices_total - self.results.devices_scanned) * avg_host_detail_sec
|
|
105
137
|
total_isalive_sec = self.results.devices_total * avg_host_detail_sec
|
|
106
138
|
|
|
107
|
-
isalive_multiplier = self.
|
|
139
|
+
isalive_multiplier = self.cfg.t_cnt('isalive')
|
|
108
140
|
|
|
109
141
|
# --- Port scanning calculations ---
|
|
110
142
|
device_ports_scanned = self.job_stats.finished.get('_test_port', 0)
|
|
@@ -116,7 +148,7 @@ class SubnetScanner:
|
|
|
116
148
|
remaining_port_test_sec = device_ports_unscanned * avg_port_test_sec
|
|
117
149
|
total_port_test_sec = est_subnet_devices * len(self.ports) * avg_port_test_sec
|
|
118
150
|
|
|
119
|
-
port_test_multiplier = self.
|
|
151
|
+
port_test_multiplier = self.cfg.t_cnt('port_scan') * self.cfg.t_cnt('port_test')
|
|
120
152
|
|
|
121
153
|
# --- Overall progress ---
|
|
122
154
|
est_total_time = (total_isalive_sec / isalive_multiplier) + (total_port_test_sec / port_test_multiplier)
|
|
@@ -126,17 +158,23 @@ class SubnetScanner:
|
|
|
126
158
|
|
|
127
159
|
|
|
128
160
|
|
|
129
|
-
def debug_active_scan(self):
|
|
161
|
+
def debug_active_scan(self,sleep_sec=1):
|
|
130
162
|
"""
|
|
131
163
|
Run this after running scan_subnet_threaded
|
|
132
164
|
to see the progress of the scan
|
|
133
165
|
"""
|
|
134
166
|
while self.running:
|
|
167
|
+
percent = self.calc_percent_complete()
|
|
168
|
+
t_elapsed = time() - self.results.start_time
|
|
169
|
+
t_remain = int((100-percent) * (t_elapsed / percent)) if percent else '∞'
|
|
170
|
+
buffer = f'{self.uid} - {self.subnet_str}\n'
|
|
171
|
+
buffer += f'Elapsed: {int(t_elapsed)} sec - Remain: {t_remain} sec\n'
|
|
172
|
+
buffer += f'Scanned: {self.results.devices_scanned}/{self.results.devices_total}'
|
|
173
|
+
buffer += f' - {percent}%\n'
|
|
174
|
+
buffer += str(self.job_stats)
|
|
135
175
|
os.system('cls' if os.name == 'nt' else 'clear')
|
|
136
|
-
print(
|
|
137
|
-
|
|
138
|
-
print(self.job_stats)
|
|
139
|
-
sleep(1)
|
|
176
|
+
print(buffer)
|
|
177
|
+
sleep(sleep_sec)
|
|
140
178
|
|
|
141
179
|
@terminator
|
|
142
180
|
@job_tracker
|
|
@@ -157,7 +195,7 @@ class SubnetScanner:
|
|
|
157
195
|
|
|
158
196
|
@terminator
|
|
159
197
|
def _scan_network_ports(self):
|
|
160
|
-
with ThreadPoolExecutor(max_workers=self.
|
|
198
|
+
with ThreadPoolExecutor(max_workers=self.cfg.t_cnt('port_scan')) as executor:
|
|
161
199
|
futures = {executor.submit(self._scan_ports, device): device for device in self.results.devices}
|
|
162
200
|
for future in futures:
|
|
163
201
|
future.result()
|
|
@@ -167,7 +205,7 @@ class SubnetScanner:
|
|
|
167
205
|
def _scan_ports(self, device: Device):
|
|
168
206
|
self.log.debug(f'[{device.ip}] Initiating port scan')
|
|
169
207
|
device.stage = 'scanning'
|
|
170
|
-
with ThreadPoolExecutor(max_workers=self.
|
|
208
|
+
with ThreadPoolExecutor(max_workers=self.cfg.t_cnt('port_test')) as executor:
|
|
171
209
|
futures = {executor.submit(self._test_port, device, int(port)): port for port in self.ports}
|
|
172
210
|
for future in futures:
|
|
173
211
|
future.result()
|
|
@@ -179,9 +217,13 @@ class SubnetScanner:
|
|
|
179
217
|
def _test_port(self,host: Device, port: int):
|
|
180
218
|
"""
|
|
181
219
|
Test if a port is open on a given host.
|
|
220
|
+
If port open, determine service.
|
|
182
221
|
Device class handles tracking open ports.
|
|
183
222
|
"""
|
|
184
|
-
|
|
223
|
+
is_alive = host.test_port(port)
|
|
224
|
+
if is_alive and self.cfg.task_scan_port_services:
|
|
225
|
+
host.scan_service(port)
|
|
226
|
+
return is_alive
|
|
185
227
|
|
|
186
228
|
|
|
187
229
|
@terminator
|
|
@@ -192,13 +234,6 @@ class SubnetScanner:
|
|
|
192
234
|
"""
|
|
193
235
|
return host.is_alive(host.ip)
|
|
194
236
|
|
|
195
|
-
def _t_cnt(self, base_threads: int) -> int:
|
|
196
|
-
"""
|
|
197
|
-
Calculate the number of threads to use based on the base number
|
|
198
|
-
of threads and the parallelism factor.
|
|
199
|
-
"""
|
|
200
|
-
return int(base_threads * self.parallelism)
|
|
201
|
-
|
|
202
237
|
def _set_stage(self,stage):
|
|
203
238
|
self.log.debug(f'[{self.uid}] Moving to Stage: {stage}')
|
|
204
239
|
self.results.stage = stage
|
|
@@ -208,9 +243,8 @@ class SubnetScanner:
|
|
|
208
243
|
class ScannerResults:
|
|
209
244
|
def __init__(self,scan: SubnetScanner):
|
|
210
245
|
self.scan = scan
|
|
211
|
-
self.port_list: str = scan.port_list
|
|
246
|
+
self.port_list: str = scan.cfg.port_list
|
|
212
247
|
self.subnet: str = scan.subnet_str
|
|
213
|
-
self.parallelism: float = scan.parallelism
|
|
214
248
|
self.uid = scan.uid
|
|
215
249
|
|
|
216
250
|
self.devices_total: int = len(list(scan.subnet))
|
|
@@ -249,6 +283,7 @@ class ScannerResults:
|
|
|
249
283
|
out = vars(self).copy()
|
|
250
284
|
out.pop('scan')
|
|
251
285
|
out.pop('log')
|
|
286
|
+
out['cfg'] = vars(self.scan.cfg)
|
|
252
287
|
|
|
253
288
|
devices: List[Device] = out.pop('devices')
|
|
254
289
|
sortedDevices = sorted(devices, key=lambda obj: ipaddress.IPv4Address(obj.ip))
|
|
@@ -262,7 +297,7 @@ class ScannerResults:
|
|
|
262
297
|
def __str__(self):
|
|
263
298
|
# Prepare data for tabulate
|
|
264
299
|
data = [
|
|
265
|
-
[device.ip, device.hostname, device.
|
|
300
|
+
[device.ip, device.hostname, device.get_mac(), ", ".join(map(str, device.ports))]
|
|
266
301
|
for device in self.devices
|
|
267
302
|
]
|
|
268
303
|
|
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
{
|
|
2
|
+
// ----------------------- Web Services -----------------------
|
|
3
|
+
"HTTP": [
|
|
4
|
+
"HTTP",
|
|
5
|
+
"Apache",
|
|
6
|
+
"Nginx",
|
|
7
|
+
"IIS",
|
|
8
|
+
"lighttpd",
|
|
9
|
+
"Caddy",
|
|
10
|
+
"OpenResty",
|
|
11
|
+
"GWS", // Google Web Server
|
|
12
|
+
"LiteSpeed",
|
|
13
|
+
"Gunicorn", // Often in X-Powered-By
|
|
14
|
+
"OpenLiteSpeed",
|
|
15
|
+
"Cloudflare"
|
|
16
|
+
],
|
|
17
|
+
"HTTPS": [
|
|
18
|
+
"HTTPS",
|
|
19
|
+
"SSL",
|
|
20
|
+
"TLS"
|
|
21
|
+
// Possibly you'd see "443" in a banner or SNI reference,
|
|
22
|
+
// but typically "SSL" or "TLS" coverage is sufficient
|
|
23
|
+
],
|
|
24
|
+
|
|
25
|
+
// ------------------ Remote Shell / Admin --------------------
|
|
26
|
+
"SSH": [
|
|
27
|
+
"SSH",
|
|
28
|
+
"OpenSSH",
|
|
29
|
+
"Dropbear",
|
|
30
|
+
"libssh"
|
|
31
|
+
],
|
|
32
|
+
"Telnet": [
|
|
33
|
+
"Telnet",
|
|
34
|
+
"BusyBox on telnetd"
|
|
35
|
+
],
|
|
36
|
+
|
|
37
|
+
// ------------------ File Transfer Protocols -----------------
|
|
38
|
+
"FTP": [
|
|
39
|
+
"FTP",
|
|
40
|
+
"FileZilla",
|
|
41
|
+
"ProFTPD",
|
|
42
|
+
"vsftpd",
|
|
43
|
+
"Pure-FTPd",
|
|
44
|
+
"WS_FTP",
|
|
45
|
+
"Microsoft ftpd"
|
|
46
|
+
],
|
|
47
|
+
"SFTP": [
|
|
48
|
+
"SFTP"
|
|
49
|
+
// SFTP typically is an SSH subsystem, so you'd often see an SSH banner anyway
|
|
50
|
+
],
|
|
51
|
+
"TFTP": [
|
|
52
|
+
"TFTP"
|
|
53
|
+
],
|
|
54
|
+
|
|
55
|
+
// -------------------- Email / Messaging ----------------------
|
|
56
|
+
"SMTP": [
|
|
57
|
+
"SMTP",
|
|
58
|
+
"Postfix",
|
|
59
|
+
"Exim",
|
|
60
|
+
"Sendmail",
|
|
61
|
+
"Qmail",
|
|
62
|
+
"Exchange"
|
|
63
|
+
],
|
|
64
|
+
"SMTPS": [
|
|
65
|
+
"SMTPS",
|
|
66
|
+
"465 secure",
|
|
67
|
+
"587 secure"
|
|
68
|
+
// Some servers might mention "TLS wrapper" or similar
|
|
69
|
+
],
|
|
70
|
+
"POP3": [
|
|
71
|
+
"POP3",
|
|
72
|
+
"Dovecot",
|
|
73
|
+
"Courier",
|
|
74
|
+
"POP3 (Internet Mail)"
|
|
75
|
+
],
|
|
76
|
+
"POP3S": [
|
|
77
|
+
"POP3S",
|
|
78
|
+
"SSL POP3",
|
|
79
|
+
"Dovecot",
|
|
80
|
+
"Courier"
|
|
81
|
+
],
|
|
82
|
+
"IMAP": [
|
|
83
|
+
"IMAP",
|
|
84
|
+
"Dovecot",
|
|
85
|
+
"Courier",
|
|
86
|
+
"Cyrus",
|
|
87
|
+
"IMAP4"
|
|
88
|
+
],
|
|
89
|
+
"IMAPS": [
|
|
90
|
+
"IMAPS",
|
|
91
|
+
"SSL IMAP",
|
|
92
|
+
"Dovecot",
|
|
93
|
+
"Courier",
|
|
94
|
+
"Cyrus"
|
|
95
|
+
],
|
|
96
|
+
|
|
97
|
+
// ---------------- Domain / Directory Services ---------------
|
|
98
|
+
"DNS": [
|
|
99
|
+
"DNS",
|
|
100
|
+
"Bind",
|
|
101
|
+
"DNSMasq",
|
|
102
|
+
"PowerDNS",
|
|
103
|
+
"Unbound",
|
|
104
|
+
"Microsoft DNS",
|
|
105
|
+
"Knot DNS"
|
|
106
|
+
],
|
|
107
|
+
"LDAP": [
|
|
108
|
+
"LDAP"
|
|
109
|
+
],
|
|
110
|
+
"Active Directory": [
|
|
111
|
+
"Active Directory",
|
|
112
|
+
"Kerberos",
|
|
113
|
+
"MSAD",
|
|
114
|
+
"LDAP for AD",
|
|
115
|
+
"LDAP Service (AD)"
|
|
116
|
+
],
|
|
117
|
+
|
|
118
|
+
// -------------------- Database Services ----------------------
|
|
119
|
+
"MySQL": [
|
|
120
|
+
"MySQL",
|
|
121
|
+
"MariaDB",
|
|
122
|
+
"Percona"
|
|
123
|
+
],
|
|
124
|
+
"PostgreSQL": [
|
|
125
|
+
"PostgreSQL",
|
|
126
|
+
"Postgres"
|
|
127
|
+
],
|
|
128
|
+
"Microsoft SQL Server": [
|
|
129
|
+
"MSSQL",
|
|
130
|
+
"Microsoft SQL Server",
|
|
131
|
+
"TDS",
|
|
132
|
+
"SQL Server",
|
|
133
|
+
"MS-SQL"
|
|
134
|
+
],
|
|
135
|
+
"Oracle Database": [
|
|
136
|
+
"Oracle",
|
|
137
|
+
"TNS",
|
|
138
|
+
"Oracle Net"
|
|
139
|
+
],
|
|
140
|
+
"MongoDB": [
|
|
141
|
+
"MongoDB"
|
|
142
|
+
],
|
|
143
|
+
"Redis": [
|
|
144
|
+
"Redis"
|
|
145
|
+
],
|
|
146
|
+
"Cassandra": [
|
|
147
|
+
"Cassandra"
|
|
148
|
+
],
|
|
149
|
+
"Memcached": [
|
|
150
|
+
"Memcached"
|
|
151
|
+
],
|
|
152
|
+
|
|
153
|
+
// ----------------- Caching / Indexing / Logging -------------
|
|
154
|
+
"Elasticsearch": [
|
|
155
|
+
"Elasticsearch"
|
|
156
|
+
],
|
|
157
|
+
"Logstash": [
|
|
158
|
+
"Logstash"
|
|
159
|
+
],
|
|
160
|
+
|
|
161
|
+
// --------------- Message Brokers & Streaming ----------------
|
|
162
|
+
"Kafka": [
|
|
163
|
+
"Kafka"
|
|
164
|
+
],
|
|
165
|
+
"RabbitMQ": [
|
|
166
|
+
"RabbitMQ",
|
|
167
|
+
"AMQP"
|
|
168
|
+
],
|
|
169
|
+
"ActiveMQ": [
|
|
170
|
+
"ActiveMQ"
|
|
171
|
+
],
|
|
172
|
+
"Mosquitto": [
|
|
173
|
+
"Mosquitto",
|
|
174
|
+
"MQTT"
|
|
175
|
+
],
|
|
176
|
+
|
|
177
|
+
// -------------------- Microsoft Services ---------------------
|
|
178
|
+
"RDP": [
|
|
179
|
+
"RDP",
|
|
180
|
+
"Terminal Services",
|
|
181
|
+
"Remote Desktop",
|
|
182
|
+
"MSTerminal"
|
|
183
|
+
],
|
|
184
|
+
"SMB": [
|
|
185
|
+
"SMB",
|
|
186
|
+
"NetBIOS",
|
|
187
|
+
"Samba"
|
|
188
|
+
],
|
|
189
|
+
"WMI": [
|
|
190
|
+
"WMI"
|
|
191
|
+
],
|
|
192
|
+
"WinRM": [
|
|
193
|
+
"WinRM"
|
|
194
|
+
],
|
|
195
|
+
|
|
196
|
+
// ---------------- Collaboration / Chat -----------------------
|
|
197
|
+
"IRC": [
|
|
198
|
+
"IRC"
|
|
199
|
+
],
|
|
200
|
+
"XMPP": [
|
|
201
|
+
"XMPP",
|
|
202
|
+
"Jabber"
|
|
203
|
+
],
|
|
204
|
+
"Matrix": [
|
|
205
|
+
"Matrix"
|
|
206
|
+
],
|
|
207
|
+
|
|
208
|
+
// ------------- Virtualization / Container Services ----------
|
|
209
|
+
"Docker API": [
|
|
210
|
+
"Docker"
|
|
211
|
+
],
|
|
212
|
+
"Kubernetes API": [
|
|
213
|
+
"Kubernetes",
|
|
214
|
+
"K8s",
|
|
215
|
+
"kube-apiserver"
|
|
216
|
+
],
|
|
217
|
+
"VMware ESXi": [
|
|
218
|
+
"VMware ESXi",
|
|
219
|
+
"ESX"
|
|
220
|
+
],
|
|
221
|
+
"Proxmox": [
|
|
222
|
+
"Proxmox"
|
|
223
|
+
],
|
|
224
|
+
|
|
225
|
+
// ----------------- Remote Desktop / Control -----------------
|
|
226
|
+
"VNC": [
|
|
227
|
+
"VNC",
|
|
228
|
+
"RFB"
|
|
229
|
+
],
|
|
230
|
+
"TeamViewer": [
|
|
231
|
+
"TeamViewer"
|
|
232
|
+
],
|
|
233
|
+
"AnyDesk": [
|
|
234
|
+
"AnyDesk"
|
|
235
|
+
],
|
|
236
|
+
|
|
237
|
+
// --------------------- Voice over IP ------------------------
|
|
238
|
+
"SIP": [
|
|
239
|
+
"SIP",
|
|
240
|
+
"Asterisk",
|
|
241
|
+
"FreeSWITCH"
|
|
242
|
+
],
|
|
243
|
+
"H.323": [
|
|
244
|
+
"H.323"
|
|
245
|
+
],
|
|
246
|
+
|
|
247
|
+
// ----------- Time, Network Config, and Infrastructure -------
|
|
248
|
+
"NTP": [
|
|
249
|
+
"NTP"
|
|
250
|
+
],
|
|
251
|
+
"DHCP": [
|
|
252
|
+
"DHCP"
|
|
253
|
+
],
|
|
254
|
+
|
|
255
|
+
// ------------------ VPN / Tunneling / Security --------------
|
|
256
|
+
"OpenVPN": [
|
|
257
|
+
"OpenVPN"
|
|
258
|
+
],
|
|
259
|
+
"IPSec": [
|
|
260
|
+
"IPSec",
|
|
261
|
+
"IKE"
|
|
262
|
+
],
|
|
263
|
+
"WireGuard": [
|
|
264
|
+
"WireGuard"
|
|
265
|
+
],
|
|
266
|
+
|
|
267
|
+
// ---------------------- Other Protocols ----------------------
|
|
268
|
+
"SNMP": [
|
|
269
|
+
"SNMP"
|
|
270
|
+
],
|
|
271
|
+
"SNMP Trap": [
|
|
272
|
+
"Trap",
|
|
273
|
+
"SNMPTRAP"
|
|
274
|
+
],
|
|
275
|
+
"Syslog": [
|
|
276
|
+
"Syslog"
|
|
277
|
+
],
|
|
278
|
+
|
|
279
|
+
// -------------------- Cloud Services / APIs -----------------
|
|
280
|
+
"AWS S3": [
|
|
281
|
+
"AmazonS3",
|
|
282
|
+
"S3"
|
|
283
|
+
],
|
|
284
|
+
"AWS RDS": [
|
|
285
|
+
"AWS RDS",
|
|
286
|
+
"amazon-rds"
|
|
287
|
+
],
|
|
288
|
+
"Azure DevOps": [
|
|
289
|
+
"Azure DevOps",
|
|
290
|
+
"VSTS"
|
|
291
|
+
],
|
|
292
|
+
"GCP Services": [
|
|
293
|
+
"GCP",
|
|
294
|
+
"googleapis.com"
|
|
295
|
+
],
|
|
296
|
+
|
|
297
|
+
// -------------------- Repo / Code Hosting --------------------
|
|
298
|
+
"Git": [
|
|
299
|
+
"git-daemon"
|
|
300
|
+
],
|
|
301
|
+
"SVN": [
|
|
302
|
+
"SVN",
|
|
303
|
+
"Subversion"
|
|
304
|
+
],
|
|
305
|
+
|
|
306
|
+
// -------------- HPC / Cluster Management / HPC --------------
|
|
307
|
+
"Slurm": [
|
|
308
|
+
"Slurm"
|
|
309
|
+
],
|
|
310
|
+
|
|
311
|
+
// --------------------- Misc / Exotic ------------------------
|
|
312
|
+
"Tor": [
|
|
313
|
+
"Tor",
|
|
314
|
+
"obfs"
|
|
315
|
+
],
|
|
316
|
+
"ZeroTier": [
|
|
317
|
+
"ZeroTier"
|
|
318
|
+
],
|
|
319
|
+
"Mumble": [
|
|
320
|
+
"Mumble",
|
|
321
|
+
"Murmur"
|
|
322
|
+
],
|
|
323
|
+
"Spice": [
|
|
324
|
+
"SPICE protocol"
|
|
325
|
+
],
|
|
326
|
+
"FusionDirectory": [
|
|
327
|
+
"FusionDirectory"
|
|
328
|
+
],
|
|
329
|
+
"Jenkins": [
|
|
330
|
+
"Jenkins"
|
|
331
|
+
],
|
|
332
|
+
"GitLab": [
|
|
333
|
+
"GitLab"
|
|
334
|
+
],
|
|
335
|
+
"GitHub": [
|
|
336
|
+
"GitHub",
|
|
337
|
+
"github.com"
|
|
338
|
+
],
|
|
339
|
+
"Bitbucket": [
|
|
340
|
+
"Bitbucket"
|
|
341
|
+
],
|
|
342
|
+
|
|
343
|
+
// ------------------ Legacy or Older Protocols ---------------
|
|
344
|
+
"Gopher": [
|
|
345
|
+
"Gopher"
|
|
346
|
+
],
|
|
347
|
+
"Finger": [
|
|
348
|
+
"Finger"
|
|
349
|
+
],
|
|
350
|
+
"Ident": [
|
|
351
|
+
"Ident"
|
|
352
|
+
],
|
|
353
|
+
"Rlogin": [
|
|
354
|
+
"rlogin"
|
|
355
|
+
],
|
|
356
|
+
"Rsync": [
|
|
357
|
+
"rsync"
|
|
358
|
+
],
|
|
359
|
+
"UUCP": [
|
|
360
|
+
"UUCP"
|
|
361
|
+
],
|
|
362
|
+
"AFS": [
|
|
363
|
+
"AFS",
|
|
364
|
+
"OpenAFS"
|
|
365
|
+
],
|
|
366
|
+
"NIS": [
|
|
367
|
+
"NIS",
|
|
368
|
+
"YPServ"
|
|
369
|
+
],
|
|
370
|
+
"Telnet SSL": [
|
|
371
|
+
"telnet-ssl"
|
|
372
|
+
],
|
|
373
|
+
|
|
374
|
+
// ----------------- Big Data / Hadoop Ecosystem --------------
|
|
375
|
+
"Hadoop": [
|
|
376
|
+
"Hadoop",
|
|
377
|
+
"MapReduce",
|
|
378
|
+
"YARN"
|
|
379
|
+
],
|
|
380
|
+
"HDFS": [
|
|
381
|
+
"HDFS"
|
|
382
|
+
],
|
|
383
|
+
"Hive": [
|
|
384
|
+
"Hive",
|
|
385
|
+
"HiveServer2"
|
|
386
|
+
],
|
|
387
|
+
"HBase": [
|
|
388
|
+
"HBase",
|
|
389
|
+
"HMaster"
|
|
390
|
+
],
|
|
391
|
+
"Zookeeper": [
|
|
392
|
+
"Zookeeper",
|
|
393
|
+
"ZooKeeper"
|
|
394
|
+
],
|
|
395
|
+
"Spark": [
|
|
396
|
+
"Spark"
|
|
397
|
+
],
|
|
398
|
+
|
|
399
|
+
// ------------ Web Frameworks / Application Servers ----------
|
|
400
|
+
"Tomcat": [
|
|
401
|
+
"Apache Tomcat",
|
|
402
|
+
"Apache-Coyote"
|
|
403
|
+
],
|
|
404
|
+
"JBoss": [
|
|
405
|
+
"JBoss",
|
|
406
|
+
"JBoss EAP"
|
|
407
|
+
],
|
|
408
|
+
"GlassFish": [
|
|
409
|
+
"GlassFish"
|
|
410
|
+
],
|
|
411
|
+
"WebLogic": [
|
|
412
|
+
"WebLogic"
|
|
413
|
+
],
|
|
414
|
+
"WebSphere": [
|
|
415
|
+
"WebSphere"
|
|
416
|
+
],
|
|
417
|
+
"Jetty": [
|
|
418
|
+
"Jetty"
|
|
419
|
+
],
|
|
420
|
+
// Gunicorn and uWSGI also appear under HTTP if they surface in the banner.
|
|
421
|
+
|
|
422
|
+
// ------- Additional Container / Orchestration Tools ---------
|
|
423
|
+
"Docker Swarm": [
|
|
424
|
+
"Swarm"
|
|
425
|
+
],
|
|
426
|
+
|
|
427
|
+
// ---------- Reverse Proxies / Load Balancers / Gateways -----
|
|
428
|
+
"HAProxy": [
|
|
429
|
+
"HAProxy"
|
|
430
|
+
],
|
|
431
|
+
"Traefik": [
|
|
432
|
+
"Traefik"
|
|
433
|
+
],
|
|
434
|
+
"Envoy": [
|
|
435
|
+
"Envoy"
|
|
436
|
+
],
|
|
437
|
+
|
|
438
|
+
// ------------------ CI/CD and DevOps Tools ------------------
|
|
439
|
+
"Bamboo": [
|
|
440
|
+
"Bamboo"
|
|
441
|
+
],
|
|
442
|
+
"TeamCity": [
|
|
443
|
+
"TeamCity"
|
|
444
|
+
],
|
|
445
|
+
"Drone CI": [
|
|
446
|
+
"Drone"
|
|
447
|
+
],
|
|
448
|
+
|
|
449
|
+
// ------------------- Just for completeness ------------------
|
|
450
|
+
"COBOL-based service": [
|
|
451
|
+
"Mainframe",
|
|
452
|
+
"AS/400",
|
|
453
|
+
// Banner might mention "Enterprise COBOL" or "z/OS"
|
|
454
|
+
"z/OS"
|
|
455
|
+
]
|
|
456
|
+
}
|
|
@@ -35,6 +35,8 @@ def get_scan(scan_id):
|
|
|
35
35
|
@api_bp.route('/api/scan/<scan_id>/summary',methods=['GET'])
|
|
36
36
|
def get_scan_summary(scan_id):
|
|
37
37
|
scan = scan_manager.get_scan(scan_id)
|
|
38
|
+
if not scan:
|
|
39
|
+
return jsonify({'error':'scan not found'}), 404
|
|
38
40
|
return jsonify({
|
|
39
41
|
'running': scan.running,
|
|
40
42
|
'percent_complete': scan.calc_percent_complete(),
|
|
@@ -61,5 +63,5 @@ def get_scan_config():
|
|
|
61
63
|
return ScanConfig(
|
|
62
64
|
subnet = data['subnet'],
|
|
63
65
|
port_list= data['port_list'],
|
|
64
|
-
|
|
66
|
+
t_multiplier=data.get('parallelism',1.0)
|
|
65
67
|
)
|
|
@@ -22,7 +22,7 @@ def index():
|
|
|
22
22
|
scan = scanner.results.export()
|
|
23
23
|
subnet = scan['subnet']
|
|
24
24
|
port_list = scan['port_list']
|
|
25
|
-
parallelism = scan['
|
|
25
|
+
parallelism = scan['cfg']['t_multiplier']
|
|
26
26
|
else:
|
|
27
27
|
log.debug(f'Redirecting, scan {scan_id} doesnt exist in memory')
|
|
28
28
|
return redirect('/')
|
|
@@ -164,7 +164,6 @@ function pollScanSummary(id) {
|
|
|
164
164
|
if (summary.running || summary.stage == 'terminating') {
|
|
165
165
|
progress.css('height','2px');
|
|
166
166
|
progress.css('width',`${summary.percent_complete}vw`);
|
|
167
|
-
// TODO: move overview here??
|
|
168
167
|
setTimeout(() => {pollScanSummary(id)},500);
|
|
169
168
|
} else {
|
|
170
169
|
progress.css('width','100vw');
|
|
@@ -179,6 +178,11 @@ function pollScanSummary(id) {
|
|
|
179
178
|
},1000);
|
|
180
179
|
}
|
|
181
180
|
updateOverviewUI(summary);
|
|
181
|
+
}).fail(function(req) {
|
|
182
|
+
if (req === 404) {
|
|
183
|
+
console.log('Scan not found, redirecting to home');
|
|
184
|
+
window.location.href = '/';
|
|
185
|
+
}
|
|
182
186
|
});
|
|
183
187
|
}
|
|
184
188
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: lanscape
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.9a2
|
|
4
4
|
Summary: A python based local network scanner
|
|
5
5
|
Author-email: Michael Dennis <michael@dipduo.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/mdennis281/py-lanscape
|
|
@@ -55,14 +55,6 @@ can sometimes require admin-level permissions to retrieve accurate results.
|
|
|
55
55
|
This is a missing dependency related to the ARP lookup. This is handled in the code, but you would get marginally faster/better results with this installed: [npcap download](https://npcap.com/#download)
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
### Unable to start webview client. Try --nogui (Linux)
|
|
59
|
-
Linux and QT (GUI package) dont seem to play well with each other very well. If you really want the gui (`python -m lanscape --nogui` is almost as good) I had success on ubuntu desktop by running these:
|
|
60
|
-
```sh
|
|
61
|
-
sudo apt install libcairo2-dev libxt-dev libgirepository1.0-dev
|
|
62
|
-
pip install pycairo PyGObject qtpy PyQt5 PyQtWebEngine
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
|
|
66
58
|
### Something else
|
|
67
59
|
Feel free to submit a github issue detailing your experience.
|
|
68
60
|
|
|
@@ -18,6 +18,7 @@ src/lanscape/libraries/mac_lookup.py
|
|
|
18
18
|
src/lanscape/libraries/net_tools.py
|
|
19
19
|
src/lanscape/libraries/port_manager.py
|
|
20
20
|
src/lanscape/libraries/runtime_args.py
|
|
21
|
+
src/lanscape/libraries/service_scan.py
|
|
21
22
|
src/lanscape/libraries/subnet_scan.py
|
|
22
23
|
src/lanscape/libraries/version_manager.py
|
|
23
24
|
src/lanscape/resources/mac_addresses/convert_csv.py
|
|
@@ -27,6 +28,7 @@ src/lanscape/resources/ports/full.json
|
|
|
27
28
|
src/lanscape/resources/ports/large.json
|
|
28
29
|
src/lanscape/resources/ports/medium.json
|
|
29
30
|
src/lanscape/resources/ports/small.json
|
|
31
|
+
src/lanscape/resources/services/definitions.jsonc
|
|
30
32
|
src/lanscape/tests/__init__.py
|
|
31
33
|
src/lanscape/tests/_helpers.py
|
|
32
34
|
src/lanscape/tests/test_api.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/img/ico/android-chrome-192x192.png
RENAMED
|
File without changes
|
{lanscape-1.2.8a3 → lanscape-1.2.9a2}/src/lanscape/ui/static/img/ico/android-chrome-512x512.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|