REGEX IP(v4) et IPv6

Actuellement, presque tous les visiteurs utilisent encore l'IPv4, le système d'adressage IP connu depuis très longtemps (xxx.xxx.xxx.xxx où xxx appartient à [0;255]). Plus de 90% des 232 possibilitées d'adresses IPv4 (pour Version 4) sont actuellement utilisées. A l'heure actuelle, seulement Free connecte ses internautes en IPv6, seulement, ce mode de connexion est amené à évoluer très rapidement du fait de l'importance crutiale de cette migration. En effet, s'il n'y as plus d'adresses IP disponibles, vous ne pourrez plus vous connecter à Internet… Note: Les regex ci-dessous sont des regex en PCRE. C'est-à-dire qu'elles sont exploitables telle qu'elles sont avec les fonction commençant par preg_ telle que preg_match.

Détecter une adresse v4

La structure de l'adresse IP version 4 est très simple. Elle est contituée de 4 nombres allant de 0 à 255 séparés par un point : 1.2.3.4 La regex correspondante est la suivante :

^(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]?)$

Il y a beaucoup plus simple, comme :

^([0-9]{1,3}.){3}.([0-9]{1,3})$

Cependant, cette REGEX est beaucoup moins complète car elle accepte les adresses comme 999.999.999.999 par exemple, complètement invalides car elles sortent de la plage d'adresses disponibles.

Les adresses IPv6

A voir: Gérer les adresses IPv6 avec Net_IPv6. La structure des adresses IPv6 est très complexe. En effet, contrairement à l'IPv4, les mêmes adresses IPv6 peuvent s'écrire différement. Par exemple, l'adresse 0:0:0:0:0:0:0:1 est la même que l'adresse ::1. Cette complexité se traduit par une REGEX très longue car elle comprend en elle-même les types d'adresse IPv6 possibles. La voici :

^((([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})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|(([0-9A-Fa-f]{1,4}:){0,5}:((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|(::([0-9A-Fa-f]{1,4}:){0,5}((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$

Cette REGEX n'est pas la plus simple mais elle as le mérite de faire ce qu'on lui demande, avec tous les types de nouvelles adresses.

IPv6 et IPv4 ?

Si vous souhaitez simplement tester la validitée d'une adresse IP, sans savoir quelle version est-ce, combinez les deux expressions pour donner :

^((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]?))|((([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})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|(([0-9A-Fa-f]{1,4}:){0,5}:((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|(::([0-9A-Fa-f]{1,4}:){0,5}((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$

Performances ?

Pour ce qui est de l'éfficacité de cette dernière REGEX, combinant les deux types d'IPs, sur un serveur avec un load average de 0.10, voici quelques tests de parsage avec preg_match :

Malgré la taille, les performances sont tout de même excellentes.

facebooktwittergoogle_plusredditpinterestlinkedinmail

5 thoughts on “REGEX IP(v4) et IPv6”

  1. These regexps are completely wrong if you don’t ESCAPE the dot (.) character in IPv4 dotted-decimal addresss formats.

    please replace “.” by “\.” everywhere, and recompute your performance test.

    For now your regexp accepts too many things that are definitely not IP addresses

  2. So the correct regexp for IPv4 is:

    (?:(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?)\.){3}(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?)

    Here, the regexp is optimized:
    – to maximize the context-free parsing (with single active states) as much as possible,
    – the “(?: … )” construct (as implemented in Javascript), rather than “( … )”, to create only non-capturing groups ; if the regexp engine does not implement capturing groups or does not allow controling their inclusion just use “( … )” instead.

  3. Note also that my regexp accepts “1.2.3.4” but NOT “001.002.003.004” which is invalid in IPv4 addresses used in URLs and email addresses, which forbids leading zeroes. Extra leading zeroes would transform the apparent IPv4 address into a domain name :
    – “000” is a DNS label (just like “999”)
    – “0” is restricted for use with IPv4 addresses.

    Note also that IPv4 and IPv6 addresses used in email addresses (in the host part) or in URLs (in the hostname part) may be surrounded by “[]” square brackets: this is a requirement for IPv6 addresses used in the hostname part of URLs, due to the syntax of URLs that use “:” as a delimiter for the optional port number.

  4. For IPv6:
    – the “\d” and “\.” have also been incorrectly written as “d” and “.”: restore the escaping backslashes everywhere!
    – the “b” are also wrong, they should be “\d” too (these occur where an IPv6 address is terminated by a IPv4-compatible fragment in dotted decimal format, instead of two hexadecimal segments separated by colon)

  5. for IPV4

    #!/bin/bash
    PATTERN=’\d{1,3}(\.\d{1,3}){3}’
    NPATTERN='[3-9]\d\d|2[6-9]\d|25[6-9]|\.0\d|^0′
    echo $1 | grep -P ^$PATTERN$ | grep -Pv $NPATTERN

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">