OK
This commit is contained in:
@@ -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}")
|
||||
Reference in New Issue
Block a user