head	1.1;
branch	1.1.1;
access;
symbols
	RELENG_9_1_0_RELEASE:1.1.1.2
	RELENG_9_1:1.1.1.2.0.54
	RELENG_9_1_BP:1.1.1.2
	RELENG_8_3_0_RELEASE:1.1.1.2
	RELENG_8_3:1.1.1.2.0.52
	RELENG_8_3_BP:1.1.1.2
	RELENG_9_0_0_RELEASE:1.1.1.2
	RELENG_9_0:1.1.1.2.0.50
	RELENG_9_0_BP:1.1.1.2
	RELENG_9:1.1.1.2.0.48
	RELENG_9_BP:1.1.1.2
	RELENG_7_4_0_RELEASE:1.1.1.2
	RELENG_8_2_0_RELEASE:1.1.1.2
	RELENG_7_4:1.1.1.2.0.46
	RELENG_7_4_BP:1.1.1.2
	RELENG_8_2:1.1.1.2.0.44
	RELENG_8_2_BP:1.1.1.2
	RELENG_8_1_0_RELEASE:1.1.1.2
	RELENG_8_1:1.1.1.2.0.42
	RELENG_8_1_BP:1.1.1.2
	RELENG_7_3_0_RELEASE:1.1.1.2
	RELENG_7_3:1.1.1.2.0.40
	RELENG_7_3_BP:1.1.1.2
	RELENG_8_0_0_RELEASE:1.1.1.2
	RELENG_8_0:1.1.1.2.0.38
	RELENG_8_0_BP:1.1.1.2
	RELENG_8:1.1.1.2.0.36
	RELENG_8_BP:1.1.1.2
	RELENG_7_2_0_RELEASE:1.1.1.2
	RELENG_7_2:1.1.1.2.0.34
	RELENG_7_2_BP:1.1.1.2
	RELENG_7_1_0_RELEASE:1.1.1.2
	RELENG_6_4_0_RELEASE:1.1.1.2
	RELENG_7_1:1.1.1.2.0.32
	RELENG_7_1_BP:1.1.1.2
	RELENG_6_4:1.1.1.2.0.30
	RELENG_6_4_BP:1.1.1.2
	RELENG_7_0_0_RELEASE:1.1.1.2
	RELENG_6_3_0_RELEASE:1.1.1.2
	RELENG_7_0:1.1.1.2.0.28
	RELENG_7_0_BP:1.1.1.2
	RELENG_6_3:1.1.1.2.0.26
	RELENG_6_3_BP:1.1.1.2
	RELENG_7:1.1.1.2.0.24
	RELENG_7_BP:1.1.1.2
	RELENG_6_2_0_RELEASE:1.1.1.2
	RELENG_6_2:1.1.1.2.0.22
	RELENG_6_2_BP:1.1.1.2
	RELENG_5_5_0_RELEASE:1.1.1.2
	RELENG_5_5:1.1.1.2.0.20
	RELENG_5_5_BP:1.1.1.2
	RELENG_6_1_0_RELEASE:1.1.1.2
	RELENG_6_1:1.1.1.2.0.18
	RELENG_6_1_BP:1.1.1.2
	RELENG_6_0_0_RELEASE:1.1.1.2
	RELENG_6_0:1.1.1.2.0.16
	RELENG_6_0_BP:1.1.1.2
	RELENG_6:1.1.1.2.0.14
	RELENG_6_BP:1.1.1.2
	RELENG_5_4_0_RELEASE:1.1.1.2
	RELENG_5_4:1.1.1.2.0.12
	RELENG_5_4_BP:1.1.1.2
	RELENG_4_11_0_RELEASE:1.1.1.1
	RELENG_4_11:1.1.1.1.0.20
	RELENG_4_11_BP:1.1.1.1
	RELENG_5_3_0_RELEASE:1.1.1.2
	RELENG_5_3:1.1.1.2.0.10
	RELENG_5_3_BP:1.1.1.2
	RELENG_5:1.1.1.2.0.8
	RELENG_5_BP:1.1.1.2
	RELENG_4_10_0_RELEASE:1.1.1.1
	RELENG_4_10:1.1.1.1.0.18
	RELENG_4_10_BP:1.1.1.1
	RELENG_5_2_1_RELEASE:1.1.1.2
	RELENG_5_2_0_RELEASE:1.1.1.2
	RELENG_5_2:1.1.1.2.0.6
	RELENG_5_2_BP:1.1.1.2
	RELENG_4_9_0_RELEASE:1.1.1.1
	RELENG_4_9:1.1.1.1.0.16
	RELENG_4_9_BP:1.1.1.1
	RELENG_5_1_0_RELEASE:1.1.1.2
	RELENG_5_1:1.1.1.2.0.4
	RELENG_5_1_BP:1.1.1.2
	RELENG_4_8_0_RELEASE:1.1.1.1
	RELENG_4_8:1.1.1.1.0.14
	RELENG_4_8_BP:1.1.1.1
	RELENG_5_0_0_RELEASE:1.1.1.2
	RELENG_5_0:1.1.1.2.0.2
	RELENG_5_0_BP:1.1.1.2
	RELENG_4_7_0_RELEASE:1.1.1.1
	RELENG_4_7:1.1.1.1.0.12
	RELENG_4_7_BP:1.1.1.1
	RELENG_4_6_2_RELEASE:1.1.1.1
	RELENG_4_6_1_RELEASE:1.1.1.1
	RELENG_4_6_0_RELEASE:1.1.1.1
	RELENG_4_6:1.1.1.1.0.10
	RELENG_4_6_BP:1.1.1.1
	RELENG_4_5_0_RELEASE:1.1.1.1
	RELENG_4_5:1.1.1.1.0.8
	RELENG_4_5_BP:1.1.1.1
	RELENG_4_4_0_RELEASE:1.1.1.1
	RELENG_4_4:1.1.1.1.0.6
	RELENG_4_4_BP:1.1.1.1
	RELENG_4_3_0_RELEASE:1.1.1.1
	RELENG_4_3:1.1.1.1.0.4
	RELENG_4_3_BP:1.1.1.1
	RELENG_4_2_0_RELEASE:1.1.1.1
	RELENG_4_1_1_RELEASE:1.1.1.1
	PRE_SMPNG:1.1.1.1
	RELENG_4_1_0_RELEASE:1.1.1.1
	RELENG_4_0_0_RELEASE:1.1.1.1
	RELENG_4:1.1.1.1.0.2
	RELENG_4_BP:1.1.1.1
	v4_0_99b:1.1.1.1
	DMILLS:1.1.1;
locks; strict;
comment	@# @;


1.1
date	2000.01.28.14.51.01;	author roberto;	state Exp;
branches
	1.1.1.1;
next	;

1.1.1.1
date	2000.01.28.14.51.01;	author roberto;	state Exp;
branches;
next	1.1.1.2;

1.1.1.2
date	2002.10.29.20.11.45;	author roberto;	state dead;
branches;
next	;


desc
@@


1.1
log
@Initial revision
@
text
@#!/usr/local/bin/perl -w
#
# $Id: ntpsweep,v 1.3 2000/01/15 07:37:52 stenn Exp $
#
# DISCLAIMER
# 
# Copyright (C) 1999,2000 Hans Lambermont and Origin B.V.
# 
# Permission to use, copy, modify and distribute this software and its
# documentation for any purpose and without fee is hereby granted,
# provided that the above copyright notice appears in all copies and
# that both the copyright notice and this permission notice appear in
# supporting documentation. This software is supported as is and without
# any express or implied warranties, including, without limitation, the
# implied warranties of merchantability and fitness for a particular
# purpose. The name Origin B.V. must not be used to endorse or promote
# products derived from this software without prior written permission.
#
# Hans Lambermont <Hans.Lambermont@@nl.origin-it.com>/<H.Lambermont@@chello.nl>
# 14 Jan 2000

require 5.0;		# But actually tested on 5.004 ;)
use Getopt::Long;       # GetOptions()
use strict;

my $version = 1.3;
(my $program = $0) =~ s%.*/(.+?)(.pl)?$%$1%;

# Hardcoded paths/program names
my $ntpdate = "ntpdate";
my $ntpq = "ntpq";

# no STDOUT buffering
$| = 1;

