#! /usr/bin/env perl
use Net::IP;
use IO::Socket::INET;
use IO::Socket::INET6;
# This script will remove:
#
# - A line with invalid IPv4 or IPv6 addresses.
# - A line with an IPv4 address or IPv6 address that has been seen before.
# - A line with an IPv4 or IPv6 address that we cannot connect to.
# - A line with a domain name that has been seen before.
#
# Input format: <domain name>,<ipv4 address>,<ipv6 address>
# These are used to avoid duplicate domains or addresses.
my %domain_names;
my %ipv4s;
my %ipv6s;
# Used for keeping statistics
my $reachable_ipv4s;
my $unreachable_ipv4s;
my $reachable_ipv6s;
my $unreachable_ipv6s;
my %ipv4_types;
my %ipv6_types;
my $port = shift(@ARGV);
while (<>)
{
chomp;
if (/(.+),(.+),(.+)/)
{
my ($domain_name, $ipv4, $ipv6) = ($1, $2, $3);
# First check for duplicates
next if (exists $domain_names{$domain_name});
$domain_names{$domain_name} = 1;
next if (exists $ipv4s{$ipv4});
$ipv4s{$ipv4} = 1;
next if (exists $ipv6s{$ipv6});
$ipv6s{$ipv6} = 1;
# Skip non-globally-routable addresses
my $ip = new Net::IP($ipv4) || next;
$ipv4_types{$ip->iptype()}++;
my $ip6 = new Net::IP($ipv6) || next;
$ipv6_types{$ip6->iptype()}++;
next if ($ip->iptype() ne "PUBLIC");
next if ($ip6->iptype() ne "GLOBAL-UNICAST");
# Skip if we cannot connect to both addresses.
my $unreachable_address = 0;
my $ipv4_sock;
my $ipv6_sock;
# Try establishing a connection to the IPv4 address.
if ($ipv4_sock = new IO::Socket::INET(PeerAddr => $ipv4, PeerPort => $port, Proto => 'tcp', Timeout => 5))
{
$reachable_ipv4s++;
close($ipv4_sock); # Graceful Shutdown
}
else
{
$unreachable_ipv4s++;
$unreachable_address = 1;
}
# Try establishing a connection to the IPv6 address.
if ($ipv6_sock = new IO::Socket::INET6(PeerAddr => $ipv6, PeerPort => $port, Proto => 'tcp', Timeout => 5))
{
$reachable_ipv6s++;
close($ipv4_sock); # Graceful Shutdown
}
else
{
$unreachable_ipv6s++;
$unreachable_address = 1;
}
next if ($unreachable_address);
print "$_\n";
}
}
my $total = 0;
$total += $_ for (values %ipv4_types);
print "IPv4 Address Types:\n\n";
printf "%-30s%-15s%s\n", "Type", "Frequency", "Percentage";
for $key (sort { $ipv4_types{$b} <=> $ipv4_types{$a} } keys %ipv4_types)
{
printf("%-30s%-15d%.2f\n", $key, $ipv4_types{$key}, $ipv4_types{$key} / $total * 100);
}
printf "%-30s%-15d%.2f\n", "Total", $total, 100;
print "\n";
print "IPv6 Address Types:\n\n";
printf "%-30s%-15s%s\n", "Type", "Frequency", "Percentage";
for $key (sort { $ipv6_types{$b} <=> $ipv6_types{$a} } keys %ipv6_types)
{
printf("%-30s%-15d%.2f\n", $key, $ipv6_types{$key}, $ipv6_types{$key} / $total * 100);
}
printf "%-30s%-15d%.2f\n", "Total", $total, 100;
print "\n";
$total = $reachable_ipv4s + $unreachable_ipv4s;
printf "Reachable IPv4 Addresses: %d/%d (%.2f%%)\n", $reachable_ipv4s, $total, $reachable_ipv4s / $total * 100;
$total = $reachable_ipv6s + $unreachable_ipv6s;
printf "Reachable IPv6 Addresses: %d/%d (%.2f%%)\n", $reachable_ipv6s, $total, $reachable_ipv6s / $total * 100;