ntpsweep.in revision 1.1.1.4
1234285Sdim#! @PATH_PERL@ -w
2234285Sdim#
3234285Sdim# Id
4234285Sdim#
5234285Sdim# DISCLAIMER
6234285Sdim# 
7234285Sdim# Copyright (C) 1999,2000 Hans Lambermont and Origin B.V.
8234285Sdim# 
9234285Sdim# Permission to use, copy, modify and distribute this software and its
10234285Sdim# documentation for any purpose and without fee is hereby granted,
11234285Sdim# provided that the above copyright notice appears in all copies and
12234285Sdim# that both the copyright notice and this permission notice appear in
13234285Sdim# supporting documentation. This software is supported as is and without
14234285Sdim# any express or implied warranties, including, without limitation, the
15234285Sdim# implied warranties of merchantability and fitness for a particular
16234285Sdim# purpose. The name Origin B.V. must not be used to endorse or promote
17234285Sdim# products derived from this software without prior written permission.
18234285Sdim#
19234285Sdim# Hans Lambermont <ntpsweep@lambermont.dyndns.org>
20234285Sdim
21234285Sdimpackage ntpsweep;
22234285Sdimuse 5.006_000;
23234285Sdimuse strict;
24234285Sdimuse lib "@PERLLIBDIR@";
25234285Sdimuse NTP::Util qw(do_dns ntp_read_vars ntp_peers ntp_sntp_line);
26234285Sdim
27234285Sdim(my $program = $0) =~ s%.*/(.+?)(.pl)?$%$1%;
28234285Sdimmy ($showpeers, $maxlevel, $strip);
29234285Sdimmy (%known_host_info, %known_host_peers);
30234285Sdim
31234285Sdimexit run(@ARGV) unless caller;
32234285Sdim
33234285Sdimsub run {
34234285Sdim    my $opts;
35234285Sdim    if (!processOptions(\@_, $opts) || 
36234285Sdim        (((@_ != 1) && !$opts->{host} && !@{$opts->{'host-list'}}))) {
37234285Sdim        usage(1);
38234285Sdim    };
39234285Sdim
40234285Sdim    # no STDOUT buffering
41234285Sdim    $| = 1;
42234285Sdim    ($showpeers, $maxlevel, $strip) = 
43234285Sdim        ($opts->{peers}, $opts->{maxlevel}, $opts->{strip});
44234285Sdim
45234285Sdim    my $hostsfile = shift;
46234285Sdim
47234285Sdim    # Main program
48234285Sdim
49234285Sdim    my @hosts;
50234285Sdim
51234285Sdim    if ($opts->{host}) {
52234285Sdim        push @hosts, $opts->{host};
53234285Sdim    }
54234285Sdim    else {
55234285Sdim        @hosts = read_hosts($hostsfile) if $hostsfile;
56234285Sdim        push @hosts, @{$opts->{'host-list'}};
57234285Sdim    }
58234285Sdim
59234285Sdim    # Print header
60234285Sdim    print <<EOF;
61234285SdimHost                             st offset(s) version     system       processor
62234285Sdim--------------------------------+--+---------+-----------+------------+---------
63234285SdimEOF
64234285Sdim
65234285Sdim    %known_host_info = ();
66234285Sdim    %known_host_peers = ();
67234285Sdim    scan_hosts(@hosts);
68234285Sdim
69234285Sdim    return 0;
70234285Sdim}
71234285Sdim
72234285Sdimsub scan_hosts {
73234285Sdim    my (@hosts) = @_;
74234285Sdim
75234285Sdim    my $host;
76234285Sdim    for $host (@hosts) {
77234285Sdim        scan_host($host, 0, $host => 1);
78234285Sdim    }
79234285Sdim}
80234285Sdim
81234285Sdimsub read_hosts {
82234285Sdim    my ($hostsfile) = @_;
83234285Sdim    my @hosts;
84234285Sdim
85234285Sdim    open my $hosts, $hostsfile 
86234285Sdim        or die "$program: FATAL: unable to read $hostsfile: $!\n";
87234285Sdim
88234285Sdim    while (<$hosts>) {
89234285Sdim        next if /^\s*(#|$)/; # comment/empty
90234285Sdim        chomp;
91234285Sdim        push @hosts, $_;
92234285Sdim    }
93234285Sdim
94234285Sdim    close $hosts;
95234285Sdim    return @hosts;
96234285Sdim}
97234285Sdim
98234285Sdimsub scan_host {
99234285Sdim    my ($host, $level, %trace) = @_;
100234285Sdim    my $stratum = 0;
101234285Sdim    my $offset = 0;
102234285Sdim    my $daemonversion = "";
103234285Sdim    my $system = "";
104234285Sdim    my $processor = "";
105234285Sdim    my @peers;
106234285Sdim    my $known_host = 0;
107234285Sdim
108234285Sdim    if (exists $known_host_info{$host}) {
109239462Sdim        $known_host = 1;
110234285Sdim    }
111234285Sdim    else {
112234285Sdim        ($offset, $stratum) = ntp_sntp_line($host);
113234285Sdim
114234285Sdim        # got answers ? If so, go on.
115234285Sdim        if ($stratum) {
116234285Sdim            my $vars = ntp_read_vars(0, [qw(processor system daemon_version)], $host) || {};
117234285Sdim            $daemonversion = $vars->{daemon_version};
118234285Sdim            $system        = $vars->{system};
119234285Sdim            $processor     = $vars->{processor};
120234285Sdim
121234285Sdim            # Shorten daemon_version string.
122234285Sdim            $daemonversion =~ s/(;|Mon|Tue|Wed|Thu|Fri|Sat|Sun).*$//;
123234285Sdim            $daemonversion =~ s/version=//;
124234285Sdim            $daemonversion =~ s/(x|)ntpd //;
125234285Sdim            $daemonversion =~ s/(\(|\))//g;
126234285Sdim            $daemonversion =~ s/beta/b/;
127234285Sdim            $daemonversion =~ s/multicast/mc/;
128234285Sdim
129234285Sdim            # Shorten system string
130234285Sdim            $system =~ s/UNIX\///;
131234285Sdim            $system =~ s/RELEASE/r/;
132234285Sdim            $system =~ s/CURRENT/c/;
133234285Sdim
134234285Sdim            # Shorten processor string
135234285Sdim            $processor =~ s/unknown//;
136234285Sdim        }
137234285Sdim
138234285Sdim        # got answers ? If so, go on.
139234285Sdim        if ($daemonversion) {
140234285Sdim            if ($showpeers) {
141234285Sdim                my $peers_ref = ntp_peers($host);
142234285Sdim                my @peers_tmp = @$peers_ref;
143234285Sdim                for (@peers_tmp) {
144234285Sdim                    $_->{remote} =~ s/^(?: |x|\.|-|\+|#|\*|o)([^ ]+)/$1/;
145234285Sdim                    push @peers, $_->{remote};
146234285Sdim                }
147234285Sdim            }
148234285Sdim        }
149234285Sdim
150234285Sdim        # Add scanned host to known_hosts array
151234285Sdim        #push @known_hosts, $host;
152234285Sdim        if ($stratum) {
153234285Sdim            $known_host_info{$host} = sprintf "%2d %9.3f %-11s %-12s %s",
154234285Sdim                $stratum, $offset, (substr $daemonversion, 0, 11),
155234285Sdim                (substr $system, 0, 12), (substr $processor, 0, 9);
156234285Sdim        }
157234285Sdim        else {
158234285Sdim            # Stratum level 0 is consider invalid
159234285Sdim            $known_host_info{$host} = " ?";
160234285Sdim        }
161234285Sdim        $known_host_peers{$host} = [@peers];
162234285Sdim    }
163234285Sdim
164234285Sdim    if ($stratum || $known_host) { # Valid or known host
165234285Sdim        my $printhost = ' ' x $level . (do_dns($host) || $host);
166234285Sdim        # Shorten host string
167234285Sdim        if ($strip) {
168234285Sdim            $printhost =~ s/$strip//;
169234285Sdim        }
170234285Sdim        # append number of peers in brackets if requested and valid
171234285Sdim        if ($showpeers && ($known_host_info{$host} ne " ?")) {
172234285Sdim            $printhost .= " (" . @{$known_host_peers{$host}} . ")";
173234285Sdim        }
174234285Sdim        # Finally print complete host line
175234285Sdim        printf "%-32s %s\n",
176234285Sdim            (substr $printhost, 0, 32), $known_host_info{$host};
177234285Sdim        if ($showpeers && ($maxlevel ? $level < $maxlevel : 1)) {
178234285Sdim            $trace{$host} = 1;
179234285Sdim            # Loop through peers
180234285Sdim            foreach my $peer (@{$known_host_peers{$host}}) {
181234285Sdim                if (exists $trace{$peer}) {
182234285Sdim                    # we've detected a loop !
183234285Sdim                    $printhost = ' ' x ($level + 1) . "= " . $peer;
184234285Sdim                    # Shorten host string
185234285Sdim                    $printhost =~ s/$strip// if $strip;
186234285Sdim                    printf "%-32s\n", substr $printhost, 0, 32;
187234285Sdim                } else {
188234285Sdim                    if ((substr $peer, 0, 3) ne "127") {
189234285Sdim                        scan_host($peer, $level + 1, %trace);
190234285Sdim                    }
191234285Sdim                }
192234285Sdim            }
193234285Sdim        }
194234285Sdim    }
195234285Sdim    else { # We did not get answers from this host
196234285Sdim        my $printhost = ' ' x $level . (do_dns($host) || $host);
197234285Sdim        $printhost =~ s/$strip// if $strip;
198234285Sdim        printf "%-32s  ?\n", substr $printhost, 0, 32;
199234285Sdim    }
200234285Sdim}
201234285Sdim
202234285Sdim@ntpsweep_opts@
203234285Sdim
204234285Sdim1;
205234285Sdim__END__
206234285Sdim