line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::IPv6Addr; |
2
|
|
|
|
|
|
|
|
3
|
15
|
|
|
15
|
|
651214
|
use strict; |
|
15
|
|
|
|
|
208
|
|
|
15
|
|
|
|
|
459
|
|
4
|
15
|
|
|
15
|
|
89
|
use warnings; |
|
15
|
|
|
|
|
28
|
|
|
15
|
|
|
|
|
1778
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
7
|
|
|
|
|
|
|
our @EXPORT = qw(); |
8
|
|
|
|
|
|
|
our @EXPORT_OK = qw( |
9
|
|
|
|
|
|
|
from_bigint |
10
|
|
|
|
|
|
|
in_network |
11
|
|
|
|
|
|
|
in_network_of_size |
12
|
|
|
|
|
|
|
ipv6_chkip |
13
|
|
|
|
|
|
|
ipv6_parse |
14
|
|
|
|
|
|
|
is_ipv6 |
15
|
|
|
|
|
|
|
to_array |
16
|
|
|
|
|
|
|
to_bigint |
17
|
|
|
|
|
|
|
to_intarray |
18
|
|
|
|
|
|
|
to_string_base85 |
19
|
|
|
|
|
|
|
to_string_compressed |
20
|
|
|
|
|
|
|
to_string_ip6_int |
21
|
|
|
|
|
|
|
to_string_ipv4 |
22
|
|
|
|
|
|
|
to_string_ipv4_compressed |
23
|
|
|
|
|
|
|
to_string_preferred |
24
|
|
|
|
|
|
|
); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
our %EXPORT_TAGS = (all => \@EXPORT_OK); |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
our $VERSION = '1.02'; |
29
|
|
|
|
|
|
|
|
30
|
15
|
|
|
15
|
|
105
|
use Carp; |
|
15
|
|
|
|
|
35
|
|
|
15
|
|
|
|
|
1051
|
|
31
|
15
|
|
|
15
|
|
17697
|
use Math::BigInt '1.999813'; |
|
15
|
|
|
|
|
450038
|
|
|
15
|
|
|
|
|
87
|
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
my $base85ok; |
34
|
|
|
|
|
|
|
eval { |
35
|
|
|
|
|
|
|
require Math::Base85; |
36
|
|
|
|
|
|
|
}; |
37
|
|
|
|
|
|
|
if (! $@) { |
38
|
|
|
|
|
|
|
$base85ok = 1; |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
sub base85ok |
42
|
|
|
|
|
|
|
{ |
43
|
1
|
|
|
1
|
0
|
85
|
return $base85ok |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# ____ _ _ |
47
|
|
|
|
|
|
|
# | _ \ __ _| |_| |_ ___ _ __ _ __ ___ |
48
|
|
|
|
|
|
|
# | |_) / _` | __| __/ _ \ '__| '_ \/ __| |
49
|
|
|
|
|
|
|
# | __/ (_| | |_| || __/ | | | | \__ \ |
50
|
|
|
|
|
|
|
# |_| \__,_|\__|\__\___|_| |_| |_|___/ |
51
|
|
|
|
|
|
|
# |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# Match one to four digits of hexadecimal |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
my $h = qr/[a-f0-9]{1,4}/i; |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
my $ipn = qr! |
58
|
|
|
|
|
|
|
( |
59
|
|
|
|
|
|
|
25[0-5] |
60
|
|
|
|
|
|
|
| |
61
|
|
|
|
|
|
|
2[0-4][0-9] |
62
|
|
|
|
|
|
|
| |
63
|
|
|
|
|
|
|
1[0-9]{2} |
64
|
|
|
|
|
|
|
| |
65
|
|
|
|
|
|
|
[1-9][0-9] |
66
|
|
|
|
|
|
|
| |
67
|
|
|
|
|
|
|
[0-9] |
68
|
|
|
|
|
|
|
) |
69
|
|
|
|
|
|
|
!x; |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
my $ipv4 = qr!($ipn\.){3}$ipn!; |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
sub ipv4_validate |
74
|
|
|
|
|
|
|
{ |
75
|
30
|
|
|
30
|
0
|
74
|
my ($ip) = @_; |
76
|
30
|
50
|
|
|
|
309
|
if ($ip !~ /$ipv4/) { |
77
|
0
|
|
|
|
|
0
|
croak "Holy macaroni batman"; |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# base-85 |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
my $base85_re; |
84
|
|
|
|
|
|
|
if ($base85ok) { |
85
|
|
|
|
|
|
|
my $digits = $Math::Base85::base85_digits; |
86
|
|
|
|
|
|
|
$digits =~ s/-//; |
87
|
|
|
|
|
|
|
$base85_re = qr![$digits-]{20}!; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
my %ipv6_patterns = ( |
91
|
|
|
|
|
|
|
'preferred' => [ |
92
|
|
|
|
|
|
|
qr/^(?:$h:){7}$h$/i, |
93
|
|
|
|
|
|
|
\&ipv6_parse_preferred, |
94
|
|
|
|
|
|
|
], |
95
|
|
|
|
|
|
|
'compressed' => [ |
96
|
|
|
|
|
|
|
qr/^[a-f0-9]{0,4}::$/i, |
97
|
|
|
|
|
|
|
qr/^:(?::$h){1,7}$/i, |
98
|
|
|
|
|
|
|
qr/^(?:$h:){1,}:$/i, |
99
|
|
|
|
|
|
|
qr/^(?:$h:)(?::$h){1,6}$/i, |
100
|
|
|
|
|
|
|
qr/^(?:$h:){2}(?::$h){1,5}$/i, |
101
|
|
|
|
|
|
|
qr/^(?:$h:){3}(?::$h){1,4}$/i, |
102
|
|
|
|
|
|
|
qr/^(?:$h:){4}(?::$h){1,3}$/i, |
103
|
|
|
|
|
|
|
qr/^(?:$h:){5}(?::$h){1,2}$/i, |
104
|
|
|
|
|
|
|
qr/^(?:$h:){6}(?::$h)$/i, |
105
|
|
|
|
|
|
|
\&ipv6_parse_compressed, |
106
|
|
|
|
|
|
|
], |
107
|
|
|
|
|
|
|
'ipv4' => [ |
108
|
|
|
|
|
|
|
qr/^(?:0:){5}ffff:$ipv4$/i, |
109
|
|
|
|
|
|
|
qr/^(?:0:){6}$ipv4$/, |
110
|
|
|
|
|
|
|
\&ipv6_parse_ipv4, |
111
|
|
|
|
|
|
|
], |
112
|
|
|
|
|
|
|
'ipv4 compressed' => [ |
113
|
|
|
|
|
|
|
qr/^::(?:ffff:)?$ipv4$/i, |
114
|
|
|
|
|
|
|
\&ipv6_parse_ipv4_compressed, |
115
|
|
|
|
|
|
|
], |
116
|
|
|
|
|
|
|
'ipv6v4' => [ |
117
|
|
|
|
|
|
|
qr/^[a-f0-9]{0,4}::$ipv4$/i, |
118
|
|
|
|
|
|
|
# ::1:2:3:4:1.2.3.4 |
119
|
|
|
|
|
|
|
qr/^::(?:$h:){1,5}$ipv4$/i, |
120
|
|
|
|
|
|
|
qr/^(?:$h:):(?:$h:){1,4}$ipv4$/i, |
121
|
|
|
|
|
|
|
qr/^(?:$h:){2}:(?:$h:){1,3}$ipv4$/i, |
122
|
|
|
|
|
|
|
qr/^(?:$h:){3}:(?:$h:){1,2}$ipv4$/i, |
123
|
|
|
|
|
|
|
qr/^(?:$h:){4}:(?:$h:){1}$ipv4$/i, |
124
|
|
|
|
|
|
|
# 1:2:3:4:5::1.2.3.4 |
125
|
|
|
|
|
|
|
qr/^(?:$h:){1,5}:$ipv4$/i, |
126
|
|
|
|
|
|
|
# 1:2:3:4:5:6:1.2.3.4 |
127
|
|
|
|
|
|
|
qr/^(?:$h:){6}$ipv4$/i, |
128
|
|
|
|
|
|
|
\&parse_mixed_ipv6v4_compressed, |
129
|
|
|
|
|
|
|
], |
130
|
|
|
|
|
|
|
); |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
if ($base85ok) { |
133
|
|
|
|
|
|
|
$ipv6_patterns{'base85'} = [ |
134
|
|
|
|
|
|
|
$base85_re, |
135
|
|
|
|
|
|
|
\&ipv6_parse_base85, |
136
|
|
|
|
|
|
|
], |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
# ____ _ _ |
140
|
|
|
|
|
|
|
# | _ \ _ __(_)_ ____ _| |_ ___ |
141
|
|
|
|
|
|
|
# | |_) | '__| \ \ / / _` | __/ _ \ |
142
|
|
|
|
|
|
|
# | __/| | | |\ V / (_| | || __/ |
143
|
|
|
|
|
|
|
# |_| |_| |_| \_/ \__,_|\__\___| |
144
|
|
|
|
|
|
|
# |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# Errors which include the package name and the subroutine name. This |
147
|
|
|
|
|
|
|
# is for consistency with earlier versions of the module. |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub mycroak |
150
|
|
|
|
|
|
|
{ |
151
|
74
|
|
|
74
|
0
|
137
|
my ($message) = @_; |
152
|
74
|
|
|
|
|
426
|
my @caller = caller (1); |
153
|
74
|
|
|
|
|
8086
|
croak $caller[3] . ' -- ' . $message; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
# Given one argument with a slash or two arguments, return them as two |
157
|
|
|
|
|
|
|
# arguments, and check there are one or two arguments. |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
sub getargs |
160
|
|
|
|
|
|
|
{ |
161
|
21
|
|
|
21
|
0
|
36
|
my ($ip, $pfx); |
162
|
21
|
100
|
|
|
|
109
|
if (@_ == 2) { |
|
|
50
|
|
|
|
|
|
163
|
5
|
|
|
|
|
17
|
($ip, $pfx) = @_; |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
elsif (@_ == 1) { |
166
|
16
|
|
|
|
|
62
|
($ip, $pfx) = split(m!/!, $_[0], 2) |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
else { |
169
|
0
|
|
|
|
|
0
|
mycroak "wrong number of arguments (need 1 or 2)"; |
170
|
|
|
|
|
|
|
} |
171
|
21
|
|
|
|
|
60
|
return ($ip, $pfx); |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# Match $ip against the regexes of type $type, or die. |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
sub match_or_die |
177
|
|
|
|
|
|
|
{ |
178
|
497
|
|
|
497
|
0
|
960
|
my ($ip, $type) = @_; |
179
|
|
|
|
|
|
|
# Instead of trying to construct a gigantic regex which only |
180
|
|
|
|
|
|
|
# allows two colons in a row, just check here. |
181
|
497
|
100
|
|
|
|
1239
|
if ($ip =~ /:::/) { |
182
|
2
|
|
|
|
|
14
|
mycroak "invalid address $ip for type $type"; |
183
|
|
|
|
|
|
|
} |
184
|
495
|
|
|
|
|
830
|
my $patterns = $ipv6_patterns{$type}; |
185
|
495
|
|
|
|
|
858
|
for my $p (@$patterns) { |
186
|
|
|
|
|
|
|
# The last thing in the pattern is a code reference, so this |
187
|
|
|
|
|
|
|
# match indicates no matches were found. |
188
|
896
|
100
|
|
|
|
1800
|
if (ref($p) eq 'CODE') { |
189
|
33
|
|
|
|
|
134
|
mycroak "invalid address $ip for type $type"; |
190
|
|
|
|
|
|
|
} |
191
|
863
|
100
|
|
|
|
3996
|
if ($ip =~ $p) { |
192
|
462
|
|
|
|
|
871
|
return; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
# Make the bit mask for "in_network_of_size". |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
sub bitmask |
200
|
|
|
|
|
|
|
{ |
201
|
3
|
|
|
3
|
0
|
4
|
my ($j) = @_; |
202
|
3
|
|
|
|
|
19
|
my $bitmask = '1' x $j . '0' x (16 - $j); |
203
|
3
|
|
|
|
|
15
|
my $k = unpack("n",pack("B16", $bitmask)); |
204
|
3
|
|
|
|
|
6
|
return $k; |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
# ____ |
208
|
|
|
|
|
|
|
# | _ \ __ _ _ __ ___ ___ _ __ ___ |
209
|
|
|
|
|
|
|
# | |_) / _` | '__/ __|/ _ \ '__/ __| |
210
|
|
|
|
|
|
|
# | __/ (_| | | \__ \ __/ | \__ \ |
211
|
|
|
|
|
|
|
# |_| \__,_|_| |___/\___|_| |___/ |
212
|
|
|
|
|
|
|
# |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
# Private parser |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub ipv6_parse_preferred |
217
|
|
|
|
|
|
|
{ |
218
|
358
|
|
|
358
|
0
|
1570
|
my $ip = shift; |
219
|
358
|
|
|
|
|
758
|
match_or_die ($ip, 'preferred'); |
220
|
350
|
|
|
|
|
1214
|
my @pieces = split (/:/, $ip); |
221
|
350
|
|
|
|
|
622
|
splice (@pieces, 8); |
222
|
350
|
|
|
|
|
614
|
return map { hex } @pieces; |
|
2800
|
|
|
|
|
4565
|
|
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
# Private parser |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
sub ipv6_parse_compressed |
228
|
|
|
|
|
|
|
{ |
229
|
87
|
|
|
87
|
0
|
864
|
my $ip = shift; |
230
|
87
|
|
|
|
|
137
|
my $type = 'compressed'; |
231
|
87
|
|
|
|
|
223
|
match_or_die ($ip, $type); |
232
|
82
|
|
|
|
|
226
|
my $colons = ($ip =~ tr/:/:/); |
233
|
82
|
|
|
|
|
240
|
my $expanded = ':' x (9 - $colons); |
234
|
82
|
|
|
|
|
335
|
$ip =~ s/::/$expanded/; |
235
|
82
|
|
|
|
|
450
|
my @pieces = split (/:/, $ip, 8); |
236
|
82
|
|
|
|
|
207
|
return map { hex } @pieces; |
|
656
|
|
|
|
|
1341
|
|
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
sub parse_mixed_ipv6v4_compressed |
240
|
|
|
|
|
|
|
{ |
241
|
17
|
|
|
17
|
0
|
36
|
my $ip = shift; |
242
|
17
|
|
|
|
|
44
|
match_or_die ($ip, 'ipv6v4'); |
243
|
17
|
|
|
|
|
46
|
my @result; |
244
|
|
|
|
|
|
|
my $v4addr; |
245
|
17
|
|
|
|
|
0
|
my $colons; |
246
|
17
|
|
|
|
|
44
|
$colons = ($ip =~ tr/:/:/); |
247
|
17
|
|
|
|
|
47
|
my $expanded = ':' x (8 - $colons); |
248
|
17
|
|
|
|
|
69
|
$ip =~ s/::/$expanded/; |
249
|
17
|
|
|
|
|
90
|
my @v6pcs = split(/:/, $ip, 7); |
250
|
17
|
|
|
|
|
32
|
$v4addr = $v6pcs[-1]; |
251
|
17
|
|
|
|
|
35
|
splice(@v6pcs, 6); |
252
|
17
|
|
|
|
|
39
|
push @result, map { hex } @v6pcs; |
|
102
|
|
|
|
|
211
|
|
253
|
17
|
|
|
|
|
54
|
ipv4_validate($v4addr); |
254
|
17
|
|
|
|
|
65
|
my @v4pcs = split(/\./, $v4addr); |
255
|
17
|
|
|
|
|
32
|
splice(@v4pcs, 4); |
256
|
17
|
|
|
|
|
110
|
push @result, unpack("n", pack("CC", @v4pcs[0,1])); |
257
|
17
|
|
|
|
|
53
|
push @result, unpack("n", pack("CC", @v4pcs[2,3])); |
258
|
17
|
|
|
|
|
66
|
return @result; |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
# Private parser |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
sub ipv6_parse_ipv4 |
264
|
|
|
|
|
|
|
{ |
265
|
14
|
|
|
14
|
0
|
1513
|
my $ip = shift; |
266
|
14
|
|
|
|
|
45
|
match_or_die ($ip, 'ipv4'); |
267
|
3
|
|
|
|
|
6
|
my @result; |
268
|
|
|
|
|
|
|
my $v4addr; |
269
|
3
|
|
|
|
|
35
|
my @v6pcs = split(/:/, $ip); |
270
|
3
|
|
|
|
|
9
|
$v4addr = $v6pcs[-1]; |
271
|
3
|
|
|
|
|
26
|
splice(@v6pcs, 6); |
272
|
3
|
|
|
|
|
10
|
push @result, map { hex } @v6pcs; |
|
18
|
|
|
|
|
38
|
|
273
|
3
|
|
|
|
|
19
|
ipv4_validate($v4addr); |
274
|
3
|
|
|
|
|
42
|
my @v4pcs = split(/\./, $v4addr); |
275
|
3
|
|
|
|
|
51
|
push @result, unpack("n", pack("CC", @v4pcs[0,1])); |
276
|
3
|
|
|
|
|
19
|
push @result, unpack("n", pack("CC", @v4pcs[2,3])); |
277
|
3
|
|
|
|
|
16
|
return @result; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
# Private parser |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
sub ipv6_parse_ipv4_compressed |
283
|
|
|
|
|
|
|
{ |
284
|
21
|
|
|
21
|
0
|
1848
|
my $ip = shift; |
285
|
21
|
|
|
|
|
59
|
match_or_die ($ip, 'ipv4 compressed'); |
286
|
10
|
|
|
|
|
51
|
my @result; |
287
|
|
|
|
|
|
|
my $v4addr; |
288
|
10
|
|
|
|
|
0
|
my $colons; |
289
|
10
|
|
|
|
|
31
|
$colons = ($ip =~ tr/:/:/); |
290
|
10
|
|
|
|
|
33
|
my $expanded = ':' x (8 - $colons); |
291
|
10
|
|
|
|
|
47
|
$ip =~ s/::/$expanded/; |
292
|
10
|
|
|
|
|
66
|
my @v6pcs = split(/:/, $ip, 7); |
293
|
10
|
|
|
|
|
23
|
$v4addr = $v6pcs[-1]; |
294
|
10
|
|
|
|
|
26
|
splice(@v6pcs, 6); |
295
|
10
|
|
|
|
|
27
|
push @result, map { hex } @v6pcs; |
|
60
|
|
|
|
|
126
|
|
296
|
10
|
|
|
|
|
48
|
ipv4_validate($v4addr); |
297
|
10
|
|
|
|
|
42
|
my @v4pcs = split(/\./, $v4addr); |
298
|
10
|
|
|
|
|
23
|
splice(@v4pcs, 4); |
299
|
10
|
|
|
|
|
104
|
push @result, unpack("n", pack("CC", @v4pcs[0,1])); |
300
|
10
|
|
|
|
|
42
|
push @result, unpack("n", pack("CC", @v4pcs[2,3])); |
301
|
10
|
|
|
|
|
43
|
return @result; |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
# Private parser |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
sub ipv6_parse_base85 |
307
|
|
|
|
|
|
|
{ |
308
|
0
|
0
|
|
0
|
0
|
0
|
if (! $base85ok) { |
309
|
0
|
|
|
|
|
0
|
carp "Math::Base85 is not installed"; |
310
|
0
|
|
|
|
|
0
|
return (); |
311
|
|
|
|
|
|
|
} |
312
|
0
|
|
|
|
|
0
|
my $ip = shift; |
313
|
0
|
|
|
|
|
0
|
match_or_die ($ip, 'base85'); |
314
|
0
|
|
|
|
|
0
|
my $r; |
315
|
0
|
|
|
|
|
0
|
my $bigint = Math::Base85::from_base85($ip); |
316
|
0
|
|
|
|
|
0
|
my @result; |
317
|
0
|
|
|
|
|
0
|
while ($bigint > 0) { |
318
|
0
|
|
|
|
|
0
|
$r = $bigint & 0xffff; |
319
|
0
|
|
|
|
|
0
|
unshift @result, sprintf("%d", $r); |
320
|
0
|
|
|
|
|
0
|
$bigint = $bigint >> 16; |
321
|
|
|
|
|
|
|
} |
322
|
0
|
|
|
|
|
0
|
foreach $r ($#result+1..7) { |
323
|
0
|
|
|
|
|
0
|
$result[$r] = 0; |
324
|
|
|
|
|
|
|
} |
325
|
0
|
|
|
|
|
0
|
return @result; |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
# ____ _ _ _ |
329
|
|
|
|
|
|
|
# | _ \ _ _| |__ | (_) ___ |
330
|
|
|
|
|
|
|
# | |_) | | | | '_ \| | |/ __| |
331
|
|
|
|
|
|
|
# | __/| |_| | |_) | | | (__ |
332
|
|
|
|
|
|
|
# |_| \__,_|_.__/|_|_|\___| |
333
|
|
|
|
|
|
|
# |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
# Public |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
sub new |
338
|
|
|
|
|
|
|
{ |
339
|
486
|
|
|
486
|
1
|
228279
|
my $proto = shift; |
340
|
486
|
|
33
|
|
|
1813
|
my $class = ref ($proto) || $proto; |
341
|
486
|
|
|
|
|
738
|
my $maybe_ip = shift; |
342
|
486
|
|
|
|
|
866
|
my $parser = ipv6_chkip ($maybe_ip); |
343
|
486
|
100
|
|
|
|
1168
|
if (ref $parser ne 'CODE') { |
344
|
29
|
|
|
|
|
78
|
mycroak "invalid IPv6 address $maybe_ip"; |
345
|
|
|
|
|
|
|
} |
346
|
457
|
|
|
|
|
1344
|
my @hexadecets = $parser->($maybe_ip); |
347
|
457
|
|
|
|
|
864
|
my $self = \@hexadecets; |
348
|
457
|
|
|
|
|
789
|
bless $self, $class; |
349
|
457
|
|
|
|
|
1189
|
return $self; |
350
|
|
|
|
|
|
|
} |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
# Public |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
sub ipv6_chkip |
355
|
|
|
|
|
|
|
{ |
356
|
733
|
|
|
733
|
1
|
66692
|
my $ip = shift; |
357
|
|
|
|
|
|
|
|
358
|
733
|
|
|
|
|
1056
|
my $parser = undef; |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
TYPE: |
361
|
733
|
|
|
|
|
2170
|
for my $k (keys %ipv6_patterns) { |
362
|
1934
|
|
|
|
|
2429
|
my @patlist = @{$ipv6_patterns{$k}}; |
|
1934
|
|
|
|
|
3911
|
|
363
|
|
|
|
|
|
|
PATTERN: |
364
|
1934
|
|
|
|
|
2859
|
for my $pattern (@patlist) { |
365
|
7589
|
100
|
|
|
|
14802
|
last PATTERN if (ref($pattern) eq 'CODE'); |
366
|
6233
|
100
|
|
|
|
20555
|
if ($ip =~ $pattern) { |
367
|
578
|
|
|
|
|
1051
|
$parser = $patlist[-1]; |
368
|
578
|
|
|
|
|
1221
|
last TYPE; |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
} |
372
|
733
|
|
|
|
|
1915
|
return $parser; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
# Public |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
sub ipv6_parse |
378
|
|
|
|
|
|
|
{ |
379
|
16
|
|
|
16
|
1
|
493
|
my ($ip, $pfx) = getargs (@_); |
380
|
|
|
|
|
|
|
|
381
|
16
|
100
|
|
|
|
41
|
if (! ipv6_chkip ($ip)) { |
382
|
3
|
|
|
|
|
14
|
mycroak "invalid IPv6 address $ip"; |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
|
385
|
13
|
100
|
|
|
|
29
|
if (! defined $pfx) { |
386
|
3
|
|
|
|
|
24
|
return $ip; |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
|
389
|
10
|
|
|
|
|
23
|
$pfx =~ s/\s+//g; |
390
|
|
|
|
|
|
|
|
391
|
10
|
100
|
|
|
|
30
|
if ($pfx =~ /^[0-9]+$/) { |
392
|
6
|
100
|
|
|
|
36
|
if ($pfx > 128) { |
393
|
2
|
|
|
|
|
8
|
mycroak "invalid prefix length $pfx"; |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
else { |
397
|
4
|
|
|
|
|
13
|
mycroak "non-numeric prefix length $pfx"; |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
|
400
|
4
|
100
|
|
|
|
10
|
if (wantarray ()) { |
401
|
2
|
|
|
|
|
10
|
return ($ip, $pfx); |
402
|
|
|
|
|
|
|
} |
403
|
2
|
|
|
|
|
9
|
return "$ip/$pfx"; |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
# Public |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
sub is_ipv6 |
409
|
|
|
|
|
|
|
{ |
410
|
7
|
|
|
7
|
1
|
6097
|
my $r; |
411
|
7
|
|
|
|
|
11
|
eval { |
412
|
7
|
|
|
|
|
18
|
$r = ipv6_parse (@_); |
413
|
|
|
|
|
|
|
}; |
414
|
7
|
100
|
|
|
|
25
|
if ($@) { |
415
|
4
|
|
|
|
|
20
|
return undef; |
416
|
|
|
|
|
|
|
} |
417
|
3
|
|
|
|
|
14
|
return $r; |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
# Public |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
sub to_string_preferred |
423
|
|
|
|
|
|
|
{ |
424
|
26
|
|
|
26
|
1
|
103
|
my $self = shift; |
425
|
26
|
50
|
|
|
|
68
|
if (ref $self ne __PACKAGE__) { |
426
|
0
|
|
|
|
|
0
|
$self = Net::IPv6Addr->new ($self); |
427
|
|
|
|
|
|
|
} |
428
|
26
|
|
|
|
|
86
|
return v6part (@$self); |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
# Public |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
sub to_string_compressed |
434
|
|
|
|
|
|
|
{ |
435
|
426
|
|
|
426
|
1
|
3624
|
my $self = shift; |
436
|
426
|
100
|
|
|
|
916
|
if (ref $self ne __PACKAGE__) { |
437
|
212
|
|
|
|
|
444
|
$self = Net::IPv6Addr->new ($self); |
438
|
|
|
|
|
|
|
} |
439
|
426
|
|
|
|
|
817
|
my $expanded = v6part (@$self); |
440
|
426
|
|
|
|
|
1019
|
$expanded =~ s/^0:/:/; |
441
|
426
|
|
|
|
|
1390
|
$expanded =~ s/:0/:/g; |
442
|
426
|
100
|
100
|
|
|
2862
|
if ($expanded =~ s/:::::::/_/ or |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
443
|
|
|
|
|
|
|
$expanded =~ s/::::::/_/ or |
444
|
|
|
|
|
|
|
$expanded =~ s/:::::/_/ or |
445
|
|
|
|
|
|
|
$expanded =~ s/::::/_/ or |
446
|
|
|
|
|
|
|
$expanded =~ s/:::/_/ or |
447
|
|
|
|
|
|
|
$expanded =~ s/::/_/ |
448
|
|
|
|
|
|
|
) { |
449
|
409
|
|
|
|
|
1088
|
$expanded =~ s/:(?=:)/:0/g; |
450
|
409
|
|
|
|
|
592
|
$expanded =~ s/^:(?=[0-9a-f])/0:/; |
451
|
409
|
|
|
|
|
638
|
$expanded =~ s/([0-9a-f]):$/$1:0/; |
452
|
409
|
|
|
|
|
820
|
$expanded =~ s/_/::/; |
453
|
|
|
|
|
|
|
} |
454
|
426
|
|
|
|
|
1238
|
return $expanded; |
455
|
|
|
|
|
|
|
} |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
# Private |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
sub bytes |
460
|
|
|
|
|
|
|
{ |
461
|
24
|
|
|
24
|
0
|
40
|
my ($in) = @_; |
462
|
24
|
|
|
|
|
39
|
my $low = $in & 0xff; |
463
|
24
|
|
|
|
|
36
|
my $high = $in >> 8; |
464
|
24
|
|
|
|
|
68
|
return ($high, $low); |
465
|
|
|
|
|
|
|
} |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
# Private |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
sub v4part |
470
|
|
|
|
|
|
|
{ |
471
|
12
|
|
|
12
|
0
|
30
|
my ($t, $b) = @_; |
472
|
12
|
|
|
|
|
29
|
return join('.', bytes ($t), bytes ($b)); |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
# Private |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
sub v6part |
478
|
|
|
|
|
|
|
{ |
479
|
464
|
|
|
464
|
0
|
817
|
return join(':', map { sprintf("%x", $_) } @_); |
|
3688
|
|
|
|
|
7953
|
|
480
|
|
|
|
|
|
|
} |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
# Public |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
sub to_string_ipv4 |
485
|
|
|
|
|
|
|
{ |
486
|
6
|
|
|
6
|
1
|
17
|
my $self = shift; |
487
|
6
|
50
|
|
|
|
26
|
if (ref $self ne __PACKAGE__) { |
488
|
0
|
|
|
|
|
0
|
$self = Net::IPv6Addr->new ($self); |
489
|
|
|
|
|
|
|
} |
490
|
6
|
|
|
|
|
24
|
my $v6part = v6part (@$self[0..5]); |
491
|
6
|
|
|
|
|
19
|
my $v4part = v4part (@$self[6, 7]); |
492
|
6
|
|
|
|
|
36
|
return "$v6part:$v4part"; |
493
|
|
|
|
|
|
|
} |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
# Public |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
sub to_string_ipv4_compressed |
498
|
|
|
|
|
|
|
{ |
499
|
6
|
|
|
6
|
1
|
17
|
my $self = shift; |
500
|
6
|
50
|
|
|
|
26
|
if (ref $self ne __PACKAGE__) { |
501
|
0
|
|
|
|
|
0
|
$self = Net::IPv6Addr->new ($self); |
502
|
|
|
|
|
|
|
} |
503
|
6
|
|
|
|
|
24
|
my $v6part = v6part (@$self[0..5]); |
504
|
6
|
|
|
|
|
17
|
$v6part .= ':'; |
505
|
6
|
|
|
|
|
45
|
$v6part =~ s/(^|:)(0:)+/::/; |
506
|
6
|
|
|
|
|
18
|
my $v4part = v4part (@$self[6, 7]); |
507
|
6
|
|
|
|
|
30
|
return "$v6part$v4part"; |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
# Public |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
sub to_string_base85 |
513
|
|
|
|
|
|
|
{ |
514
|
0
|
0
|
|
0
|
1
|
0
|
if (! $base85ok) { |
515
|
0
|
|
|
|
|
0
|
carp "Math::Base85 is not installed"; |
516
|
0
|
|
|
|
|
0
|
return undef; |
517
|
|
|
|
|
|
|
} |
518
|
0
|
|
|
|
|
0
|
my $self = shift; |
519
|
0
|
0
|
|
|
|
0
|
if (ref $self ne __PACKAGE__) { |
520
|
0
|
|
|
|
|
0
|
$self = Net::IPv6Addr->new ($self); |
521
|
|
|
|
|
|
|
} |
522
|
0
|
|
|
|
|
0
|
my $bigint = new Math::BigInt("0"); |
523
|
0
|
|
|
|
|
0
|
for my $i (@{$self}[0..6]) { |
|
0
|
|
|
|
|
0
|
|
524
|
0
|
|
|
|
|
0
|
$bigint = $bigint + $i; |
525
|
0
|
|
|
|
|
0
|
$bigint = $bigint << 16; |
526
|
|
|
|
|
|
|
} |
527
|
0
|
|
|
|
|
0
|
$bigint = $bigint + $self->[7]; |
528
|
0
|
|
|
|
|
0
|
return Math::Base85::to_base85($bigint); |
529
|
|
|
|
|
|
|
} |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
# Public |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
sub to_bigint |
534
|
|
|
|
|
|
|
{ |
535
|
104
|
|
|
104
|
1
|
380
|
my $self = shift; |
536
|
104
|
50
|
|
|
|
234
|
if (ref $self ne __PACKAGE__) { |
537
|
0
|
|
|
|
|
0
|
$self = Net::IPv6Addr->new ($self); |
538
|
|
|
|
|
|
|
} |
539
|
104
|
|
|
|
|
340
|
my $bigint = new Math::BigInt("0"); |
540
|
104
|
|
|
|
|
10972
|
for my $i (@{$self}[0..6]) { |
|
104
|
|
|
|
|
256
|
|
541
|
728
|
|
|
|
|
149409
|
$bigint = $bigint + $i; |
542
|
728
|
|
|
|
|
131159
|
$bigint = $bigint << 16; |
543
|
|
|
|
|
|
|
} |
544
|
104
|
|
|
|
|
27171
|
$bigint = $bigint + $self->[7]; |
545
|
104
|
|
|
|
|
16656
|
$bigint =~ s/\+//; |
546
|
104
|
|
|
|
|
3353
|
return $bigint; |
547
|
|
|
|
|
|
|
} |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
# Public |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
sub to_array |
552
|
|
|
|
|
|
|
{ |
553
|
104
|
|
|
104
|
1
|
354
|
my $self = shift; |
554
|
104
|
50
|
|
|
|
222
|
if (ref $self ne __PACKAGE__) { |
555
|
0
|
|
|
|
|
0
|
$self = Net::IPv6Addr->new ($self); |
556
|
|
|
|
|
|
|
} |
557
|
104
|
|
|
|
|
198
|
return map {sprintf "%04x", $_} @$self; |
|
832
|
|
|
|
|
1829
|
|
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
# Public |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
sub to_intarray |
563
|
|
|
|
|
|
|
{ |
564
|
114
|
|
|
114
|
1
|
423
|
my $self = shift; |
565
|
114
|
50
|
|
|
|
323
|
if (ref $self ne __PACKAGE__) { |
566
|
0
|
|
|
|
|
0
|
$self = Net::IPv6Addr->new ($self); |
567
|
|
|
|
|
|
|
} |
568
|
114
|
|
|
|
|
346
|
return @$self; |
569
|
|
|
|
|
|
|
} |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
# Public |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
sub to_string_ip6_int |
574
|
|
|
|
|
|
|
{ |
575
|
6
|
|
|
6
|
1
|
17
|
my $self = shift; |
576
|
6
|
50
|
|
|
|
29
|
if (ref $self ne __PACKAGE__) { |
577
|
0
|
|
|
|
|
0
|
$self = Net::IPv6Addr->new ($self); |
578
|
|
|
|
|
|
|
} |
579
|
6
|
|
|
|
|
34
|
my $hexdigits = sprintf("%04x" x 8, @$self); |
580
|
6
|
|
|
|
|
58
|
my @nibbles = ('INT', 'IP6', split(//, $hexdigits)); |
581
|
6
|
|
|
|
|
28
|
my $ptr = join('.', reverse @nibbles); |
582
|
6
|
|
|
|
|
42
|
return $ptr . "."; |
583
|
|
|
|
|
|
|
} |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
# Private - validate a given netsize |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
sub validate_netsize |
588
|
|
|
|
|
|
|
{ |
589
|
15
|
|
|
15
|
0
|
25
|
my ($netsize) = @_; |
590
|
15
|
100
|
66
|
|
|
98
|
if ($netsize !~ /^[0-9]+$/ || $netsize > 128) { |
591
|
1
|
|
|
|
|
5
|
mycroak "invalid network size $netsize"; |
592
|
|
|
|
|
|
|
} |
593
|
|
|
|
|
|
|
} |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
# Public |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
sub in_network_of_size |
598
|
|
|
|
|
|
|
{ |
599
|
10
|
|
|
10
|
1
|
629
|
my $self = shift; |
600
|
10
|
50
|
|
|
|
22
|
if (ref $self ne __PACKAGE__) { |
601
|
0
|
0
|
|
|
|
0
|
if ($self =~ m!(.+)/(.+)!) { |
602
|
0
|
|
|
|
|
0
|
unshift @_, $2; |
603
|
0
|
|
|
|
|
0
|
$self = $1; |
604
|
|
|
|
|
|
|
} |
605
|
0
|
|
|
|
|
0
|
$self = Net::IPv6Addr->new($self); |
606
|
|
|
|
|
|
|
} |
607
|
10
|
|
|
|
|
16
|
my $netsize = shift; |
608
|
10
|
50
|
|
|
|
19
|
if (! defined $netsize) { |
609
|
0
|
|
|
|
|
0
|
mycroak "network size not given"; |
610
|
|
|
|
|
|
|
} |
611
|
10
|
|
|
|
|
17
|
$netsize =~ s!/!!; |
612
|
10
|
|
|
|
|
19
|
validate_netsize ($netsize); |
613
|
10
|
|
|
|
|
30
|
my @parts = @$self; |
614
|
10
|
|
|
|
|
29
|
my $i = int ($netsize / 16); |
615
|
10
|
50
|
|
|
|
20
|
if ($i < 8) { |
616
|
10
|
|
|
|
|
16
|
my $j = $netsize % 16; |
617
|
10
|
100
|
|
|
|
46
|
if ($j) { |
618
|
|
|
|
|
|
|
# If $netsize is not a multiple of 16, truncate the lowest |
619
|
|
|
|
|
|
|
# 16-$j bits of the $ith element of @parts. |
620
|
3
|
|
|
|
|
7
|
$parts[$i] &= bitmask ($j); |
621
|
|
|
|
|
|
|
# Jump over this element. |
622
|
3
|
|
|
|
|
4
|
$i++; |
623
|
|
|
|
|
|
|
} |
624
|
|
|
|
|
|
|
# Set all the remaining lower parts to zero. |
625
|
10
|
|
|
|
|
25
|
for ($i..$#parts) { |
626
|
41
|
|
|
|
|
63
|
$parts[$_] = 0; |
627
|
|
|
|
|
|
|
} |
628
|
|
|
|
|
|
|
} |
629
|
10
|
|
|
|
|
29
|
return bless \@parts; |
630
|
|
|
|
|
|
|
} |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
# Public |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
sub in_network |
635
|
|
|
|
|
|
|
{ |
636
|
5
|
|
|
5
|
1
|
1414
|
my $self = shift; |
637
|
5
|
50
|
|
|
|
16
|
if (ref $self ne __PACKAGE__) { |
638
|
0
|
|
|
|
|
0
|
$self = Net::IPv6Addr->new ($self); |
639
|
|
|
|
|
|
|
} |
640
|
5
|
|
|
|
|
17
|
my ($net, $netsize) = getargs (@_); |
641
|
5
|
50
|
|
|
|
13
|
unless (defined $netsize) { |
642
|
0
|
|
|
|
|
0
|
mycroak "not enough parameters, need netsize"; |
643
|
|
|
|
|
|
|
} |
644
|
5
|
|
|
|
|
12
|
$netsize =~ s!/!!; |
645
|
5
|
|
|
|
|
13
|
validate_netsize ($netsize); |
646
|
4
|
50
|
|
|
|
11
|
if (! ref $net) { |
647
|
4
|
|
|
|
|
11
|
$net = Net::IPv6Addr->new($net); |
648
|
|
|
|
|
|
|
} |
649
|
4
|
|
|
|
|
11
|
my @s = $self->in_network_of_size($netsize)->to_intarray; |
650
|
4
|
|
|
|
|
21
|
my @n = $net->in_network_of_size($netsize)->to_intarray; |
651
|
4
|
|
|
|
|
12
|
my $i = int ($netsize / 16) + 1; |
652
|
4
|
50
|
|
|
|
11
|
if ($i > $#s) { |
653
|
0
|
|
|
|
|
0
|
$i = $#s; |
654
|
|
|
|
|
|
|
} |
655
|
4
|
|
|
|
|
9
|
for (0..$i) { |
656
|
17
|
100
|
|
|
|
30
|
if ($s[$_] != $n[$_]) { |
657
|
1
|
|
|
|
|
4
|
return undef; |
658
|
|
|
|
|
|
|
} |
659
|
|
|
|
|
|
|
} |
660
|
3
|
|
|
|
|
11
|
return 1; |
661
|
|
|
|
|
|
|
} |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
# Public |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
sub from_bigint |
666
|
|
|
|
|
|
|
{ |
667
|
104
|
|
|
104
|
1
|
433
|
my ($big) = @_; |
668
|
|
|
|
|
|
|
# Input is a scalar or a Math::BigInt object. |
669
|
104
|
50
|
|
|
|
235
|
if (! ref ($big)) { |
670
|
0
|
|
|
|
|
0
|
$big = Math::BigInt->new ($big); |
671
|
|
|
|
|
|
|
} |
672
|
104
|
50
|
|
|
|
226
|
if (ref ($big) ne 'Math::BigInt') { |
673
|
0
|
|
|
|
|
0
|
mycroak "Cannot process non-scalar, non-Math::BigInt input"; |
674
|
|
|
|
|
|
|
} |
675
|
|
|
|
|
|
|
# Convert the number to a hexadecimal string |
676
|
104
|
|
|
|
|
276
|
my $hex = $big->to_hex (); |
677
|
|
|
|
|
|
|
# Pad if necessary for the colon placement |
678
|
104
|
100
|
|
|
|
30374
|
if (length ($hex) < 32) { |
679
|
66
|
|
|
|
|
152
|
my $leading = '0' x (32 - length ($hex)); |
680
|
66
|
|
|
|
|
142
|
$hex = $leading . $hex; |
681
|
|
|
|
|
|
|
} |
682
|
|
|
|
|
|
|
# Reversing the string makes adding colons with a substitution |
683
|
|
|
|
|
|
|
# operator easier. |
684
|
104
|
|
|
|
|
277
|
my $ipr = reverse $hex; |
685
|
104
|
|
|
|
|
1161
|
$ipr =~ s/(....)/$1:/g; |
686
|
104
|
|
|
|
|
287
|
$ipr = reverse $ipr; |
687
|
|
|
|
|
|
|
# Remove the excess colon. |
688
|
104
|
|
|
|
|
357
|
$ipr =~ s/^://; |
689
|
|
|
|
|
|
|
# Should be OK now, let "new" handle any further issues. |
690
|
104
|
|
|
|
|
302
|
return Net::IPv6Addr->new ($ipr); |
691
|
|
|
|
|
|
|
} |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
1; |