Files
DDSRem 2de976f6b3 Merge pull request #7050 from DDSRem-Dev/codex-comment-migration
docs: 统一全项目中文注释和结构化契约说明
2026-10-17 19:26:29 +08:00

108 lines
3.3 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.
"""
基于系统套接字和标准库解析 IP,并提供兼容的内网地址判定。
"""
import ipaddress
import socket
from urllib.parse import urlparse
class IpUtils:
"""
提供 IP 地址、域名和内外网判断能力。
"""
@staticmethod
def is_ipv4(ip: str) -> bool:
"""
检查 IPv4 地址文本,系统不提供 inet_pton 时回退至 inet_aton 并检查分段。
:param ip: 要检查的地址文本
:return: 可解析为 IPv4 地址时返回 True
"""
try:
socket.inet_pton(socket.AF_INET, ip)
# 部分平台没有 inet_pton,使用旧接口保留 IPv4 检查能力。
except AttributeError:
try:
socket.inet_aton(ip)
except socket.error:
return False
return ip.count('.') == 3
except socket.error:
return False
return True
@staticmethod
def is_ipv6(ip: str) -> bool:
"""
检查 IPv6 地址文本。
:param ip: 要检查的地址文本
:return: 系统可以将其解析为 IPv6 地址时返回 True
"""
try:
socket.inet_pton(socket.AF_INET6, ip)
except socket.error:
return False
return True
@staticmethod
def is_internal(hostname: str) -> bool:
"""
从 URL 提取主机名,并检查地址或域名解析结果是否为内网地址。
:param hostname: 包含主机部分的 URL;无法提取主机名时按非内网处理
:return: 主机被识别为私有地址时返回 True,否则返回 False
"""
parsed_hostname = urlparse(hostname).hostname
if not parsed_hostname:
return False
if IpUtils.is_ip(parsed_hostname):
return IpUtils.is_private_ip(parsed_hostname)
else:
return IpUtils.is_internal_domain(parsed_hostname)
@staticmethod
def is_ip(addr: str) -> bool:
"""
使用系统 inet_aton 检查 IPv4 地址,沿用其对缩写格式的接受规则。
:param addr: 待解析的 IPv4 文本;本方法不检查 IPv6
:return: 系统可以解析时返回 True,否则返回 False
"""
try:
socket.inet_aton(addr)
return True
except socket.error:
return False
@staticmethod
def is_internal_domain(domain: str) -> bool:
"""
同步查询域名的单个 IPv4 地址并判断是否为私有地址。
:param domain: 要提交给系统 DNS 的域名
:return: 解析地址为私有地址时返回 True;解析失败时返回 False
"""
try:
ip = socket.gethostbyname(domain)
except socket.error:
return False
return IpUtils.is_private_ip(ip)
@staticmethod
def is_private_ip(ip_str: str) -> bool:
"""
按 Python 标准库的 is_private 规则检查 IPv4 或 IPv6 地址。
:param ip_str: 地址文本,首尾空白会被去除
:return: 标准库判定为私有地址时返回 True;无效地址返回 False
"""
try:
return ipaddress.ip_address(ip_str.strip()).is_private
except Exception as e:
print(str(e))
return False