This commit is contained in:
qsc
2026-06-06 01:57:43 +08:00
parent 2a97e1df17
commit 129dc41208
17 changed files with 2582 additions and 1048 deletions
+108
View File
@@ -0,0 +1,108 @@
import ipaddress
import locale
import re
import subprocess
import sys
from typing import Iterable, List
CREATE_NO_WINDOW = subprocess.CREATE_NO_WINDOW if sys.platform.startswith("win") else 0
def preferred_encoding() -> str:
return locale.getpreferredencoding(False) or "utf-8"
def run_hidden(command: List[str], timeout=None) -> subprocess.CompletedProcess:
return subprocess.run(
command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
encoding=preferred_encoding(),
errors="replace",
timeout=timeout,
creationflags=CREATE_NO_WINDOW,
)
def popen_hidden(command: List[str]) -> subprocess.Popen:
return subprocess.Popen(
command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
encoding=preferred_encoding(),
errors="replace",
creationflags=CREATE_NO_WINDOW,
)
def validate_host(value: str) -> str:
host = value.strip()
if not host:
raise ValueError("请输入目标地址或域名")
return host
def validate_ip(value: str, allow_empty: bool = False) -> str:
ip = value.strip()
if allow_empty and not ip:
return ""
try:
ipaddress.ip_address(ip)
except ValueError as exc:
raise ValueError(f"IP 地址无效: {value}") from exc
return ip
def validate_port(value, label: str = "端口") -> int:
try:
port = int(str(value).strip())
except ValueError as exc:
raise ValueError(f"{label}必须是整数") from exc
if port < 1 or port > 65535:
raise ValueError(f"{label}必须在 1-65535 之间")
return port
def parse_ports(text: str) -> List[int]:
ports = set()
for part in re.split(r"[,;\s]+", text.strip()):
part = part.strip()
if not part:
continue
if "-" in part:
start_raw, end_raw = part.split("-", 1)
start = validate_port(start_raw, "起始端口")
end = validate_port(end_raw, "结束端口")
if start > end:
raise ValueError("端口范围的起始值不能大于结束值")
ports.update(range(start, end + 1))
else:
ports.add(validate_port(part))
if not ports:
raise ValueError("请输入至少一个端口")
return sorted(ports)
def prefix_to_netmask(prefix_length) -> str:
if prefix_length in ("", None):
return ""
try:
prefix = int(prefix_length)
return str(ipaddress.IPv4Network(f"0.0.0.0/{prefix}").netmask)
except Exception:
return ""
def iter_hosts(prefix: str, start: int, end: int) -> Iterable[str]:
if not prefix.endswith("."):
raise ValueError("网段前缀必须以点号结尾,例如 192.168.1.")
for value in (start, end):
if value < 1 or value > 254:
raise ValueError("主机号范围必须在 1-254 之间")
if start > end:
raise ValueError("起始主机号不能大于结束主机号")
for host_id in range(start, end + 1):
yield validate_ip(f"{prefix}{host_id}")