xref: /freebsd/contrib/ntp/scripts/ntpsweep/ntpsweep.in (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
1#! @PATH_PERL@ -w
2# @configure_input@
3#
4# $Id$
5#
6# DISCLAIMER
7#
8# Copyright (C) 1999,2000 Hans Lambermont and Origin B.V.
9#
10# Permission to use, copy, modify and distribute this software and its
11# documentation for any purpose and without fee is hereby granted,
12# provided that the above copyright notice appears in all copies and
13# that both the copyright notice and this permission notice appear in
14# supporting documentation. This software is supported as is and without
15# any express or implied warranties, including, without limitation, the
16# implied warranties of merchantability and fitness for a particular
17# purpose. The name Origin B.V. must not be used to endorse or promote
18# products derived from this software without prior written permission.
19#
20# Hans Lambermont <ntpsweep@lambermont.dyndns.org>
21
22package ntpsweep;
23use 5.006_000;
24use strict;
25use lib "@PERLLIBDIR@";
26use NTP::Util qw(do_dns ntp_read_vars ntp_peers ntp_sntp_line);
27
28(my $program = $0) =~ s%.*/(.+?)(.pl)?$%$1%;
29my ($showpeers, $maxlevel, $strip);
30my (%known_host_info, %known_host_peers);
31
32exit run(@ARGV) unless caller;
33
34sub run {
35    my $opts;
36    if (!processOptions(\@_, $opts) ||
37        (((@_ != 1) && !$opts->{host} && !@{$opts->{'host-list'}}))) {
38        usage(1);
39    };
40
41    # no STDOUT buffering
42    $| = 1;
43    ($showpeers, $maxlevel, $strip) =
44        ($opts->{peers}, $opts->{maxlevel}, $opts->{strip});
45
46    my $hostsfile = shift;
47
48    # Main program
49
50    my @hosts;
51
52    if ($opts->{host}) {
53        push @hosts, $opts->{host};
54    }
55    else {
56        @hosts = read_hosts($hostsfile) if $hostsfile;
57        push @hosts, @{$opts->{'host-list'}};
58    }
59
60    # Print header
61    print <<EOF;
62Host                             st offset(s) version     system       processor
63--------------------------------+--+---------+-----------+------------+---------
64EOF
65
66    %known_host_info = ();
67    %known_host_peers = ();
68    scan_hosts(@hosts);
69
70    return 0;
71}
72
73sub scan_hosts {
74    my (@hosts) = @_;
75
76    my $host;
77    for $host (@hosts) {
78        scan_host($host, 0, $host => 1);
79    }
80}
81
82sub read_hosts {
83    my ($hostsfile) = @_;
84    my @hosts;
85
86    open my $hosts, $hostsfile
87        or die "$program: FATAL: unable to read $hostsfile: $!\n";
88
89    while (<$hosts>) {
90        next if /^\s*(#|$)/; # comment/empty
91        chomp;
92        push @hosts, $_;
93    }
94
95    close $hosts;
96    return @hosts;
97}
98
99sub scan_host {
100    my ($host, $level, %trace) = @_;
101    my $stratum = 0;
102    my $offset = 0;
103    my $daemonversion = "";
104    my $system = "";
105    my $processor = "";
106    my @peers;
107    my $known_host = 0;
108
109    if (exists $known_host_info{$host}) {
110        $known_host = 1;
111    }
112    else {
113        ($offset, $stratum) = ntp_sntp_line($host);
114
115        # got answers ? If so, go on.
116        if ($stratum) {
117            my $vars = ntp_read_vars(0, [qw(processor system daemon_version)], $host) || {};
118            $daemonversion = $vars->{daemon_version};
119            $system        = $vars->{system};
120            $processor     = $vars->{processor};
121
122            # Shorten daemon_version string.
123            $daemonversion =~ s/(;|Mon|Tue|Wed|Thu|Fri|Sat|Sun).*$//;
124            $daemonversion =~ s/version=//;
125            $daemonversion =~ s/(x|)ntpd //;
126            $daemonversion =~ s/(\(|\))//g;
127            $daemonversion =~ s/beta/b/;
128            $daemonversion =~ s/multicast/mc/;
129
130            # Shorten system string
131            $system =~ s/UNIX\///;
132            $system =~ s/RELEASE/r/;
133            $system =~ s/CURRENT/c/;
134
135            # Shorten processor string
136            $processor =~ s/unknown//;
137        }
138
139        # got answers ? If so, go on.
140        if ($daemonversion) {
141            if ($showpeers) {
142                my $peers_ref = ntp_peers($host);
143                my @peers_tmp = @$peers_ref;
144                for (@peers_tmp) {
145                    $_->{remote} =~ s/^(?: |x|\.|-|\+|#|\*|o)([^ ]+)/$1/;
146                    push @peers, $_->{remote};
147                }
148            }
149        }
150
151        # Add scanned host to known_hosts array
152        #push @known_hosts, $host;
153        if ($stratum) {
154            $known_host_info{$host} = sprintf "%2d %9.3f %-11s %-12s %s",
155                $stratum, $offset, (substr $daemonversion, 0, 11),
156                (substr $system, 0, 12), (substr $processor, 0, 9);
157        }
158        else {
159            # Stratum level 0 is consider invalid
160            $known_host_info{$host} = " ?";
161        }
162        $known_host_peers{$host} = [@peers];
163    }
164
165    if ($stratum || $known_host) { # Valid or known host
166        my $printhost = ' ' x $level . (do_dns($host) || $host);
167        # Shorten host string
168        if ($strip) {
169            $printhost =~ s/$strip//;
170        }
171        # append number of peers in brackets if requested and valid
172        if ($showpeers && ($known_host_info{$host} ne " ?")) {
173            $printhost .= " (" . @{$known_host_peers{$host}} . ")";
174        }
175        # Finally print complete host line
176        printf "%-32s %s\n",
177            (substr $printhost, 0, 32), $known_host_info{$host};
178        if ($showpeers && ($maxlevel ? $level < $maxlevel : 1)) {
179            $trace{$host} = 1;
180            # Loop through peers
181            foreach my $peer (@{$known_host_peers{$host}}) {
182                if (exists $trace{$peer}) {
183                    # we've detected a loop !
184                    $printhost = ' ' x ($level + 1) . "= " . $peer;
185                    # Shorten host string
186                    $printhost =~ s/$strip// if $strip;
187                    printf "%-32s\n", substr $printhost, 0, 32;
188                } else {
189                    if ((substr $peer, 0, 3) ne "127") {
190                        scan_host($peer, $level + 1, %trace);
191                    }
192                }
193            }
194        }
195    }
196    else { # We did not get answers from this host
197        my $printhost = ' ' x $level . (do_dns($host) || $host);
198        $printhost =~ s/$strip// if $strip;
199        printf "%-32s  ?\n", substr $printhost, 0, 32;
200    }
201}
202
203@ntpsweep_opts@
204
2051;
206__END__
207