Saltar al contenido

Validar IPv4, IPv6 y nombre de host

Solución:

Me las arreglé para armar una expresión regular que coincida con IPv6, IPv4 y el nombre de host en el que puedo pensar, desafortunadamente, lo que parece ser una dirección IP no válida es un nombre de host válido, en algunos casos, pero supongo que está bien.
Así que aquí está la expresión regular 🙂 el programa de prueba se puede encontrar aquí

(^s*((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]?).(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]?))s*$)|(^s*((?=.1,255$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|b-)0,61[0-9A-Za-z])?(?:.[0-9A-Za-z](?:(?:[0-9A-Za-z]|b-)0,61[0-9A-Za-z])?)*.?)s*$)|(^s*((([0-9A-Fa-f]1,4:)7([0-9A-Fa-f]1,4|:))|(([0-9A-Fa-f]1,4:)6(:[0-9A-Fa-f]1,4|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d))3)|:))|(([0-9A-Fa-f]1,4:)5(((:[0-9A-Fa-f]1,4)1,2)|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d))3)|:))|(([0-9A-Fa-f]1,4:)4(((:[0-9A-Fa-f]1,4)1,3)|((:[0-9A-Fa-f]1,4)?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d))3))|:))|(([0-9A-Fa-f]1,4:)3(((:[0-9A-Fa-f]1,4)1,4)|((:[0-9A-Fa-f]1,4)0,2:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d))3))|:))|(([0-9A-Fa-f]1,4:)2(((:[0-9A-Fa-f]1,4)1,5)|((:[0-9A-Fa-f]1,4)0,3:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d))3))|:))|(([0-9A-Fa-f]1,4:)1(((:[0-9A-Fa-f]1,4)1,6)|((:[0-9A-Fa-f]1,4)0,4:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d))3))|:))|(:(((:[0-9A-Fa-f]1,4)1,7)|((:[0-9A-Fa-f]1,4)0,5:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d))3))|:)))(%.+)?s*$)


 (
   ^ 
    s*( //IPv4
        (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]?).(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]?)
    )s* 
   $
 )
 |
 (
   ^
    s*( //Hostname RFC 1123
         (?=.1,255$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|b-)0,61[0-9A-Za-z])?(?:.[0-9A-Za-z](?:(?:[0-9A-Za-z]|b-)0,61[0-9A-Za-z])?)*.?
    )s* 
   $
 )
 |
 (
   ^
    s*( //IPv6
      (([0-9A-Fa-f]1,4:)7([0-9A-Fa-f]1,4|:))|(([0-9A-Fa-f]1,4:)6(:[0-9A-Fa-f]1,4|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d))3)|:))|(([0-9A-Fa-f]1,4:)5(((:[0-9A-Fa-f]1,4)1,2)|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d))3)|:))|(([0-9A-Fa-f]1,4:)4(((:[0-9A-Fa-f]1,4)1,3)|((:[0-9A-Fa-f]1,4)?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d))3))|:))|(([0-9A-Fa-f]1,4:)3(((:[0-9A-Fa-f]1,4)1,4)|((:[0-9A-Fa-f]1,4)0,2:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d))3))|:))|(([0-9A-Fa-f]1,4:)2(((:[0-9A-Fa-f]1,4)1,5)|((:[0-9A-Fa-f]1,4)0,3:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d))3))|:))|(([0-9A-Fa-f]1,4:)1(((:[0-9A-Fa-f]1,4)1,6)|((:[0-9A-Fa-f]1,4)0,4:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d))3))|:))|(:(((:[0-9A-Fa-f]1,4)1,7)|((:[0-9A-Fa-f]1,4)0,5:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d))3))|:))
    )(%.+)?s*
   $
 )

ver también:
¿Expresión regular para que coincida con el nombre de host DNS o la dirección IP?
RFC 1123
Validador de IPv6

Lo he clavado: http://jsfiddle.net/AJEzQ/

^(([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])$|^(([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])$|^(?:(?:(?:(?:(?:(?:(?:[0-9a-fA-F]1,4)):)6)(?:(?:(?:(?:(?:[0-9a-fA-F]1,4)):(?:(?:[0-9a-fA-F]1,4)))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])).)3(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:::(?:(?:(?:[0-9a-fA-F]1,4)):)5)(?:(?:(?:(?:(?:[0-9a-fA-F]1,4)):(?:(?:[0-9a-fA-F]1,4)))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])).)3(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:[0-9a-fA-F]1,4)))?::(?:(?:(?:[0-9a-fA-F]1,4)):)4)(?:(?:(?:(?:(?:[0-9a-fA-F]1,4)):(?:(?:[0-9a-fA-F]1,4)))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])).)3(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]1,4)):)0,1(?:(?:[0-9a-fA-F]1,4)))?::(?:(?:(?:[0-9a-fA-F]1,4)):)3)(?:(?:(?:(?:(?:[0-9a-fA-F]1,4)):(?:(?:[0-9a-fA-F]1,4)))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])).)3(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]1,4)):)0,2(?:(?:[0-9a-fA-F]1,4)))?::(?:(?:(?:[0-9a-fA-F]1,4)):)2)(?:(?:(?:(?:(?:[0-9a-fA-F]1,4)):(?:(?:[0-9a-fA-F]1,4)))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])).)3(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]1,4)):)0,3(?:(?:[0-9a-fA-F]1,4)))?::(?:(?:[0-9a-fA-F]1,4)):)(?:(?:(?:(?:(?:[0-9a-fA-F]1,4)):(?:(?:[0-9a-fA-F]1,4)))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])).)3(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]1,4)):)0,4(?:(?:[0-9a-fA-F]1,4)))?::)(?:(?:(?:(?:(?:[0-9a-fA-F]1,4)):(?:(?:[0-9a-fA-F]1,4)))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])).)3(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]1,4)):)0,5(?:(?:[0-9a-fA-F]1,4)))?::)(?:(?:[0-9a-fA-F]1,4)))|(?:(?:(?:(?:(?:(?:[0-9a-fA-F]1,4)):)0,6(?:(?:[0-9a-fA-F]1,4)))?::))))$

