验证主机名字符串

32 投票
9 回答
67658 浏览
提问于 2025-04-15 20:56

接着之前关于匹配主机名或IP地址的正则表达式的问题,以及参考有效主机名的限制,在Python中,有什么最简单易读、又简洁的方法来匹配或验证主机名/完全合格域名(fqdn)呢?我在下面分享了我的尝试,欢迎大家提出改进意见。

9 个回答

7

根据The Old New Thing的说法,DNS名称的最大长度是253个字符。(实际上可以有255个字节,但其中2个字节是用来编码的。)

import re

def validate_fqdn(dn):
    if dn.endswith('.'):
        dn = dn[:-1]
    if len(dn) < 1 or len(dn) > 253:
        return False
    ldh_re = re.compile('^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$',
                        re.IGNORECASE)
    return all(ldh_re.match(x) for x in dn.split('.'))

有人可能会争论是否应该接受空的域名,这要看具体的目的是什么。

13

这里有一个更严格的版本,参考了Tim Pietzcker的回答,并做了以下改进:

  • 将主机名的长度限制为253个字符(去掉可选的结尾点后计算)。
  • 字符集限制为ASCII字符(也就是说,使用[0-9]而不是\d)。
  • 检查顶级域名(TLD)不能全是数字。
import re

def is_valid_hostname(hostname):
    if hostname[-1] == ".":
        # strip exactly one dot from the right, if present
        hostname = hostname[:-1]
    if len(hostname) > 253:
        return False

    labels = hostname.split(".")

    # the TLD must be not all-numeric
    if re.match(r"[0-9]+$", labels[-1]):
        return False

    allowed = re.compile(r"(?!-)[a-z0-9-]{1,63}(?<!-)$", re.IGNORECASE)
    return all(allowed.match(label) for label in labels)
58
import re
def is_valid_hostname(hostname):
    if len(hostname) > 255:
        return False
    if hostname[-1] == ".":
        hostname = hostname[:-1] # strip exactly one dot from the right, if present
    allowed = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
    return all(allowed.match(x) for x in hostname.split("."))

确保每个部分

  • 至少包含一个字符,最多可以有63个字符
  • 只能由允许的字符组成
  • 不能以连字符开头或结尾。

它还避免使用双重否定(比如not disallowed),如果hostname以一个.结尾,那也是可以的。不过,如果hostname以多个点结尾,那就会出错(而且应该出错)。

撰写回答