Validar una cadena de nombre de host

¿Siguiendo a la expresión regular para que coincida con el nombre de host o la dirección IP? y al usar Restricciones en 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 bash a continuación, las mejoras bienvenidas.

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("(?!-)[AZ\d-]{1,63}(? 

asegura que cada segmento

  • contiene al menos un carácter y un máximo de 63 caracteres
  • consiste solo de caracteres permitidos
  • No comienza ni termina con un guión.

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

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] lugar de \d ).
  • Compruebe que el TLD no sea todo 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}(? 

Según The Old New Thing , la longitud máxima de un nombre DNS es de 253 caracteres. (Se permite uno hasta 255 octetos, pero 2 de ellos son consumidos por la encoding).

 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 para aceptar nombres de dominio vacíos, o no, dependiendo del propósito de uno.

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 (? “Notación de extensión”. Además, creo que el enfoque “doble negativo” es más obvio, ya que limita la responsabilidad de la expresión regular a solo encontrar cualquier carácter no válido. Me gusta que re.IGNORECASE permita que la expresión regular se acorte.

Así que aquí hay otra oportunidad; Es más largo pero se lee algo así como 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("[^AZ\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(".")) 

Complementario a la respuesta @TimPietzcker. El subrayado es un nombre de host válido, el doble guión es común para IDN Punycode. El número de puerto debe ser eliminado. 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("(?!-)[AZ\d\-\_]{1,63}(? 
 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)) 

Este regex puro debe cumplir con todos los parámetros: ^(?=.{1,253}\.?$)(?!-)[A-Za-z0-9\-]{1,63}(\.[A-Za-z0-9\-]{1,63})*\.?(?

Procese cada etiqueta DNS individualmente, excluyendo los caracteres no válidos y garantizando 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("."))) 

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