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; |