File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / scripts / monitoring / ntptrap
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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>