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