Skip to content

Instantly share code, notes, and snippets.

@cpetschnig
Created February 4, 2010 09:19
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save cpetschnig/294476 to your computer and use it in GitHub Desktop.
Save cpetschnig/294476 to your computer and use it in GitHub Desktop.
Regular Expression Validation for IPv6 Addresses in Ruby
# Regular Expression Validation for IPv6 addresses in Ruby
#
# Inspired by (if not to say copied from): http://forums.dartware.com/viewtopic.php?t=452
# Thanks, Dartware!
IPV6_REGEX = /^\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|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[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|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[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|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[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|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[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|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[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|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[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|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/
class Validator
def initialize
@valid_false = []
@invalid_false = []
end
def ipv6(string)
result = string =~ IPV6_REGEX
print result ? '.' : 'F'
@valid_false << string unless result
end
def not_ipv6(string)
result = (string =~ IPV6_REGEX).nil?
print result ? '.' : 'F'
@invalid_false << string unless result
end
def to_s
output = "\n"
output += "\nEverything's fine!" if @valid_false.empty? && @invalid_false.empty?
unless @valid_false.empty?
output += "\nThe following addresses are valid, but fail the test:\n"
@valid_false.each{|obj| output += "#{obj}\n"}
end
unless @invalid_false.empty?
output += "\nThe following addresses are not valid, but pass the test:\n"
@invalid_false.each{|obj| output += "#{obj}\n"}
end
output
end
end
assert = Validator.new
assert.not_ipv6("")
assert.ipv6("2001:0000:1234:0000:0000:C1C0:ABCD:0876")
assert.ipv6("3ffe:0b00:0000:0000:0001:0000:0000:000a")
assert.ipv6("FF02:0000:0000:0000:0000:0000:0000:0001")
assert.ipv6("0000:0000:0000:0000:0000:0000:0000:0001")
assert.ipv6("0000:0000:0000:0000:0000:0000:0000:0000")
assert.ipv6("::ffff:192.168.1.26")
assert.not_ipv6("02001:0000:1234:0000:0000:C1C0:ABCD:0876") # extra 0 not allowed!
assert.not_ipv6("2001:0000:1234:0000:00001:C1C0:ABCD:0876") # extra 0 not allowed!
assert.ipv6(" 2001:0000:1234:0000:0000:C1C0:ABCD:0876")
assert.ipv6(" 2001:0000:1234:0000:0000:C1C0:ABCD:0876 ")
assert.not_ipv6(" 2001:0000:1234:0000:0000:C1C0:ABCD:0876 0")
assert.not_ipv6("2001:0000:1234: 0000:0000:C1C0:ABCD:0876")
assert.not_ipv6("3ffe:0b00:0000:0001:0000:0000:000a")
assert.not_ipv6("FF02:0000:0000:0000:0000:0000:0000:0000:0001")
assert.not_ipv6("3ffe:b00::1::a")
assert.not_ipv6("::1111:2222:3333:4444:5555:6666::")
assert.ipv6("2::10")
assert.ipv6("ff02::1")
assert.ipv6("fe80::")
assert.ipv6("2002::")
assert.ipv6("2001:db8::")
assert.ipv6("2001:0db8:1234::")
assert.ipv6("::ffff:0:0")
assert.ipv6("::1")
assert.ipv6("::ffff:192.168.1.1")
assert.ipv6("1:2:3:4:5:6:7:8")
assert.ipv6("1:2:3:4:5:6::8")
assert.ipv6("1:2:3:4:5::8")
assert.ipv6("1:2:3:4::8")
assert.ipv6("1:2:3::8")
assert.ipv6("1:2::8")
assert.ipv6("1::8")
assert.ipv6("1::2:3:4:5:6:7")
assert.ipv6("1::2:3:4:5:6")
assert.ipv6("1::2:3:4:5")
assert.ipv6("1::2:3:4")
assert.ipv6("1::2:3")
assert.ipv6("1::8")
assert.ipv6("::2:3:4:5:6:7:8")
assert.ipv6("::2:3:4:5:6:7")
assert.ipv6("::2:3:4:5:6")
assert.ipv6("::2:3:4:5")
assert.ipv6("::2:3:4")
assert.ipv6("::2:3")
assert.ipv6("::8")
assert.ipv6("1:2:3:4:5:6::")
assert.ipv6("1:2:3:4:5::")
assert.ipv6("1:2:3:4::")
assert.ipv6("1:2:3::")
assert.ipv6("1:2::")
assert.ipv6("1::")
assert.ipv6("1:2:3:4:5::7:8")
assert.not_ipv6("1:2:3::4:5::7:8")
assert.not_ipv6("12345::6:7:8")
assert.ipv6("1:2:3:4::7:8")
assert.ipv6("1:2:3::7:8")
assert.ipv6("1:2::7:8")
assert.ipv6("1::7:8")
assert.ipv6("1:2:3:4:5:6:1.2.3.4")
assert.ipv6("1:2:3:4:5::1.2.3.4")
assert.ipv6("1:2:3:4::1.2.3.4")
assert.ipv6("1:2:3::1.2.3.4")
assert.ipv6("1:2::1.2.3.4")
assert.ipv6("1::1.2.3.4")
assert.ipv6("1:2:3:4::5:1.2.3.4")
assert.ipv6("1:2:3::5:1.2.3.4")
assert.ipv6("1:2::5:1.2.3.4")
assert.ipv6("1::5:1.2.3.4")
assert.ipv6("1::5:11.22.33.44")
assert.not_ipv6("1::5:400.2.3.4")
assert.not_ipv6("1::5:260.2.3.4")
assert.not_ipv6("1::5:256.2.3.4")
assert.not_ipv6("1::5:1.256.3.4")
assert.not_ipv6("1::5:1.2.256.4")
assert.not_ipv6("1::5:1.2.3.256")
assert.not_ipv6("1::5:300.2.3.4")
assert.not_ipv6("1::5:1.300.3.4")
assert.not_ipv6("1::5:1.2.300.4")
assert.not_ipv6("1::5:1.2.3.300")
assert.not_ipv6("1::5:900.2.3.4")
assert.not_ipv6("1::5:1.900.3.4")
assert.not_ipv6("1::5:1.2.900.4")
assert.not_ipv6("1::5:1.2.3.900")
assert.not_ipv6("1::5:300.300.300.300")
assert.not_ipv6("1::5:3000.30.30.30")
assert.not_ipv6("1::400.2.3.4")
assert.not_ipv6("1::260.2.3.4")
assert.not_ipv6("1::256.2.3.4")
assert.not_ipv6("1::1.256.3.4")
assert.not_ipv6("1::1.2.256.4")
assert.not_ipv6("1::1.2.3.256")
assert.not_ipv6("1::300.2.3.4")
assert.not_ipv6("1::1.300.3.4")
assert.not_ipv6("1::1.2.300.4")
assert.not_ipv6("1::1.2.3.300")
assert.not_ipv6("1::900.2.3.4")
assert.not_ipv6("1::1.900.3.4")
assert.not_ipv6("1::1.2.900.4")
assert.not_ipv6("1::1.2.3.900")
assert.not_ipv6("1::300.300.300.300")
assert.not_ipv6("1::3000.30.30.30")
assert.not_ipv6("::400.2.3.4")
assert.not_ipv6("::260.2.3.4")
assert.not_ipv6("::256.2.3.4")
assert.not_ipv6("::1.256.3.4")
assert.not_ipv6("::1.2.256.4")
assert.not_ipv6("::1.2.3.256")
assert.not_ipv6("::300.2.3.4")
assert.not_ipv6("::1.300.3.4")
assert.not_ipv6("::1.2.300.4")
assert.not_ipv6("::1.2.3.300")
assert.not_ipv6("::900.2.3.4")
assert.not_ipv6("::1.900.3.4")
assert.not_ipv6("::1.2.900.4")
assert.not_ipv6("::1.2.3.900")
assert.not_ipv6("::300.300.300.300")
assert.not_ipv6("::3000.30.30.30")
assert.ipv6("fe80::217:f2ff:254.7.237.98")
assert.ipv6("fe80::217:f2ff:fe07:ed62")
assert.ipv6("2001:DB8:0:0:8:800:200C:417A") # unicast, full
assert.ipv6("FF01:0:0:0:0:0:0:101") # multicast, full
assert.ipv6("0:0:0:0:0:0:0:1") # loopback, full
assert.ipv6("0:0:0:0:0:0:0:0") # unspecified, full
assert.ipv6("2001:DB8::8:800:200C:417A") # unicast, compressed
assert.ipv6("FF01::101") # multicast, compressed
assert.ipv6("::1") # loopback, compressed, non-routable
assert.ipv6("::") # unspecified, compressed, non-routable
assert.ipv6("0:0:0:0:0:0:13.1.68.3") # IPv4-compatible IPv6 address, full, deprecated
assert.ipv6("0:0:0:0:0:FFFF:129.144.52.38") # IPv4-mapped IPv6 address, full
assert.ipv6("::13.1.68.3") # IPv4-compatible IPv6 address, compressed, deprecated
assert.ipv6("::FFFF:129.144.52.38") # IPv4-mapped IPv6 address, compressed
# assert.ipv6("2001:0DB8:0000:CD30:0000:0000:0000:0000/60") # full, with prefix
# assert.ipv6("2001:0DB8::CD30:0:0:0:0/60") # compressed, with prefix
# assert.ipv6("2001:0DB8:0:CD30::/60") # compressed, with prefix #2
# assert.ipv6("::/128") # compressed, unspecified address type, non-routable
# assert.ipv6("::1/128") # compressed, loopback address type, non-routable
# assert.ipv6("FF00::/8") # compressed, multicast address type
# assert.ipv6("FE80::/10") # compressed, link-local unicast, non-routable
# assert.ipv6("FEC0::/10") # compressed, site-local unicast, deprecated
# assert.not_ipv6("124.15.6.89/60") # standard IPv4, prefix not allowed
assert.not_ipv6("2001:DB8:0:0:8:800:200C:417A:221") # unicast, full
assert.not_ipv6("FF01::101::2") # multicast, compressed
assert.not_ipv6("") # nothing
assert.ipv6("fe80:0000:0000:0000:0204:61ff:fe9d:f156")
assert.ipv6("fe80:0:0:0:204:61ff:fe9d:f156")
assert.ipv6("fe80::204:61ff:fe9d:f156")
# Not sure about this one; apparently some systems treat the leading "0" in ".086" as the start of an octal number
assert.not_ipv6("fe80:0000:0000:0000:0204:61ff:254.157.241.086")
assert.ipv6("fe80:0:0:0:204:61ff:254.157.241.86")
assert.ipv6("fe80::204:61ff:254.157.241.86")
assert.ipv6("::1")
assert.ipv6("fe80::")
assert.ipv6("fe80::1")
assert.not_ipv6(":")
# Aeron supplied these test cases.
assert.not_ipv6("1111:2222:3333:4444::5555:")
assert.not_ipv6("1111:2222:3333::5555:")
assert.not_ipv6("1111:2222::5555:")
assert.not_ipv6("1111::5555:")
assert.not_ipv6("::5555:")
assert.not_ipv6(":::")
assert.not_ipv6("1111:")
assert.not_ipv6(":")
assert.not_ipv6(":1111:2222:3333:4444::5555")
assert.not_ipv6(":1111:2222:3333::5555")
assert.not_ipv6(":1111:2222::5555")
assert.not_ipv6(":1111::5555")
assert.not_ipv6(":::5555")
assert.not_ipv6(":::")
assert.not_ipv6("1.2.3.4:1111:2222:3333:4444::5555")
assert.not_ipv6("1.2.3.4:1111:2222:3333::5555")
assert.not_ipv6("1.2.3.4:1111:2222::5555")
assert.not_ipv6("1.2.3.4:1111::5555")
assert.not_ipv6("1.2.3.4::5555")
assert.not_ipv6("1.2.3.4::")
assert.not_ipv6("2001:1:1:1:1:1:255Z255X255Y255")
assert.not_ipv6("::ffff:192x168.1.26")
#assert.ipv6("foo")
#assert.not_ipv6("::1")
puts assert
@kont-noor
Copy link

This fails:

assert.ipv6("2001:0:ffff:ffff:ffff:ffff:ffff:ffff")

@b4ldr
Copy link

b4ldr commented Sep 5, 2016

theres always one ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment