111

I'm having trouble writing a regular expression that matches valid IPv6 addresses, including those in their compressed form (with :: or leading zeros omitted from each byte pair).

Can someone suggest a regular expression that would fulfill the requirement?

I'm considering expanding each byte pair and matching the result with a simpler regex.

Stefan Lasiewski
  • 17,380
  • 5
  • 28
  • 35
readonly
  • 343,444
  • 107
  • 203
  • 205
  • 1
    Check out http://www.intermapper.com/ipv6validator.. it links to this [perl test script](http://download.dartware.com/thirdparty/test-ipv6-regex.pl) – Mottie Jan 25 '13 at 22:51
  • I have tried all of the answers below and they do not work for all my test cases and/or they also include IPv4 which wasn't asked for. I have found this to be the cleanest solution so far: http://stackoverflow.com/a/21944928/3112803 – gfrobenius Feb 21 '14 at 20:56

30 Answers30

314

I was unable to get @Factor Mystic's answer to work with POSIX regular expressions, so I wrote one that works with POSIX regular expressions and PERL regular expressions.

It should match:

IPv6 Regular Expression:

(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))

For ease of reading, the following is the above regular expression split at major OR points into separate lines:

# IPv6 RegEx
(
([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|          # 1:2:3:4:5:6:7:8
([0-9a-fA-F]{1,4}:){1,7}:|                         # 1::                              1:2:3:4:5:6:7::
([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|         # 1::8             1:2:3:4:5:6::8  1:2:3:4:5:6::8
([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|  # 1::7:8           1:2:3:4:5::7:8  1:2:3:4:5::8
([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|  # 1::6:7:8         1:2:3:4::6:7:8  1:2:3:4::8
([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|  # 1::5:6:7:8       1:2:3::5:6:7:8  1:2:3::8
([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|  # 1::4:5:6:7:8     1:2::4:5:6:7:8  1:2::8
[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|       # 1::3:4:5:6:7:8   1::3:4:5:6:7:8  1::8  
:((:[0-9a-fA-F]{1,4}){1,7}|:)|                     # ::2:3:4:5:6:7:8  ::2:3:4:5:6:7:8 ::8       ::     
fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|     # fe80::7:8%eth0   fe80::7:8%1     (link-local IPv6 addresses with zone index)
::(ffff(:0{1,4}){0,1}:){0,1}
((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}
(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|          # ::255.255.255.255   ::ffff:255.255.255.255  ::ffff:0:255.255.255.255  (IPv4-mapped IPv6 addresses and IPv4-translated addresses)
([0-9a-fA-F]{1,4}:){1,4}:
((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}
(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])           # 2001:db8:3:4::192.0.2.33  64:ff9b::192.0.2.33 (IPv4-Embedded IPv6 Address)
)

# IPv4 RegEx
((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])

To make the above easier to understand, the following "pseudo" code replicates the above:

IPV4SEG  = (25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])
IPV4ADDR = (IPV4SEG\.){3,3}IPV4SEG
IPV6SEG  = [0-9a-fA-F]{1,4}
IPV6ADDR = (
           (IPV6SEG:){7,7}IPV6SEG|                # 1:2:3:4:5:6:7:8
           (IPV6SEG:){1,7}:|                      # 1::                                 1:2:3:4:5:6:7::
           (IPV6SEG:){1,6}:IPV6SEG|               # 1::8               1:2:3:4:5:6::8   1:2:3:4:5:6::8
           (IPV6SEG:){1,5}(:IPV6SEG){1,2}|        # 1::7:8             1:2:3:4:5::7:8   1:2:3:4:5::8
           (IPV6SEG:){1,4}(:IPV6SEG){1,3}|        # 1::6:7:8           1:2:3:4::6:7:8   1:2:3:4::8
           (IPV6SEG:){1,3}(:IPV6SEG){1,4}|        # 1::5:6:7:8         1:2:3::5:6:7:8   1:2:3::8
           (IPV6SEG:){1,2}(:IPV6SEG){1,5}|        # 1::4:5:6:7:8       1:2::4:5:6:7:8   1:2::8
           IPV6SEG:((:IPV6SEG){1,6})|             # 1::3:4:5:6:7:8     1::3:4:5:6:7:8   1::8
           :((:IPV6SEG){1,7}|:)|                  # ::2:3:4:5:6:7:8    ::2:3:4:5:6:7:8  ::8       ::       
           fe80:(:IPV6SEG){0,4}%[0-9a-zA-Z]{1,}|  # fe80::7:8%eth0     fe80::7:8%1  (link-local IPv6 addresses with zone index)
           ::(ffff(:0{1,4}){0,1}:){0,1}IPV4ADDR|  # ::255.255.255.255  ::ffff:255.255.255.255  ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses)
           (IPV6SEG:){1,4}:IPV4ADDR               # 2001:db8:3:4::192.0.2.33  64:ff9b::192.0.2.33 (IPv4-Embedded IPv6 Address)
           )

I posted a script on GitHub which tests the regular expression: https://gist.github.com/syzdek/6086792

Community
  • 1
  • 1
David M. Syzdek
  • 15,360
  • 6
  • 30
  • 40
  • Excellent response. I only could wish that RegexPlanet worked right now (somehow it won't let me make share link), since I've made non capturing variant and I have added all your examples as test. – Rade_303 Jan 24 '14 at 12:15
  • Why are you using escaping in front of `.` in ip4 pattern, while `.` is unescaped in ip6 pattern? Is this intentional? – Kuba Wyrostek Feb 27 '14 at 12:26
  • 3
    You IPv4 regex does not match IPs like `127.000.000.001` – Kentzo Mar 13 '14 at 12:48
  • 29
    IPv4 segments should not include leading zeros. If a leading zero is present, the IPv4 segment should be interpreted in octal. So the IPV4SEG above is correct in not allowing '000'. It does however permit '00' which it should not. – par Jul 25 '14 at 21:56
  • 4
    Did not work for me in the browser as I would expect. Validated even reg.test('3zzzzffe:1900:4545:3:200:f8ff:fe21:67cf') which obviously is not a valid IPv6 adress. Had much better results with regex here: http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/tutorials/useful_regex.ipynb – Capaj Feb 08 '15 at 23:16
  • 1
    Matches "::_" which is not a valid IP address, as far as I can tell. – Seth Holladay Mar 23 '15 at 00:25
  • 8
    fantastic ipv6 regex. found a small bug with the link local section. you had `fe80` where it should be something like `[fF][eE]80` and a `ffff` which should be something like `[fF]{4}` – user2831628 Mar 25 '15 at 11:35
  • You have mistake in mapped ipv4 it should expect double colon like(([0-9a-fA-F]{1,4}:){1,4}:)([0-9a-fA-F]{1,4}:)IPv4regex – teodozjan Jun 16 '15 at 14:28
  • For IPv4 matching with leading zeros you can use: (25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3} – serfer2 Aug 20 '15 at 11:34
  • Question by Aria http://stackoverflow.com/questions/32368008/regular-expression-that-matches-all-valid-format-ipv6-addresses/32368136 contains answer to last comment. – Alexei Levenkov Sep 03 '15 at 07:17
  • 6
    +1 for showing that regexes can be (in the same manner as any source code) actually readable if you take the care and format them. – Natix Dec 15 '15 at 13:26
  • 1
    While writing regex patterns isn't a big deal if you know what you're looking for, it is a mundane and error-prone task. Thanks a lot for taking the time to do this the right way and for also breaking it down with useful comments! – Marcin Kaminski Feb 17 '16 at 21:56
  • It doesn't work for me: $ [[ "2001:bobbydavro::1" =~ $RE_IPV6 ]] && echo "yes" || echo "no" yes – fileinsert Mar 15 '16 at 15:16
  • I've put this into Python RE form: https://gist.github.com/dfee/6ed3a4b05cfe7a6faf40a2102408d5d8 – Devin Oct 26 '16 at 10:18
  • Failing test case: fe80::0202:B3FF:FE1E:8329 – pmarreck Oct 20 '17 at 16:49
  • Because some platforms have a lazy exit you get an unintended lazy match, leaving out the last segment of the address. To handle this, you have to move the `(IPV6SEG:){7,7}:` to come after the other compression matches and reverse the order of the compression matches. (See https://stackoverflow.com/a/14453696/4151626) – ergohack Dec 06 '17 at 21:43
  • ... (continued) ... move the `fe80` rule first and the `:((:IPV6SEG){1,7}` rule last, preceded by the `::(ffff` rule (second to last). `(IPV6SEG:){7,7}:` is third from last. – ergohack Dec 06 '17 at 22:28
  • ... (continued)... move the `(IPV6SEG:){1,4}:IPV4ADDR` rule ahead of the `(IPV6SEG:){1,4}(:IPVSEG){1,3}` rule. – ergohack Dec 06 '17 at 23:01
  • Lastly, ... on my platform, for unknown reasons, I had to change the `IPV4SEG` to `(25[0-5]|2[0-4][0-9]|1{0,1}[0-9]{0,1}[0-9])` or the more rigorous `(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]{0,1}[0-9])` to avoid `09` and `08` being interpreted as illegal octals. – ergohack Dec 06 '17 at 23:10
  • I have found by chance a form that passes mistakenly: "2. 81fa:a3c:206e:334e:b77f::" – Mr.B Feb 14 '18 at 14:32
  • @ergohack, can you post your working Regex solution to handle the lazy exit? – OwN Aug 09 '18 at 17:42
  • 2
    @OwN, unfortunately, 78 characters too long and cannot be posted as an alternative answer to this closed thread, ... I will post it in successive comments, please stitch together carefully: `(fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:` – ergohack Aug 10 '18 at 17:14
  • 2
    @OwN - part 2: `|([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|2[0-4][0-9]|1{0,1}[0-9]{0,1}[0-9])\.{3,3})(25[0-5]|2[0-4][0-9]|1{0,1}[0-9]{0,1}[0-9])|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|2[0-4][0-9]|1{0,1}[0-9]{0,1}[0-9])\.{3,3})(25[0-5]|2[0-4][0-9]|1{0,1}[0-9]{0,1}[0-9])|:((:[0-9a-fA-F]{1,4}){1,7}|:))` – ergohack Aug 10 '18 at 17:15
  • 1
    The above regex says this `1::2::3` IPv6 address is valid :) – Temüjin Oct 30 '19 at 10:16
  • 2
    All IP address in the middle column are wrong. As per [this answer](https://serverfault.com/questions/444554/what-does-mean-as-an-ip-address-bracket-colon-colon-bracket), the double colon can be used to replace consecutive blocks of zeroes, IF the length of zeroes is greater than a single block. – Marko Dec 20 '19 at 09:52
  • @ChandraNakka no it doesn't. – nicolai May 11 '20 at 08:00
  • fails of f102::1 – Konrads May 27 '20 at 04:09
  • 2
    Please consider that `[0-9a-fA-F]` wrongly matches with some locales like the Turkish `ç`. You have to use the dedicated characters class names `[[:xdigit:]]` and `[[:digit:]]` or switches the locale to `POSIX` or `C` before performing such Regex match. – Léa Gris Jun 04 '20 at 13:05
  • Curious. It [doesn't appear to match](https://regex101.com/r/nveIA8/1) `127.0.0.1` despite the IPv4 segment's presence – JamesTheAwesomeDude May 16 '21 at 23:14
  • The IPv4 regex can be replaced by `((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9])` – Rukamakama Nov 20 '21 at 10:46
  • I [tested this answer](https://regex101.com/r/dq03km/1) but it didn't work for all ip v6 formats – Sh eldeeb Nov 04 '22 at 01:42
  • Note, since RFC5952, the characters "a", "b", "c", "d", "e", and "f" in an IPv6 address MUST be represented in lowercase. – Tom Kuschel Jan 28 '23 at 18:55
57

The following will validate IPv4, IPv6 (full and compressed), and IPv6v4 (full and compressed) addresses:

'/^(?>(?>([a-f0-9]{1,4})(?>:(?1)){7}|(?!(?:.*[a-f0-9](?>:|$)){8,})((?1)(?>:(?1)){0,6})?::(?2)?)|(?>(?>(?1)(?>:(?1)){5}:|(?!(?:.*[a-f0-9]:){6,})(?3)?::(?>((?1)(?>:(?1)){0,4}):)?)?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?4)){3}))$/iD'
Michael
  • 11,912
  • 6
  • 49
  • 64
  • 8
    Even though validating ip-s could be done as Frank Krueger suggests, this solution is the one that actually answers the question (though I haven't fully tested it yet) as well as if you have many IP-s that you want syntactically test and maybe match for in a line of text, you can't use the IP validation technique. – Gyuri Dec 06 '11 at 00:33
  • Hi, I tested this RegExp and don't worked for me. It says D is an invalid flag and when I remove it it says "SyntaxError: invalid quantifier" – Diosney Dec 04 '12 at 06:37
  • What software are you using? This works with PCRE, but not with Perl. – Michael Dec 04 '12 at 16:20
  • Front-end javascript. Here is the code I used `var pattern = /PATTERN/; return [pattern.test(value), 'The Address entered is invalid.'];` – Diosney Dec 04 '12 at 17:55
  • 3
    JavaScript implements a subset of Perl-style regular expressions, not the entirety of PCRE. My regex won't work without some of the advanced features of PCRE. – Michael Dec 04 '12 at 18:29
  • 2
    This gives exception for me in C# – sarat May 07 '13 at 05:01
  • 2
    Failing test case: FE80:0000:0000:0000:0202:B3FF:FE1E:8329 Using latest version of Elixir on this date, which uses PCRE underneath. – pmarreck Oct 20 '17 at 16:23
  • C# does not support atomic grouping (e.g. `(?>`). – ergohack Dec 06 '17 at 23:16
  • This form doesn't work for all possible forms of ipv6 – Mr.B Feb 14 '18 at 14:35
27

From "IPv6 regex":

(\A([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,6}\Z)|
(\A([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,5}\Z)|
(\A([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,4}\Z)|
(\A([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,3}\Z)|
(\A([0-9a-f]{1,4}:){1,5}(:[0-9a-f]{1,4}){1,2}\Z)|
(\A([0-9a-f]{1,4}:){1,6}(:[0-9a-f]{1,4}){1,1}\Z)|
(\A(([0-9a-f]{1,4}:){1,7}|:):\Z)|
(\A:(:[0-9a-f]{1,4}){1,7}\Z)|
(\A((([0-9a-f]{1,4}:){6})(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})\Z)|
(\A(([0-9a-f]{1,4}:){5}[0-9a-f]{1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})\Z)|
(\A([0-9a-f]{1,4}:){5}:[0-9a-f]{1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,3}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,2}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,1}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A(([0-9a-f]{1,4}:){1,5}|:):(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A:(:[0-9a-f]{1,4}){1,5}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Factor Mystic
  • 26,279
  • 16
  • 79
  • 95
  • 52
    Regular expression like this should be a "code smell" that perhaps regular expression are not the best suited solution here. (Although, I guess the op did ask for it...) – Thanatos Aug 17 '10 at 20:40
  • 12
    @user712092 -- everyone who has seen a code base with eyesores such as that – danielpops Jan 12 '12 at 03:28
  • 3
    This is a completely unnecessary travesty to REs. The program that generated it didn't understand what it was doing. A human would never do it this way. Don't be fooled by the apparent complexity - REs are indeed "black magic" to many people, but there's no reason to place them on another planet! – Chuck Kollars Sep 06 '15 at 22:47
  • +1 but O.M.G. there has to be a better way to do this :P For reference: for Rails this might help: http://stackoverflow.com/questions/16965697/rails-3-validate-ipv4-and-ipv6-format – Tilo Jul 29 '16 at 05:58
  • 2
    It is indeed a code smell; however after taking a look you'll see that each regex is fairly concise. The problem is that there are different patterns created by the 'compression' of ipv6 -- Colons beginning,middle, and end, on top of if you've used your double colon you can't use it again, on top of the total colons before and after the double have to add up. Perl 6 *might* be able to tackle this, but it is way beyond PCRE syntax. (PS -- I don't count the embedded ipv4 at the end, which is longer than the ipv6 section!) – Gerard ONeill Apr 12 '17 at 20:28
27

It sounds like you may be using Python. If so, you can use something like this:

import socket

def check_ipv6(n):
    try:
        socket.inet_pton(socket.AF_INET6, n)
        return True
    except socket.error:
        return False

print check_ipv6('::1') # True
print check_ipv6('foo') # False
print check_ipv6(5)     # TypeError exception
print check_ipv6(None)  # TypeError exception

I don't think you have to have IPv6 compiled in to Python to get inet_pton, which can also parse IPv4 addresses if you pass in socket.AF_INET as the first parameter. Note: this may not work on non-Unix systems.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Joe Hildebrand
  • 10,354
  • 2
  • 38
  • 48
  • 4
    You should specify the exception type in the `except` clause. Otherwise, `except` will catch everything and may mask unrelated errors. The type here should be `socket.error`. – Ayman Hourieh Dec 20 '09 at 14:54
  • A) inet_pton doesn't throw other exceptions, unless the docs are wrong, and B) even if it did, what else would you return but False? – Joe Hildebrand Dec 22 '09 at 00:35
  • 2
    Re: other errors... if the user passes in a non-string, TypeError gets eaten. Clearly a list isn't an ipv6, but I'd probably want to have it carp that I was passing in the wrong type. – Gregg Lind Apr 21 '10 at 20:44
  • 1
    +1 This helped me a lot. A couple of additional points that should be added: 1) socket.inet_pton can be used to test the validity of both families of IP addresses (IP and IPv6). 2) The docs here (http://docs.python.org/2/library/socket.html) suggest that this is available on Unix platforms. It might not be available on Win-platforms. – mkoistinen Dec 05 '13 at 09:13
  • using django and this helps! – elad silver May 18 '15 at 11:24
16

This catches the loopback(::1) as well and ipv6 addresses. changed {} to + and put : inside the first square bracket.

([a-f0-9:]+:+)+[a-f0-9]+

tested on with ifconfig -a output http://regexr.com/

Unix or Mac OSx terminal o option returns only the matching output(ipv6) including ::1

ifconfig -a | egrep -o '([a-f0-9:]+:+)+[a-f0-9]+'

Get All IP addresses (IPv4 OR IPv6) and print match on unix OSx term

ifconfig -a | egrep -o '([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}) | (([a-f0-9:]+:+)+[a-f0-9]+)'
11

I'd have to strongly second the answer from Frank Krueger.

Whilst you say you need a regular expression to match an IPv6 address, I'm assuming what you really need is to be able to check if a given string is a valid IPv6 address. There is a subtle but important distinction here.

There is more than one way to check if a given string is a valid IPv6 address and regular expression matching is only one solution.

Use an existing library if you can. The library will have fewer bugs and its use will result in less code for you to maintain.

The regular expression suggested by Factor Mystic is long and complex. It most likely works, but you should also consider how you'd cope if it unexpectedly fails. The point I'm trying to make here is that if you can't form a required regular expression yourself you won't be able to easily debug it.

If you have no suitable library it may be better to write your own IPv6 validation routine that doesn't depend on regular expressions. If you write it you understand it and if you understand it you can add comments to explain it so that others can also understand and subsequently maintain it.

Act with caution when using a regular expression whose functionality you can't explain to someone else.

Jon Cram
  • 16,609
  • 24
  • 76
  • 107
  • 1
    Using two regular expressions, a liberal expression and an exceptions expression to trap invalid addresses allowed by the first, might be easier than one expression (`return ex1.match(S) && ! ex2.match(S)`). – Raedwald Apr 02 '13 at 11:37
  • 5
    You're assuming that he is validating individual IPs when he is almost certainly searching for IPs in a large block of text. – Navin Apr 06 '16 at 09:58
9

This regular expression will match valid IPv6 and IPv4 addresses in accordance with GNU C++ implementation of regex with REGULAR EXTENDED mode used:

"^\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][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){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][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){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][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){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][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){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][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:)))(%.+)?\s*$"
Egor
  • 39,695
  • 10
  • 113
  • 130
janCoffee
  • 375
  • 3
  • 5
7

I'm not an Ipv6 expert but I think you can get a pretty good result more easily with this one:

^([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{1,4}$|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})$

to answer "is a valid ipv6" it look like ok to me. To break it down in parts... forget it. I've omitted the unspecified one (::) since there is no use to have "unpecified adress" in my database.

the beginning: ^([0-9A-Fa-f]{0,4}:){2,7} <-- match the compressible part, we can translate this as: between 2 and 7 colon who may have heaxadecimal number between them.

followed by: [0-9A-Fa-f]{1,4}$ <-- an hexadecimal number (leading 0 omitted) OR ((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4} <-- an Ipv4 adress

Remi Morin
  • 292
  • 2
  • 6
  • 11
  • 1
    +1 for actually sticking to the OPs question and presenting a relatively handsome regex that somewhat works. – xebeche Jun 11 '13 at 18:21
  • 2
    This don't match "::1" – lsalamon Aug 11 '14 at 20:05
  • Huh? In java regex syntaxt it does match: `start() = 0, end() = 3 group(0) = "::1" group(1) = ":" group(2) = "1" group(3) = "null" group(4) = "null" group(5) = "null"` – Remi Morin Nov 05 '14 at 13:47
  • Somewhere else someone notify me of a problem with my regex, compressed part "::" can only appear once. So "::1::2" would match with my regex but it's not a valid IPV6. A second regex may validate this case. The full recommendation was to use a stateful parser to validate. I agree that resulting code will be easier to read and maintain (and someone probably already coded it in an open source somewhere). – Remi Morin Apr 07 '15 at 13:18
  • IPv4 regex also isn't perfect. For example, `1.1.1.1.` would match with it. I.e. any address with a trailing dot. – whtyger Jul 20 '22 at 13:00
5

Beware! In Java, the use of InetAddress and related classes (Inet4Address, Inet6Address, URL) may involve network trafic! E.g. DNS resolving (URL.equals, InetAddress from string!). This call may take long and is blocking!

For IPv6 I have something like this. This of course does not handle the very subtle details of IPv6 like that zone indices are allowed only on some classes of IPv6 addresses. And this regex is not written for group capturing, it is only a "matches" kind of regexp.

S - IPv6 segment = [0-9a-f]{1,4}

I - IPv4 = (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9]{1,2})\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9]{1,2})

Schematic (first part matches IPv6 addresses with IPv4 suffix, second part matches IPv6 addresses, last patrt the zone index):

(
(
::(S:){0,5}|
S::(S:){0,4}|
(S:){2}:(S:){0,3}|
(S:){3}:(S:){0,2}|
(S:){4}:(S:)?|
(S:){5}:|
(S:){6}
)
I

|

:(:|(:S){1,7})|
S:(:|(:S){1,6})|
(S:){2}(:|(:S){1,5})|
(S:){3}(:|(:S){1,4})|
(S:){4}(:|(:S){1,3})|
(S:){5}(:|(:S){1,2})|
(S:){6}(:|(:S))|
(S:){7}:|
(S:){7}S
)

(?:%[0-9a-z]+)?

And here the might regex (case insensitive, surround with what ever needed like beginning/end of line, etc.):

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

:(?::|(?::[0-9a-f]{1,4}){1,7})|
[0-9a-f]{1,4}:(?::|(?::[0-9a-f]{1,4}){1,6})|
(?:[0-9a-f]{1,4}:){2}(?::|(?::[0-9a-f]{1,4}){1,5})|
(?:[0-9a-f]{1,4}:){3}(?::|(?::[0-9a-f]{1,4}){1,4})|
(?:[0-9a-f]{1,4}:){4}(?::|(?::[0-9a-f]{1,4}){1,3})|
(?:[0-9a-f]{1,4}:){5}(?::|(?::[0-9a-f]{1,4}){1,2})|
(?:[0-9a-f]{1,4}:){6}(?::|(?::[0-9a-f]{1,4}))|
(?:[0-9a-f]{1,4}:){7}:|
(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}
)

(?:%[0-9a-z]+)?
user2623580
  • 91
  • 1
  • 2
  • Only works if you force it to match from begin to end of line and the line only contains an IPv6 address, otherwise it may only match part of the address; see here https://regex101.com/r/QZJu0x/1 – Mecki Nov 13 '21 at 01:57
5

Following regex is for IPv6 only. Group 1 matches with the IP.

(([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4})
  • +1 It is not always necessary to have a perfect super complex regex that a human can't understand. I will use this one because I understand what it does and in my case, I can be sure that if I got something that resembles a valid ipv6, so it is a valid ipv6. – David L. Jan 27 '19 at 17:42
  • 7
    this wouldn't match say: fe80::1 or 2342:32fd::2d32 – James Apr 24 '19 at 15:39
  • The regex matches: 2020-09-09 **16:36:10**,978 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs). – Kaymaz Oct 21 '20 at 08:58
  • @Kaymaz use some context in your regex. Compression can't be easily regexed, as you see on the top replies. – grin Mar 05 '21 at 11:49
  • (([0-9a-fA-F]{0,4}:){7}[0-9a-fA-F]{0,4}) {1,7} it's violating the ipv6 rules. replace with {7} – Yashwant Mahawar Oct 06 '21 at 19:13
5

If you use Perl try Net::IPv6Addr

use Net::IPv6Addr;

if( defined Net::IPv6Addr::is_ipv6($ip_address) ){
  print "Looks like an ipv6 address\n";
}

NetAddr::IP

use NetAddr::IP;

my $obj = NetAddr::IP->new6($ip_address);

Validate::IP

use Validate::IP qw'is_ipv6';

if( is_ipv6($ip_address) ){
  print "Looks like an ipv6 address\n";
}
Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129
  • Or Data::Validate::IP http://search.cpan.org/~neely/Data-Validate-IP-0.11/lib/Data/Validate/IP.pm. – Calimo Dec 16 '10 at 12:02
4

A simple regex that will match, but I wouldn't recommend for validation of any sort is this:

([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}

Note this matches compression anywhere in the address, though it won't match the loopback address ::1. I find this a reasonable compromise in order to keep the regex simple.

I successfully use this in iTerm2 smart selection rules to quad-click IPv6 addresses.

David M. Syzdek
  • 15,360
  • 6
  • 30
  • 40
JinnKo
  • 908
  • 10
  • 13
  • 4
    You meant `A-F`, not `A-Z`! Also note that you are excluding dotted-quad notation. – xebeche Jun 11 '13 at 18:10
  • It would match with something like `1::2::3::4::5::6::7::8`. Sadly, there's no easy way to implement the compressed IPv6 addresses. – whtyger Jul 20 '22 at 13:12
  • It matches the invalid address`1::2::3`, while cannot match the valid address `2a11::`. – Arnie97 Jun 26 '23 at 10:59
4

Regexes for ipv6 can get really tricky when you consider addresses with embedded ipv4 and addresses that are compressed, as you can see from some of these answers.

The open-source IPAddress Java library will validate all standard representations of IPv6 and IPv4 and also supports prefix-length (and validation of such). Disclaimer: I am the project manager of that library.

Code example:

        try {
            IPAddressString str = new IPAddressString("::1");
            IPAddress addr = str.toAddress();
            if(addr.isIPv6() || addr.isIPv6Convertible()) {
                IPv6Address ipv6Addr = addr.toIPv6();
            }
            //use address
        } catch(AddressStringException e) {
            //e.getMessage has validation error
        }
Sean F
  • 4,344
  • 16
  • 30
2

Looking at the patterns included in the other answers there are a number of good patterns that can be improved by referencing groups and utilizing lookaheads. Here is an example of a pattern that is self referencing that I would utilize in PHP if I had to:

^(?<hgroup>(?<hex>[[:xdigit:]]{0,4}) # grab a sequence of up to 4 hex digits
                                     # and name this pattern for usage later
     (?<!:::):{1,2})                 # match 1 or 2 ':' characters
                                     # as long as we can't match 3
 (?&hgroup){1,6} # match our hex group 1 to 6 more times
 (?:(?:
    # match an ipv4 address or
    (?<dgroup>2[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3}(?&dgroup)
    # match our hex group one last time
    |(?&hex))$

Note: PHP has a built in filter for this which would be a better solution than this pattern.

Regex101 Analysis

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Steve Buzonas
  • 5,300
  • 1
  • 33
  • 55
2

In Scala use the well known Apache Commons validators.

http://mvnrepository.com/artifact/commons-validator/commons-validator/1.4.1

libraryDependencies += "commons-validator" % "commons-validator" % "1.4.1"


import org.apache.commons.validator.routines._

/**
 * Validates if the passed ip is a valid IPv4 or IPv6 address.
 *
 * @param ip The IP address to validate.
 * @return True if the passed IP address is valid, false otherwise.
 */  
 def ip(ip: String) = InetAddressValidator.getInstance().isValid(ip)

Following the test's of the method ip(ip: String):

"The `ip` validator" should {
  "return false if the IPv4 is invalid" in {
    ip("123") must beFalse
    ip("255.255.255.256") must beFalse
    ip("127.1") must beFalse
    ip("30.168.1.255.1") must beFalse
    ip("-1.2.3.4") must beFalse
  }

  "return true if the IPv4 is valid" in {
    ip("255.255.255.255") must beTrue
    ip("127.0.0.1") must beTrue
    ip("0.0.0.0") must beTrue
  }

  //IPv6
  //@see: http://www.ronnutter.com/ipv6-cheatsheet-on-identifying-valid-ipv6-addresses/
  "return false if the IPv6 is invalid" in {
    ip("1200::AB00:1234::2552:7777:1313") must beFalse
  }

  "return true if the IPv6 is valid" in {
    ip("1200:0000:AB00:1234:0000:2552:7777:1313") must beTrue
    ip("21DA:D3:0:2F3B:2AA:FF:FE28:9C5A") must beTrue
  }
}
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
OliverKK
  • 505
  • 4
  • 15
  • Interesting, It claims to check that it is a valid address, "_Validates if the passed ip is a valid IPv4 or IPv6 address._", but it really only checks that it is formatted as a valid address. For instance, `1200:0000:AB00:1234:0000:2552:7777:1313` is a valid format for an IPv6 address, but it is not a valid IPv6 address as the test method returns. I'll bet it thinks `241.54.113.65` is a valid IPv4 address. – Ron Maupin Nov 03 '15 at 02:00
2

Depending on your needs, an approximation like:

[0-9a-f:]+

may be enough (as with simple log file grepping, for example.)

Bill Lipa
  • 2,039
  • 1
  • 19
  • 11
2

I generated the following using python and works with the re module. The look-ahead assertions ensure that the correct number of dots or colons appear in the address. It does not support IPv4 in IPv6 notation.

pattern = '^(?=\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$)(?:(?:25[0-5]|[12][0-4][0-9]|1[5-9][0-9]|[1-9]?[0-9])\.?){4}$|(?=^(?:[0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}$)(?![^:]*::.+::[^:]*$)(?:(?=.*::.*)|(?=\w+:\w+:\w+:\w+:\w+:\w+:\w+:\w+))(?:(?:^|:)(?:[0-9a-f]{4}|[1-9a-f][0-9a-f]{0,3})){0,8}(?:::(?:[0-9a-f]{1,4}(?:$|:)){0,6})?$'
result = re.match(pattern, ip)
if result: result.group(0)
1

Using Ruby? Try this:

/^(((?=.*(::))(?!.*\3.+\3))\3?|[\dA-F]{1,4}:)([\dA-F]{1,4}(\3|:\b)|\2){5}(([\dA-F]{1,4}(\3|:\b|$)|\2){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})\z/i
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Ahamx
  • 21
  • 1
1

It is difficult to find a regular expression which works for all IPv6 cases. They are usually hard to maintain, not easily readable and may cause performance problems. Hence, I want to share an alternative solution which I have developed: Regular Expression (RegEx) for IPv6 Separate from IPv4

Now you may ask that "This method only finds IPv6, how can I find IPv6 in a text or file?" Here are methods for this issue too.

Note: If you do not want to use IPAddress class in .NET, you can also replace it with my method. It also covers mapped IPv4 and special cases too, while IPAddress does not cover.

class IPv6
{
    public List<string> FindIPv6InFile(string filePath)
    {
        Char ch;
        StringBuilder sbIPv6 = new StringBuilder();
        List<string> listIPv6 = new List<string>();
        StreamReader reader = new StreamReader(filePath);
        do
        {
            bool hasColon = false;
            int length = 0;

            do
            {
                ch = (char)reader.Read();

                if (IsEscapeChar(ch))
                    break;

                //Check the first 5 chars, if it has colon, then continue appending to stringbuilder
                if (!hasColon && length < 5)
                {
                    if (ch == ':')
                    {
                        hasColon = true;
                    }
                    sbIPv6.Append(ch.ToString());
                }
                else if (hasColon) //if no colon in first 5 chars, then dont append to stringbuilder
                {
                    sbIPv6.Append(ch.ToString());
                }

                length++;

            } while (!reader.EndOfStream);

            if (hasColon && !listIPv6.Contains(sbIPv6.ToString()) && IsIPv6(sbIPv6.ToString()))
            {
                listIPv6.Add(sbIPv6.ToString());
            }

            sbIPv6.Clear();

        } while (!reader.EndOfStream);
        reader.Close();
        reader.Dispose();

        return listIPv6;
    }

    public List<string> FindIPv6InText(string text)
    {
        StringBuilder sbIPv6 = new StringBuilder();
        List<string> listIPv6 = new List<string>();

        for (int i = 0; i < text.Length; i++)
        {
            bool hasColon = false;
            int length = 0;

            do
            {
                if (IsEscapeChar(text[length + i]))
                    break;

                //Check the first 5 chars, if it has colon, then continue appending to stringbuilder
                if (!hasColon && length < 5)
                {
                    if (text[length + i] == ':')
                    {
                        hasColon = true;
                    }
                    sbIPv6.Append(text[length + i].ToString());
                }
                else if (hasColon) //if no colon in first 5 chars, then dont append to stringbuilder
                {
                    sbIPv6.Append(text[length + i].ToString());
                }

                length++;

            } while (i + length != text.Length);

            if (hasColon && !listIPv6.Contains(sbIPv6.ToString()) && IsIPv6(sbIPv6.ToString()))
            {
                listIPv6.Add(sbIPv6.ToString());
            }

            i += length;
            sbIPv6.Clear();
        }

        return listIPv6;
    }

    bool IsEscapeChar(char ch)
    {
        if (ch != ' ' && ch != '\r' && ch != '\n' && ch!='\t')
        {
            return false;
        }

        return true;
    }

    bool IsIPv6(string maybeIPv6)
    {
        IPAddress ip;
        if (IPAddress.TryParse(maybeIPv6, out ip))
        {
            return ip.AddressFamily == AddressFamily.InterNetworkV6;
        }
        else
        {
            return false;
        }
    }

}
Community
  • 1
  • 1
Nuh Metin Güler
  • 1,075
  • 8
  • 9
1

InetAddressUtils has all the patterns defined. I ended-up using their pattern directly, and am pasting it here for reference:

private static final String IPV4_BASIC_PATTERN_STRING =
        "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}" + // initial 3 fields, 0-255 followed by .
         "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])"; // final field, 0-255

private static final Pattern IPV4_PATTERN =
    Pattern.compile("^" + IPV4_BASIC_PATTERN_STRING + "$");

private static final Pattern IPV4_MAPPED_IPV6_PATTERN = // TODO does not allow for redundant leading zeros
        Pattern.compile("^::[fF]{4}:" + IPV4_BASIC_PATTERN_STRING + "$");

private static final Pattern IPV6_STD_PATTERN =
    Pattern.compile(
            "^[0-9a-fA-F]{1,4}(:[0-9a-fA-F]{1,4}){7}$");

private static final Pattern IPV6_HEX_COMPRESSED_PATTERN =
    Pattern.compile(
            "^(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)" + // 0-6 hex fields
             "::" +
             "(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)$"); // 0-6 hex fields 
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
1

In Java, you can use the library class sun.net.util.IPAddressUtil:

IPAddressUtil.isIPv6LiteralAddress(iPaddress);
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
user463639
  • 27
  • 1
0

For PHP 5.2+ users filter_var works great.

I know this doesn't answer the original question (specifically a regex solution), but I post this in the hope it may help someone else in the future.

$is_ip4address = (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== FALSE);
$is_ip6address = (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== FALSE);
Wireblue
  • 1,329
  • 1
  • 14
  • 24
0

Here's what I came up with, using a bit of lookahead and named groups. This is of course just IPv6, but it shouldn't interfere with additional patterns if you want to add IPv4:

(?=([0-9a-f]+(:[0-9a-f])*)?(?P<wild>::)(?!([0-9a-f]+:)*:))(::)?([0-9a-f]{1,4}:{1,2}){0,6}(?(wild)[0-9a-f]{0,4}|[0-9a-f]{1,4}:[0-9a-f]{1,4})
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
0

Just matching local ones from an origin with square brackets included. I know it's not as comprehensive but in javascript the other ones had difficult to trace issues primarily that of not working, so this seems to get me what I needed for now. extra capitals A-F aren't needed either.

^\[([0-9a-fA-F]{1,4})(\:{1,2})([0-9a-fA-F]{1,4})(\:{1,2})([0-9a-fA-F]{1,4})(\:{1,2})([0-9a-fA-F]{1,4})(\:{1,2})([0-9a-fA-F]{1,4})\]

Jinnko's version is simplified and better I see.

Master James
  • 1,691
  • 15
  • 19
0

As stated above, another way to get an IPv6 textual representation validating parser is to use programming. Here is one that is fully compliant with RFC-4291 and RFC-5952. I've written this code in ANSI C (works with GCC, passed tests on Linux - works with clang, passed tests on FreeBSD). Thus, it does only rely on the ANSI C standard library, so it can be compiled everywhere (I've used it for IPv6 parsing inside a kernel module with FreeBSD).

// IPv6 textual representation validating parser fully compliant with RFC-4291 and RFC-5952
// BSD-licensed / Copyright 2015-2017 Alexandre Fenyo

#include <string.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

typedef enum { false, true } bool;

static const char hexdigits[] = "0123456789abcdef";
static int digit2int(const char digit) {
  return strchr(hexdigits, digit) - hexdigits;
}

// This IPv6 address parser handles any valid textual representation according to RFC-4291 and RFC-5952.
// Other representations will return -1.
//
// note that str input parameter has been modified when the function call returns
//
// parse_ipv6(char *str, struct in6_addr *retaddr)
// parse textual representation of IPv6 addresses
// str:     input arg
// retaddr: output arg
int parse_ipv6(char *str, struct in6_addr *retaddr) {
  bool compressed_field_found = false;
  unsigned char *_retaddr = (unsigned char *) retaddr;
  char *_str = str;
  char *delim;

  bzero((void *) retaddr, sizeof(struct in6_addr));
  if (!strlen(str) || strchr(str, ':') == NULL || (str[0] == ':' && str[1] != ':') ||
      (strlen(str) >= 2 && str[strlen(str) - 1] == ':' && str[strlen(str) - 2] != ':')) return -1;

  // convert transitional to standard textual representation
  if (strchr(str, '.')) {
    int ipv4bytes[4];
    char *curp = strrchr(str, ':');
    if (curp == NULL) return -1;
    char *_curp = ++curp;
    int i;
    for (i = 0; i < 4; i++) {
      char *nextsep = strchr(_curp, '.');
      if (_curp[0] == '0' || (i < 3 && nextsep == NULL) || (i == 3 && nextsep != NULL)) return -1;
      if (nextsep != NULL) *nextsep = 0;
      int j;
      for (j = 0; j < strlen(_curp); j++) if (_curp[j] < '0' || _curp[j] > '9') return -1;
      if (strlen(_curp) > 3) return -1;
      const long val = strtol(_curp, NULL, 10);
      if (val < 0 || val > 255) return -1;
      ipv4bytes[i] = val;
      _curp = nextsep + 1;
    }
    sprintf(curp, "%x%02x:%x%02x", ipv4bytes[0], ipv4bytes[1], ipv4bytes[2], ipv4bytes[3]);
  }

  // parse standard textual representation
  do {
    if ((delim = strchr(_str, ':')) == _str || (delim == NULL && !strlen(_str))) {
      if (delim == str) _str++;
      else if (delim == NULL) return 0;
      else {
        if (compressed_field_found == true) return -1;
        if (delim == str + strlen(str) - 1 && _retaddr != (unsigned char *) (retaddr + 1)) return 0;
        compressed_field_found = true;
        _str++;
        int cnt = 0;
        char *__str;
        for (__str = _str; *__str; ) if (*(__str++) == ':') cnt++;
        unsigned char *__retaddr = - 2 * ++cnt + (unsigned char *) (retaddr + 1);
        if (__retaddr <= _retaddr) return -1;
        _retaddr = __retaddr;
      }
    } else {
      char hexnum[4] = "0000";
      if (delim == NULL) delim = str + strlen(str);
      if (delim - _str > 4) return -1;
      int i;
      for (i = 0; i < delim - _str; i++)
        if (!isxdigit(_str[i])) return -1;
        else hexnum[4 - (delim - _str) + i] = tolower(_str[i]);
      _str = delim + 1;
      *(_retaddr++) = (digit2int(hexnum[0]) << 4) + digit2int(hexnum[1]);
      *(_retaddr++) = (digit2int(hexnum[2]) << 4) + digit2int(hexnum[3]);
    }
  } while (_str < str + strlen(str));
  return 0;
}
Alexandre Fenyo
  • 4,526
  • 1
  • 17
  • 24
-1

The regex allows the use of leading zeros in the IPv4 parts.

Some Unix and Mac distros convert those segments into octals.

I suggest using 25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d as an IPv4 segment.

Jason Plank
  • 2,336
  • 5
  • 31
  • 40
Aeron
  • 11
-1

This will work for IPv4 and IPv6:

^(([0-9a-f]{0,4}:){1,7}[0-9a-f]{1,4}|([0-9]{1,3}\.){3}[0-9]{1,3})$
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Chris
  • 15
  • 1
-1

You can use the ipextract shell tools I made for this purpose. They are based on regexp and grep.

Usage:

$ ifconfig | ipextract6
fe80::1%lo0
::1
fe80::7ed1:c3ff:feec:dee1%en0
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Phil L.
  • 2,637
  • 1
  • 17
  • 11
-1

Try this small one-liner. It should only match valid uncompressed/compressed IPv6 addresses (no IPv4 hybrids)

/(?!.*::.*::)(?!.*:::.*)(?!:[a-f0-9])((([a-f0-9]{1,4})?[:](?!:)){7}|(?=(.*:[:a-f0-9]{1,4}::|^([:a-f0-9]{1,4})?::))(([a-f0-9]{1,4})?[:]{1,2}){1,6})[a-f0-9]{1,4}/
  • Actually, valid IPv6 addresses include uncompressed, compressed, uncompressed-hybrid, and compressed hybrid. It really takes a lot more than what you have to actually match any valid text representation of an IPv6 address. – Ron Maupin Jun 19 '16 at 02:15
-2

If you want only normal IP-s (no slashes), here:

^(?:[0-9a-f]{1,4}(?:::)?){0,7}::[0-9a-f]+$

I use it for my syntax highlighter in hosts file editor application. Works as charm.

Harry
  • 4,524
  • 4
  • 42
  • 81
  • No way that this ever works decently, it can't match a single ipv6 address with a single colon in it, all your matches are on double colons, and you explicitly require a double colon for your last group, summarization can happen anywhere... . – KillianDS Jul 24 '13 at 14:46
  • (?:[0-9a-f]{1,4}(?:::?)?){0,7}::?[0-9a-f]{1,4} – Harry Jul 24 '13 at 15:01
  • Still wrong, but even then you'll end up repeating JinnKo's answer, which is good enough for simple purposes, but still has flaws (does not catch double summarization and doesn't allow dotted quads, nor localhost, nor :: termination, ...) – KillianDS Jul 24 '13 at 15:07