Validar una cadena de nombre de host


Siguiendo la expresión regular para que coincida con el nombre de host o la dirección IP? y usando Restricciones sobre nombres de host válidos como referencia, ¿cuál es la forma más legible y concisa de hacer coincidir/validar un nombre de host/fqdn (nombre de dominio completo) en Python? He respondido con mi intento a continuación, mejoras bienvenidas.

Author: Community, 2010-03-28

9 answers

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("."))

Asegura que cada segmento

  • contiene al menos un carácter y un máximo de 63 caracteres
  • consiste solo en caracteres permitidos
  • no comienza ni termina con un guion.

También evita los negativos dobles (not disallowed), y si hostname termina en un ., eso también está bien. Fallará (y debería fallar) si hostname termina en más de un punto.

 41
Author: Tim Pietzcker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-28 12:42:55

Aquí hay una versión un poco más estricta de La respuesta de Tim Pietzcker con las siguientes mejoras:

  • Limite la longitud del nombre de host a 253 caracteres (después de eliminar el punto final opcional).
  • Limite el conjunto de caracteres a ASCII (es decir, use [0-9] en lugar de \d).
  • Compruebe que el TLD no es totalmente numérico.
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)
 4
Author: Eugene Yarmash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:05

Por La Vieja Cosa Nueva, la longitud máxima de un nombre DNS es de 253 caracteres. (Uno está permitido hasta 255 octetos, pero 2 de ellos son consumidos por la codificación.)

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('.'))

Uno podría argumentar a favor de aceptar nombres de dominio vacíos, o no, dependiendo del propósito de uno.

 3
Author: solidsnack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-15 02:32:30

Me gusta la minuciosidad de la respuesta de Tim Pietzcker, pero prefiero descargar parte de la lógica de las expresiones regulares para facilitar la lectura. Honestamente, tuve que buscar el significado de esas (? partes de "notación de extensión". Además, creo que el enfoque "doble negativo" es más obvio en que limita la responsabilidad de la expresión regular a solo encontrar cualquier carácter inválido. Me gusta ese re.IGNORECASE permite acortar la expresión regular.

Así que aquí hay otra oportunidad; es más largo, pero se lee como en prosa. Supongo que " legible "está algo en desacuerdo con"conciso". Creo que todas las restricciones de validación mencionadas en el hilo hasta ahora están cubiertas:


def isValidHostname(hostname):
    if len(hostname) > 255:
        return False
    if hostname.endswith("."): # A single trailing dot is legal
        hostname = hostname[:-1] # strip exactly one dot from the right, if present
    disallowed = re.compile("[^A-Z\d-]", re.IGNORECASE)
    return all( # Split by labels and verify individually
        (label and len(label) <= 63 # length is within proper range
         and not label.startswith("-") and not label.endswith("-") # no bordering hyphens
         and not disallowed.search(label)) # contains only legal characters
        for label in hostname.split("."))
 1
Author: kostmo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-23 19:10:21
def is_valid_host(host):
    '''IDN compatible domain validator'''
    host = host.encode('idna').lower()
    if not hasattr(is_valid_host, '_re'):
        import re
        is_valid_host._re = re.compile(r'^([0-9a-z][-\w]*[0-9a-z]\.)+[a-z0-9\-]{2,15}$')
    return bool(is_valid_host._re.match(host))
 0
Author: imbolc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-13 11:42:42

Cortesía de la respuesta @TimPietzcker. El guion bajo es un nombre de host válido, doubel dash es común para IDN punycode. El número de puerto debe ser despojado. Esta es la limpieza del código.

import re
def is_valid_hostname(hostname):
    if len(hostname) > 255:
        return False
    hostname = hostname.rstrip(".")
    allowed = re.compile("(?!-)[A-Z\d\-\_]{1,63}(?<!-)$", re.IGNORECASE)
    return all(allowed.match(x) for x in hostname.split("."))

# convert your unicode hostname to punycode (python 3 ) 
# Remove the port number from hostname
normalise_host = hostname.encode("idna").decode().split(":")[0]
is_valid_hostanme(normalise_host )
 0
Author: mootmoot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-04 15:22:37

Esta expresión regular pura debe cumplir con todos los parámetros: ^(?=.{1,253}\.?$)(?!-)[A-Za-z0-9\-]{1,63}(\.[A-Za-z0-9\-]{1,63})*\.?(?<!-)$

 0
Author: Steve Goossens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-29 17:04:51

Procesa cada etiqueta DNS individualmente excluyendo caracteres no válidos y asegurando una longitud distinta de cero.


def isValidHostname(hostname):
    disallowed = re.compile("[^a-zA-Z\d\-]")
    return all(map(lambda x: len(x) and not disallowed.search(x), hostname.split(".")))
 -1
Author: kostmo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-28 06:16:07

Si está buscando validar el nombre de un host existente, la mejor manera es intentar resolverlo. Nunca escribirás una expresión regular para proporcionar ese nivel de validación.

 -4
Author: Donal Fellows,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-28 11:51:38