#!/usr/bin/env perl
# dnsperf.pl  DNS server performance test program.
#             Graham Jenkins <grahjenk@cpan.org> Revised: 2020-08-03

=head1 NAME

dnsperf - a tool for comparing DNS servers

=head1 USAGE

dnsperf duration

A set of DNS queries is performed for the 'duration' period in seconds
using each of the servers shown at the end of this program, and the
success counts for each server are then listed in order.

=head1 SCRIPT CATEGORIES

UNIX/System_administration
Networking

=head1 AUTHOR

Graham Jenkins <grahjenk@cpan.org>

=head1 README

A simple tool for comparing the response times of designated DNS servers.

=head1 COPYRIGHT

Copyright (c) 2020 Graham Jenkins. All rights reserved.
This program is free software; you can redistribute it
and/or modify it under the same terms as Perl itself.

=cut

use strict;
use warnings;
use File::Basename;
use Getopt::Long;
use Config;
use HTTP::Tiny;
use Net::Nslookup;
use Time::HiRes qw(time);
use vars qw($VERSION);
$VERSION=1.05;

# Collect options, check usage
my ($type,$secs)=("A",1);
die "Usage: ".basename($0)." duration(secs)\n".
    " e.g.: ".basename($0)." 3\n".
    " Note: Duration must be in the range 1 through 10\n" 
  if( ($#ARGV!=0) || ($ARGV[0]!~m/\d+$/) || ($ARGV[0]<1) || ($ARGV[0]>10) );

# Get a list of the most popular websites
my $count=int(100*$ARGV[0]*1.1**($ARGV[0]-1));
my $resp= HTTP::Tiny->new->get(
    'https://tranco-list.eu/download/K3VW/'.$count);
$resp->{success} or die "$resp->{status} $resp->{reason}\n";

# Extract and store the entries in a table
my @lines=split("\n",$resp->{content});
for (my $i=0;$i<=$#lines;$i++) {
  my ($d1,$d2)=split(",",$lines[$i]);
  $d2=~s/\r|\n//g;
  $lines[$i]=$d2
}

# Swallow STDERR, autoflush STDOUT
my $null;
if ( $Config{osname} =~ /Win(32|64)$/i ) {$null="NUL"} else {$null="/dev/null"}
open(STDERR,">$null");
$|++;

# Test each server in turn by counting queries returned in designated duration
my ($key,$address,,%success,$clock0,$result);
print "Generating results using a list of ",$#lines+1," websites: ";
while ( <DATA> ) {
  chomp;
  $key=$_;
  if ( $key=~m/\#/ ) { next }
  ($address,)=split(/\s+/);
  $success{$key}=0;
  my $i=-1;
  $clock0=time();
  while (time() < $clock0+$ARGV[0]) {
    if ( $i>=$#lines ) { $i=-1 }
    my $host=$lines[$i++];
    if ( substr($address,0,1) eq "L") {
      $result=nslookup(host=>$host,type=>$type,timeout=>$secs)
    } else {
      $result=nslookup(host=>$host,type=>$type,timeout=>$secs,server=>$address)
    }
    if ( defined($result) ) { $success{$key}+=1 }
  }
  print "."
}

# Sort and print in ascending order of average query time
my @sorted= sort {$success{$b} <=> $success{$a}} keys(%success);
print "\nCount\n-----\n";
foreach my $line (@sorted) {
  my $a=$success{$line};
  print substr("     ",0,5-length($a)).$a," ",$line,"\n"
}

__END__
Local-Cache     ==
8.8.8.8         Google
1.1.1.1         Cloudflare
9.9.9.9         Quad9
192.168.1.1     Router .. adjust as appropriate 
203.29.125.2    Provider DNS .. adjust as appropriate
# 1.2.3.4       Insert further entries here