lanscape 2.2.1a1__py3-none-any.whl → 2.3.0b1__py3-none-any.whl
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/core/net_tools.py +14 -3
- lanscape/core/service_scan.py +38 -3
- lanscape/ui/blueprints/api/port.py +14 -0
- lanscape/ui/static/css/style.css +2 -2
- lanscape/ui/static/js/scan-config.js +17 -6
- lanscape/ui/templates/scan/config.html +5 -3
- {lanscape-2.2.1a1.dist-info → lanscape-2.3.0b1.dist-info}/METADATA +3 -1
- {lanscape-2.2.1a1.dist-info → lanscape-2.3.0b1.dist-info}/RECORD +12 -12
- {lanscape-2.2.1a1.dist-info → lanscape-2.3.0b1.dist-info}/WHEEL +0 -0
- {lanscape-2.2.1a1.dist-info → lanscape-2.3.0b1.dist-info}/entry_points.txt +0 -0
- {lanscape-2.2.1a1.dist-info → lanscape-2.3.0b1.dist-info}/licenses/LICENSE +0 -0
- {lanscape-2.2.1a1.dist-info → lanscape-2.3.0b1.dist-info}/top_level.txt +0 -0
lanscape/core/net_tools.py
CHANGED
|
@@ -138,18 +138,29 @@ class Device(BaseModel):
|
|
|
138
138
|
@timeout_enforcer(enforcer_timeout, False)
|
|
139
139
|
def do_test():
|
|
140
140
|
for attempt in range(port_config.retries + 1):
|
|
141
|
-
sock =
|
|
142
|
-
sock.settimeout(port_config.timeout)
|
|
141
|
+
sock = None
|
|
143
142
|
try:
|
|
143
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
144
|
+
sock.settimeout(port_config.timeout)
|
|
144
145
|
result = sock.connect_ex((self.ip, port))
|
|
145
146
|
if result == 0:
|
|
146
147
|
if port not in self.ports:
|
|
147
148
|
self.ports.append(port)
|
|
148
149
|
return True
|
|
150
|
+
except OSError as e:
|
|
151
|
+
# Handle socket creation failures (e.g., "Too many open files")
|
|
152
|
+
# Log and continue to retry if attempts remain
|
|
153
|
+
log = logging.getLogger('Device.test_port')
|
|
154
|
+
log.debug(f"OSError on {self.ip}:{port} attempt {attempt + 1}: {e}")
|
|
149
155
|
except Exception:
|
|
150
156
|
pass # Connection failed, try again if retries remain
|
|
151
157
|
finally:
|
|
152
|
-
|
|
158
|
+
# Always close socket if it was created
|
|
159
|
+
if sock is not None:
|
|
160
|
+
try:
|
|
161
|
+
sock.close()
|
|
162
|
+
except Exception:
|
|
163
|
+
pass # Ignore errors during cleanup
|
|
153
164
|
|
|
154
165
|
# Wait before retry (except on last attempt)
|
|
155
166
|
if attempt < port_config.retries:
|
lanscape/core/service_scan.py
CHANGED
|
@@ -154,7 +154,9 @@ def get_port_probes(port: int, strategy: ServiceScanStrategy):
|
|
|
154
154
|
|
|
155
155
|
def scan_service(ip: str, port: int, cfg: ServiceScanConfig) -> str:
|
|
156
156
|
"""
|
|
157
|
-
Synchronous function that attempts to identify the service
|
|
157
|
+
Synchronous function that attempts to identify the service
|
|
158
|
+
running on a given port.
|
|
159
|
+
TODO: This is AI slop and needs to be reworked properly.
|
|
158
160
|
"""
|
|
159
161
|
|
|
160
162
|
async def _async_scan_service(
|
|
@@ -183,5 +185,38 @@ def scan_service(ip: str, port: int, cfg: ServiceScanConfig) -> str:
|
|
|
183
185
|
log.debug(traceback.format_exc())
|
|
184
186
|
return "Unknown"
|
|
185
187
|
|
|
186
|
-
#
|
|
187
|
-
|
|
188
|
+
# Create and properly manage event loop to avoid file descriptor leaks
|
|
189
|
+
# Using new_event_loop + explicit close is safer in threaded environments
|
|
190
|
+
# than asyncio.run() which can leave resources open under heavy load
|
|
191
|
+
loop = None
|
|
192
|
+
try:
|
|
193
|
+
try:
|
|
194
|
+
# Try to get existing loop first (if running in async context)
|
|
195
|
+
loop = asyncio.get_running_loop()
|
|
196
|
+
# If we're already in an async context, just await directly
|
|
197
|
+
return asyncio.run_coroutine_threadsafe(
|
|
198
|
+
_async_scan_service(ip, port, cfg=cfg), loop
|
|
199
|
+
).result(timeout=cfg.timeout + 5)
|
|
200
|
+
except RuntimeError:
|
|
201
|
+
# No running loop, create a new one
|
|
202
|
+
loop = asyncio.new_event_loop()
|
|
203
|
+
asyncio.set_event_loop(loop)
|
|
204
|
+
try:
|
|
205
|
+
return loop.run_until_complete(_async_scan_service(ip, port, cfg=cfg))
|
|
206
|
+
finally:
|
|
207
|
+
# Clean up the loop properly
|
|
208
|
+
try:
|
|
209
|
+
# Cancel all remaining tasks
|
|
210
|
+
pending = asyncio.all_tasks(loop)
|
|
211
|
+
for task in pending:
|
|
212
|
+
task.cancel()
|
|
213
|
+
# Run loop once more to process cancellations
|
|
214
|
+
if pending:
|
|
215
|
+
loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True))
|
|
216
|
+
except Exception:
|
|
217
|
+
pass
|
|
218
|
+
finally:
|
|
219
|
+
loop.close()
|
|
220
|
+
except Exception as e:
|
|
221
|
+
log.error(f"Event loop error scanning {ip}:{port}: {e}")
|
|
222
|
+
return "Unknown"
|
|
@@ -21,6 +21,20 @@ def get_port_lists():
|
|
|
21
21
|
return jsonify(PortManager().get_port_lists())
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
@api_bp.route('/api/port/list/summary', methods=['GET'])
|
|
25
|
+
def get_port_lists_summary():
|
|
26
|
+
"""Get port list names with their port counts."""
|
|
27
|
+
manager = PortManager()
|
|
28
|
+
summaries = []
|
|
29
|
+
for name in manager.get_port_lists():
|
|
30
|
+
ports = manager.get_port_list(name) or {}
|
|
31
|
+
summaries.append({
|
|
32
|
+
'name': name,
|
|
33
|
+
'count': len(ports)
|
|
34
|
+
})
|
|
35
|
+
return jsonify(summaries)
|
|
36
|
+
|
|
37
|
+
|
|
24
38
|
@api_bp.route('/api/port/list/<port_list>', methods=['GET'])
|
|
25
39
|
def get_port_list(port_list):
|
|
26
40
|
"""
|
lanscape/ui/static/css/style.css
CHANGED
|
@@ -564,8 +564,8 @@ input[type="range"] {
|
|
|
564
564
|
/* Service Strategy Select Styles */
|
|
565
565
|
.service-strategy-wrapper {
|
|
566
566
|
position: relative;
|
|
567
|
-
display:
|
|
568
|
-
width:
|
|
567
|
+
display: block;
|
|
568
|
+
width: 100%;
|
|
569
569
|
}
|
|
570
570
|
|
|
571
571
|
.service-strategy {
|
|
@@ -139,15 +139,26 @@ function getScanConfig() {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
function getPortLists(callback=null) {
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
const customSelectDropdown = $('#port_list');
|
|
143
|
+
|
|
144
|
+
const renderOptions = (items) => {
|
|
144
145
|
customSelectDropdown.empty();
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
items.forEach((item) => {
|
|
147
|
+
const name = item.name || item;
|
|
148
|
+
const count = item.count;
|
|
149
|
+
const label = count !== undefined ? `${name} (${count} ports)` : name;
|
|
150
|
+
customSelectDropdown.append(`<option value="${name}">${label}</option>`);
|
|
149
151
|
});
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
$.get('/api/port/list/summary', function(data) {
|
|
155
|
+
renderOptions(data || []);
|
|
150
156
|
if (callback) callback();
|
|
157
|
+
}).fail(function() {
|
|
158
|
+
$.get('/api/port/list', function(data) {
|
|
159
|
+
renderOptions(data || []);
|
|
160
|
+
if (callback) callback();
|
|
161
|
+
});
|
|
151
162
|
});
|
|
152
163
|
}
|
|
153
164
|
|
|
@@ -201,7 +201,7 @@
|
|
|
201
201
|
<div id="section-service-scan" class="form-group mt-2 config-section div-hide">
|
|
202
202
|
<h6>Service Scanning</h6>
|
|
203
203
|
<div class="row">
|
|
204
|
-
<div class="col">
|
|
204
|
+
<div class="col-12">
|
|
205
205
|
<label for="service_lookup_type" class="form-label">Strategy</label>
|
|
206
206
|
<div class="service-strategy-wrapper">
|
|
207
207
|
<select id="service_lookup_type" class="service-strategy">
|
|
@@ -211,11 +211,13 @@
|
|
|
211
211
|
</select>
|
|
212
212
|
</div>
|
|
213
213
|
</div>
|
|
214
|
-
|
|
214
|
+
</div>
|
|
215
|
+
<div class="row mt-2">
|
|
216
|
+
<div class="col-12 col-md-6">
|
|
215
217
|
<label for="service_timeout" class="form-label">Timeout (sec)</label>
|
|
216
218
|
<input type="number" step="0.1" id="service_timeout" class="form-control">
|
|
217
219
|
</div>
|
|
218
|
-
<div class="col">
|
|
220
|
+
<div class="col-12 col-md-6 mt-2 mt-md-0">
|
|
219
221
|
<label for="service_max_concurrent_probes" class="form-label">Max Concurrent Probes</label>
|
|
220
222
|
<input type="number" id="service_max_concurrent_probes" class="form-control">
|
|
221
223
|
</div>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lanscape
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0b1
|
|
4
4
|
Summary: A python based local network scanner
|
|
5
5
|
Author-email: Michael Dennis <michael@dipduo.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -31,6 +31,8 @@ Requires-Dist: pytest>=8.0; extra == "dev"
|
|
|
31
31
|
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
32
32
|
Requires-Dist: pytest-xdist>=3.0; extra == "dev"
|
|
33
33
|
Requires-Dist: openai>=1.0.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pylint>=3.0; extra == "dev"
|
|
35
|
+
Requires-Dist: autopep8>=2.0; extra == "dev"
|
|
34
36
|
Dynamic: license-file
|
|
35
37
|
|
|
36
38
|
# LANscape
|
|
@@ -8,11 +8,11 @@ lanscape/core/errors.py,sha256=QTf42UzR9Zxj1t1mdwfLvZIp0c9a5EItELOdCR7kTmE,1322
|
|
|
8
8
|
lanscape/core/ip_parser.py,sha256=kn5H4ERitLnreRAqifWphwbxdjItGqwu50lsMCPDMcA,3474
|
|
9
9
|
lanscape/core/logger.py,sha256=nzo6J8UdlMdhRkOJEDOIHKztoE3Du8PQZad7ixvNgeM,2534
|
|
10
10
|
lanscape/core/mac_lookup.py,sha256=PxBSMe3wEVDtivCsh5NclSAguZz9rqdAS7QshBiuWvM,3519
|
|
11
|
-
lanscape/core/net_tools.py,sha256=
|
|
11
|
+
lanscape/core/net_tools.py,sha256=o5A7e-YHC7VKp0fHJccrhY404qlEDV84P3-fhr8bsbc,21925
|
|
12
12
|
lanscape/core/port_manager.py,sha256=3_ROOb6JEiB0NByZVtADuGcldFkgZwn1RKtvwgs9AIk,4479
|
|
13
13
|
lanscape/core/runtime_args.py,sha256=2vIqRrcWr-NHRSBlZGrxh1PdkPY0ytkPguu8KZqy2L8,2543
|
|
14
14
|
lanscape/core/scan_config.py,sha256=A2ZKXqXKW9nrP6yLb7b9b3XqSY_cQB3LZ5K0LVCSebE,11114
|
|
15
|
-
lanscape/core/service_scan.py,sha256=
|
|
15
|
+
lanscape/core/service_scan.py,sha256=umDVOoCNNVJhWMtxDV-rn7hcS7t_V073srSMPTl5gMo,7943
|
|
16
16
|
lanscape/core/subnet_scan.py,sha256=PtSOk92dK05-reyr8LBkOXaI15qpYnar5nDqALCX1tQ,14850
|
|
17
17
|
lanscape/core/version_manager.py,sha256=eGjyKgsv31QO0W26se9pPQ1TwmEN8qn37dHULtoocqc,2841
|
|
18
18
|
lanscape/resources/mac_addresses/convert_csv.py,sha256=hvlyLs0XmuuhBuvXBNRGP1cKJzYVRSf8VfUJ1VqROms,1189
|
|
@@ -30,13 +30,13 @@ lanscape/ui/main.py,sha256=KXVPfHbKbMP2mMvJ3e2nqdmMTbTadEfuZ7tP4SIDIqE,4334
|
|
|
30
30
|
lanscape/ui/shutdown_handler.py,sha256=HrEnWrdYSzLDVsPgD8tf9FgtAwQrZNECDu6wnEs27EY,1704
|
|
31
31
|
lanscape/ui/blueprints/__init__.py,sha256=EjPtaR5Nh17pGiOVYTJULVNaZntpFZOiYyep8rBWAiE,265
|
|
32
32
|
lanscape/ui/blueprints/api/__init__.py,sha256=5Z4Y7B36O-bNFenpomfuNhPuJ9dW_MC0TPUU3pCFVfA,103
|
|
33
|
-
lanscape/ui/blueprints/api/port.py,sha256=
|
|
33
|
+
lanscape/ui/blueprints/api/port.py,sha256=enqJ87hpVHSTBoaV9bJ7IgsvHrWDTga704wV33dtwUg,2384
|
|
34
34
|
lanscape/ui/blueprints/api/scan.py,sha256=2rsW4xkI4X2Q2ocwaE469aU1VxQ3xHuBRjD9xE36WdI,3326
|
|
35
35
|
lanscape/ui/blueprints/api/tools.py,sha256=jr9gt0VhvBFgJ61MLgNIM6hin-MUmJLGdmStPx3e3Yc,2432
|
|
36
36
|
lanscape/ui/blueprints/web/__init__.py,sha256=NvgnjP0X4LwqVhSEyh5RUzoG45N44kHK1MEFlfvBxTg,118
|
|
37
37
|
lanscape/ui/blueprints/web/routes.py,sha256=f5TzfTzelJ_erslyBXTOpFr4BlIfB1Mb1ye6ioH7IL0,4534
|
|
38
38
|
lanscape/ui/static/lanscape.webmanifest,sha256=07CqA-PQsO35KJD8R96sI3Pxix6UuBjijPDCuy9vM3s,446
|
|
39
|
-
lanscape/ui/static/css/style.css,sha256=
|
|
39
|
+
lanscape/ui/static/css/style.css,sha256=dOlmk0pt03TGFgx2TixTRALX_VpYX9eGDLTFJoUlovA,21196
|
|
40
40
|
lanscape/ui/static/img/ico/android-chrome-192x192.png,sha256=JmFT6KBCCuoyxMV-mLNtF9_QJbVBvfWPUizKN700fi8,18255
|
|
41
41
|
lanscape/ui/static/img/ico/android-chrome-512x512.png,sha256=88Jjx_1-4XAnZYz64KP6FdTl_kYkNG2_kQIKteQwSh4,138055
|
|
42
42
|
lanscape/ui/static/img/ico/apple-touch-icon.png,sha256=tEJlLwBZtF4v-NC90YCfRJQ2prTsF4i3VQLK_hnv2Mw,16523
|
|
@@ -49,7 +49,7 @@ lanscape/ui/static/js/layout-sizing.js,sha256=U2dsyJi-YKpOpudu3kg2whiU4047ghzDTY
|
|
|
49
49
|
lanscape/ui/static/js/main.js,sha256=Bgb5Ld_UPWzBVzxWkLD0kJGjOoLJyzni2TKE6Uk99VA,7428
|
|
50
50
|
lanscape/ui/static/js/on-tab-close.js,sha256=3icxYWlLpY81iLoW7kQTJeWQ3UnyyboG0dESHF2wLPQ,1376
|
|
51
51
|
lanscape/ui/static/js/quietReload.js,sha256=8POH0t1KVzGCJas9fNsOVbBG-ULwZT2wiS14URgkeAU,702
|
|
52
|
-
lanscape/ui/static/js/scan-config.js,sha256=
|
|
52
|
+
lanscape/ui/static/js/scan-config.js,sha256=nQ2dWkgpf8yer-lCMTZ25DBqOuWt0SIyzzfdP_fS-bE,8086
|
|
53
53
|
lanscape/ui/static/js/shutdown-server.js,sha256=Mx8UGmmktHaCK7DL8TVUxah6VEcN0wwLFfhbCId-K8U,453
|
|
54
54
|
lanscape/ui/static/js/subnet-info.js,sha256=osZM6CGs-TC5QpBJWkNWCtXNOKzjyIiWKHwKi4vlDf8,559
|
|
55
55
|
lanscape/ui/static/js/subnet-selector.js,sha256=2YKCAuKU2Ti1CmJrqi4_vNTD2LQbxx7chIDqND_1eAY,358
|
|
@@ -61,16 +61,16 @@ lanscape/ui/templates/scan.html,sha256=00QX2_1S_1wGzk42r00LjEkJvoioCLs6JgjOibi6r
|
|
|
61
61
|
lanscape/ui/templates/shutdown.html,sha256=iXVCq2yl5TjZfNFl4esbDJra3gJA2VQpae0jj4ipy9w,701
|
|
62
62
|
lanscape/ui/templates/core/head.html,sha256=zP1RkTYuaKCC6RtnSEHFKPw3wKWfSyV0HZg5XsAxWik,719
|
|
63
63
|
lanscape/ui/templates/core/scripts.html,sha256=rSRi4Ut8iejajMPhOc5bzEz-Z3EHxpj_3PxwwyyhmTQ,640
|
|
64
|
-
lanscape/ui/templates/scan/config.html,sha256=
|
|
64
|
+
lanscape/ui/templates/scan/config.html,sha256=_XrumonSY0i2Zr8nlHB4UmFUwLc0Wx-yNXqr7sNZ2z8,14806
|
|
65
65
|
lanscape/ui/templates/scan/device-detail.html,sha256=3N0WcdnWopbSFwsnKogBaHOYsLMAfKBZdkP7HQG4vLA,4794
|
|
66
66
|
lanscape/ui/templates/scan/export.html,sha256=Nvs_unojzT3qhN_ZnEgYHou2C9wqWGr3dVr2UiLnYjY,749
|
|
67
67
|
lanscape/ui/templates/scan/ip-table-row.html,sha256=iSW3PYev3_k7pxTZUJUboqDUgdhsWNOrYxysYismyI0,1255
|
|
68
68
|
lanscape/ui/templates/scan/ip-table.html,sha256=AT2ZvCPYdKl-XJiAkEAawPOVuQw-w0MXumGQTr3zyKM,926
|
|
69
69
|
lanscape/ui/templates/scan/overview.html,sha256=xWj9jWDPg2KcPLvS8fnSins23_UXjKCdb2NJwNG2U2Q,1176
|
|
70
70
|
lanscape/ui/templates/scan/scan-error.html,sha256=wmAYQ13IJHUoO8fAGNDjMvNml7tu4rsIU3Vav71ETlA,999
|
|
71
|
-
lanscape-2.
|
|
72
|
-
lanscape-2.
|
|
73
|
-
lanscape-2.
|
|
74
|
-
lanscape-2.
|
|
75
|
-
lanscape-2.
|
|
76
|
-
lanscape-2.
|
|
71
|
+
lanscape-2.3.0b1.dist-info/licenses/LICENSE,sha256=VLoE0IrNTIc09dFm7hMN0qzk4T3q8V0NaPcFQqMemDs,1070
|
|
72
|
+
lanscape-2.3.0b1.dist-info/METADATA,sha256=r89dv1bzcmNA9z_DEK8bHa4n9CX28wqpiRyKUVpEGzI,3703
|
|
73
|
+
lanscape-2.3.0b1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
74
|
+
lanscape-2.3.0b1.dist-info/entry_points.txt,sha256=evxSxUikFa1OEd4e0Boky9sLH87HdgM0YqB_AbB2HYc,51
|
|
75
|
+
lanscape-2.3.0b1.dist-info/top_level.txt,sha256=E9D4sjPz_6H7c85Ycy_pOS2xuv1Wm-ilKhxEprln2ps,9
|
|
76
|
+
lanscape-2.3.0b1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|