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