xref: /freebsd/contrib/ntp/scripts/monitoring/ntptrap (revision 416ba5c74546f32a993436a99516d35008e9f384)
1c0b746e5SOllivier Robert#!/local/bin/perl --*-perl-*-
2c0b746e5SOllivier Robert;#
3c0b746e5SOllivier Robert;# ntptrap,v 3.1 1993/07/06 01:09:15 jbj Exp
4c0b746e5SOllivier Robert;#
5c0b746e5SOllivier Robert;# a client for the xntp mode 6 trap mechanism
6c0b746e5SOllivier Robert;#
7c0b746e5SOllivier Robert;# Copyright (c) 1992
8c0b746e5SOllivier Robert;#  Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg
9c0b746e5SOllivier Robert;#
10c0b746e5SOllivier Robert;#
11c0b746e5SOllivier Robert;#############################################################
12c0b746e5SOllivier Robert$0 =~ s!^.*/([^/]+)$!$1!;		# strip to filename
13c0b746e5SOllivier Robert;# enforce STDOUT and STDERR to be line buffered
14c0b746e5SOllivier Robert$| = 1;
15c0b746e5SOllivier Robertselect((select(STDERR),$|=1)[$[]);
16c0b746e5SOllivier Robert
17c0b746e5SOllivier Robert;#######################################
18c0b746e5SOllivier Robert;# load utility routines and definitions
19c0b746e5SOllivier Robert;#
20c0b746e5SOllivier Robertrequire('ntp.pl');			# implementation of the NTP protocol
21c0b746e5SOllivier Robertuse Socket;
22c0b746e5SOllivier Robert
23c0b746e5SOllivier Robert#eval { require('sys/socket.ph'); require('netinet/in.ph') unless defined(&INADDR_ANY); } ||
24c0b746e5SOllivier Robert#do {
25c0b746e5SOllivier Robert  #die("$0: $@") unless $[ == index($@, "Can't locate ");
26c0b746e5SOllivier Robert  #warn "$0: $@";
27c0b746e5SOllivier Robert  #warn "$0: supplying some default definitions\n";
28c0b746e5SOllivier Robert  #eval 'sub INADDR_ANY { 0; } sub AF_INET {2;} sub SOCK_DGRAM {2;} 1;' || die "$0: $@";
29c0b746e5SOllivier Robert#};
30c0b746e5SOllivier Robertrequire('getopts.pl');			# option parsing
31c0b746e5SOllivier Robertrequire('ctime.pl');			# date/time formatting
32c0b746e5SOllivier Robert
33c0b746e5SOllivier Robert;######################################
34c0b746e5SOllivier Robert;# define some global constants
35c0b746e5SOllivier Robert;#
36c0b746e5SOllivier Robert$BASE_TIMEOUT=10;
37c0b746e5SOllivier Robert$FRAG_TIMEOUT=10;
38c0b746e5SOllivier Robert$MAX_TRY = 5;
39c0b746e5SOllivier Robert$REFRESH_TIME=60*15;		# 15 minutes (server uses 1 hour)
40c0b746e5SOllivier Robert$ntp'timeout = $FRAG_TIMEOUT; #';
41c0b746e5SOllivier Robert$ntp'timeout if 0;
42c0b746e5SOllivier Robert
43c0b746e5SOllivier Robert;######################################
44c0b746e5SOllivier Robert;# now process options
45c0b746e5SOllivier Robert;#
46c0b746e5SOllivier Robertsub usage
47c0b746e5SOllivier Robert{
48*2b15cb3dSCy Schubert    die("usage: $0 [-p <port>] [-l <logfile>] [host] ...\n");
49c0b746e5SOllivier Robert}
50c0b746e5SOllivier Robert
51c0b746e5SOllivier Robert&usage unless &Getopts('l:p:');
52c0b746e5SOllivier Robert&Getopts if 0;	# make -w happy
53c0b746e5SOllivier Robert
54*2b15cb3dSCy Schubert$opt_l = "/dev/null"	# where to write debug messages to
55*2b15cb3dSCy Schubert    if (!$opt_l);
56*2b15cb3dSCy Schubert$opt_p = 0		# port to use locally - (0 does mean: will be chosen by kernel)
57*2b15cb3dSCy Schubert    if (!$opt_p);
58*2b15cb3dSCy Schubert
59c0b746e5SOllivier Robert@Hosts = ($#ARGV < $[) ? ("localhost") : @ARGV;
60c0b746e5SOllivier Robert
61c0b746e5SOllivier Robert;# setup for debug output
62c0b746e5SOllivier Robert$DEBUGFILE=$opt_l;
63c0b746e5SOllivier Robert$DEBUGFILE="&STDERR" if $DEBUGFILE eq '-';
64c0b746e5SOllivier Robert
65c0b746e5SOllivier Robertopen(DEBUG,">>$DEBUGFILE") || die("Cannot open \"$DEBUGFILE\": $!\n");
66c0b746e5SOllivier Robertselect((select(DEBUG),$|=1)[$[]);
67c0b746e5SOllivier Robert
68c0b746e5SOllivier Robert;# &log prints a single trap record (adding a (local) time stamp)
69c0b746e5SOllivier Robertsub log
70c0b746e5SOllivier Robert{
71c0b746e5SOllivier Robert    chop($date=&ctime(time));
72c0b746e5SOllivier Robert    print "$date ",@_,"\n";
73c0b746e5SOllivier Robert}
74c0b746e5SOllivier Robert
75c0b746e5SOllivier Robertsub debug
76c0b746e5SOllivier Robert{
77c0b746e5SOllivier Robert    print DEBUG @_,"\n";
78c0b746e5SOllivier Robert}
79c0b746e5SOllivier Robert;#
80c0b746e5SOllivier Robert$proto_udp = (getprotobyname('udp'))[$[+2] ||
81c0b746e5SOllivier Robert		(warn("$0: Could not get protocoll number for 'udp' using 17"), 17);
82c0b746e5SOllivier Robert
83c0b746e5SOllivier Robert$ntp_port = (getservbyname('ntp','udp'))[$[+2] ||
84c0b746e5SOllivier Robert	      (warn("$0: Could not get port number for service ntp/udp using 123"), 123);
85c0b746e5SOllivier Robert
86c0b746e5SOllivier Robert;#
87c0b746e5SOllivier Robertsocket(S, &AF_INET, &SOCK_DGRAM, $proto_udp) || die("Cannot open socket: $!\n");
88c0b746e5SOllivier Robert
89c0b746e5SOllivier Robert;#
90c0b746e5SOllivier Robertbind(S, pack("S n a4 x8", &AF_INET, $opt_p, &INADDR_ANY)) ||
91c0b746e5SOllivier Robert    die("Cannot bind: $!\n");
92c0b746e5SOllivier Robert
93c0b746e5SOllivier Robert($my_port, $my_addr) = (unpack("S n a4 x8",getsockname(S)))[$[+1,$[+2];
94c0b746e5SOllivier Robert&log(sprintf("Listening at address %d.%d.%d.%d port %d",
95c0b746e5SOllivier Robert	     unpack("C4",$my_addr), $my_port));
96c0b746e5SOllivier Robert
97c0b746e5SOllivier Robert;# disregister with all servers in case of termination
98c0b746e5SOllivier Robertsub cleanup
99c0b746e5SOllivier Robert{
100c0b746e5SOllivier Robert    &log("Aborted by signal \"$_[$[]\"") if defined($_[$[]);
101c0b746e5SOllivier Robert
102c0b746e5SOllivier Robert    foreach (@Hosts)
103c0b746e5SOllivier Robert    {
104c0b746e5SOllivier Robert	if ( ! defined($Host{$_}) )
105c0b746e5SOllivier Robert	{
106c0b746e5SOllivier Robert		print "no info for host '$_'\n";
107c0b746e5SOllivier Robert		next;
108c0b746e5SOllivier Robert	}
109c0b746e5SOllivier Robert	&ntp'send(S,31,0,"",pack("Sna4x8",&AF_INET,$ntp_port,$Host{$_})); #';
110c0b746e5SOllivier Robert    }
111c0b746e5SOllivier Robert    close(S);
112c0b746e5SOllivier Robert    exit(2);
113c0b746e5SOllivier Robert}
114c0b746e5SOllivier Robert
115c0b746e5SOllivier Robert$SIG{'HUP'} = 'cleanup';
116c0b746e5SOllivier Robert$SIG{'INT'} = 'cleanup';
117c0b746e5SOllivier Robert$SIG{'QUIT'} = 'cleanup';
118c0b746e5SOllivier Robert$SIG{'TERM'} = 'cleanup';
119c0b746e5SOllivier Robert
120c0b746e5SOllivier Robert0 && $a && $b;
121c0b746e5SOllivier Robertsub timeouts			# sort timeout id array
122c0b746e5SOllivier Robert{
123c0b746e5SOllivier Robert    $TIMEOUTS{$a} <=> $TIMEOUTS{$b};
124c0b746e5SOllivier Robert}
125c0b746e5SOllivier Robert
126c0b746e5SOllivier Robert;# a Request element looks like: pack("a4SC",addr,associd,op)
127c0b746e5SOllivier Robert@Requests= ();
128c0b746e5SOllivier Robert
129c0b746e5SOllivier Robert;# compute requests for set trap control msgs to each host given
130c0b746e5SOllivier Robert{
131c0b746e5SOllivier Robert    local($name,$addr);
132c0b746e5SOllivier Robert
133c0b746e5SOllivier Robert    foreach (@Hosts)
134c0b746e5SOllivier Robert    {
135c0b746e5SOllivier Robert	if (/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/)
136c0b746e5SOllivier Robert	{
137c0b746e5SOllivier Robert	    ($name,$addr) =
138c0b746e5SOllivier Robert		(gethostbyaddr(pack("C4",$1,$2,$3,$4),&AF_INET))[$[,$[+4];
139c0b746e5SOllivier Robert	    unless (defined($name))
140c0b746e5SOllivier Robert	    {
141c0b746e5SOllivier Robert		$name = sprintf("[[%d.%d.%d.%d]]",$1,$2,$3,$4);
142c0b746e5SOllivier Robert		$addr = pack("C4",$1,$2,$3,$4);
143c0b746e5SOllivier Robert	    }
144c0b746e5SOllivier Robert	}
145c0b746e5SOllivier Robert	else
146c0b746e5SOllivier Robert	{
147c0b746e5SOllivier Robert	    ($name,$addr) = (gethostbyname($_))[$[,$[+4];
148c0b746e5SOllivier Robert	    unless (defined($name))
149c0b746e5SOllivier Robert	    {
150c0b746e5SOllivier Robert		warn "$0: unknown host \"$_\" - ignored\n";
151c0b746e5SOllivier Robert		next;
152c0b746e5SOllivier Robert	    }
153c0b746e5SOllivier Robert	}
154c0b746e5SOllivier Robert	next if defined($Host{$name});
155c0b746e5SOllivier Robert	$Host{$name} = $addr;
156c0b746e5SOllivier Robert	$Host{$_} = $addr;
157c0b746e5SOllivier Robert	push(@Requests,pack("a4SC",$addr,0,6));	# schedule a set trap request for $name
158c0b746e5SOllivier Robert    }
159c0b746e5SOllivier Robert}
160c0b746e5SOllivier Robert
161c0b746e5SOllivier Robertsub hostname
162c0b746e5SOllivier Robert{
163c0b746e5SOllivier Robert    local($addr) = @_;
164c0b746e5SOllivier Robert    return $HostName{$addr} if defined($HostName{$addr});
165c0b746e5SOllivier Robert    local($name) = gethostbyaddr($addr,&AF_INET);
166c0b746e5SOllivier Robert    &debug(sprintf("hostname(%d.%d.%d.%d) = \"%s\"",unpack("C4",$addr),$name))
167c0b746e5SOllivier Robert	if defined($name);
168c0b746e5SOllivier Robert    defined($name) && ($HostName{$addr} = $name) && (return $name);
169c0b746e5SOllivier Robert    &debug(sprintf("Failed to get name for %d.%d.%d.%d",unpack("C4",$addr)));
170c0b746e5SOllivier Robert    return sprintf("[%d.%d.%d.%d]",unpack("C4",$addr));
171c0b746e5SOllivier Robert}
172c0b746e5SOllivier Robert
173c0b746e5SOllivier Robert;# when no hosts were given on the commandline no requests have been scheduled
174c0b746e5SOllivier Robert&usage unless (@Requests);
175c0b746e5SOllivier Robert
176c0b746e5SOllivier Robert&debug(sprintf("%d request(s) scheduled",scalar(@Requests)));
177c0b746e5SOllivier Robertgrep(&debug("    - ".$_),keys(%Host));
178c0b746e5SOllivier Robert
179c0b746e5SOllivier Robert;# allocate variables;
180c0b746e5SOllivier Robert$addr="";
181c0b746e5SOllivier Robert$assoc=0;
182c0b746e5SOllivier Robert$op = 0;
183c0b746e5SOllivier Robert$timeout = 0;
184c0b746e5SOllivier Robert$ret="";
185c0b746e5SOllivier Robert%TIMEOUTS = ();
186c0b746e5SOllivier Robert%TIMEOUT_PROCS = ();
187c0b746e5SOllivier Robert@TIMEOUTS = ();
188c0b746e5SOllivier Robert
189c0b746e5SOllivier Robert$len = 512;
190c0b746e5SOllivier Robert$buf = " " x $len;
191c0b746e5SOllivier Robert
192c0b746e5SOllivier Robertwhile (1)
193c0b746e5SOllivier Robert{
194c0b746e5SOllivier Robert    if (@Requests || @TIMEOUTS)		# if there is some work pending
195c0b746e5SOllivier Robert    {
196c0b746e5SOllivier Robert	if (@Requests)
197c0b746e5SOllivier Robert	{
198c0b746e5SOllivier Robert	    ($addr,$assoc,$op) = unpack("a4SC",($req = shift(@Requests)));
199c0b746e5SOllivier Robert	    &debug(sprintf("Request: %s: %s(%d)",&hostname($addr), &ntp'cntrlop_name($op), $assoc)); #';))
200c0b746e5SOllivier Robert	    $ret = &ntp'send(S,$op,$assoc,"", #'(
201c0b746e5SOllivier Robert                             pack("Sna4x8",&AF_INET,$ntp_port,$addr));
202c0b746e5SOllivier Robert	    &set_timeout("retry-".unpack("H*",$req),time+$BASE_TIMEOUT,
203c0b746e5SOllivier Robert			 sprintf("&retry(\"%s\");",unpack("H*",$req)));
204c0b746e5SOllivier Robert
205c0b746e5SOllivier Robert	    last unless (defined($ret)); # warn called by ntp'send();
206c0b746e5SOllivier Robert
207c0b746e5SOllivier Robert	    ;# if there are more requests just have a quick look for new messages
208c0b746e5SOllivier Robert	    ;# otherwise grant server time for a response
209c0b746e5SOllivier Robert	    $timeout = @Requests ? 0 : $BASE_TIMEOUT;
210c0b746e5SOllivier Robert	}
211c0b746e5SOllivier Robert	if ($timeout && @TIMEOUTS)
212c0b746e5SOllivier Robert	{
213c0b746e5SOllivier Robert	    ;# ensure not to miss a timeout
214c0b746e5SOllivier Robert	    if ($timeout + time > $TIMEOUTS{$TIMEOUTS[$[]})
215c0b746e5SOllivier Robert	    {
216c0b746e5SOllivier Robert		$timeout = $TIMEOUTS{$TIMEOUTS[$[]} - time;
217c0b746e5SOllivier Robert		$timeout = 0 if $timeout < 0;
218c0b746e5SOllivier Robert	    }
219c0b746e5SOllivier Robert	}
220c0b746e5SOllivier Robert    }
221c0b746e5SOllivier Robert    else
222c0b746e5SOllivier Robert    {
223c0b746e5SOllivier Robert	;# no work yet - wait for some messages dropping in
224c0b746e5SOllivier Robert	;# usually this will not hapen as the refresh semantic will
225c0b746e5SOllivier Robert	;# always have a pending timeout
226c0b746e5SOllivier Robert	undef($timeout);
227c0b746e5SOllivier Robert    }
228c0b746e5SOllivier Robert
229c0b746e5SOllivier Robert    vec($mask="",fileno(S),1) = 1;
230c0b746e5SOllivier Robert    $ret = select($mask,undef,undef,$timeout);
231c0b746e5SOllivier Robert
232c0b746e5SOllivier Robert    warn("$0: select: $!\n"),last if $ret < 0;	# give up on error return from select
233c0b746e5SOllivier Robert
234c0b746e5SOllivier Robert    if ($ret == 0)
235c0b746e5SOllivier Robert    {
236c0b746e5SOllivier Robert	;# timeout
237c0b746e5SOllivier Robert	if (@TIMEOUTS && time > $TIMEOUTS{$TIMEOUTS[$[]})
238c0b746e5SOllivier Robert	{
239c0b746e5SOllivier Robert	    ;# handle timeout
240c0b746e5SOllivier Robert	    $timeout_proc =
241c0b746e5SOllivier Robert		(delete $TIMEOUT_PROCS{$TIMEOUTS[$[]},
242c0b746e5SOllivier Robert		 delete $TIMEOUTS{shift(@TIMEOUTS)})[$[];
243c0b746e5SOllivier Robert	    eval $timeout_proc;
244c0b746e5SOllivier Robert	    die "timeout eval (\"$timeout_proc\"): $@\n" if $@;
245c0b746e5SOllivier Robert	}
246c0b746e5SOllivier Robert	;# else: there may be something to be sent
247c0b746e5SOllivier Robert    }
248c0b746e5SOllivier Robert    else
249c0b746e5SOllivier Robert    {
250c0b746e5SOllivier Robert	;# data avail
251c0b746e5SOllivier Robert	$from = recv(S,$buf,$len,0);
252c0b746e5SOllivier Robert	;# give up on error return from recv
253c0b746e5SOllivier Robert	warn("$0: recv: $!\n"), last unless (defined($from));
254c0b746e5SOllivier Robert
255c0b746e5SOllivier Robert	$from = (unpack("Sna4",$from))[$[+2]; # keep host addr only
256c0b746e5SOllivier Robert	;# could check for ntp_port - but who cares
257c0b746e5SOllivier Robert	&debug("-Packet from ",&hostname($from));
258c0b746e5SOllivier Robert
259c0b746e5SOllivier Robert	;# stuff packet into ntp mode 6 receive machinery
260c0b746e5SOllivier Robert	($ret,$data,$status,$associd,$op,$seq,$auth_keyid) =
261c0b746e5SOllivier Robert	    &ntp'handle_packet($buf,$from); # ';
262c0b746e5SOllivier Robert	&debug(sprintf("%s uses auth_keyid %d",&hostname($from),$auth_keyid)) if defined($auth_keyid);
263c0b746e5SOllivier Robert	next unless defined($ret);
264c0b746e5SOllivier Robert
265c0b746e5SOllivier Robert	if ($ret eq "")
266c0b746e5SOllivier Robert	{
267c0b746e5SOllivier Robert	    ;# handle packet
268c0b746e5SOllivier Robert	    ;# simple trap response messages have neither timeout nor retries
269c0b746e5SOllivier Robert	    &clear_timeout("retry-".unpack("H*",pack("a4SC",$from,$associd,$op))) unless $op == 7;
270c0b746e5SOllivier Robert	    delete $RETRY{pack("a4SC",$from,$associd,$op)} unless $op == 7;
271c0b746e5SOllivier Robert
272c0b746e5SOllivier Robert	    &process_response($from,$ret,$data,$status,$associd,$op,$seq,$auth_keyid);
273c0b746e5SOllivier Robert	}
274c0b746e5SOllivier Robert	else
275c0b746e5SOllivier Robert	{
276c0b746e5SOllivier Robert	    ;# some kind of error
277c0b746e5SOllivier Robert	    &log(sprintf("%50s: %s: %s",(gethostbyaddr($from,&AF_INET))[$[],$ret,$data));
278c0b746e5SOllivier Robert	    if ($ret ne "TIMEOUT" && $ret ne "ERROR")
279c0b746e5SOllivier Robert	    {
280c0b746e5SOllivier Robert		&clear_timeout("retry-".unpack("H*",pack("a4SC",$from,$associd,$op)));
281c0b746e5SOllivier Robert	    }
282c0b746e5SOllivier Robert	}
283c0b746e5SOllivier Robert    }
284c0b746e5SOllivier Robert
285c0b746e5SOllivier Robert}
286c0b746e5SOllivier Robert
287c0b746e5SOllivier Robertwarn("$0: terminating\n");
288c0b746e5SOllivier Robert&cleanup;
289c0b746e5SOllivier Robertexit 0;
290c0b746e5SOllivier Robert
291c0b746e5SOllivier Robert;##################################################
292c0b746e5SOllivier Robert;# timeout support
293c0b746e5SOllivier Robert;#
294c0b746e5SOllivier Robertsub set_timeout
295c0b746e5SOllivier Robert{
296c0b746e5SOllivier Robert    local($id,$time,$proc) = @_;
297c0b746e5SOllivier Robert
298c0b746e5SOllivier Robert    $TIMEOUTS{$id} = $time;
299c0b746e5SOllivier Robert    $TIMEOUT_PROCS{$id} = $proc;
300c0b746e5SOllivier Robert    @TIMEOUTS = sort timeouts keys(%TIMEOUTS);
301c0b746e5SOllivier Robert    chop($date=&ctime($time));
302c0b746e5SOllivier Robert    &debug(sprintf("Schedule timeout \"%s\" for %s", $id, $date));
303c0b746e5SOllivier Robert}
304c0b746e5SOllivier Robert
305c0b746e5SOllivier Robertsub clear_timeout
306c0b746e5SOllivier Robert{
307c0b746e5SOllivier Robert    local($id) = @_;
308c0b746e5SOllivier Robert    delete $TIMEOUTS{$id};
309c0b746e5SOllivier Robert    delete $TIMEOUT_PROCS{$id};
310c0b746e5SOllivier Robert    @TIMEOUTS = sort timeouts keys(%TIMEOUTS);
311c0b746e5SOllivier Robert    &debug("Clear  timeout \"$id\"");
312c0b746e5SOllivier Robert}
313c0b746e5SOllivier Robert
314c0b746e5SOllivier Robert0 && &refresh;
315c0b746e5SOllivier Robertsub refresh
316c0b746e5SOllivier Robert{
317c0b746e5SOllivier Robert    local($addr) = @_[$[];
318c0b746e5SOllivier Robert    $addr = pack("H*",$addr);
319c0b746e5SOllivier Robert    &debug(sprintf("Refreshing trap for %s", &hostname($addr)));
320c0b746e5SOllivier Robert    push(@Requests,pack("a4SC",$addr,0,6));
321c0b746e5SOllivier Robert}
322c0b746e5SOllivier Robert
323c0b746e5SOllivier Robert0 && &retry;
324c0b746e5SOllivier Robertsub retry
325c0b746e5SOllivier Robert{
326c0b746e5SOllivier Robert    local($tag) = @_;
327c0b746e5SOllivier Robert    $tag = pack("H*",$tag);
328c0b746e5SOllivier Robert    $RETRY{$tag} = 0 if (!defined($RETRY{$tag}));
329c0b746e5SOllivier Robert
330c0b746e5SOllivier Robert    if (++$RETRY{$tag} > $MAX_TRY)
331c0b746e5SOllivier Robert    {
332c0b746e5SOllivier Robert	&debug(sprintf("Retry failed: %s assoc %5d op %d",
333c0b746e5SOllivier Robert		       &hostname(substr($tag,$[,4)),
334c0b746e5SOllivier Robert		       unpack("x4SC",$tag)));
335c0b746e5SOllivier Robert	return;
336c0b746e5SOllivier Robert    }
337c0b746e5SOllivier Robert    &debug(sprintf("Retrying: %s assoc %5d op %d",
338c0b746e5SOllivier Robert		       &hostname(substr($tag,$[,4)),
339c0b746e5SOllivier Robert		       unpack("x4SC",$tag)));
340c0b746e5SOllivier Robert    push(@Requests,$tag);
341c0b746e5SOllivier Robert}
342c0b746e5SOllivier Robert
343c0b746e5SOllivier Robertsub process_response
344c0b746e5SOllivier Robert{
345c0b746e5SOllivier Robert    local($from,$ret,$data,$status,$associd,$op,$seq,$auth_keyid) = @_;
346c0b746e5SOllivier Robert
347c0b746e5SOllivier Robert    $msg="";
348c0b746e5SOllivier Robert    if ($op == 7)		# trap response
349c0b746e5SOllivier Robert    {
350c0b746e5SOllivier Robert	$msg .= sprintf("%40s trap#%-5d",
351c0b746e5SOllivier Robert			&hostname($from),$seq);
352c0b746e5SOllivier Robert	&debug (sprintf("\nTrap %d associd %d:\n%s\n===============\n",$seq,$associd,$data));
353c0b746e5SOllivier Robert	if ($associd == 0)	# system event
354c0b746e5SOllivier Robert	{
355c0b746e5SOllivier Robert	    $msg .= "  SYSTEM   ";
356c0b746e5SOllivier Robert	    $evnt = &ntp'SystemEvent($status); #';
357c0b746e5SOllivier Robert	    $msg .= "$evnt ";
358c0b746e5SOllivier Robert	    ;# for special cases add additional info
359c0b746e5SOllivier Robert	    ($stratum) = ($data =~ /stratum=(\d+)/);
360c0b746e5SOllivier Robert	    ($refid) = ($data =~ /refid=([\w\.]+)/);
361c0b746e5SOllivier Robert	    $msg .= "stratum=$stratum refid=$refid";
362c0b746e5SOllivier Robert	    if ($refid =~ /\[?(\d+)\.(\d+)\.(\d+)\.(\d+)/)
363c0b746e5SOllivier Robert	    {
364c0b746e5SOllivier Robert		local($x) = (gethostbyaddr(pack("C4",$1,$2,$3,$4),&AF_INET));
365c0b746e5SOllivier Robert		$msg .= " " . $x if defined($x)
366c0b746e5SOllivier Robert	    }
367c0b746e5SOllivier Robert	    if ($evnt eq "event_sync_chg")
368c0b746e5SOllivier Robert	    {
369c0b746e5SOllivier Robert		$msg .= sprintf("%s %s ",
370c0b746e5SOllivier Robert				&ntp'LI($status), #',
371c0b746e5SOllivier Robert				&ntp'ClockSource($status) #'
372c0b746e5SOllivier Robert				);
373c0b746e5SOllivier Robert	    }
374c0b746e5SOllivier Robert	    elsif ($evnt eq "event_sync/strat_chg")
375c0b746e5SOllivier Robert	    {
376c0b746e5SOllivier Robert		($peer) = ($data =~ /peer=([0-9]+)/);
377c0b746e5SOllivier Robert		$msg .= " peer=$peer";
378c0b746e5SOllivier Robert	    }
379c0b746e5SOllivier Robert	    elsif ($evnt eq "event_clock_excptn")
380c0b746e5SOllivier Robert	    {
381c0b746e5SOllivier Robert		if (($device) = ($data =~ /device=\"([^\"]+)\"/))
382c0b746e5SOllivier Robert		{
383c0b746e5SOllivier Robert		    ($cstatus) = ($data =~ /refclockstatus=0?x?([\da-fA-F]+)/);
384c0b746e5SOllivier Robert		    $Cstatus = hex($cstatus);
385c0b746e5SOllivier Robert		    $msg .= sprintf("- %-32s",&ntp'clock_status($Cstatus)); #');
386c0b746e5SOllivier Robert		    ($timecode) = ($data =~ /timecode=\"([^\"]+)\"/);
387c0b746e5SOllivier Robert		    $msg .= " \"$device\" \"$timecode\"";
388c0b746e5SOllivier Robert		}
389c0b746e5SOllivier Robert		else
390c0b746e5SOllivier Robert		{
391c0b746e5SOllivier Robert		    push(@Requests,pack("a4SC",$from, $associd, 4));
392c0b746e5SOllivier Robert		}
393c0b746e5SOllivier Robert	    }
394c0b746e5SOllivier Robert	}
395c0b746e5SOllivier Robert	else			# peer event
396c0b746e5SOllivier Robert	{
397c0b746e5SOllivier Robert	    $msg .= sprintf("peer %5d ",$associd);
398c0b746e5SOllivier Robert	    ($srcadr) = ($data =~ /srcadr=\[?([\d\.]+)/);
399c0b746e5SOllivier Robert	    $msg .= sprintf("%-18s %40s ", "[$srcadr]",
400c0b746e5SOllivier Robert			    &hostname(pack("C4",split(/\./,$srcadr))));
401c0b746e5SOllivier Robert	    $evnt = &ntp'PeerEvent($status); #';
402c0b746e5SOllivier Robert	    $msg .= "$evnt ";
403c0b746e5SOllivier Robert	    ;# for special cases include additional info
404c0b746e5SOllivier Robert	    if ($evnt eq "event_clock_excptn")
405c0b746e5SOllivier Robert	    {
406c0b746e5SOllivier Robert		if (($device) = ($data =~ /device=\"([^\"]+)\"/))
407c0b746e5SOllivier Robert		{
408c0b746e5SOllivier Robert		    ;#&debug("----\n$data\n====\n");
409c0b746e5SOllivier Robert		    ($cstatus) = ($data =~ /refclockstatus=0?x?([\da-fA-F]+)/);
410c0b746e5SOllivier Robert		    $Cstatus = hex($cstatus);
411c0b746e5SOllivier Robert		    $msg .= sprintf("- %-32s",&ntp'clock_status($Cstatus)); #');
412c0b746e5SOllivier Robert		    ($timecode) = ($data =~ /timecode=\"([^\"]+)\"/);
413c0b746e5SOllivier Robert		    $msg .= " \"$device\" \"$timecode\"";
414c0b746e5SOllivier Robert		}
415c0b746e5SOllivier Robert		else
416c0b746e5SOllivier Robert		{
417c0b746e5SOllivier Robert		    ;# no clockvars included - post a cv request
418c0b746e5SOllivier Robert		    push(@Requests,pack("a4SC",$from, $associd, 4));
419c0b746e5SOllivier Robert		}
420c0b746e5SOllivier Robert	    }
421c0b746e5SOllivier Robert	    elsif ($evnt eq "event_stratum_chg")
422c0b746e5SOllivier Robert	    {
423c0b746e5SOllivier Robert		($stratum) = ($data =~ /stratum=(\d+)/);
424c0b746e5SOllivier Robert		$msg .= "new stratum $stratum";
425c0b746e5SOllivier Robert	    }
426c0b746e5SOllivier Robert	}
427c0b746e5SOllivier Robert    }
428c0b746e5SOllivier Robert    elsif ($op == 6)		# set trap resonse
429c0b746e5SOllivier Robert    {
430c0b746e5SOllivier Robert	&debug("Set trap ok from ",&hostname($from));
431c0b746e5SOllivier Robert	&set_timeout("refresh-".unpack("H*",$from),time+$REFRESH_TIME,
432c0b746e5SOllivier Robert		     sprintf("&refresh(\"%s\");",unpack("H*",$from)));
433c0b746e5SOllivier Robert	return;
434c0b746e5SOllivier Robert    }
435c0b746e5SOllivier Robert    elsif ($op == 4)		# read clock variables response
436c0b746e5SOllivier Robert    {
437c0b746e5SOllivier Robert	;# status of clock
438c0b746e5SOllivier Robert	$msg .= sprintf(" %40s ", &hostname($from));
439c0b746e5SOllivier Robert	if ($associd == 0)
440c0b746e5SOllivier Robert	{
441c0b746e5SOllivier Robert	    $msg .= "system clock status: ";
442c0b746e5SOllivier Robert	}
443c0b746e5SOllivier Robert	else
444c0b746e5SOllivier Robert	{
445c0b746e5SOllivier Robert	    $msg .= sprintf("peer %5d clock",$associd);
446c0b746e5SOllivier Robert	}
447c0b746e5SOllivier Robert	$msg .= sprintf("%-32s",&ntp'clock_status($status)); #');
448c0b746e5SOllivier Robert	($device) = ($data =~ /device=\"([^\"]+)\"/);
449c0b746e5SOllivier Robert	($timecode) = ($data =~ /timecode=\"([^\"]+)\"/);
450c0b746e5SOllivier Robert	$msg .= " \"$device\" \"$timecode\"";
451c0b746e5SOllivier Robert    }
452c0b746e5SOllivier Robert    elsif ($op == 31)		# unset trap response (UNOFFICIAL op)
453c0b746e5SOllivier Robert    {
454c0b746e5SOllivier Robert	;# clear timeout
455c0b746e5SOllivier Robert	&debug("Clear Trap ok from ",&hostname($from));
456c0b746e5SOllivier Robert	&clear_timeout("refresh-".unpack("H*",$from));
457c0b746e5SOllivier Robert	return;
458c0b746e5SOllivier Robert    }
459c0b746e5SOllivier Robert    else			# unexpected response
460c0b746e5SOllivier Robert    {
461c0b746e5SOllivier Robert	$msg .= "unexpected response to op $op assoc=$associd";
462c0b746e5SOllivier Robert	$msg .= sprintf(" status=%04x",$status);
463c0b746e5SOllivier Robert    }
464c0b746e5SOllivier Robert    &log($msg);
465c0b746e5SOllivier Robert}
466