Construir expresiones regulares de validación mediante programación

Como se encuentra aquí en la formidable biblioteca ippaddr.js [2]:

https://github.com/whitequark/ipaddr.js/blob/8c18488416e20f2d624ab6f727638673018a2a46/lib/ipaddr.js#L6-L30

Una lista JS completa – (a diferencia del campo de batalla de RegEx de las respuestas anteriores :)) – para construir expresiones regulares programáticamente de una manera modular.

Esto permite descomponer la complejidad de estas expresiones regulares en más fácilmente para comprender las partes esenciales. También te permite ahorrar en el tamaño del código 🙂

Nota: esto es para validar solamente Versiones de dirección IP 4 y 6 (no nombres de host u otras cosas relacionadas con URI RFC):

    // A list of regular expressions that match arbitrary IPv4 addresses,
    // for which a number of weird notations exist.
    // Note that an address like 0010.0xa5.1.1 is considered legal.
    const ipv4Part = '(0?\d+|0x[a-f0-9]+)';
    const ipv4Regexes = 
        fourOctet: new RegExp(`^$ipv4Part\.$ipv4Part\.$ipv4Part\.$ipv4Part$`, 'i'),
        threeOctet: new RegExp(`^$ipv4Part\.$ipv4Part\.$ipv4Part$`, 'i'),
        twoOctet: new RegExp(`^$ipv4Part\.$ipv4Part$`, 'i'),
        longValue: new RegExp(`^$ipv4Part$`, 'i')
    ;

    // Regular Expression for checking Octal numbers
    const octalRegex = new RegExp(`^0[0-7]+$`, 'i');
    const hexRegex = new RegExp(`^0x[a-f0-9]+$`, 'i');

    const zoneIndex = '%[0-9a-z]1,';

    // IPv6-matching regular expressions.
    // For IPv6, the task is simpler: it is enough to match the colon-delimited
    // hexadecimal IPv6 and a transitional variant with dotted-decimal IPv4 at
    // the end.
    const ipv6Part = '(?:[0-9a-f]+::?)+';
    const ipv6Regexes = (?:::)(?:$ipv6Part)?)$ipv4Part\.$ipv4Part\.$ipv4Part\.$ipv4Part($zoneIndex)?$`, 'i')
    ;

Costo de la simplicidad, necesidad de más lógica de análisis

Este orden de la parte reg-ex viene con un precio, la lógica de análisis necesaria es más “forky” 🙂

Consulte los métodos de análisis respectivos aquí:

IPv4.parser: https://github.com/whitequark/ipaddr.js/blob/8c18488416e20f2d624ab6f727638673018a2a46/lib/ipaddr.js#L405

IPv6.parser: https://github.com/whitequark/ipaddr.js/blob/8c18488416e20f2d624ab6f727638673018a2a46/lib/ipaddr.js#L799

Condiciones suficientes vs necesarias

Las expresiones regulares combinadas con la lógica de análisis anterior coinciden con suficiente condición para la afirmación en cualquier tipo de dirección (al igual que la coincidencia directa en las megaregexes de respuestas anteriores).

OTOH puede haber una serie de necesario condiciones para cada tipo de dirección. Podemos usarlos para afirmar lo contrario (que una entrada es no de cualquier tipo): Comprobación de falta : caracteres es una forma de afirmar una dirección es definitivamente no IP v6. Lo que puede resultar útil cuando se desea simplemente diferenciar (es decir, categorizar) las entradas de su tipo de manera óptima. Ejecutar todo el IPv6-regex en una entrada que no contiene dos puntos en primer lugar sería una sobrecarga.

Asimismo, es notable que la biblioteca antes mencionada también implementa las diferencias entre condiciones suficientes versus necesarias cuando se realiza la validación de IPv6 (o especialmente con la intención de diferenciar entre entradas de ambos tipos de direcciones) [1]:

    ipaddr.IPv6.isValid = function (string) 

        // Since IPv6.isValid is always called first, this shortcut
        // provides a substantial performance gain.
        if (typeof string === 'string' && string.indexOf(':') === -1) 
            return false;
        

        try 
            const addr = this.parser(string);
            new this(addr.parts, addr.zoneId);
            return true;
         catch (e) 
            return false;
        
    ;

Diferenciar entre v4 y v6 usando ipaddr.js:

function getIpVersionNum(addr) 
  try 
    const parse_addr = ipaddr.parse(addr);
    const kind = parse_addr.kind();

    if (kind === 'ipv4') 
      return 4; //IPv4
     else if (kind === 'ipv6') 
      return 6; //IPv6
     else 
      throw new Error('unexpected return value');
    

  // parse() will throw an error when address passes neither validation
   catch (err)  
    return 0; //not 4 or 6
  


[1] https://github.com/whitequark/ipaddr.js/blob/master/lib/ipaddr.js#L750-L765
[2] https://www.npmjs.com/package/ipaddr.js

valoraciones y reseñas

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *