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