¿Expresión regular para que coincida con el nombre de host DNS o la dirección IP?

369

¿Alguien tiene una expresión regular a mano que coincida con cualquier nombre de host DNS o dirección IP?

Es fácil escribir uno que funcione el 95% del tiempo, pero espero obtener algo que esté bien probado para que coincida exactamente con las últimas especificaciones RFC para nombres de host DNS.

DonGar
fuente

Respuestas:

535

Puede usar las siguientes expresiones regulares por separado o combinándolas en una expresión OR conjunta.

ValidIpAddressRegex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$";

ValidHostnameRegex = "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$";

ValidIpAddressRegex coincide con las direcciones IP válidas y los nombres de host válidos ValidHostnameRegex . Dependiendo del idioma que use, \ podría tener que escapar con \.


ValidHostnameRegex es válido según RFC 1123 . Originalmente, RFC 952 especificaba que los segmentos de nombre de host no podían comenzar con un dígito.

http://en.wikipedia.org/wiki/Hostname

La especificación original de los nombres de host en RFC 952 , ordenaba que las etiquetas no pudieran comenzar con un dígito o con un guión, y no deberían terminar con un guión. Sin embargo, una especificación posterior ( RFC 1123 ) permitió que las etiquetas de nombre de host comenzaran con dígitos.

Valid952HostnameRegex = "^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$";
Jorge Ferreira
fuente
3
Aquí: stackoverflow.com/questions/4645126/… - Explico que los nombres que comienzan con un dígito también se consideran válidos. Además, solo un punto es un tema cuestionable. Sería genial tener más comentarios sobre eso.
BreakPhreak
16
Es posible que desee agregar IPv6. El OP no especificó qué tipo de dirección. (Por cierto, se puede encontrar aquí )
new123456
32
Antes de que la gente use esto ciegamente en su código, tenga en cuenta que no es completamente exacto. Ignora RFC2181: "El DNS en sí mismo coloca solo una restricción en las etiquetas particulares que pueden usarse para identificar registros de recursos. Esa restricción se relaciona con la longitud de la etiqueta y el nombre completo. La longitud de cualquier etiqueta está limitada entre 1 y 63 octetos. Un nombre de dominio completo está limitado a 255 octetos (incluidos los separadores) ".
rublo
77
@UserControl: los nombres de host no latinos (codificados con puny) deben convertirse primero al formulario ASCII ( éxämplè.com= xn--xmpl-loa1ab.com) y luego validarse.
Alix Axel
66
Su expresión de nombre de host coincide con algunos valores no válidos: lo intenté 123.456.789.0y dice que es un nombre de host válido.
lbarreira
62

La expresión regular del nombre de host de smink no observa la limitación en la longitud de las etiquetas individuales dentro de un nombre de host. Cada etiqueta dentro de un nombre de host válido no puede tener más de 63 octetos de longitud.

ValidHostnameRegex = "^ ([a-zA-Z0-9] | [a-zA-Z0-9] [a-zA-Z0-9 \ -] {0,61} [a-zA-Z0-9]) \
(\. ([a-zA-Z0-9] | [a-zA-Z0-9] [a-zA-Z0-9 \ -] {0,61} [a-zA-Z0-9])) PS

Tenga en cuenta que la barra diagonal inversa al final de la primera línea (arriba) es la sintaxis de shell Unix para dividir la línea larga. No es parte de la expresión regular en sí.

Aquí está solo la expresión regular sola en una sola línea:

^ ([a-zA-Z0-9] | [a-zA-Z0-9] [a-zA-Z0-9 \ -] {0,61} [a-zA-Z0-9]) (\. ([a-zA-Z0-9] | [a-zA-Z0-9] [a-zA-Z0-9 \ -] {0,61} [a-zA-Z0-9])) * $

También debe verificar por separado que la longitud total del nombre de host no debe exceder los 255 caracteres . Para obtener más información, consulte RFC-952 y RFC-1123.

Sakari A. Maaranen
fuente
66
Excelente patrón de host. Probablemente depende de la implementación de expresiones regulares de un idioma, pero para JS se puede ajustar ligeramente para ser más breve sin perder nada:/^[a-z\d]([a-z\d\-]{0,61}[a-z\d])?(\.[a-z\d]([a-z\d\-]{0,61}[a-z\d])?)*$/i
Punto
31

Para hacer coincidir una dirección IP válida , use la siguiente expresión regular:

(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}

en vez de:

