Setup of Devuan name server sub system.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
4.1 KiB

#!/usr/bin/perl
10 months ago
# report bugs to <cade@noxrun.com>
use strict;
use Data::Dumper;
use POSIX;
use LWP;
use Net::DNS;
use Net::IPv6Addr;
use Fcntl qw( :flock );
10 months ago
#
# setup: as root, use one of:
10 months ago
# apt install libwww-perl libnet-dns-perl libnet-ipv6addr-perl
# or
10 months ago
# cpan LWP Net::DNS Net::IPv6Addr
#
open my $self, '<', $0;
flock( $self, LOCK_EX | LOCK_NB ) or die "Already running, exit.\n";
my $URL = 'https://pkgmaster.devuan.org/mirror_list.txt';
my $LOC = '/etc/nsd';
my $ZONE = 'rr.devuan.org.zone';
my $ua = LWP::UserAgent->new;
my $resp = $ua->get( $URL ) or die "Could't get the mirror list: [$URL]\n";
my $data = $resp->content();
my $mirror_file = "$LOC/mirror_list.txt";
my $mirror_file_work = $mirror_file . ".work";
die "Got an empty $URL...\n" if $data eq "";
die "No changes in mirrors, nothing to do...\n" if load_file( $mirror_file ) eq $data;
save_file( $mirror_file_work, $data ) or die "Cannot save work file $mirror_file_work\n";
my @data;
my %entry;
my $line_num;
for( split /\n/, $data )
{
$line_num++;
if( /\S/ )
{
$entry{ 'LINE' } ||= "LINE $line_num";
$entry{ $1 } = $2 if /^([^:]+):\s+(.+)/ or die "Invalid syntax on line $line_num [$_] debug file: $mirror_file_work\n";
}
else
{
push @data, { %entry } if $entry{ 'LINE' };
%entry = ();
next;
}
}
push @data, { %entry } if $entry{ 'LINE' };
my %check_fields = ( FQDN => 'LINE', Active => 'FQDN', DNSRR => 'FQDN', BaseURL => 'FQDN', 'CountryCode' => 'FQDN' );
my %check_values = ( Active => 'yes', 'CountryCode' => '[a-z][a-z](\s*\|\s*[a-z][a-z])*' );
my $zonedata;
DATA:
for my $ent ( @data )
{
print "processing: $ent->{FQDN}\n";
for( keys %check_fields )
{
next if $ent->{ $_ };
print qq(\tskipping: $ent->{ $check_fields{ $_ } }\[$_] is not set (at $ent->{ 'LINE' })\n);
next DATA;
}
for( keys %check_values )
{
next if $ent->{ $_ } =~ /^$check_values{ $_ }$/i;
print qq(\tskipping: $ent->{ $check_fields{ $_ } }\[$_] = "$ent->{ $_ }" expected "$check_values{ $_ }" (at $ent->{ 'LINE' })\n);
next DATA;
}
next if $ent->{ 'FQDN' } eq 'pkgmaster.devuan.org';
next unless $ent->{'DNSRR'} eq 'yes' or $ent->{'DNSRRCC'} eq 'yes';
print "\tadding $ent->{FQDN}\n";
$zonedata .= zonedata( $ent );
}
$zonedata ||= zonedata( { 'FQDN' => 'pkgmaster.devuan.org' } );
my $zone_file = "$LOC/$ZONE";
my $z = load_file( $zone_file ) or die "Invalid zone template: $zone_file\n";
$z =~ s/^\s*(\d+)\s*;\s*\@zone\@.*?$/new_zone($1)/em or die "Zone template $zone_file is missing \@zone\@ marker\n";
$z =~ s/^\s*;\s*\@rr\@.*//sm or die "Zone template $zone_file is missing \@rr\@ marker\n";
10 months ago
my $time_str = scalar gmtime;
10 months ago
save_file( $zone_file, "$z\n; \@rr\@\n; generated at $time_str +0000 (UTC)\n$zonedata\n" )
or die "Error writing $zone_file, will retry on next run...\n";
rename( $mirror_file_work, $mirror_file )
or die "Error renaming work file $mirror_file_work to mirror file $mirror_file, will retry on next run...\n";
# reload rr.devuan.org zone
system('/usr/sbin/nsd-control reload rr.devuan.org');
#--- utils -------------------------------------------------------------------
sub zonedata
{
my $ent = shift;
my $fqdn = $ent->{'FQDN'};
10 months ago
my $zonedata .= "\n; $fqdn\n";
for my $t ( 'A', 'AAAA' )
{
for my $addr ( map { $_->address() } grep { $_->type() eq $t } rr( $fqdn, $t ) )
{
10 months ago
$addr = Net::IPv6Addr::to_string_compressed( $addr ) if $t eq 'AAAA';
if( $ent->{ 'DNSRRCC' } eq 'yes' and my $cc = lc $ent->{ 'CountryCode' } )
{
$zonedata .= "$_.deb IN $t $addr\n" for split /\s*\|\s*/, $cc;
}
$zonedata .= "deb IN $t $addr\n" if $ent->{ 'DNSRR' } eq 'yes';
}
}
return $zonedata;
}
sub new_zone
{
my $oser = shift;
my $nser = strftime( "%Y%m%d", localtime( time() ) ) . '01';
$nser++ while $nser <= $oser;
10 months ago
return "\t$nser; \@zone\@ serial number for this zone file";
}
sub load_file
{
my $fn = shift;
open( my $fi, $fn );
local $/ = undef;
return <$fi>;
}
sub save_file
{
my $fn = shift;
open( my $fo, '>', $fn ) or return undef;
print $fo @_;
return 1;
}