use strict;
use warnings;
use Test::More 0.88;
use List::AllUtils qw( each_array );
use Math::Int128 qw(uint128);
use Net::Works::Address;
use Net::Works::Network;
{
_test_remove_reserved_subnets(
[ '0.0.0.1', '1.2.3.4' ] => [ [ '1.0.0.0', '1.2.3.4' ] ] );
_test_remove_reserved_subnets( [ '9.10.11.12', '9.255.255.255' ] =>
[ [ '9.10.11.12', '9.255.255.255' ] ] );
_test_remove_reserved_subnets(
[ '9.0.0.0', '12.0.0.0' ] => [
[ '9.0.0.0', '9.255.255.255' ],
[ '11.0.0.0', '12.0.0.0' ],
]
);
_test_remove_reserved_subnets(
[ '9.0.0.0', '10.255.255.255' ] => [
[ '9.0.0.0', '9.255.255.255' ],
]
);
_test_remove_reserved_subnets(
[ '10.2.3.4', '12.255.255.255' ] => [
[ '11.0.0.0', '12.255.255.255' ],
]
);
_test_remove_reserved_subnets( [ '10.0.0.0', '10.10.10.10' ] => [] );
_test_remove_reserved_subnets(
[ '0.0.0.0', '255.255.255.255' ] => [
[ '1.0.0.0', '9.255.255.255' ],
[ '11.0.0.0', '100.63.255.255' ],
[ '100.128.0.0', '126.255.255.255' ],
[ '128.0.0.0', '169.253.255.255' ],
[ '169.255.0.0', '172.15.255.255' ],
[ '172.32.0.0', '191.255.255.255' ],
[ '192.0.0.8', '192.0.1.255' ],
[ '192.0.3.0', '192.88.98.255' ],
[ '192.88.100.0', '192.167.255.255' ],
[ '192.169.0.0', '198.17.255.255' ],
[ '198.20.0.0', '198.51.99.255' ],
[ '198.51.101.0', '203.0.112.255' ],
[ '203.0.114.0', '223.255.255.255' ],
]
);
_test_remove_reserved_subnets(
[ '::0', 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' ] => [
map {
[
map {
Net::Works::Address->new_from_string(
string => $_,
version => 6
)->as_string()
} @{$_}
]
} (
[ '::1.0.0.0', '::9.255.255.255' ],
[ '::11.0.0.0', '::100.63.255.255' ],
[ '::100.128.0.0', '::126.255.255.255' ],
[ '::128.0.0.0', '::169.253.255.255' ],
[ '::169.255.0.0', '::172.15.255.255' ],
[ '::172.32.0.0', '::191.255.255.255' ],
[ '::192.0.0.8', '::192.0.1.255' ],
[ '::192.0.3.0', '::192.88.98.255' ],
[ '::192.88.100.0', '::192.167.255.255' ],
[ '::192.169.0.0', '::198.17.255.255' ],
[ '::198.20.0.0', '::198.51.99.255' ],
[ '::198.51.101.0', '::203.0.112.255' ],
[ '::203.0.114.0', '::223.255.255.255' ],
[
'::1:0:0',
'ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
],
[
'100:0000:0000:0001::',
'2000:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
],
[
'2001:0200::',
'2001:db7:ffff:ffff:ffff:ffff:ffff:ffff',
],
[
'2001:db9::',
'fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
],
[
'fe00::',
'fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
],
[
'fec0::',
'feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
],
),
],
);
}
{
my $start = '1.0.0.1';
my $end = '1.0.0.255';
my @expect = (
map { Net::Works::Network->new_from_string( string => $_ ) }
qw(
1.0.0.1/32
1.0.0.2/31
1.0.0.4/30
1.0.0.8/29
1.0.0.16/28
1.0.0.32/27
1.0.0.64/26
1.0.0.128/25
)
);
_test_range_as_subnets( $start, $end, \@expect );
}
{
my $start = '10.0.0.0';
my $end = '12.0.0.0';
my @expect = (
map { Net::Works::Network->new_from_string( string => $_ ) }
qw(
11.0.0.0/8
12.0.0.0/32
)
);
_test_range_as_subnets( $start, $end, \@expect );
}
{
my $start = '10.0.0.0';
my $end = '12.0.0.0';
my @expect = (
map { Net::Works::Network->new_from_string( string => $_ ) }
qw(
::11.0.0.0/104
::12.0.0.0/128
)
);
_test_range_as_subnets( $start, $end, \@expect, 6 );
}
{
my $start = '0.0.0.1';
my $end = '19.255.255.255';
my @expect = (
map { Net::Works::Network->new_from_string( string => $_ ) }
qw(
1.0.0.0/8
2.0.0.0/7
4.0.0.0/6
8.0.0.0/7
11.0.0.0/8
12.0.0.0/6
16.0.0.0/6
)
);
_test_range_as_subnets( $start, $end, \@expect );
}
{
my $start = '::1';
my $end = 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff';
my @expect = (
map {
Net::Works::Network->new_from_string( string => $_, version => 6 )
} qw(
::1.0.0.0/104
::2.0.0.0/103
::4.0.0.0/102
::8.0.0.0/103
::11.0.0.0/104
::12.0.0.0/102
::16.0.0.0/100
::32.0.0.0/99
::64.0.0.0/99
::96.0.0.0/102
::100.0.0.0/106
::100.128.0.0/105
::101.0.0.0/104
::102.0.0.0/103
::104.0.0.0/101
::112.0.0.0/101
::120.0.0.0/102
::124.0.0.0/103
::126.0.0.0/104
::128.0.0.0/99
::160.0.0.0/101
::168.0.0.0/104
::169.0.0.0/105
::169.128.0.0/106
::169.192.0.0/107
::169.224.0.0/108
::169.240.0.0/109
::169.248.0.0/110
::169.252.0.0/111
::169.255.0.0/112
::170.0.0.0/103
::172.0.0.0/108
::172.32.0.0/107
::172.64.0.0/106
::172.128.0.0/105
::173.0.0.0/104
::174.0.0.0/103
::176.0.0.0/100
::192.0.0.8/125
::192.0.0.16/124
::192.0.0.32/123
::192.0.0.64/122
::192.0.0.128/121
::192.0.1.0/120
::192.0.3.0/120
::192.0.4.0/118
::192.0.8.0/117
::192.0.16.0/116
::192.0.32.0/115
::192.0.64.0/114
::192.0.128.0/113
::192.1.0.0/112
::192.2.0.0/111
::192.4.0.0/110
::192.8.0.0/109
::192.16.0.0/108
::192.32.0.0/107
::192.64.0.0/108
::192.80.0.0/109
::192.88.0.0/114
::192.88.64.0/115
::192.88.96.0/119
::192.88.98.0/120
::192.88.100.0/118
::192.88.104.0/117
::192.88.112.0/116
::192.88.128.0/113
::192.89.0.0/112
::192.90.0.0/111
::192.92.0.0/110
::192.96.0.0/107
::192.128.0.0/107
::192.160.0.0/109
::192.169.0.0/112
::192.170.0.0/111
::192.172.0.0/110
::192.176.0.0/108
::192.192.0.0/106
::193.0.0.0/104
::194.0.0.0/103
::196.0.0.0/103
::198.0.0.0/108
::198.16.0.0/111
::198.20.0.0/110
::198.24.0.0/109
::198.32.0.0/108
::198.48.0.0/111
::198.50.0.0/112
::198.51.0.0/114
::198.51.64.0/115
::198.51.96.0/118
::198.51.101.0/120
::198.51.102.0/119
::198.51.104.0/117
::198.51.112.0/116
::198.51.128.0/113
::198.52.0.0/110
::198.56.0.0/109
::198.64.0.0/106
::198.128.0.0/105
::199.0.0.0/104
::200.0.0.0/103
::202.0.0.0/104
::203.0.0.0/114
::203.0.64.0/115
::203.0.96.0/116
::203.0.112.0/120
::203.0.114.0/119
::203.0.116.0/118
::203.0.120.0/117
::203.0.128.0/113
::203.1.0.0/112
::203.2.0.0/111
::203.4.0.0/110
::203.8.0.0/109
::203.16.0.0/108
::203.32.0.0/107
::203.64.0.0/106
::203.128.0.0/105
::204.0.0.0/102
::208.0.0.0/100
::1:0:0/96
::2:0:0/95
::4:0:0/94
::8:0:0/93
::10:0:0/92
::20:0:0/91
::40:0:0/90
::80:0:0/89
::100:0:0/88
::200:0:0/87
::400:0:0/86
::800:0:0/85
::1000:0:0/84
::2000:0:0/83
::4000:0:0/82
::8000:0:0/81
::1:0:0:0/80
::2:0:0:0/79
::4:0:0:0/78
::8:0:0:0/77
::10:0:0:0/76
::20:0:0:0/75
::40:0:0:0/74
::80:0:0:0/73
::100:0:0:0/72
::200:0:0:0/71
::400:0:0:0/70
::800:0:0:0/69
::1000:0:0:0/68
::2000:0:0:0/67
::4000:0:0:0/66
::8000:0:0:0/65
0:0:0:1::/64
0:0:0:2::/63
0:0:0:4::/62
0:0:0:8::/61
0:0:0:10::/60
0:0:0:20::/59
0:0:0:40::/58
0:0:0:80::/57
0:0:0:100::/56
0:0:0:200::/55
0:0:0:400::/54
0:0:0:800::/53
0:0:0:1000::/52
0:0:0:2000::/51
0:0:0:4000::/50
0:0:0:8000::/49
0:0:1::/48
0:0:2::/47
0:0:4::/46
0:0:8::/45
0:0:10::/44
0:0:20::/43
0:0:40::/42
0:0:80::/41
0:0:100::/40
0:0:200::/39
0:0:400::/38
0:0:800::/37
0:0:1000::/36
0:0:2000::/35
0:0:4000::/34
0:0:8000::/33
0:1::/32
0:2::/31
0:4::/30
0:8::/29
0:10::/28
0:20::/27
0:40::/26
0:80::/25
0:100::/24
0:200::/23
0:400::/22
0:800::/21
0:1000::/20
0:2000::/19
0:4000::/18
0:8000::/17
1::/16
2::/15
4::/14
8::/13
10::/12
20::/11
40::/10
80::/9
100:0:0:1::/64
100:0:0:2::/63
100:0:0:4::/62
100:0:0:8::/61
100:0:0:10::/60
100:0:0:20::/59
100:0:0:40::/58
100:0:0:80::/57
100:0:0:100::/56
100:0:0:200::/55
100:0:0:400::/54
100:0:0:800::/53
100:0:0:1000::/52
100:0:0:2000::/51
100:0:0:4000::/50
100:0:0:8000::/49
100:0:1::/48
100:0:2::/47
100:0:4::/46
100:0:8::/45
100:0:10::/44
100:0:20::/43
100:0:40::/42
100:0:80::/41
100:0:100::/40
100:0:200::/39
100:0:400::/38
100:0:800::/37
100:0:1000::/36
100:0:2000::/35
100:0:4000::/34
100:0:8000::/33
100:1::/32
100:2::/31
100:4::/30
100:8::/29
100:10::/28
100:20::/27
100:40::/26
100:80::/25
100:100::/24
100:200::/23
100:400::/22
100:800::/21
100:1000::/20
100:2000::/19
100:4000::/18
100:8000::/17
101::/16
102::/15
104::/14
108::/13
110::/12
120::/11
140::/10
180::/9
200::/7
400::/6
800::/5
1000::/4
2000::/16
2001:200::/23
2001:400::/22
2001:800::/22
2001:c00::/24
2001:d00::/25
2001:d80::/27
2001:da0::/28
2001:db0::/29
2001:db9::/32
2001:dba::/31
2001:dbc::/30
2001:dc0::/26
2001:e00::/23
2001:1000::/20
2001:2000::/19
2001:4000::/18
2001:8000::/17
2002::/15
2004::/14
2008::/13
2010::/12
2020::/11
2040::/10
2080::/9
2100::/8
2200::/7
2400::/6
2800::/5
3000::/4
4000::/2
8000::/2
c000::/3
e000::/4
f000::/5
f800::/6
fe00::/9
fec0::/10
)
);
_test_range_as_subnets( $start, $end, \@expect );
}
done_testing();
sub _test_remove_reserved_subnets {
my $range = shift;
my $expect = shift;
my $version = $range->[0] =~ /:/ ? 6 : 4;
# All these conversions are gross but normally this is handled by the
# range_as_subnets method.
my $first_ip = Net::Works::Address->new_from_string(
string => $range->[0],
version => $version,
)->as_integer();
my $last_ip = Net::Works::Address->new_from_string(
string => $range->[1],
version => $version
)->as_integer();
## no critic (Subroutines::ProtectPrivateSubs)
my @got = map {
[
map {
Net::Works::Address->new_from_integer(
integer => $_,
version => $version
)
} @{$_}
]
} Net::Works::Network->_remove_reserved_subnets_from_range(
$first_ip,
$last_ip,
$version,
);
is_deeply(
\@got,
$expect,
"_remove_reserved_subnets_from_range returned expected result for $range->[0] - $range->[1]"
);
}
sub _test_range_as_subnets {
my $start = shift;
my $end = shift;
my $expect_subnets = shift;
my $version = shift;
my @subnets
= Net::Works::Network->range_as_subnets( $start, $end, $version );
is(
scalar @subnets,
scalar @{$expect_subnets},
'got the same number of subnets as we expect'
);
my $iter = each_array( @subnets, @{$expect_subnets} );
while ( my ( $got, $expect ) = $iter->() ) {
last unless $got && $expect;
my $first_ip = eval { $expect->first()->as_ipv4_string() }
// $expect->first()->as_string();
is(
$got->first()->as_string(),
$expect->first()->as_string(),
"subnet first matches expected first - split $start - $end ($first_ip)"
);
my $last_ip = eval { $expect->last()->as_ipv4_string() }
// $expect->last()->as_string();
is(
$got->last()->as_string(),
$expect->last()->as_string(),
"subnet last matches expected last - split $start - $end ($last_ip)"
);
my $prefix_length = $expect->prefix_length();
is(
$got->prefix_length(),
$prefix_length,
"prefix length matches expected value - split $start - $end ($prefix_length)"
);
}
}