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