~ubuntu-branches/ubuntu/trusty/zonecheck/trusty-proposed

« back to all changes in this revision

Viewing changes to lib/address/ipv6.rb

  • Committer: Bazaar Package Importer
  • Author(s): Stephane Bortzmeyer
  • Date: 2004-03-10 14:08:05 UTC
  • Revision ID: james.westby@ubuntu.com-20040310140805-ij55fso1e23bk8ye
Tags: upstream-2.0.3
ImportĀ upstreamĀ versionĀ 2.0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# $Id: ipv6.rb,v 1.12 2003/07/25 22:51:24 sdalu Exp $
 
2
 
 
3
 
4
# AUTHOR   : Stephane D'Alu <sdalu@nic.fr>
 
5
# CREATED  : 2002/07/19 07:28:13
 
6
#
 
7
# COPYRIGHT: AFNIC (c) 2003
 
8
# LICENSE  : RUBY
 
9
# CONTACT  : 
 
10
#
 
11
# $Revision: 1.12 $ 
 
12
# $Date: 2003/07/25 22:51:24 $
 
13
#
 
14
# INSPIRED BY:
 
15
#   - the ruby file: resolv.rb 
 
16
#
 
17
# CONTRIBUTORS: (see also CREDITS file)
 
18
#
 
19
#
 
20
 
 
21
require 'socket'
 
22
require 'address/common'
 
23
require 'address/ipv4'
 
24
 
 
25
 
 
26
class Address
 
27
    ##
 
28
    ## IPv6 address
 
29
    ##
 
30
    class IPv6 < Address
 
31
        private
 
32
        Regex_8Hex = /\A
 
33
            (?:[0-9A-Fa-f]{1,4}:){7}
 
34
            [0-9A-Fa-f]{1,4}
 
35
            \z/x
 
36
        
 
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})*)?)
 
40
            \z/x
 
41
        
 
42
        Regex_6Hex4Dec = /\A
 
43
            ((?:[0-9A-Fa-f]{1,4}:){6,6})
 
44
            (\d+)\.(\d+)\.(\d+)\.(\d+)
 
45
            \z/x
 
46
        
 
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+)
 
51
            \z/x
 
52
 
 
53
        Regex_4Dec = /\A
 
54
            (\d+)\.(\d+)\.(\d+)\.(\d+)
 
55
            \z/x
 
56
 
 
57
        public
 
58
        IPv6Regex = /
 
59
            (?:#{Regex_8Hex.source})              |
 
60
            (?:#{Regex_CompressedHex.source})     |
 
61
            (?:#{Regex_6Hex4Dec.source})          |
 
62
            (?:#{Regex_CompressedHex4Dec.source})
 
63
            /x
 
64
 
 
65
        IPv6StrictRegex = /
 
66
            (?:#{Regex_8Hex.source})              |
 
67
            (?:#{Regex_CompressedHex.source})
 
68
            /x
 
69
 
 
70
        IPv6LooseRegex = /
 
71
            (?:#{Regex_8Hex.source})              |
 
72
            (?:#{Regex_CompressedHex.source})     |
 
73
            (?:#{Regex_6Hex4Dec.source})          |
 
74
            (?:#{Regex_CompressedHex4Dec.source}) |
 
75
            (?:#{Regex_4Dec.source})
 
76
            /x
 
77
        
 
78
        Regex = IPv6Regex
 
79
 
 
80
 
 
81
 
 
82
        def self.hex_pack(str, data='')
 
83
            str.scan(/[0-9A-Fa-f]+/) { |hex| data << [hex.hex].pack('n') }
 
84
            data
 
85
        end
 
86
 
 
87
        def self.is_valid(str, opt=Regex)
 
88
            str =~ opt
 
89
        end
 
90
 
 
91
        def self.create(arg, opt=Regex)
 
92
            case arg
 
93
            when IPv6
 
94
                return arg
 
95
            when IPv4
 
96
                return self.create("::ffff:#{arg.to_s}")
 
97
            when String
 
98
                address = ''
 
99
 
 
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'
 
106
                       end
 
107
 
 
108
                # Test: a:b:c:d:e:f:g:h
 
109
                if    (test >= 1) && Regex_8Hex             =~ arg
 
110
                    hex_pack(arg, address)
 
111
 
 
112
                # Test: a:b:c::d:e:f
 
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
 
119
 
 
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')
 
127
                    end
 
128
 
 
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')
 
138
                    end
 
139
 
 
140
                # Test: a.b.c.d
 
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')
 
146
                    end
 
147
                end
 
148
 
 
149
                # Check if conversion succed
 
150
                if address.length != 16
 
151
                    raise InvalidAddress, 
 
152
                        "IPv6 address with invalid value: #{arg}"
 
153
                end
 
154
 
 
155
                # Return new address
 
156
                return IPv6::new(address.untaint.freeze)
 
157
            else
 
158
                raise InvalidAddress,
 
159
                    "can't interprete as IPv6 address: #{arg.inspect}"
 
160
            end
 
161
        end
 
162
        
 
163
        def initialize(address)
 
164
            unless (address.instance_of?(String) && 
 
165
                    address.length == 16 && address.frozen?)
 
166
                raise Argument,
 
167
                    'IPv6 raw address must be a 16 byte frozen string'
 
168
            end
 
169
            @address = address
 
170
            freeze
 
171
        end
 
172
        
 
173
        def private?
 
174
            return false
 
175
        end
 
176
 
 
177
        def prefix(size=nil)
 
178
            if size.nil?
 
179
                prefix(64)
 
180
            else
 
181
                if size > @address.size * 8
 
182
                    raise ArgumentError, 'prefix size too big'
 
183
                end
 
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)
 
189
            end
 
190
        end
 
191
 
 
192
        def to_s
 
193
            address = '%X:%X:%X:%X:%X:%X:%X:%X' % @address.unpack('nnnnnnnn')
 
194
            unless address.sub!(/(^|:)0(:0)+(:|$)/, '::')
 
195
                address.sub!(/(^|:)0(:|$)/, '::')
 
196
            end
 
197
            address
 
198
        end
 
199
        
 
200
        def to_dnsform
 
201
            @address.unpack('H32')[0].split(//).reverse.join('.')
 
202
        end
 
203
 
 
204
        def protocol  ; Socket::AF_INET6 ; end
 
205
        def namespace ; 'ip6.arpa.'      ; end
 
206
 
 
207
        ##
 
208
        ## IPv6 address
 
209
        ##  (allow creation of IPv4 mapped address by default)
 
210
        ##
 
211
        class Compatibility < IPv6
 
212
            def self.create(arg, opt=IPv6LooseRegex)
 
213
                IPv6::create(arg, opt)
 
214
            end
 
215
        end
 
216
 
 
217
        ##
 
218
        ## IPv6 Loopback
 
219
        ## 
 
220
        Loopback = IPv6::create('::1')
 
221
    end
 
222
end