Blame contrib/dlz/modules/bdbhpt/testing/bdbhpt-populate.pl

Packit Service ae04f2
#!/usr/bin/perl -w
Packit Service ae04f2
use strict;
Packit Service ae04f2
use BerkeleyDB;
Packit Service ae04f2
use Getopt::Long;
Packit Service ae04f2
Packit Service ae04f2
my $opt = {};
Packit Service ae04f2
if (!GetOptions($opt, qw/bdb|b:s input|i:s zones|z:s help|h/)) {
Packit Service ae04f2
    usage('GetOptions processing failed.');
Packit Service ae04f2
    exit 1;
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
if ($opt->{help}) {
Packit Service ae04f2
    usage();
Packit Service ae04f2
    exit 0;
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
my $db_file = $opt->{bdb};
Packit Service ae04f2
if (!defined $db_file || $db_file eq '') {
Packit Service ae04f2
    usage('Please specify an output BerkeleyDB filename.');
Packit Service ae04f2
    exit 1;
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
my $input_file = $opt->{input};
Packit Service ae04f2
if (!defined $input_file || $input_file eq '') {
Packit Service ae04f2
    usage('Please specify an input records file.');
Packit Service ae04f2
    exit 1;
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
my $zone_list = $opt->{zones};
Packit Service ae04f2
if (!defined $zone_list || $zone_list eq '') {
Packit Service ae04f2
    usage('Please specify a space separated list of zones');
Packit Service ae04f2
    exit 1;
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
my $records = [];
Packit Service ae04f2
my $unique_names = [];
Packit Service ae04f2
populate_records(records=>$records, input_file=>$input_file, unique_names=>$unique_names);
Packit Service ae04f2
Packit Service ae04f2
my $flags =  DB_CREATE;
Packit Service ae04f2
Packit Service ae04f2
my $dns_data = new BerkeleyDB::Hash
Packit Service ae04f2
    -Filename  => $db_file,
Packit Service ae04f2
    -Flags     => $flags,
Packit Service ae04f2
    -Property  => DB_DUP | DB_DUPSORT,
Packit Service ae04f2
    -Subname   => "dns_data"
Packit Service ae04f2
    ||    die "Cannot create dns_data: $BerkeleyDB::Error";
Packit Service ae04f2
Packit Service ae04f2
my $replId = 0;
Packit Service ae04f2
my @zones = split(/\s+/, $zone_list);
Packit Service ae04f2
foreach my $zone (@zones) {
Packit Service ae04f2
    foreach my $r (@$records) {
Packit Service ae04f2
        my $name = $r->{name};
Packit Service ae04f2
        my $ttl = $r->{ttl};
Packit Service ae04f2
        my $type = $r->{type};
Packit Service ae04f2
        my $data = $r->{data};
Packit Service ae04f2
        
Packit Service ae04f2
        $data =~ s/\%zone\%/$zone/g;
Packit Service ae04f2
        $data =~ s/\%driver\%/bdbhpt-dynamic/g;
Packit Service ae04f2
        
Packit Service ae04f2
        my $row_name  = "$zone $name";
Packit Service ae04f2
        my $row_value = "$replId $name $ttl $type $data";
Packit Service ae04f2
        if ($dns_data->db_put($row_name, $row_value) != 0) {
Packit Service ae04f2
            die "Cannot add record '$row_name' -> '$row_value' to dns_data: $BerkeleyDB::Error";
Packit Service ae04f2
        }
Packit Service ae04f2
        $replId++;
Packit Service ae04f2
    }
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
$dns_data->db_close();
Packit Service ae04f2
Packit Service ae04f2
my $dns_xfr = new BerkeleyDB::Hash
Packit Service ae04f2
    -Filename  => $db_file,
Packit Service ae04f2
    -Flags     => $flags,
Packit Service ae04f2
    -Property  => DB_DUP | DB_DUPSORT,
Packit Service ae04f2
    -Subname   => "dns_xfr"
Packit Service ae04f2
    or die "Cannot create dns_xfr: $BerkeleyDB::Error";
Packit Service ae04f2
Packit Service ae04f2
foreach my $zone (@zones) {
Packit Service ae04f2
    foreach my $name (@$unique_names) {
Packit Service ae04f2
        if ($dns_xfr->db_put($zone, $name) != 0) {
Packit Service ae04f2
            die "Cannot add record '$zone' -> '$name' to dns_xfr: $BerkeleyDB::Error";
Packit Service ae04f2
        }
Packit Service ae04f2
    }
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
$dns_xfr->db_close();
Packit Service ae04f2
Packit Service ae04f2
my $dns_client = new BerkeleyDB::Hash
Packit Service ae04f2
    -Filename  => $db_file,
Packit Service ae04f2
    -Flags     => $flags,
Packit Service ae04f2
    -Property  => DB_DUP | DB_DUPSORT,
Packit Service ae04f2
    -Subname   => "dns_client"
Packit Service ae04f2
    or die "Cannot create dns_client: $BerkeleyDB::Error";
Packit Service ae04f2
Packit Service ae04f2
foreach my $zone (@zones) {
Packit Service ae04f2
    my $ip = '127.0.0.1';
Packit Service ae04f2
    if ($dns_client->db_put($zone, $ip) != 0) {
Packit Service ae04f2
        die "Cannot add record '$zone' -> '$ip' to dns_client: $BerkeleyDB::Error";
Packit Service ae04f2
    }
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
$dns_client->db_close();
Packit Service ae04f2
Packit Service ae04f2
my $dns_zone = new BerkeleyDB::Btree
Packit Service ae04f2
    -Filename  => $db_file,
Packit Service ae04f2
    -Flags     => $flags,
Packit Service ae04f2
    -Property  => 0,
Packit Service ae04f2
    -Subname   => "dns_zone"
Packit Service ae04f2
    or die "Cannot create dns_zone: $BerkeleyDB::Error";
Packit Service ae04f2
Packit Service ae04f2
foreach my $zone (@zones) {
Packit Service ae04f2
    my $reversed_zone = reverse($zone);
Packit Service ae04f2
    if ($dns_zone->db_put($reversed_zone, "1") != 0) {
Packit Service ae04f2
        die "Cannot add record '$reversed_zone' -> '1' to dns_zone: $BerkeleyDB::Error";
Packit Service ae04f2
    }
Packit Service ae04f2
};
Packit Service ae04f2
Packit Service ae04f2
$dns_zone->db_close();
Packit Service ae04f2
Packit Service ae04f2
exit 0;
Packit Service ae04f2
Packit Service ae04f2
sub usage {
Packit Service ae04f2
    my ($message) = @_;
Packit Service ae04f2
    if (defined $message && $message ne '') {
Packit Service ae04f2
        print STDERR $message . "\n\n";
Packit Service ae04f2
    }
Packit Service ae04f2
Packit Service ae04f2
    print STDERR "usage: $0 --bdb=<bdb-file> --input=<input-file> --zones=<zone-list>\n\n";
Packit Service ae04f2
    print STDERR "\tbdb-file: The output BerkeleyDB file you wish to create and use with bdbhpt-dynamic\n\n";
Packit Service ae04f2
    print STDERR "\tinput-file: The input text-file containing records to populate within your zones\n\n";
Packit Service ae04f2
    print STDERR "\tzone-list: The space-separated list of zones you wish to create\n\n";
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
sub populate_records {
Packit Service ae04f2
    my (%args) = @_;
Packit Service ae04f2
    my $records = $args{records};
Packit Service ae04f2
    my $input_file = $args{input_file};
Packit Service ae04f2
    my $unique_names = $args{unique_names};
Packit Service ae04f2
Packit Service ae04f2
    my %unique;
Packit Service ae04f2
Packit Service ae04f2
    open(RECORDS, $input_file) || die "unable to open $input_file: $!";
Packit Service ae04f2
    while (<RECORDS>) {
Packit Service ae04f2
        chomp;
Packit Service ae04f2
        s/\#.*$//;
Packit Service ae04f2
        s/^\s+//;
Packit Service ae04f2
        if ($_ eq '') {
Packit Service ae04f2
            next;
Packit Service ae04f2
        }
Packit Service ae04f2
        my ($name, $ttl, $type, $data) = split(/\s+/, $_, 4);
Packit Service ae04f2
        my $record = { name=>$name, ttl=>$ttl, type=>$type, data=>$data };
Packit Service ae04f2
        if (validate_record($record)) {
Packit Service ae04f2
            push @$records, $record;
Packit Service ae04f2
            $unique{$name} = 1;
Packit Service ae04f2
        }
Packit Service ae04f2
    }
Packit Service ae04f2
    close(RECORDS);
Packit Service ae04f2
Packit Service ae04f2
    foreach my $name (sort keys %unique) {
Packit Service ae04f2
        push @$unique_names, $name;
Packit Service ae04f2
    }
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
# This could probably do more in-depth tests, but these tests are better than nothing!
Packit Service ae04f2
sub validate_record {
Packit Service ae04f2
    my ($r) = @_;
Packit Service ae04f2
Packit Service ae04f2
    # http://en.wikipedia.org/wiki/List_of_DNS_record_types
Packit Service ae04f2
    my @TYPES = qw/A AAAA AFSDB APL CERT CNAME DHCID DLV DNAME DNSKEY DS HIP IPSECKEY KEY KX LOC MX NAPTR NS NSEC NSEC3 NSEC3PARAM PTR RRSIG RP SIG SOA SPF SRV SSHFP TA TKEY TLSA TSIG TXT/;
Packit Service ae04f2
    my $VALID_TYPE = {};
Packit Service ae04f2
    foreach my $t (@TYPES) {
Packit Service ae04f2
        $VALID_TYPE->{$t} = 1;
Packit Service ae04f2
    }
Packit Service ae04f2
    
Packit Service ae04f2
    if (!defined $r->{name} || $r->{name} eq '') {
Packit Service ae04f2
        die "Record name must be set";
Packit Service ae04f2
    }
Packit Service ae04f2
Packit Service ae04f2
    if (!defined $r->{ttl} || $r->{ttl} eq '') {
Packit Service ae04f2
        die "Record TTL must be set";
Packit Service ae04f2
    }
Packit Service ae04f2
Packit Service ae04f2
    if ($r->{ttl} =~ /\D/ || $r->{ttl} < 0) {
Packit Service ae04f2
        die "Record TTL must be an integer 0 or greater";
Packit Service ae04f2
    }
Packit Service ae04f2
Packit Service ae04f2
    if (!defined $r->{type} || $r->{type} eq '') {
Packit Service ae04f2
        die "Record type must be set";
Packit Service ae04f2
    }
Packit Service ae04f2
Packit Service ae04f2
    if (!$VALID_TYPE->{$r->{type}}) {
Packit Service ae04f2
        die "Unsupported record type: $r->{type}";
Packit Service ae04f2
    }
Packit Service ae04f2
Packit Service ae04f2
    # Lets do some data validation for the records which will cause bind to crash if they're wrong
Packit Service ae04f2
    if ($r->{type} eq 'SOA') {
Packit Service ae04f2
        my $soa_error = "SOA records must take the form: 'server email refresh retry expire negative_cache_ttl'";
Packit Service ae04f2
        my ($server, $email, $version, $refresh, $retry, $expire, $negative_cache_ttl) = split(/\s+/, $r->{data});
Packit Service ae04f2
        if (!defined $server || $server eq '') {
Packit Service ae04f2
            die "$soa_error, missing server";
Packit Service ae04f2
        }
Packit Service ae04f2
        if (!defined $email || $email eq '') {
Packit Service ae04f2
            die "$soa_error, missing email";
Packit Service ae04f2
        }
Packit Service ae04f2
        if (!defined $refresh || $refresh eq '') {
Packit Service ae04f2
            die "$soa_error, missing refresh";
Packit Service ae04f2
        }
Packit Service ae04f2
        if ($refresh =~ /\D/ || $refresh <= 0) {
Packit Service ae04f2
            die "$soa_error, refresh must be an integer greater than 0";
Packit Service ae04f2
        }
Packit Service ae04f2
        if (!defined $retry || $retry eq '') {
Packit Service ae04f2
            die "$soa_error, missing retry";
Packit Service ae04f2
        }
Packit Service ae04f2
        if ($retry =~ /\D/ || $retry <= 0) {
Packit Service ae04f2
            die "$soa_error, retry must be an integer greater than 0";
Packit Service ae04f2
        }
Packit Service ae04f2
        if (!defined $expire || $expire eq '') {
Packit Service ae04f2
            die "$soa_error, missing expire";
Packit Service ae04f2
        }
Packit Service ae04f2
        if ($expire =~ /\D/ || $expire <= 0) {
Packit Service ae04f2
            die "$soa_error, expire must be an integer greater than 0";
Packit Service ae04f2
        }
Packit Service ae04f2
        if (!defined $negative_cache_ttl || $negative_cache_ttl eq '') {
Packit Service ae04f2
            die "$soa_error, missing negative cache ttl";
Packit Service ae04f2
        }
Packit Service ae04f2
        if ($negative_cache_ttl =~ /\D/ || $negative_cache_ttl <= 0) {
Packit Service ae04f2
            die "$soa_error, negative cache ttl must be an integer greater than 0";
Packit Service ae04f2
        }
Packit Service ae04f2
    }
Packit Service ae04f2
Packit Service ae04f2
    return 1;
Packit Service ae04f2
}