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