my ($help, $single_host, $showpeers, $maxlevel, $strip, $askversion);
my $res = GetOptions("help!"      => \$help,
		     "host=s"     => \$single_host,
		     "peers!"     => \$showpeers,
		     "maxlevel=s" => \$maxlevel,
		     "strip=s"    => \$strip,
		     "version!"   => \$askversion);

if ($askversion) {
    print("$version\n");
    exit 0;
}

if ($help || ((@@ARGV != 1) && !$single_host)) {
    warn <<EOF;
This is $program, version $version
Copyright (C) 1999,2000 Hans Lambermont and Origin B.V.  Disclaimer inside.

Usage:
  $program [--help|--peers|--strip <string>|--maxlevel <level>|--version] \\
    <file>|[--host <hostname>]

Description:
  $program prints per host given in <file> the NTP stratum level, the
  clock offset in seconds, the daemon version, the operating system and
  the processor. Optionally recursing through all peers.

Options:
--help
    Print this short help text and exit.
--version
    Print version ($version) and exit.
<file>
    Specify hosts file. File format is one hostname or ip number per line.
    Lines beginning with # are considered as comment.
--host <hostname>
    Speficy a single host, bypassing the need for a hosts file.
--peers
    Recursively list all peers a host synchronizes to.
    An '= ' before a peer means a loop. Recursion stops here.
--maxlevel <level>
    Traverse peers up to this level (4 is a reasonable number).
--strip <string>
    Strip <string> from hostnames.

Examples:
    $program myhosts.txt --strip .foo.com
    $program --host some.host --peers --maxlevel 4
EOF
    exit 1;
}

my $hostsfile = shift;
my (@@hosts, @@known_hosts);
my (%known_host_info, %known_host_peers);

sub read_hosts()
{
    local *HOSTS;
    open (HOSTS, $hostsfile) ||
	die "$program: FATAL: unable to read $hostsfile: $!\n";
    while (<HOSTS>) {
	next if /^\s*(#|$)/; # comment/empty
	chomp;
	push(@@hosts, $_);
    }
    close(HOSTS);
}

# translate IP to hostname if possible
sub ip2name {
    my($ip) = @@_;
    my($addr, $name, $aliases, $addrtype, $length, @@addrs);
    $addr = pack('C4', split(/\./, $ip));
    ($name, $aliases, $addrtype, $length, @@addrs) = gethostbyaddr($addr, 2);
    if ($name) {
        # return lower case name
	return("\L$name");
    } else {
	return($ip);
    }
}

# item_in_list($item, @@list): returns 1 if $item is in @@list, 0 if not
sub item_in_list {
    my($item, @@list) = @@_;
    my($i);
    foreach $i (@@list) {
	return 1 if ($item eq $i);
    }
    return 0;
}

sub scan_host($;$;$) {
    my($host, $level, @@trace) = @@_;
    my $stratum = 0;
    my $offset = 0;
    my $daemonversion = "";
    my $system = "";
    my $processor = "";
    my @@peers;
    my $known_host = 0;

    if (&item_in_list($host, @@known_hosts)) {
	$known_host = 1;
    } else {
	# ntpdate part
	open(NTPDATE, "$ntpdate -bd $host 2>/dev/null |") ||
    	die "Cannot open ntpdate pipe: $!\n";
	while (<NTPDATE>) {
	    /^stratum\s+(\d+).*$/ && do {
		$stratum = $1;
	    };
	    /^offset\s+([0-9.-]+)$/ && do {
		$offset = $1;
	    };
	}
	close(NTPDATE);
    
	# got answers ? If so, go on.
	if ($stratum) {
	    # ntpq part
	    my $ntpqparams = "-c 'rv 0 processor,system,daemon_version'";
	    open(NTPQ, "$ntpq $ntpqparams $host 2>/dev/null |") ||
		die "Cannot open ntpq pipe: $!\n";
	    while (<NTPQ>) {
		/daemon_version="(.*)"/ && do {
		    $daemonversion = $1;
		};
		/system="([^"]*)"/ && do {
		    $system = $1;
		};
		/processor="([^"]*)"/ && do {
		    $processor = $1;
		};
	    }
	    close(NTPQ);
	    
	    # Shorten daemon_version string.
	    $daemonversion =~ s/(;|Mon|Tue|Wed|Thu|Fri|Sat|Sun).*$//;
	    $daemonversion =~ s/version=//;
	    $daemonversion =~ s/(x|)ntpd //;
	    $daemonversion =~ s/(\(|\))//g;
	    $daemonversion =~ s/beta/b/;
	    $daemonversion =~ s/multicast/mc/;
	
	    # Shorten system string
	    $system =~ s/UNIX\///;
	    $system =~ s/RELEASE/r/;
	    $system =~ s/CURRENT/c/;

	    # Shorten processor string
	    $processor =~ s/unknown//;
	}
    
	# got answers ? If so, go on.
	if ($daemonversion) {
	    # ntpq again, find out the peers this time
	    if ($showpeers) {
		my $ntpqparams = "-pn";
		open(NTPQ, "$ntpq $ntpqparams $host 2>/dev/null |") ||
		    die "Cannot open ntpq pipe: $!\n";
		while (<NTPQ>) {
		    /^No association ID's returned$/ && do {
			last;
		    };
		    /^     remote/ && do {
			next;
		    };
		    /^==/ && do {
			next;
		    };
		    /^( |x|\.|-|\+|#|\*|o)([^ ]+)/ && do {
			push(@@peers, ip2name($2));
			next;
		    };
		    print "ERROR: $_";
		}
		close(NTPQ);
	    }
	}
    
	# Add scanned host to known_hosts array
	push(@@known_hosts, $host);
	if ($stratum) {
	    $known_host_info{$host} = sprintf("%2d %9.3f %-11s %-12s %s",
		$stratum, $offset, substr($daemonversion,0,11),
		substr($system,0,12), substr($processor,0,9));
	} else {
	    # Stratum level 0 is consider invalid
	    $known_host_info{$host} = sprintf(" ?");
	}
	$known_host_peers{$host} = [@@peers];
    }

    if ($stratum || $known_host) { # Valid or known host
	my $printhost = ' ' x $level . $host;
	# Shorten host string
	if ($strip) {
	    $printhost =~ s/$strip//;
	}
	# append number of peers in brackets if requested and valid
	if ($showpeers && ($known_host_info{$host} ne " ?")) {
	    $printhost .= " (" . @@{$known_host_peers{$host}} . ")";
	}
	# Finally print complete host line
	printf("%-32s %s\n",
	    substr($printhost,0,32), $known_host_info{$host});
	if ($showpeers && (eval($maxlevel ? $level < $maxlevel : 1))) {
	    my $peer;
	    push(@@trace, $host);
	    # Loop through peers
	    foreach $peer (@@{$known_host_peers{$host}}) {
		if (&item_in_list($peer, @@trace)) {
		    # we've detected a loop !
		    $printhost = ' ' x ($level + 1) . "= " . $peer;
		    # Shorten host string
		    if ($strip) {
			$printhost =~ s/$strip//;
		    }
		    printf("%-32s %s\n",
			substr($printhost,0,32));
		} else {
		    if (substr($peer,0,3) ne "127") {
			&scan_host($peer, $level + 1, @@trace);
		    }
		}
	    }
	}
    } else { # We did not get answers from this host
	my $printhost = ' ' x $level . $host;
	# Shorten host string
	if ($strip) {
	    $printhost =~ s/$strip//;
	}
	printf("%-32s  ?\n", substr($printhost,0,32));
    }
}

sub scan_hosts()
{
    my $host;
    for $host (@@hosts) {
	my @@trace;
	push(@@trace, $host);
	scan_host($host, 0, @@trace);
    }
}

# Main program

if ($single_host) {
    push(@@hosts, $single_host);
} else {
    &read_hosts($hostsfile);
}

# Print header
print <<EOF;
Host                             st offset(s) version     system       processor
--------------------------------+--+---------+-----------+------------+---------
EOF

&scan_hosts();

exit 0;
@


1.1.1.1
log
@Virgin import of ntpd 4.0.99b
@
text
@@


1.1.1.2
log
@Remove files not present in 4.1.1a import.
@
text
@@

