Files
2026-06-06 01:57:43 +08:00

109 lines
3.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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}")