1
# $Id: ipv6.rb,v 1.12 2003/07/25 22:51:24 sdalu Exp $
4
# AUTHOR : Stephane D'Alu <sdalu@nic.fr>
5
# CREATED : 2002/07/19 07:28:13
7
# COPYRIGHT: AFNIC (c) 2003
12
# $Date: 2003/07/25 22:51:24 $
15
# - the ruby file: resolv.rb
17
# CONTRIBUTORS: (see also CREDITS file)
22
require 'address/common'
23
require 'address/ipv4'
33
(?:[0-9A-Fa-f]{1,4}:){7}
37
Regex_CompressedHex = /\A
38
((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
39
((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)
43
((?:[0-9A-Fa-f]{1,4}:){6,6})
44
(\d+)\.(\d+)\.(\d+)\.(\d+)
47
Regex_CompressedHex4Dec = /\A
48
((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
49
((?:[0-9A-Fa-f]{1,4}:)*)
50
(\d+)\.(\d+)\.(\d+)\.(\d+)
54
(\d+)\.(\d+)\.(\d+)\.(\d+)
59
(?:#{Regex_8Hex.source}) |
60
(?:#{Regex_CompressedHex.source}) |
61
(?:#{Regex_6Hex4Dec.source}) |
62
(?:#{Regex_CompressedHex4Dec.source})
66
(?:#{Regex_8Hex.source}) |
67
(?:#{Regex_CompressedHex.source})
71
(?:#{Regex_8Hex.source}) |
72
(?:#{Regex_CompressedHex.source}) |
73
(?:#{Regex_6Hex4Dec.source}) |
74
(?:#{Regex_CompressedHex4Dec.source}) |
75
(?:#{Regex_4Dec.source})
82
def self.hex_pack(str, data='')
83
str.scan(/[0-9A-Fa-f]+/) { |hex| data << [hex.hex].pack('n') }
87
def self.is_valid(str, opt=Regex)
91
def self.create(arg, opt=Regex)
96
return self.create("::ffff:#{arg.to_s}")
100
# According to the option, select the test that
101
# should be performed
102
test = if opt == IPv6StrictRegex then 1
103
elsif opt == IPv6Regex then 2
104
elsif opt == IPv6LooseRegex then 3
105
else raise ArgumentError, 'unknown option'
108
# Test: a:b:c:d:e:f:g:h
109
if (test >= 1) && Regex_8Hex =~ arg
110
hex_pack(arg, address)
113
elsif (test >= 1) && Regex_CompressedHex =~ arg
114
prefix, suffix = $1, $2
115
a1 = hex_pack(prefix)
116
a2 = hex_pack(suffix)
117
omitlen = 16 - a1.length - a2.length
118
address << a1 << "\0" * omitlen << a2
120
# Test: a:b:c:d:e:f:g.h.i.j
121
elsif (test >= 2) && Regex_6Hex4Dec =~ arg
122
prefix, a, b, c, d = $1, $2.to_i, $3.to_i, $4.to_i, $5.to_i
123
if (0..255) === a && (0..255) === b &&
124
(0..255) === c && (0..255) === d
125
hex_pack(prefix, address)
126
address << [a, b, c, d].pack('CCCC')
129
# Test: a::b:c:d.e.f.g
130
elsif (test >= 2) && Regex_CompressedHex4Dec =~ arg
131
prefix, suffix, a, b, c, d = $1, $2, $3.to_i, $4.to_i, $5.to_i, $6.to_i
132
if (0..255) === a && (0..255) === b &&
133
(0..255) === c && (0..255) === d
134
a1 = hex_pack(prefix)
135
a2 = hex_pack(suffix)
136
omitlen = 12 - a1.length - a2.length
137
address << a1 << "\0" * omitlen << a2 << [a, b, c, d].pack('CCCC')
141
elsif (test >= 3) && Regex_4Dec =~ arg
142
a, b, c, d = $1.to_i, $2.to_i, $3.to_i, $4.to_i
143
if (0..255) === a && (0..255) === b &&
144
(0..255) === c && (0..255) === d
145
address << "\0" * 10 << "\377" * 2 << [a, b, c, d].pack('CCCC')
149
# Check if conversion succed
150
if address.length != 16
151
raise InvalidAddress,
152
"IPv6 address with invalid value: #{arg}"
156
return IPv6::new(address.untaint.freeze)
158
raise InvalidAddress,
159
"can't interprete as IPv6 address: #{arg.inspect}"
163
def initialize(address)
164
unless (address.instance_of?(String) &&
165
address.length == 16 && address.frozen?)
167
'IPv6 raw address must be a 16 byte frozen string'
181
if size > @address.size * 8
182
raise ArgumentError, 'prefix size too big'
184
bytes, bits_shift = size / 8, 8 - (size % 8)
185
address = @address.slice(0, bytes) +
186
("\0" * (@address.size - bytes))
187
address[bytes] = (@address[bytes] >> bits_shift) << bits_shift
188
IPv6::new(address.freeze)
193
address = '%X:%X:%X:%X:%X:%X:%X:%X' % @address.unpack('nnnnnnnn')
194
unless address.sub!(/(^|:)0(:0)+(:|$)/, '::')
195
address.sub!(/(^|:)0(:|$)/, '::')
201
@address.unpack('H32')[0].split(//).reverse.join('.')
204
def protocol ; Socket::AF_INET6 ; end
205
def namespace ; 'ip6.arpa.' ; end
209
## (allow creation of IPv4 mapped address by default)
211
class Compatibility < IPv6
212
def self.create(arg, opt=IPv6LooseRegex)
213
IPv6::create(arg, opt)
220
Loopback = IPv6::create('::1')