Python wrapper for netscope-scan port scanner
Project description
netscope-py
RU | EN
Русский
Тонкая Python-обертка над бинарником netscope-scan — форком RustScan без nmap и скриптинга. Бинарник принимает цели, сканирует порты и возвращает чистый JSON; эта библиотека превращает его в удобный Python-API с полной типизацией.
Требования
- Python ≥ 3.12
- Бинарник
netscope-scanвPATHили переменная окруженияNETSCOPE_BIN
Установка
# из исходников (editable)
uv pip install -e .
# сборка wheel
uv build
Быстрый старт
from netscope import scan, scan_async, ScanResult, ScanError
# --- Синхронный вызов ---
results: list[ScanResult] = scan(
["192.168.1.0/24", "10.0.0.1"],
ports=[22, 80, 443],
)
for r in results:
print(r.ip, r.ports)
# 192.168.1.5 [22, 80]
# 10.0.0.1 [22, 443]
# --- Асинхронный вызов ---
import asyncio
async def main() -> None:
results = await scan_async(["10.0.0.0/24"], range=(1, 1000))
for r in results:
print(r.ip, r.ports)
asyncio.run(main())
Справочник API
scan(addresses, *, ...) → list[ScanResult]
Синхронное сканирование. Блокирует поток до завершения бинарника.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
addresses |
list[str] |
— | Цели: IP, CIDR, хосты |
ports |
list[int] | None |
None |
Конкретные порты |
range |
tuple[int, int] | None |
None |
Диапазон портов (start, end) включительно |
top |
bool |
False |
Топ-1000 популярных портов |
batch_size |
int |
4500 |
Одновременных сокетов |
timeout |
int |
1500 |
Таймаут на порт, мс |
tries |
int |
1 |
Попыток на порт |
ulimit |
int | None |
None |
Лимит файловых дескрипторов (Unix) |
scan_order |
str |
"serial" |
"serial" или "random" |
exclude_ports |
list[int] | None |
None |
Исключить порты |
exclude_addresses |
list[str] | None |
None |
Исключить адреса/CIDR |
udp |
bool |
False |
UDP-режим |
resolver |
str | None |
None |
Кастомные DNS-резолверы |
Приоритет выбора портов:
ports>range>top. Если задано несколько — используется первое ненулевое.
scan_async(addresses, *, ...) → Awaitable[list[ScanResult]]
Асинхронная версия. Принимает те же аргументы, что и scan. Использует asyncio.create_subprocess_exec — event loop не блокируется.
ScanResult
@dataclass
class ScanResult:
ip: str # IP-адрес хоста
ports: list[int] # Открытые порты
ScanError
Наследует RuntimeError. Выбрасывается, если netscope-scan завершился с ненулевым кодом. Сообщение содержит вывод stderr.
try:
results = scan(["10.0.0.1"], ports=[80])
except ScanError as e:
print(e) # netscope-scan error output
Расположение бинарника
Порядок поиска:
- Переменная окружения
NETSCOPE_BIN - Файл
bin/netscope-scanвнутри установленного пакета netscope-scanвPATH
# Явно указать путь
NETSCOPE_BIN=/opt/tools/netscope-scan python my_script.py
Примеры
# Сканирование подсети, случайный порядок
results = scan(
["10.10.0.0/16"],
range=(1, 65535),
batch_size=8000,
timeout=800,
scan_order="random",
ulimit=65536,
)
# Исключить служебные адреса
results = scan(
["192.168.0.0/24"],
top=True,
exclude_addresses=["192.168.0.1", "192.168.0.254"],
exclude_ports=[135, 139, 445],
)
# UDP
results = scan(["10.0.0.1"], ports=[53, 161, 500], udp=True)
# Несколько целей параллельно (asyncio)
import asyncio
async def multi_scan() -> None:
tasks = [
scan_async(["10.0.0.0/24"], ports=[22]),
scan_async(["172.16.0.0/24"], ports=[80, 443]),
]
all_results = await asyncio.gather(*tasks)
for batch in all_results:
for r in batch:
print(r.ip, r.ports)
asyncio.run(multi_scan())
English
A thin Python wrapper around netscope-scan — a RustScan fork with nmap and scripting removed. The binary accepts targets, scans ports, and emits clean JSON; this library turns it into a typed Python API.
Requirements
- Python ≥ 3.12
netscope-scanbinary onPATHorNETSCOPE_BINenvironment variable
Installation
# editable install from source
uv pip install -e .
# build a wheel
uv build
Quick start
from netscope import scan, scan_async, ScanResult, ScanError
# --- Synchronous ---
results: list[ScanResult] = scan(
["192.168.1.0/24", "10.0.0.1"],
ports=[22, 80, 443],
)
for r in results:
print(r.ip, r.ports)
# 192.168.1.5 [22, 80]
# 10.0.0.1 [22, 443]
# --- Asynchronous ---
import asyncio
async def main() -> None:
results = await scan_async(["10.0.0.0/24"], range=(1, 1000))
for r in results:
print(r.ip, r.ports)
asyncio.run(main())
API reference
scan(addresses, *, ...) → list[ScanResult]
Synchronous port scan. Blocks the calling thread until the binary exits.
| Parameter | Type | Default | Description |
|---|---|---|---|
addresses |
list[str] |
— | Targets: IPs, CIDRs, hostnames |
ports |
list[int] | None |
None |
Explicit port list |
range |
tuple[int, int] | None |
None |
Port range (start, end) inclusive |
top |
bool |
False |
Scan top-1000 common ports |
batch_size |
int |
4500 |
Concurrent socket count |
timeout |
int |
1500 |
Per-port timeout in ms |
tries |
int |
1 |
Probe attempts per port |
ulimit |
int | None |
None |
File-descriptor limit (Unix) |
scan_order |
str |
"serial" |
"serial" or "random" |
exclude_ports |
list[int] | None |
None |
Ports to skip |
exclude_addresses |
list[str] | None |
None |
Addresses/CIDRs to skip |
udp |
bool |
False |
UDP mode |
resolver |
str | None |
None |
Custom DNS resolvers |
Port selection priority:
ports>range>top. The first non-None/ truthy value wins.
scan_async(addresses, *, ...) → Awaitable[list[ScanResult]]
Async variant with identical parameters. Uses asyncio.create_subprocess_exec — the event loop is never blocked.
ScanResult
@dataclass
class ScanResult:
ip: str # Host IP address
ports: list[int] # Open port numbers
ScanError
Subclass of RuntimeError. Raised when netscope-scan exits with a non-zero code. The error message includes the binary's stderr output.
try:
results = scan(["10.0.0.1"], ports=[80])
except ScanError as e:
print(e) # netscope-scan error output
Binary resolution
The binary is located in this order:
NETSCOPE_BINenvironment variablebin/netscope-scanbundled inside the installed packagenetscope-scananywhere onPATH
# Point to a custom binary
NETSCOPE_BIN=/opt/tools/netscope-scan python my_script.py
Examples
# Large subnet, random order, raised ulimit
results = scan(
["10.10.0.0/16"],
range=(1, 65535),
batch_size=8000,
timeout=800,
scan_order="random",
ulimit=65536,
)
# Exclude gateway and broadcast, skip Windows noise ports
results = scan(
["192.168.0.0/24"],
top=True,
exclude_addresses=["192.168.0.1", "192.168.0.254"],
exclude_ports=[135, 139, 445],
)
# UDP scan
results = scan(["10.0.0.1"], ports=[53, 161, 500], udp=True)
# Run multiple subnets in parallel with asyncio
import asyncio
async def multi_scan() -> None:
tasks = [
scan_async(["10.0.0.0/24"], ports=[22]),
scan_async(["172.16.0.0/24"], ports=[80, 443]),
]
all_results = await asyncio.gather(*tasks)
for batch in all_results:
for r in batch:
print(r.ip, r.ports)
asyncio.run(multi_scan())
Project structure
netscope-py/
├── pyproject.toml
└── src/
└── netscope/
├── __init__.py # Public re-exports: scan, scan_async, ScanResult, ScanError
├── _models.py # ScanResult dataclass, ScanError exception
├── _runner.py # subprocess / asyncio implementation
└── py.typed # PEP 561 marker — full type information shipped
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file netscope_py-0.1.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.
File metadata
- Download URL: netscope_py-0.1.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
- Upload date:
- Size: 2.0 MB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
03ab77b8bcaefb782b38a26eb6a8fed0698058913a92cb7cf1349790e8871dfb
|
|
| MD5 |
bbcd759429e59213f63dc7c724255fb6
|
|
| BLAKE2b-256 |
3ccc07d030d8ba125002732154dc50c35034bcf45fe9295008c7dbdb5c839be1
|
Provenance
The following attestation bundles were made for netscope_py-0.1.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl:
Publisher:
publish.yml on NetSc0pe/netscope-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
netscope_py-0.1.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl -
Subject digest:
03ab77b8bcaefb782b38a26eb6a8fed0698058913a92cb7cf1349790e8871dfb - Sigstore transparency entry: 1632984435
- Sigstore integration time:
-
Permalink:
NetSc0pe/netscope-py@18a4eb68d4e74a701a7c3afa66b3a9f604b46652 -
Branch / Tag:
refs/tags/v0.1.5 - Owner: https://github.com/NetSc0pe
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@18a4eb68d4e74a701a7c3afa66b3a9f604b46652 -
Trigger Event:
push
-
Statement type:
File details
Details for the file netscope_py-0.1.5-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: netscope_py-0.1.5-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.7 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0611318a81202f9e5f7ae381dae03987c476a888325b27b20d226461572b926e
|
|
| MD5 |
4fa51cec0d5002eea2c447faea938278
|
|
| BLAKE2b-256 |
2254817d7f433e9ca05caa3d48a8f2630b1e4c972524ce4c750d16ee30d75dd2
|
Provenance
The following attestation bundles were made for netscope_py-0.1.5-py3-none-macosx_11_0_arm64.whl:
Publisher:
publish.yml on NetSc0pe/netscope-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
netscope_py-0.1.5-py3-none-macosx_11_0_arm64.whl -
Subject digest:
0611318a81202f9e5f7ae381dae03987c476a888325b27b20d226461572b926e - Sigstore transparency entry: 1632984444
- Sigstore integration time:
-
Permalink:
NetSc0pe/netscope-py@18a4eb68d4e74a701a7c3afa66b3a9f604b46652 -
Branch / Tag:
refs/tags/v0.1.5 - Owner: https://github.com/NetSc0pe
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@18a4eb68d4e74a701a7c3afa66b3a9f604b46652 -
Trigger Event:
push
-
Statement type: