#! /usr/bin/perl -w

# John Hay -- John.Hay@icomtek.csir.co.za / jhay@FreeBSD.org

use Socket;
use Getopt::Std;
use vars qw($opt_n $opt_m);

$ntpq = "/usr/sbin/ntpq";

getopts('nm:');

$dodns = 1;
$dodns = 0 if (defined($opt_n));

$max_hosts = (defined($opt_m) ? $opt_m :  99);
$max_hosts = 0 if ( $max_hosts !~ /^\d+$/ );
$nb_host = 1;

$host = shift;
$host ||= "127.0.0.1";

for (;;) {
    $nb_host++;
    $rootdelay = 0;
    $rootdispersion = 0;
    $stratum = 255;
    $cmd = "$ntpq -n -c rv $host";
    open(PH, $cmd . "|") || die "failed to start command $cmd: $!";
    while (<PH>) {
        $stratum = $1 if (/stratum=(\d+)/);
        $peer = $1 if (/peer=(\d+)/);
        # Very old servers report phase and not offset.
        $offset = $1 if (/(?:offset|phase)=([^\s,]+)/);
        $rootdelay = $1 if (/rootdelay=([^\s,]+)/);
        $rootdispersion = $1 if (/rootdispersion=([^\s,]+)/);
        $refid = $1 if (/refid=([^\s,]+)/);
    }
    close(PH) || die "$cmd failed";
    last if ($stratum == 255);
    $offset /= 1000;
    $syncdistance = ($rootdispersion + ($rootdelay / 2)) / 1000;
    $dhost = $host;
    # Only do lookups of IPv4 addresses. The standard lookup functions
    # of perl only do IPv4 and I don't know if we should require extras.
    if ($dodns && $host =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/) {
        $iaddr = inet_aton($host);
        $name = (gethostbyaddr($iaddr, AF_INET))[0];
        $dhost = $name if (defined($name));
    }
    printf("%s: stratum %d, offset %f, synch distance %f",
        $dhost, $stratum, $offset, $syncdistance);
    printf(", refid '%s'", $refid) if ($stratum == 1);
    printf("\n");
    last if ($stratum == 0 || $stratum == 1 || $stratum == 16);
    last if ($refid =~ /^127\.127\.\d{1,3}\.\d{1,3}$/);
    last if ($nb_host > $max_hosts);

    $cmd = "$ntpq -n -c \"pstat $peer\" $host";
    open(PH, $cmd . "|") || die "failed to start command $cmd: $!";
    $thost = "";
    while (<PH>) {
        $thost = $1, last if (/srcadr=(\S+),/);
    }
    close(PH) || die "$cmd failed";
    last if ($thost eq "");
    last if ($thost =~ /^127\.127\.\d{1,3}\.\d{1,3}$/);
    $host = $thost;
}