📄 ntptrap
字号:
#!/local/bin/perl --*-perl-*-;#;# ntptrap,v 3.1 1993/07/06 01:09:15 jbj Exp;#;# a client for the xntp mode 6 trap mechanism;#;# Copyright (c) 1992 ;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg;#;#;#############################################################$0 =~ s!^.*/([^/]+)$!\1!; # strip to filename;# enforce STDOUT and STDERR to be line buffered$| = 1;select((select(STDERR),$|=1)[$[]);;#######################################;# load utility routines and definitions;#require('ntp.pl'); # implementation of the NTP protocoleval { require('sys/socket.ph'); require('netinet/in.ph') unless defined(&INADDR_ANY); } ||do { die("$0: $@") unless $[ == index($@, "Can't locate "); warn "$0: $@"; warn "$0: supplying some default definitions\n"; eval 'sub INADDR_ANY { 0; } sub AF_INET {2;} sub SOCK_DGRAM {2;} 1;' || die "$0: $@";};require('getopts.pl'); # option parsingrequire('ctime.pl'); # date/time formatting;######################################;# define some global constants;#$BASE_TIMEOUT=10;$FRAG_TIMEOUT=10;$MAX_TRY = 5;$REFRESH_TIME=60*15; # 15 minutes (server uses 1 hour)$ntp'timeout = $FRAG_TIMEOUT; #';;######################################;# now process options;#sub usage{ die("usage: $0 [-n] [-p <port>] [-l <logfile>] [host] ...\n");}$opt_l = "/dev/null"; # where to write debug messages to$opt_p = 0; # port to use locally - (0 does mean: will be choosen by kernel)&usage unless &Getopts('l:p:');&Getopts if 0; # make -w happy@Hosts = ($#ARGV < $[) ? ("localhost") : @ARGV;;# setup for debug output$DEBUGFILE=$opt_l;$DEBUGFILE="&STDERR" if $DEBUGFILE eq '-';open(DEBUG,">>$DEBUGFILE") || die("Cannot open \"$DEBUGFILE\": $!\n");select((select(DEBUG),$|=1)[$[]);;# &log prints a single trap record (adding a (local) time stamp)sub log{ chop($date=&ctime(time)); print "$date ",@_,"\n";}sub debug{ print DEBUG @_,"\n";};# $proto_udp = (getprotobyname('udp'))[$[+2] || (warn("$0: Could not get protocoll number for 'udp' using 17"), 17);$ntp_port = (getservbyname('ntp','udp'))[$[+2] || (warn("$0: Could not get port number for service ntp/udp using 123"), 123);;# socket(S, &AF_INET, &SOCK_DGRAM, $proto_udp) || die("Cannot open socket: $!\n");;# bind(S, pack("S n N x8", &AF_INET, $opt_p, &INADDR_ANY)) || die("Cannot bind: $!\n");($my_port, $my_addr) = (unpack("S n a4 x8",getsockname(S)))[$[+1,$[+2];&log(sprintf("Listening at address %d.%d.%d.%d port %d", unpack("C4",$my_addr), $my_port));;# disregister with all servers in case of terminationsub cleanup{ &log("Aborted by signal \"$_[$[]\"") if defined($_[$[]); foreach (@Hosts) { &ntp'send(S,31,0,"",pack("Sna4x8",&AF_INET,$ntp_port,$Hosts{$_})); #'; } close(S); exit(2);}$SIG{'HUP'} = 'cleanup';$SIG{'INT'} = 'cleanup';$SIG{'QUIT'} = 'cleanup';$SIG{'TERM'} = 'cleanup';0 && $a && $b;sub timeouts # sort timeout id array{ $TIMEOUTS{$a} <=> $TIMEOUTS{$b};};# a Request element looks like: pack("a4SC",addr,associd,op)@Requests= ();;# compute requests for set trap control msgs to each host given{ local($name,$addr); foreach (@Hosts) { if (/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) { ($name,$addr) = (gethostbyaddr(pack("C4",$1,$2,$3,$4),&AF_INET))[$[,$[+4]; unless (defined($name)) { $name = sprintf("[[%d.%d.%d.%d]]",$1,$2,$3,$4); $addr = pack("C4",$1,$2,$3,$4); } } else { ($name,$addr) = (gethostbyname($_))[$[,$[+4]; unless (defined($name)) { warn "$0: unknown host \"$_\" - ignored\n"; next; } } next if defined($Host{$name}); $Host{$name} = $addr; push(@Requests,pack("a4SC",$addr,0,6)); # schedule a set trap request for $name }}sub hostname{ local($addr) = @_; return $HostName{$addr} if defined($HostName{$addr}); local($name) = gethostbyaddr($addr,&AF_INET); &debug(sprintf("hostname(%d.%d.%d.%d) = \"%s\"",unpack("C4",$addr),$name)) if defined($name); defined($name) && ($HostName{$addr} = $name) && (return $name); &debug(sprintf("Failed to get name for %d.%d.%d.%d",unpack("C4",$addr))); return sprintf("[%d.%d.%d.%d]",unpack("C4",$addr));};# when no hosts were given on the commandline no requests have been scheduled&usage unless (@Requests);&debug(sprintf("%d request(s) scheduled",scalar(@Requests)));grep(&debug(" - ".$_),keys(%Host));;# allocate variables;$addr="";$assoc=0;$op = 0;$timeout = 0;$ret="";%TIMEOUTS = ();%TIMEOUT_PROCS = ();@TIMEOUTS = (); $len = 512;$buf = " " x $len;while (1){ if (@Requests || @TIMEOUTS) # if there is some work pending { if (@Requests) { ($addr,$assoc,$op) = unpack("a4SC",($req = shift(@Requests))); &debug(sprintf("Request: %s: %s(%d)",&hostname($addr), &ntp'cntrlop_name($op), $assoc)); #';)) $ret = &ntp'send(S,$op,$assoc,"", #'( pack("Sna4x8",&AF_INET,$ntp_port,$addr)); &set_timeout("retry-".unpack("H*",$req),time+$BASE_TIMEOUT, sprintf("&retry(\"%s\");",unpack("H*",$req))); last unless (defined($ret)); # warn called by ntp'send(); ;# if there are more requests just have a quick look for new messages ;# otherwise grant server time for a response $timeout = @Requests ? 0 : $BASE_TIMEOUT; } if ($timeout && @TIMEOUTS) { ;# ensure not to miss a timeout if ($timeout + time > $TIMEOUTS{$TIMEOUTS[$[]}) { $timeout = $TIMEOUTS{$TIMEOUTS[$[]} - time; $timeout = 0 if $timeout < 0; } } } else { ;# no work yet - wait for some messages dropping in ;# usually this will not hapen as the refresh semantic will ;# always have a pending timeout undef($timeout); } vec($mask="",fileno(S),1) = 1; $ret = select($mask,undef,undef,$timeout); warn("$0: select: $!\n"),last if $ret < 0; # give up on error return from select if ($ret == 0) { ;# timeout if (@TIMEOUTS && time > $TIMEOUTS{$TIMEOUTS[$[]}) { ;# handle timeout $timeout_proc = (delete $TIMEOUT_PROCS{$TIMEOUTS[$[]}, delete $TIMEOUTS{shift(@TIMEOUTS)})[$[]; eval $timeout_proc; die "timeout eval (\"$timeout_proc\"): $@\n" if $@; } ;# else: there may be something to be sent } else { ;# data avail $from = recv(S,$buf,$len,0); ;# give up on error return from recv warn("$0: recv: $!\n"), last unless (defined($from)); $from = (unpack("Sna4",$from))[$[+2]; # keep host addr only ;# could check for ntp_port - but who cares &debug("-Packet from ",&hostname($from)); ;# stuff packet into ntp mode 6 receive machinery ($ret,$data,$status,$associd,$op,$seq,$auth_keyid) = &ntp'handle_packet($buf,$from); # '; &debug(sprintf("%s uses auth_keyid %d",&hostname($from),$auth_keyid)) if defined($auth_keyid); next unless defined($ret); if ($ret eq "") { ;# handle packet ;# simple trap response messages have neither timeout nor retries &clear_timeout("retry-".unpack("H*",pack("a4SC",$from,$associd,$op))) unless $op == 7; delete $RETRY{pack("a4SC",$from,$associd,$op)} unless $op == 7; &process_response($from,$ret,$data,$status,$associd,$op,$seq,$auth_keyid); } else { ;# some kind of error &log(sprintf("%50s: %s: %s",(gethostbyaddr($from,&AF_INET))[$[],$ret,$data)); if ($ret ne "TIMEOUT" && $ret ne "ERROR") { &clear_timeout("retry-".unpack("H*",pack("a4SC",$from,$associd,$op))); } } } }warn("$0: terminating\n");&cleanup;exit 0;;##################################################;# timeout support;#sub set_timeout{ local($id,$time,$proc) = @_; $TIMEOUTS{$id} = $time; $TIMEOUT_PROCS{$id} = $proc; @TIMEOUTS = sort timeouts keys(%TIMEOUTS); chop($date=&ctime($time)); &debug(sprintf("Schedule timeout \"%s\" for %s", $id, $date));}sub clear_timeout{ local($id) = @_; delete $TIMEOUTS{$id}; delete $TIMEOUT_PROCS{$id}; @TIMEOUTS = sort timeouts keys(%TIMEOUTS); &debug("Clear timeout \"$id\"");}0 && &refresh;sub refresh{ local($addr) = @_; $addr = pack("H*",$addr); &debug(sprintf("Refreshing trap for %s", &hostname($addr))); push(@Requests,pack("a4SC",$addr,0,6));}0 && &retry;sub retry{ local($tag) = @_; $tag = pack("H*",$tag); $RETRY{$tag} = 0 if (!defined($RETRY{$tag})); if (++$RETRY{$tag} > $MAX_TRY) { &debug(sprintf("Retry failed: %s assoc %5d op %d", &hostname(substr($tag,$[,4)), unpack("x4SC",$tag))); return; } &debug(sprintf("Retrying: %s assoc %5d op %d", &hostname(substr($tag,$[,4)), unpack("x4SC",$tag))); push(@Requests,$tag);}sub process_response{ local($from,$ret,$data,$status,$associd,$op,$seq,$auth_keyid) = @_; $msg=""; if ($op == 7) # trap response { $msg .= sprintf("%40s trap#%-5d", &hostname($from),$seq); &debug (sprintf("\nTrap %d associd %d:\n%s\n===============\n",$seq,$associd,$data)); if ($associd == 0) # system event { $msg .= " SYSTEM "; $evnt = &ntp'SystemEvent($status); #'; $msg .= "$evnt "; ;# for special cases add additional info ($stratum) = ($data =~ /stratum=(\d+)/); ($refid) = ($data =~ /refid=([\w\.]+)/); $msg .= "stratum=$stratum refid=$refid"; if ($refid =~ /\[?(\d+)\.(\d+)\.(\d+)\.(\d+)/) { $msg .= " " . (gethostbyaddr(pack("C4",$1,$2,$3,$4),&AF_INET))[$[]; } if ($evnt eq "event_sync_chg") { $msg .= sprintf("%s %s ", &ntp'LI($status), #', &ntp'ClockSource($status) #' ); } elsif ($evnt eq "event_sync/strat_chg") { ($peer) = ($data =~ /peer=([0-9]+)/); $msg .= " peer=$peer"; } elsif ($evnt eq "event_clock_excptn") { if (($device) = ($data =~ /device=\"([^\"]+)\"/)) { ($cstatus) = ($data =~ /refclockstatus=0?x?([\da-fA-F]+)/); $Cstatus = hex($cstatus); $msg .= sprintf("- %-32s",&ntp'clock_status($Cstatus)); #'); ($timecode) = ($data =~ /timecode=\"([^\"]+)\"/); $msg .= " \"$device\" \"$timecode\""; } else { push(@Requests,pack("a4SC",$from, $associd, 4)); } } } else # peer event { $msg .= sprintf("peer %5d ",$associd); ($srcadr) = ($data =~ /srcadr=\[?([\d\.]+)/); $msg .= sprintf("%-18s %40s ", "[$srcadr]", &hostname(pack("C4",split(/\./,$srcadr)))); $evnt = &ntp'PeerEvent($status); #'; $msg .= "$evnt "; ;# for special cases include additional info if ($evnt eq "event_clock_excptn") { if (($device) = ($data =~ /device=\"([^\"]+)\"/)) { ;#&debug("----\n$data\n====\n"); ($cstatus) = ($data =~ /refclockstatus=0?x?([\da-fA-F]+)/); $Cstatus = hex($cstatus); $msg .= sprintf("- %-32s",&ntp'clock_status($Cstatus)); #'); ($timecode) = ($data =~ /timecode=\"([^\"]+)\"/); $msg .= " \"$device\" \"$timecode\""; } else { ;# no clockvars included - post a cv request push(@Requests,pack("a4SC",$from, $associd, 4)); } } elsif ($evnt eq "event_stratum_chg") { ($stratum) = ($data =~ /stratum=(\d+)/); $msg .= "new stratum $stratum"; } } } elsif ($op == 6) # set trap resonse { &debug("Set trap ok from ",&hostname($from)); &set_timeout("refresh-".unpack("H*",$from),time+$REFRESH_TIME, sprintf("&refresh(\"%s\");",unpack("H*",$from))); return; } elsif ($op == 4) # read clock variables response { ;# status of clock $msg .= sprintf(" %40s ", &hostname($from)); if ($associd == 0) { $msg .= "system clock status: "; } else { $msg .= sprintf("peer %5d clock",$associd); } $msg .= sprintf("%-32s",&ntp'clock_status($status)); #'); ($device) = ($data =~ /device=\"([^\"]+)\"/); ($timecode) = ($data =~ /timecode=\"([^\"]+)\"/); $msg .= " \"$device\" \"$timecode\""; } elsif ($op == 31) # unset trap response (UNOFFICIAL op) { ;# clear timeout &debug("Clear Trap ok from ",&hostname($from)); &clear_timeout("refresh-".unpack("H*",$from)); return; } else # unexpected response { $msg .= "unexpected response to op $op assoc=$associd"; $msg .= sprintf(" status=%04x",$status); } &log($msg);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -