lanscape 1.3.0a6__tar.gz → 1.3.1a1__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.
- {lanscape-1.3.0a6/src/lanscape.egg-info → lanscape-1.3.1a1}/PKG-INFO +12 -3
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/README.md +10 -1
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/pyproject.toml +2 -2
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/libraries/net_tools.py +22 -9
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/libraries/runtime_args.py +2 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/libraries/web_browser.py +14 -3
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/tests/test_api.py +0 -1
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/app.py +15 -4
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/main.py +4 -4
- lanscape-1.3.1a1/src/lanscape/ui/static/js/on-tab-close.js +29 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/templates/core/scripts.html +1 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/templates/info.html +2 -2
- {lanscape-1.3.0a6 → lanscape-1.3.1a1/src/lanscape.egg-info}/PKG-INFO +12 -3
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape.egg-info/SOURCES.txt +1 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape.egg-info/requires.txt +1 -1
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/LICENSE +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/MANIFEST.in +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/setup.cfg +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/__init__.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/__main__.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/libraries/app_scope.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/libraries/decorators.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/libraries/errors.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/libraries/ip_parser.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/libraries/logger.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/libraries/mac_lookup.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/libraries/port_manager.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/libraries/service_scan.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/libraries/subnet_scan.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/libraries/version_manager.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/resources/mac_addresses/convert_csv.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/resources/mac_addresses/mac_db.json +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/resources/ports/convert_csv.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/resources/ports/full.json +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/resources/ports/large.json +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/resources/ports/medium.json +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/resources/ports/small.json +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/resources/services/definitions.jsonc +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/tests/__init__.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/tests/_helpers.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/tests/test_env.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/tests/test_library.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/blueprints/__init__.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/blueprints/api/__init__.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/blueprints/api/port.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/blueprints/api/scan.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/blueprints/api/tools.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/blueprints/web/__init__.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/blueprints/web/routes.py +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/css/style.css +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/img/ico/android-chrome-192x192.png +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/img/ico/android-chrome-512x512.png +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/img/ico/apple-touch-icon.png +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/img/ico/favicon-16x16.png +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/img/ico/favicon-32x32.png +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/img/ico/favicon.ico +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/img/ico/site.webmanifest +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/js/core.js +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/js/layout-sizing.js +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/js/main.js +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/js/quietReload.js +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/js/shutdown-server.js +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/js/subnet-info.js +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/js/subnet-selector.js +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/lanscape.webmanifest +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/templates/base.html +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/templates/core/head.html +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/templates/error.html +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/templates/main.html +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/templates/scan/export.html +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/templates/scan/ip-table-row.html +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/templates/scan/ip-table.html +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/templates/scan/overview.html +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/templates/scan/scan-error.html +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/templates/scan.html +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/templates/shutdown.html +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape.egg-info/dependency_links.txt +0 -0
- {lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lanscape
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.1a1
|
|
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
|
|
@@ -14,7 +14,7 @@ License-File: LICENSE
|
|
|
14
14
|
Requires-Dist: Flask<5.0,>=3.0
|
|
15
15
|
Requires-Dist: psutil<7.0,>=6.0
|
|
16
16
|
Requires-Dist: requests<3.0,>=2.32
|
|
17
|
-
Requires-Dist:
|
|
17
|
+
Requires-Dist: setuptools
|
|
18
18
|
Requires-Dist: scapy<3.0,>=2.3.2
|
|
19
19
|
Requires-Dist: tabulate==0.9.0
|
|
20
20
|
Requires-Dist: pytest
|
|
@@ -32,7 +32,8 @@ python -m lanscape
|
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
## Flags
|
|
35
|
-
- `--port <port number>` port of the flask app (default:
|
|
35
|
+
- `--port <port number>` port of the flask app (default: automagic)
|
|
36
|
+
- `--persistent` dont shutdown server when browser tab is closed (default: false)
|
|
36
37
|
- `--reloader` essentially flask debug mode- good for local development (default: false)
|
|
37
38
|
- `--logfile` save log output to lanscape.log
|
|
38
39
|
- `--loglevel <level>` set the logger's log level (default: INFO)
|
|
@@ -55,6 +56,14 @@ can sometimes require admin-level permissions to retrieve accurate results.
|
|
|
55
56
|
### Message "WARNING: No libpcap provider available ! pcap won't be used"
|
|
56
57
|
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)
|
|
57
58
|
|
|
59
|
+
### The accuracy of the devices found is low
|
|
60
|
+
I use a combination of ARP and Ping to determine if a device is online. This method drops in stability when used in many threads.
|
|
61
|
+
Recommendations:
|
|
62
|
+
|
|
63
|
+
- Drop parallelism value (advanced dropdown)
|
|
64
|
+
- Use python > 3.10 im noticing threadpool improvements after this version
|
|
65
|
+
- Create a bug - I'm curious
|
|
66
|
+
|
|
58
67
|
|
|
59
68
|
### Something else
|
|
60
69
|
Feel free to submit a github issue detailing your experience.
|
|
@@ -10,7 +10,8 @@ python -m lanscape
|
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
## Flags
|
|
13
|
-
- `--port <port number>` port of the flask app (default:
|
|
13
|
+
- `--port <port number>` port of the flask app (default: automagic)
|
|
14
|
+
- `--persistent` dont shutdown server when browser tab is closed (default: false)
|
|
14
15
|
- `--reloader` essentially flask debug mode- good for local development (default: false)
|
|
15
16
|
- `--logfile` save log output to lanscape.log
|
|
16
17
|
- `--loglevel <level>` set the logger's log level (default: INFO)
|
|
@@ -33,6 +34,14 @@ can sometimes require admin-level permissions to retrieve accurate results.
|
|
|
33
34
|
### Message "WARNING: No libpcap provider available ! pcap won't be used"
|
|
34
35
|
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
36
|
|
|
37
|
+
### The accuracy of the devices found is low
|
|
38
|
+
I use a combination of ARP and Ping to determine if a device is online. This method drops in stability when used in many threads.
|
|
39
|
+
Recommendations:
|
|
40
|
+
|
|
41
|
+
- Drop parallelism value (advanced dropdown)
|
|
42
|
+
- Use python > 3.10 im noticing threadpool improvements after this version
|
|
43
|
+
- Create a bug - I'm curious
|
|
44
|
+
|
|
36
45
|
|
|
37
46
|
### Something else
|
|
38
47
|
Feel free to submit a github issue detailing your experience.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "lanscape"
|
|
3
|
-
version = "1.3.
|
|
3
|
+
version = "1.3.1a1"
|
|
4
4
|
authors = [
|
|
5
5
|
{ name="Michael Dennis", email="michael@dipduo.com" },
|
|
6
6
|
]
|
|
@@ -16,7 +16,7 @@ dependencies = [
|
|
|
16
16
|
"Flask>=3.0,<5.0",
|
|
17
17
|
"psutil>=6.0,<7.0",
|
|
18
18
|
"requests>=2.32,<3.0",
|
|
19
|
-
"
|
|
19
|
+
"setuptools",
|
|
20
20
|
"scapy>=2.3.2,<3.0",
|
|
21
21
|
"tabulate==0.9.0",
|
|
22
22
|
"pytest"
|
|
@@ -38,13 +38,19 @@ class IPAlive:
|
|
|
38
38
|
for future in as_completed(futures):
|
|
39
39
|
try:
|
|
40
40
|
if future.result():
|
|
41
|
-
# one check succeeded — don
|
|
42
|
-
|
|
41
|
+
# one check succeeded — don't block on the other
|
|
42
|
+
# Cancel remaining futures in a version-compatible way
|
|
43
|
+
for f in futures:
|
|
44
|
+
if not f.done():
|
|
45
|
+
f.cancel()
|
|
46
|
+
|
|
47
|
+
executor.shutdown(wait=False) # Python 3.8 compatible
|
|
43
48
|
return True
|
|
44
49
|
except Exception as e:
|
|
45
50
|
# treat any error as a False response
|
|
51
|
+
log.debug(f'Error while checking {ip}: {e}')
|
|
46
52
|
self.caught_errors.append(DeviceError(e))
|
|
47
|
-
|
|
53
|
+
|
|
48
54
|
|
|
49
55
|
# neither check found the host alive
|
|
50
56
|
executor.shutdown()
|
|
@@ -341,17 +347,24 @@ def get_all_network_subnets():
|
|
|
341
347
|
|
|
342
348
|
return subnets
|
|
343
349
|
|
|
344
|
-
def smart_select_primary_subnet(subnets: List[dict]=
|
|
350
|
+
def smart_select_primary_subnet(subnets: List[dict] | None = None) -> str:
|
|
345
351
|
"""
|
|
346
|
-
|
|
347
|
-
|
|
352
|
+
Finds the largest subnet within max ip range. If no subnets are
|
|
353
|
+
available, returns an empty string instead of raising ``KeyError``.
|
|
348
354
|
"""
|
|
355
|
+
subnets = subnets or get_all_network_subnets()
|
|
356
|
+
|
|
357
|
+
if not subnets:
|
|
358
|
+
return ""
|
|
359
|
+
|
|
349
360
|
selected = {}
|
|
350
361
|
for subnet in subnets:
|
|
351
|
-
if selected.get(
|
|
362
|
+
if selected.get("address_cnt", 0) < subnet["address_cnt"] < MAX_IPS_ALLOWED:
|
|
352
363
|
selected = subnet
|
|
353
|
-
|
|
364
|
+
|
|
365
|
+
if not selected:
|
|
354
366
|
selected = subnets[0]
|
|
355
|
-
|
|
367
|
+
|
|
368
|
+
return selected.get("subnet", "")
|
|
356
369
|
|
|
357
370
|
|
|
@@ -10,6 +10,7 @@ class RuntimeArgs:
|
|
|
10
10
|
logfile: bool = False
|
|
11
11
|
loglevel: str = 'INFO'
|
|
12
12
|
flask_logging: bool = False
|
|
13
|
+
persistent: bool = False
|
|
13
14
|
|
|
14
15
|
def parse_args() -> RuntimeArgs:
|
|
15
16
|
parser = argparse.ArgumentParser(description='LANscape')
|
|
@@ -19,6 +20,7 @@ def parse_args() -> RuntimeArgs:
|
|
|
19
20
|
parser.add_argument('--logfile', action='store_true', help='Log output to lanscape.log')
|
|
20
21
|
parser.add_argument('--loglevel', default='INFO', help='Set the log level')
|
|
21
22
|
parser.add_argument('--flask-logging', action='store_true', help='Enable flask logging (disables click output)')
|
|
23
|
+
parser.add_argument('--persistent', action='store_true', help='Don\'t exit after browser is closed')
|
|
22
24
|
|
|
23
25
|
# Parse the arguments
|
|
24
26
|
args = parser.parse_args()
|
|
@@ -14,7 +14,7 @@ import webbrowser
|
|
|
14
14
|
import logging
|
|
15
15
|
import re
|
|
16
16
|
import time
|
|
17
|
-
import
|
|
17
|
+
from typing import Optional
|
|
18
18
|
from ..ui.app import app
|
|
19
19
|
|
|
20
20
|
log = logging.getLogger('WebBrowser')
|
|
@@ -29,6 +29,13 @@ def open_webapp(url: str) -> bool:
|
|
|
29
29
|
"""
|
|
30
30
|
start = time.time()
|
|
31
31
|
try:
|
|
32
|
+
if sys.platform.startswith("darwin"):
|
|
33
|
+
# macOS does not support chrome-style app mode via the generic
|
|
34
|
+
# method. Fallback to the system "open" command which will use the
|
|
35
|
+
# default browser.
|
|
36
|
+
subprocess.run(["open", url], check=True)
|
|
37
|
+
return True
|
|
38
|
+
|
|
32
39
|
exe = get_default_browser_executable()
|
|
33
40
|
if not exe:
|
|
34
41
|
raise RuntimeError('Unable to find browser binary')
|
|
@@ -56,7 +63,7 @@ def open_webapp(url: str) -> bool:
|
|
|
56
63
|
return False
|
|
57
64
|
|
|
58
65
|
|
|
59
|
-
def get_default_browser_executable() -> str
|
|
66
|
+
def get_default_browser_executable() -> Optional[str]:
|
|
60
67
|
if sys.platform.startswith("win"):
|
|
61
68
|
try:
|
|
62
69
|
import winreg
|
|
@@ -117,8 +124,12 @@ def get_default_browser_executable() -> str | None:
|
|
|
117
124
|
# strip arguments like “%u”, “--flag”, etc.
|
|
118
125
|
exec_cmd = exec_cmd.split()[0]
|
|
119
126
|
exec_cmd = exec_cmd.split("%")[0]
|
|
120
|
-
|
|
127
|
+
return exec_cmd
|
|
121
128
|
return None
|
|
122
129
|
|
|
130
|
+
elif sys.platform.startswith("darwin"):
|
|
131
|
+
# macOS will use the system 'open' command to launch the default browser
|
|
132
|
+
return "/usr/bin/open"
|
|
133
|
+
|
|
123
134
|
else:
|
|
124
135
|
raise NotImplementedError(f"Unsupported platform: {sys.platform!r}")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from flask import Flask, render_template
|
|
1
|
+
from flask import Flask, render_template, request
|
|
2
2
|
from time import sleep
|
|
3
3
|
import multiprocessing
|
|
4
4
|
import traceback
|
|
@@ -62,11 +62,22 @@ set_global_safe('is_local',is_local_run)
|
|
|
62
62
|
################################
|
|
63
63
|
|
|
64
64
|
exiting = False
|
|
65
|
-
@app.route("/shutdown")
|
|
65
|
+
@app.route("/shutdown", methods=['GET', 'POST'])
|
|
66
66
|
def exit_app():
|
|
67
|
+
|
|
68
|
+
req_type = request.args.get('type')
|
|
69
|
+
if req_type == 'browser-close':
|
|
70
|
+
args = parse_args()
|
|
71
|
+
if args.persistent:
|
|
72
|
+
log.info('Dectected browser close, not exiting flask.')
|
|
73
|
+
return "Ignored"
|
|
74
|
+
log.info('Web browser closed, terminating flask. (disable with --peristent)')
|
|
75
|
+
elif req_type == 'core':
|
|
76
|
+
log.info('Core requested exit, terminating flask.')
|
|
77
|
+
else:
|
|
78
|
+
log.info('Received external exit request. Terminating flask.')
|
|
67
79
|
global exiting
|
|
68
80
|
exiting = True
|
|
69
|
-
log.info('Received external exit request. Terminating flask.')
|
|
70
81
|
return "Done"
|
|
71
82
|
|
|
72
83
|
@app.teardown_request
|
|
@@ -89,7 +100,7 @@ def internal_error(e):
|
|
|
89
100
|
## Webserver creation functions
|
|
90
101
|
################################
|
|
91
102
|
|
|
92
|
-
def
|
|
103
|
+
def start_webserver_daemon(args: RuntimeArgs) -> threading.Thread:
|
|
93
104
|
proc = threading.Thread(target=start_webserver, args=(args,))
|
|
94
105
|
proc.daemon = True # Kill thread when main thread exits
|
|
95
106
|
proc.start()
|
|
@@ -12,7 +12,7 @@ args = parse_args()
|
|
|
12
12
|
configure_logging(args.loglevel, args.logfile, args.flask_logging)
|
|
13
13
|
|
|
14
14
|
from ..libraries.version_manager import get_installed_version, is_update_available
|
|
15
|
-
from .app import
|
|
15
|
+
from .app import start_webserver_daemon, start_webserver
|
|
16
16
|
import socket
|
|
17
17
|
|
|
18
18
|
|
|
@@ -100,13 +100,13 @@ def start_webserver_ui(args: RuntimeArgs):
|
|
|
100
100
|
).start()
|
|
101
101
|
start_webserver(args)
|
|
102
102
|
else:
|
|
103
|
-
flask_thread =
|
|
103
|
+
flask_thread = start_webserver_daemon(args)
|
|
104
104
|
app_closed = open_browser(uri)
|
|
105
105
|
|
|
106
106
|
# depending on env, open_browser may or
|
|
107
107
|
# may not be coupled with the closure of UI
|
|
108
108
|
# (if in browser tab, it's uncoupled)
|
|
109
|
-
if not app_closed:
|
|
109
|
+
if not app_closed or args.persistent:
|
|
110
110
|
# not doing a direct join so i can still
|
|
111
111
|
# terminate the app with ctrl+c
|
|
112
112
|
while flask_thread.is_alive():
|
|
@@ -126,7 +126,7 @@ def get_valid_port(port: int):
|
|
|
126
126
|
def terminate():
|
|
127
127
|
import requests
|
|
128
128
|
log.info('Attempting flask shutdown')
|
|
129
|
-
requests.get(f'http://127.0.0.1:{args.port}/shutdown')
|
|
129
|
+
requests.get(f'http://127.0.0.1:{args.port}/shutdown?type=core')
|
|
130
130
|
|
|
131
131
|
|
|
132
132
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// This is the payload you want to send on unload.
|
|
2
|
+
// It can be as simple as JSON or just an empty POST.
|
|
3
|
+
function sendOnUnload() {
|
|
4
|
+
const url = '/shutdown?type=browser-close';
|
|
5
|
+
const data = JSON.stringify({ });
|
|
6
|
+
// (1) Using navigator.sendBeacon
|
|
7
|
+
if (navigator.sendBeacon) {
|
|
8
|
+
const blob = new Blob([data], { type: 'application/json' });
|
|
9
|
+
navigator.sendBeacon(url, blob);
|
|
10
|
+
}
|
|
11
|
+
// (2) Or—you can use fetch with keepalive (supported in modern browsers)
|
|
12
|
+
else {
|
|
13
|
+
fetch(url, {
|
|
14
|
+
method: 'POST',
|
|
15
|
+
body: data,
|
|
16
|
+
headers: { 'Content-Type': 'application/json' },
|
|
17
|
+
keepalive: true
|
|
18
|
+
})
|
|
19
|
+
.catch((err) => {
|
|
20
|
+
// If it fails, there’s not much you can do here.
|
|
21
|
+
console.warn('sendOnUnload fetch failed:', err);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Attach to both beforeunload and unload to increase reliability.
|
|
27
|
+
// beforeunload fires slightly earlier, but some browsers block async work there.
|
|
28
|
+
window.addEventListener('beforeunload', sendOnUnload);
|
|
29
|
+
window.addEventListener('unload', sendOnUnload);
|
|
@@ -3,3 +3,4 @@
|
|
|
3
3
|
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
|
|
4
4
|
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js"></script>
|
|
5
5
|
<script src="{{ url_for('static', filename='js/core.js') }}"></script>
|
|
6
|
+
<script src="{{ url_for('static', filename='js/on-tab-close.js') }}"></script>
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
This project has been a learning journey, & I hope it helps you
|
|
34
34
|
discover more about your network as well. Enjoy!
|
|
35
35
|
</p>
|
|
36
|
-
<a href="https://github.com/mdennis281/" target="_blank"
|
|
37
|
-
<button class="btn btn-primary m-2">
|
|
36
|
+
<a href="https://github.com/mdennis281/" target="_blank">
|
|
37
|
+
<button class="btn btn-primary m-2">GitHub</button>
|
|
38
38
|
</a>
|
|
39
39
|
<a href="https://github.com/mdennis281/LANscape" target="_blank">
|
|
40
40
|
<button class="btn btn-secondary m-2">Project Repo</button>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lanscape
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.1a1
|
|
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
|
|
@@ -14,7 +14,7 @@ License-File: LICENSE
|
|
|
14
14
|
Requires-Dist: Flask<5.0,>=3.0
|
|
15
15
|
Requires-Dist: psutil<7.0,>=6.0
|
|
16
16
|
Requires-Dist: requests<3.0,>=2.32
|
|
17
|
-
Requires-Dist:
|
|
17
|
+
Requires-Dist: setuptools
|
|
18
18
|
Requires-Dist: scapy<3.0,>=2.3.2
|
|
19
19
|
Requires-Dist: tabulate==0.9.0
|
|
20
20
|
Requires-Dist: pytest
|
|
@@ -32,7 +32,8 @@ python -m lanscape
|
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
## Flags
|
|
35
|
-
- `--port <port number>` port of the flask app (default:
|
|
35
|
+
- `--port <port number>` port of the flask app (default: automagic)
|
|
36
|
+
- `--persistent` dont shutdown server when browser tab is closed (default: false)
|
|
36
37
|
- `--reloader` essentially flask debug mode- good for local development (default: false)
|
|
37
38
|
- `--logfile` save log output to lanscape.log
|
|
38
39
|
- `--loglevel <level>` set the logger's log level (default: INFO)
|
|
@@ -55,6 +56,14 @@ can sometimes require admin-level permissions to retrieve accurate results.
|
|
|
55
56
|
### Message "WARNING: No libpcap provider available ! pcap won't be used"
|
|
56
57
|
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)
|
|
57
58
|
|
|
59
|
+
### The accuracy of the devices found is low
|
|
60
|
+
I use a combination of ARP and Ping to determine if a device is online. This method drops in stability when used in many threads.
|
|
61
|
+
Recommendations:
|
|
62
|
+
|
|
63
|
+
- Drop parallelism value (advanced dropdown)
|
|
64
|
+
- Use python > 3.10 im noticing threadpool improvements after this version
|
|
65
|
+
- Create a bug - I'm curious
|
|
66
|
+
|
|
58
67
|
|
|
59
68
|
### Something else
|
|
60
69
|
Feel free to submit a github issue detailing your experience.
|
|
@@ -56,6 +56,7 @@ src/lanscape/ui/static/img/ico/site.webmanifest
|
|
|
56
56
|
src/lanscape/ui/static/js/core.js
|
|
57
57
|
src/lanscape/ui/static/js/layout-sizing.js
|
|
58
58
|
src/lanscape/ui/static/js/main.js
|
|
59
|
+
src/lanscape/ui/static/js/on-tab-close.js
|
|
59
60
|
src/lanscape/ui/static/js/quietReload.js
|
|
60
61
|
src/lanscape/ui/static/js/shutdown-server.js
|
|
61
62
|
src/lanscape/ui/static/js/subnet-info.js
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lanscape-1.3.0a6 → lanscape-1.3.1a1}/src/lanscape/ui/static/img/ico/android-chrome-192x192.png
RENAMED
|
File without changes
|
{lanscape-1.3.0a6 → lanscape-1.3.1a1}/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
|