#!/usr/bin/perl # # Converter for DBIP (Country Lite) CSV database to binary, for xt_geoip # Copyright Jan Engelhardt, 2008-2011 # Copyright Philip Prindeville, 2018 # Copyright Arjen de Korte, 2020 # use Getopt::Long; use Net::CIDR::Lite; use Socket qw(AF_INET AF_INET6 inet_pton); use warnings; use Text::CSV_XS; # or trade for Text::CSV use strict; my $csv = Text::CSV_XS->new({ allow_whitespace => 1, binary => 1, eol => $/, }); # or Text::CSV my $source_dir = "."; my $target_dir = "."; &Getopt::Long::Configure(qw(bundling)); &GetOptions( "D=s" => \$target_dir, "S=s" => \$source_dir, ); if (!-d $source_dir) { print STDERR "Source directory \"$source_dir\" does not exist.\n"; exit 1; } if (!-d $target_dir) { print STDERR "Target directory \"$target_dir\" does not exist.\n"; exit 1; } &dump(&collect()); sub collect { my ($file, $fh, $row); my (%country); $file = "$source_dir/dbip-country-lite.csv"; open($fh, '<', $file) || die "Can't open DBIP database\n"; while ($row = $csv->getline($fh)) { my ($cc, $range); $cc = $row->[2]; $range = $row->[0] . "-" . $row->[1]; if (!exists($country{$cc})) { $country{$cc} = { pool_v4 => Net::CIDR::Lite->new(), pool_v6 => Net::CIDR::Lite->new() }; } if (index($range, '.') > 0) { $country{$cc}->{pool_v4}->add_range($range); } if (index($range, ':') > 0) { $country{$cc}->{pool_v6}->add_range($range); } if ($. % 4096 == 0) { print STDERR "\r\e[2K$. entries"; } } print STDERR "\r\e[2K$. entries total\n"; close($fh); return \%country; } sub dump { my $country = shift @_; foreach my $iso_code (sort keys %{$country}) { &dump_one($iso_code, $country->{$iso_code}); } } sub dump_one { my($iso_code, $country) = @_; my @ranges; @ranges = $country->{pool_v4}->list_range(); writeCountry($iso_code, AF_INET, @ranges); @ranges = $country->{pool_v6}->list_range(); writeCountry($iso_code, AF_INET6, @ranges); } sub writeCountry { my ($iso_code, $family, @ranges) = @_; my $fh; printf "%5u IPv%s ranges for %s\n", scalar(@ranges), ($family == AF_INET ? '4' : '6'), $iso_code; my $file = "$target_dir/".uc($iso_code).".iv".($family == AF_INET ? '4' : '6'); if (!open($fh, '>', $file)) { print STDERR "Error opening $file: $!\n"; exit 1; } binmode($fh); foreach my $range (@ranges) { my ($start, $end) = split('-', $range); $start = inet_pton($family, $start); $end = inet_pton($family, $end); print $fh $start, $end; } close $fh; }