([01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\.([01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])){3}

Explicación

Muchos motores regex coinciden con la primera posibilidad en la ORsecuencia. Por ejemplo, intente la siguiente expresión regular:

10.48.0.200

Prueba

Prueba la diferencia entre lo bueno y lo malo

Alban
fuente
55
No olvide que start ^ y end $ o algo como 0.0.0.999 o 999.0.0.0 también coincidirán. ;)
andreas
1
Sí para validar una cadena, se requieren inicio ^ y final $, pero si está buscando una IP en un texto, no la use.
Alban
La "no codicia" involuntaria que identifica se aplica también a las otras soluciones de nombres de host. Valdría la pena agregar esto a su respuesta ya que los demás no coincidirán con el nombre de host completo. p.ej. ([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*versus([a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]|[a-zA-Z0-9])(\.([a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])|[a-zA-Z0-9]))*
ergohack
EDITAR: En lo anterior, use +al final en lugar de *ver el fallo.
ergohack
5

Parece que no puedo editar la publicación principal, así que agregaré mi respuesta aquí.

Para el nombre de host: respuesta fácil, en el ejemplo de egrep aquí: http: //www.linuxinsight.com/how_to_grep_for_ip_addresses_using_the_gnu_egrep_utility.html

egrep '([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}'

Aunque el caso no tiene en cuenta valores como 0 en el primer octeto, y valores superiores a 254 (direcciones IP) o 255 (máscara de red). Tal vez una declaración if adicional ayudaría.

En cuanto al nombre de host DNS legal, siempre que esté buscando solo nombres de host de Internet (y no intranet), escribí el siguiente recorte, una mezcla de shell / php, pero debería ser aplicable como cualquier expresión regular.

primero vaya al sitio web de ietf, descargue y analice una lista de nombres de dominio legales de nivel 1:

tld=$(curl -s http://data.iana.org/TLD/tlds-alpha-by-domain.txt |  sed 1d  | cut -f1 -d'-' | tr '\n' '|' | sed 's/\(.*\)./\1/')
echo "($tld)"

Eso debería darle un buen código de re que verifique la legalidad del nombre de dominio principal, como .com .org o .ca

Luego agregue la primera parte de la expresión de acuerdo con las pautas que se encuentran aquí: http: //www.domainit.com/support/faq.mhtml?category=Domain_FAQ&question=9 (cualquier combinación alfanumérica y el símbolo '-', el guión no debe estar en El principio o el final de un octeto.

(([a-z0-9]+|([a-z0-9]+[-]+[a-z0-9]+))[.])+

Luego póngalo todo junto (ejemplo de PHP preg_match):

$pattern = '/^(([a-z0-9]+|([a-z0-9]+[-]+[a-z0-9]+))[.])+(AC|AD|AE|AERO|AF|AG|AI|AL|AM|AN|AO|AQ|AR|ARPA|AS|ASIA|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BIZ|BJ|BM|BN|BO|BR|BS|BT|BV|BW|BY|BZ|CA|CAT|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|COM|COOP|CR|CU|CV|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EDU|EE|EG|ER|ES|ET|EU|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GOV|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|INFO|INT|IO|IQ|IR|IS|IT|JE|JM|JO|JOBS|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MG|MH|MIL|MK|ML|MM|MN|MO|MOBI|MP|MQ|MR|MS|MT|MU|MUSEUM|MV|MW|MX|MY|MZ|NA|NAME|NC|NE|NET|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|ORG|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PRO|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|ST|SU|SV|SY|SZ|TC|TD|TEL|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TP|TR|TRAVEL|TT|TV|TW|TZ|UA|UG|UK|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|XN|XN|XN|XN|XN|XN|XN|XN|XN|XN|XN|YE|YT|YU|ZA|ZM|ZW)[.]?$/i';

    if (preg_match, $pattern, $matching_string){
    ... do stuff
    }

También es posible que desee agregar una instrucción if para verificar que la cadena que está verificando tiene menos de 256 caracteres: http://www.ops.ietf.org/lists/namedroppers/namedroppers.2003/msg00964.html

Alex Volkov
fuente
1
-1 porque esto coincide con direcciones IP falsas como "999.999.999.999".
bdesham
1
"Aunque el caso no tiene en cuenta valores como 0 en el primer octeto y valores superiores a 254 (direcciones IP) o 255 (máscara de red)".
Alex Volkov
Vi que calificaste tu respuesta, sí. Voté en contra porque esa parte de su respuesta todavía no es útil.
bdesham
3

Vale la pena señalar que hay bibliotecas para la mayoría de los idiomas que hacen esto por usted, a menudo integradas en la biblioteca estándar. Y es probable que esas bibliotecas se actualicen mucho más a menudo que el código que copió de una respuesta de Desbordamiento de pila hace cuatro años y se olvidó. Y, por supuesto, también analizarán la dirección en una forma utilizable, en lugar de simplemente darle una coincidencia con un grupo de grupos.

Por ejemplo, detectar y analizar IPv4 en (POSIX) C:

#include <arpa/inet.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
  for (int i=1; i!=argc; ++i) {
    struct in_addr addr = {0};
    printf("%s: ", argv[i]);
    if (inet_pton(AF_INET, argv[i], &addr) != 1)
      printf("invalid\n");
    else
      printf("%u\n", addr.s_addr);
  }
  return 0;
}

Obviamente, tales funciones no funcionarán si está intentando, por ejemplo, encontrar todas las direcciones válidas en un mensaje de chat, pero incluso allí, puede ser más fácil usar una expresión regular simple pero demasiado celosa para encontrar posibles coincidencias, y luego usar el biblioteca para analizarlos.

Por ejemplo, en Python:

>>> import ipaddress
>>> import re
>>> msg = "My address is 192.168.0.42; 192.168.0.420 is not an address"
>>> for maybeip in re.findall(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', msg):
...     try:
...         print(ipaddress.ip_address(maybeip))
...     except ValueError:
...         pass
abarnert
fuente
2
def isValidHostname(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("."))
PythonDev
fuente
¿Podría explicar esta expresión regular? Exactamente, ¿qué significa (?! -), (? <! -)?
Scit
1
@Scit, se aseguran de que no comience o termine con un carácter "-" si su motor de expresiones regulares permite su uso. Por ejemplo, de Python o de Perl .
Aprenda
1

Creo que esta es la mejor expresión regular de validación Ip. por favor verifíquelo una vez !!!

^(([01]?[0-9]?[0-9]|2([0-4][0-9]|5[0-5]))\.){3}([01]?[0-9]?[0-9]|2([0-4][0-9]|5[0-5]))$
Prakash Thapa
fuente
1
"^((\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])\.){3}(\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])$"
zangw
fuente
1

Esto funciona para direcciones IP válidas:

regex = '^([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-5][0-5])[.]([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-5][0-5])[.]([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-5][0-5])[.]([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-5][0-5])$'
aliasav
fuente
1
/^(?:[a-zA-Z0-9]+|[a-zA-Z0-9][-a-zA-Z0-9]+[a-zA-Z0-9])(?:\.[a-zA-Z0-9]+|[a-zA-Z0-9][-a-zA-Z0-9]+[a-zA-Z0-9])?$/
usuario2240578
fuente
0

Aquí hay una expresión regular que utilicé en Ant para obtener una IP de host proxy o un nombre de host de ANT_OPTS. Esto se utilizó para obtener la IP del proxy para poder ejecutar una prueba "inalcanzable" de Ant antes de configurar un proxy para una JVM bifurcada.

^.*-Dhttp\.proxyHost=(\w{1,}\.\w{1,}\.\w{1,}\.*\w{0,})\s.*$
Bill Stephens
fuente
Eso es \wjusto allí, no capturará IP, solo el nombre de host en ciertas situaciones.
Yaron
0

Encontré que esto funciona bastante bien para las direcciones IP. Se valida como la respuesta principal, pero también se asegura de que la ip esté aislada para que no haya texto o más números / decimales después o antes de la ip.

(? <! \ S) (?: (?: \ D | [1-9] \ d | 1 \ d \ d | 2 [0-4] \ d | 25 [0-5]) \ b |. \ b) {7} (?! \ S)

Andrés
fuente
Intenté mucho pero no pude entender 2 cosas aquí. 1. \ b especifica el límite de palabras ¿Por qué estamos usando \ b? cual es el limite? y 2. ¿Por qué funciona solo para {7}? Por lo que he entendido, creo que debería ser {4} pero, no está funcionando. Opcionalmente, podría decir por qué está utilizando bloques que no capturan.
Srichakradhar
0

prueba esto:

((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)

Funciona en mi caso.

serafines
fuente
0

Con respecto a las direcciones IP, parece que hay cierto debate sobre si incluir ceros a la izquierda. Alguna vez fue una práctica común y generalmente se acepta, por lo que diría que deben marcarse como válidos independientemente de la preferencia actual. También hay cierta ambigüedad sobre si el texto antes y después de la cadena debe validarse y, nuevamente, creo que debería. 1.2.3.4 es una IP válida, pero 1.2.3.4.5 no lo es y ni la porción 1.2.3.4 ni la porción 2.3.4.5 deberían dar lugar a una coincidencia. Algunas de las preocupaciones se pueden manejar con esta expresión:

grep -E '(^|[^[:alnum:]+)(([0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])\.){3}([0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])([^[:alnum:]]|$)' 

La parte desafortunada aquí es el hecho de que la porción de expresión regular que valida un octeto se repite como es cierto en muchas soluciones ofrecidas. Aunque esto es mejor que para las instancias del patrón, la repetición puede eliminarse por completo si las subrutinas son compatibles con la expresión regular que se utiliza. El siguiente ejemplo habilita esas funciones con el -Pinterruptor de grepy también aprovecha la funcionalidad de mirar hacia adelante y hacia atrás. (El nombre de la función que seleccioné es 'o' para octeto. Podría haber usado 'octeto' como nombre pero quería ser conciso).

grep -P '(?<![\d\w\.])(?<o>([0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]))(\.\g<o>){3}(?![\d\w\.])'

El manejo del punto en realidad podría crear falsos negativos si las direcciones IP están en un archivo con texto en forma de oraciones, ya que podría seguir un punto sin que sea parte de la notación punteada. Una variante de lo anterior solucionaría eso:

grep -P '(?<![\d\w\.])(?<x>([0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]))(\.\g<x>){3}(?!([\d\w]|\.\d))'
Thom Anderson
fuente
0
>>> my_hostname = "testhostn.ame"
>>> print bool(re.match("^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$", my_hostname))
True
>>> my_hostname = "testhostn....ame"
>>> print bool(re.match("^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$", my_hostname))
False
>>> my_hostname = "testhostn.A.ame"
>>> print bool(re.match("^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$", my_hostname))
True
Mohammad Shahid Siddiqui
fuente
0

El nuevo marco de red tiene inicializadores disponibles para struct IPv4Address y struct IPv6Address que manejan la parte de la dirección IP con mucha facilidad. Hacer esto en IPv6 con una expresión regular es difícil con todas las reglas de acortamiento.

Lamentablemente, no tengo una respuesta elegante para el nombre de host.

Tenga en cuenta que el marco de red es reciente, por lo que puede obligarlo a compilar para versiones recientes del sistema operativo.

import Network
let tests = ["192.168.4.4","fkjhwojfw","192.168.4.4.4","2620:3","2620::33"]

for test in tests {
    if let _ = IPv4Address(test) {
        debugPrint("\(test) is valid ipv4 address")
    } else if let _ = IPv6Address(test) {
        debugPrint("\(test) is valid ipv6 address")
    } else {
        debugPrint("\(test) is not a valid IP address")
    }
}

output:
"192.168.4.4 is valid ipv4 address"
"fkjhwojfw is not a valid IP address"
"192.168.4.4.4 is not a valid IP address"
"2620:3 is not a valid IP address"
"2620::33 is valid ipv6 address"
Raíz de Darrell
fuente
-1

¿Qué tal esto?

([0-9]{1,3}\.){3}[0-9]{1,3}
Saikrishna Rao
fuente
Y también lo es 9999999999.0.0.9999999999 :) Pero para la mayoría de los programadores, este breve enfoque será suficiente.
andreas
3
-1 porque esto coincide con direcciones IP sin sentido (como señala @Shebuka).
bdesham
-1

en php: filter_var(gethostbyname($dns), FILTER_VALIDATE_IP) == true ? 'ip' : 'not ip'

sirjay
fuente
2
Si bien este código puede responder la pregunta, generalmente la explicación junto con el código hace que la respuesta sea mucho más útil. Por favor, editar su respuesta y proporcionar un cierto contexto y explicación.
user4642212
Y, a menos que me equivoque, FILTER_VALIDATE_IP es un valor solo de PHP.
DonGar
-2

Comprobando nombres de host como ... mywebsite.co.in, thangaraj.name, 18thangaraj.in, thangaraj106.in, etc.

[a-z\d+].*?\\.\w{2,4}$
Thangaraj
fuente
3
-1. El OP solicitó algo "bien probado para que coincida exactamente con las últimas especificaciones RFC", pero esto no coincide, por ejemplo, * .museum, mientras que coincidirá con * .foo. Aquí hay una lista de TLD válidos.
bdesham
No estoy seguro de que sea una buena idea poner el signo más dentro de la clase de caracteres (corchetes), además, hay TLD con 5 letras ( .expert, por ejemplo).
Yaron
La mejor manera de lograr con RFC es utilizar las funciones del sistema / lenguaje. inet_atones bastante bueno.
m3nda
-2

Pensé en este patrón simple de coincidencia de expresiones regulares para la coincidencia de direcciones IP \ d + [.] \ D + [.] \ D + [.] \ D +

Dody
fuente
1111.1.1.1 no es una ip válida. No hay forma de probar realmente un formato ip si no se preocupa por las subredes. Al menos debe tener cuidado con la cantidad de apariciones con algo así ^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}y, por supuesto, esa no será la forma correcta. Si tiene un idioma para escribir script, seguramente tendrá acceso a sus funciones de red. La mejor manera de verificar una IP REAL es decirle al sistema que convierta e ip al formato correcto y luego verifique si es verdadero / falso. En el caso de Python que uso socket.inet_aton(ip). Caso de PHP que necesita inet_aton($ip).
m3nda
Los usuarios de Python pueden echar un vistazo aquí: gist.github.com/erm3nda/f25439bba66931d3ca9699b2816e796c
m3nda