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