Annotation of embedaddon/ntp/scripts/monitoring/ntp.pl, revision 1.1.1.1
1.1 misho 1: #!/usr/bin/perl -w
2: ;#
3: ;# ntp.pl,v 3.1 1993/07/06 01:09:09 jbj Exp
4: ;#
5: ;# process loop filter statistics file and either
6: ;# - show statistics periodically using gnuplot
7: ;# - or print a single plot
8: ;#
9: ;# Copyright (c) 1992
10: ;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg
11: ;#
12: ;#
13: ;#############################################################
14:
15: package ntp;
16:
17: $NTP_version = 2;
18: $ctrl_mode=6;
19:
20: $byte1 = (($NTP_version & 0x7)<< 3) & 0x34 | ($ctrl_mode & 0x7);
21: $MAX_DATA = 468;
22:
23: $sequence = 0; # initial sequence number incred before used
24: $pad=4;
25: $do_auth=0; # no possibility today
26: $keyid=0;
27: ;#list if known keys (passwords)
28: %KEYS = ( 0, "\200\200\200\200\200\200\200\200",
29: );
30:
31: ;#-----------------------------------------------------------------------------
32: ;# access routines for ntp control packet
33: ;# NTP control message format
34: ;# C LI|VN|MODE LI 2bit=00 VN 3bit=2(3) MODE 3bit=6 : $byte1
35: ;# C R|E|M|Op R response E error M more Op opcode
36: ;# n sequence
37: ;# n status
38: ;# n associd
39: ;# n offset
40: ;# n count
41: ;# a+ data (+ padding)
42: ;# optional authentication data
43: ;# N key
44: ;# N2 checksum
45:
46: ;# first byte of packet
47: sub pkt_LI { return ($_[$[] >> 6) & 0x3; }
48: sub pkt_VN { return ($_[$[] >> 3) & 0x7; }
49: sub pkt_MODE { return ($_[$[] ) & 0x7; }
50:
51: ;# second byte of packet
52: sub pkt_R { return ($_[$[] & 0x80) == 0x80; }
53: sub pkt_E { return ($_[$[] & 0x40) == 0x40; }
54: sub pkt_M { return ($_[$[] & 0x20) == 0x20; }
55: sub pkt_OP { return $_[$[] & 0x1f; }
56:
57: ;#-----------------------------------------------------------------------------
58:
59: sub setkey
60: {
61: local($id,$key) = @_;
62:
63: $KEYS{$id} = $key if (defined($key));
64: if (! defined($KEYS{$id}))
65: {
66: warn "Key $id not yet specified - key not changed\n";
67: return undef;
68: }
69: return ($keyid,$keyid = $id)[$[];
70: }
71:
72: ;#-----------------------------------------------------------------------------
73: sub numerical { $a <=> $b; }
74:
75: ;#-----------------------------------------------------------------------------
76:
77: sub send #'
78: {
79: local($fh,$opcode, $associd, $data,$address) = @_;
80: $fh = caller(0)."'$fh";
81:
82: local($junksize,$junk,$packet,$offset,$ret);
83: $offset = 0;
84:
85: $sequence++;
86: while(1)
87: {
88: $junksize = length($data);
89: $junksize = $MAX_DATA if $junksize > $MAX_DATA;
90:
91: ($junk,$data) = $data =~ /^(.{$junksize})(.*)$/;
92: $packet
93: = pack("C2n5a".(($junk eq "") ? 0 : &pad($junksize+12,$pad)-12),
94: $byte1,
95: ($opcode & 0x1f) | ($data ? 0x20 : 0),
96: $sequence,
97: 0, $associd,
98: $offset, $junksize, $junk);
99: if ($do_auth)
100: {
101: ;# not yet
102: }
103: $offset += $junksize;
104:
105: if (defined($address))
106: {
107: $ret = send($fh, $packet, 0, $address);
108: }
109: else
110: {
111: $ret = send($fh, $packet, 0);
112: }
113:
114: if (! defined($ret))
115: {
116: warn "send failed: $!\n";
117: return undef;
118: }
119: elsif ($ret != length($packet))
120: {
121: warn "send failed: sent only $ret from ".length($packet). "bytes\n";
122: return undef;
123: }
124: return $sequence unless $data;
125: }
126: }
127:
128: ;#-----------------------------------------------------------------------------
129: ;# status interpretation
130: ;#
131: sub getval
132: {
133: local($val,*list) = @_;
134:
135: return $list{$val} if defined($list{$val});
136: return sprintf("%s#%d",$list{"-"},$val) if defined($list{"-"});
137: return "unknown-$val";
138: }
139:
140: ;#---------------------------------
141: ;# system status
142: ;#
143: ;# format: |LI|CS|SECnt|SECode| LI=2bit CS=6bit SECnt=4bit SECode=4bit
144: sub ssw_LI { return ($_[$[] >> 14) & 0x3; }
145: sub ssw_CS { return ($_[$[] >> 8) & 0x3f; }
146: sub ssw_SECnt { return ($_[$[] >> 4) & 0xf; }
147: sub ssw_SECode { return $_[$[] & 0xf; }
148:
149: %LI = ( 0, "leap_none", 1, "leap_add_sec", 2, "leap_del_sec", 3, "sync_alarm", "-", "leap");
150: %ClockSource = (0, "sync_unspec",
151: 1, "sync_lf_clock",
152: 2, "sync_uhf_clock",
153: 3, "sync_hf_clock",
154: 4, "sync_local_proto",
155: 5, "sync_ntp",
156: 6, "sync_udp/time",
157: 7, "sync_wristwatch",
158: "-", "ClockSource",
159: );
160:
161: %SystemEvent = (0, "event_unspec",
162: 1, "event_restart",
163: 2, "event_fault",
164: 3, "event_sync_chg",
165: 4, "event_sync/strat_chg",
166: 5, "event_clock_reset",
167: 6, "event_bad_date",
168: 7, "event_clock_excptn",
169: "-", "event",
170: );
171: sub LI
172: {
173: &getval(&ssw_LI($_[$[]),*LI);
174: }
175: sub ClockSource
176: {
177: &getval(&ssw_CS($_[$[]),*ClockSource);
178: }
179:
180: sub SystemEvent
181: {
182: &getval(&ssw_SECode($_[$[]),*SystemEvent);
183: }
184:
185: sub system_status
186: {
187: return sprintf("%s, %s, %d event%s, %s", &LI($_[$[]), &ClockSource($_[$[]),
188: &ssw_SECnt($_[$[]), ((&ssw_SECnt($_[$[])==1) ? "" : "s"),
189: &SystemEvent($_[$[]));
190: }
191: ;#---------------------------------
192: ;# peer status
193: ;#
194: ;# format: |PStat|PSel|PCnt|PCode| Pstat=6bit PSel=2bit PCnt=4bit PCode=4bit
195: sub psw_PStat_config { return ($_[$[] & 0x8000) == 0x8000; }
196: sub psw_PStat_authenable { return ($_[$[] & 0x4000) == 0x4000; }
197: sub psw_PStat_authentic { return ($_[$[] & 0x2000) == 0x2000; }
198: sub psw_PStat_reach { return ($_[$[] & 0x1000) == 0x1000; }
199: sub psw_PStat_sane { return ($_[$[] & 0x0800) == 0x0800; }
200: sub psw_PStat_dispok { return ($_[$[] & 0x0400) == 0x0400; }
201: sub psw_PStat { return ($_[$[] >> 10) & 0x3f; }
202: sub psw_PSel { return ($_[$[] >> 8) & 0x3; }
203: sub psw_PCnt { return ($_[$[] >> 4) & 0xf; }
204: sub psw_PCode { return $_[$[] & 0xf; }
205:
206: %PeerSelection = (0, "sel_reject",
207: 1, "sel_candidate",
208: 2, "sel_selcand",
209: 3, "sel_sys.peer",
210: "-", "PeerSel",
211: );
212: %PeerEvent = (0, "event_unspec",
213: 1, "event_ip_err",
214: 2, "event_authen",
215: 3, "event_unreach",
216: 4, "event_reach",
217: 5, "event_clock_excptn",
218: 6, "event_stratum_chg",
219: "-", "event",
220: );
221:
222: sub PeerSelection
223: {
224: &getval(&psw_PSel($_[$[]),*PeerSelection);
225: }
226:
227: sub PeerEvent
228: {
229: &getval(&psw_PCode($_[$[]),*PeerEvent);
230: }
231:
232: sub peer_status
233: {
234: local($x) = ("");
235: $x .= "config," if &psw_PStat_config($_[$[]);
236: $x .= "authenable," if &psw_PStat_authenable($_[$[]);
237: $x .= "authentic," if &psw_PStat_authentic($_[$[]);
238: $x .= "reach," if &psw_PStat_reach($_[$[]);
239: $x .= &psw_PStat_sane($_[$[]) ? "sane," : "insane,";
240: $x .= "hi_disp," unless &psw_PStat_dispok($_[$[]);
241:
242: $x .= sprintf(" %s, %d event%s, %s", &PeerSelection($_[$[]),
243: &psw_PCnt($_[$[]), ((&psw_PCnt($_[$[]) == 1) ? "" : "s"),
244: &PeerEvent($_[$[]));
245: return $x;
246: }
247:
248: ;#---------------------------------
249: ;# clock status
250: ;#
251: ;# format: |CStat|CEvnt| CStat=8bit CEvnt=8bit
252: sub csw_CStat { return ($_[$[] >> 8) & 0xff; }
253: sub csw_CEvnt { return $_[$[] & 0xff; }
254:
255: %ClockStatus = (0, "clk_nominal",
256: 1, "clk_timeout",
257: 2, "clk_badreply",
258: 3, "clk_fault",
259: 4, "clk_prop",
260: 5, "clk_baddate",
261: 6, "clk_badtime",
262: "-", "clk",
263: );
264:
265: sub clock_status
266: {
267: return sprintf("%s, last %s",
268: &getval(&csw_CStat($_[$[]),*ClockStatus),
269: &getval(&csw_CEvnt($_[$[]),*ClockStatus));
270: }
271:
272: ;#---------------------------------
273: ;# error status
274: ;#
275: ;# format: |Err|reserved| Err=8bit
276: ;#
277: sub esw_Err { return ($_[$[] >> 8) & 0xff; }
278:
279: %ErrorStatus = (0, "err_unspec",
280: 1, "err_auth_fail",
281: 2, "err_invalid_fmt",
282: 3, "err_invalid_opcode",
283: 4, "err_unknown_assoc",
284: 5, "err_unknown_var",
285: 6, "err_invalid_value",
286: 7, "err_adm_prohibit",
287: );
288:
289: sub error_status
290: {
291: return sprintf("%s", &getval(&esw_Err($_[$[]),*ErrorStatus));
292: }
293:
294: ;#-----------------------------------------------------------------------------
295: ;#
296: ;# cntrl op name translation
297:
298: %CntrlOpName = (1, "read_status",
299: 2, "read_variables",
300: 3, "write_variables",
301: 4, "read_clock_variables",
302: 5, "write_clock_variables",
303: 6, "set_trap",
304: 7, "trap_response",
305: 31, "unset_trap", # !!! unofficial !!!
306: "-", "cntrlop",
307: );
308:
309: sub cntrlop_name
310: {
311: return &getval($_[$[],*CntrlOpName);
312: }
313:
314: ;#-----------------------------------------------------------------------------
315:
316: $STAT_short_pkt = 0;
317: $STAT_pkt = 0;
318:
319: ;# process a NTP control message (response) packet
320: ;# returns a list ($ret,$data,$status,$associd,$op,$seq,$auth_keyid)
321: ;# $ret: undef --> not yet complete
322: ;# "" --> complete packet received
323: ;# "ERROR" --> error during receive, bad packet, ...
324: ;# else --> error packet - list may contain useful info
325:
326:
327: sub handle_packet
328: {
329: local($pkt,$from) = @_; # parameters
330: local($len_pkt) = (length($pkt));
331: ;# local(*FRAGS,*lastseen);
332: local($li_vn_mode,$r_e_m_op,$seq,$status,$associd,$offset,$count,$data);
333: local($autch_keyid,$auth_cksum);
334:
335: $STAT_pkt++;
336: if ($len_pkt < 12)
337: {
338: $STAT_short_pkt++;
339: return ("ERROR","short packet received");
340: }
341:
342: ;# now break packet apart
343: ($li_vn_mode,$r_e_m_op,$seq,$status,$associd,$offset,$count,$data) =
344: unpack("C2n5a".($len_pkt-12),$pkt);
345: $data=substr($data,$[,$count);
346: if ((($len_pkt - 12) - &pad($count,4)) >= 12)
347: {
348: ;# looks like an authenticator
349: ($auth_keyid,$auth_cksum) =
350: unpack("Na8",substr($pkt,$len_pkt-12+$[,12));
351: $STAT_auth++;
352: ;# no checking of auth_cksum (yet ?)
353: }
354:
355: if (&pkt_VN($li_vn_mode) != $NTP_version)
356: {
357: $STAT_bad_version++;
358: return ("ERROR","version ".&pkt_VN($li_vn_mode)."packet ignored");
359: }
360:
361: if (&pkt_MODE($li_vn_mode) != $ctrl_mode)
362: {
363: $STAT_bad_mode++;
364: return ("ERROR", "mode ".&pkt_MODE($li_vn_mode)." packet ignored");
365: }
366:
367: ;# handle single fragment fast
368: if ($offset == 0 && &pkt_M($r_e_m_op) == 0)
369: {
370: $STAT_single_frag++;
371: if (&pkt_E($r_e_m_op))
372: {
373: $STAT_err_pkt++;
374: return (&error_status($status),
375: $data,$status,$associd,&pkt_OP($r_e_m_op),$seq,
376: $auth_keyid);
377: }
378: else
379: {
380: return ("",
381: $data,$status,$associd,&pkt_OP($r_e_m_op),$seq,
382: $auth_keyid);
383: }
384: }
385: else
386: {
387: ;# fragment - set up local name space
388: $id = "$from$seq".&pkt_OP($r_e_m_op);
389: $ID{$id} = 1;
390: *FRAGS = "$id FRAGS";
391: *lastseen = "$id lastseen";
392:
393: $STAT_frag++;
394:
395: $lastseen = 1 if !&pkt_M($r_e_m_op);
396: if (!defined(%FRAGS))
397: {
398: print((&pkt_M($r_e_m_op) ? " more" : "")."\n");
399: $FRAGS{$offset} = $data;
400: ;# save other info
401: @FRAGS = ($status,$associd,&pkt_OP($r_e_m_op),$seq,$auth_keyid,$r_e_m_op);
402: }
403: else
404: {
405: print((&pkt_M($r_e_m_op) ? " more" : "")."\n");
406: ;# add frag to previous - combine on the fly
407: if (defined($FRAGS{$offset}))
408: {
409: $STAT_dup_frag++;
410: return ("ERROR","duplicate fragment at $offset seq=$seq");
411: }
412:
413: $FRAGS{$offset} = $data;
414:
415: undef($loff);
416: foreach $off (sort numerical keys(%FRAGS))
417: {
418: next unless defined($FRAGS{$off});
419: if (defined($loff) &&
420: ($loff + length($FRAGS{$loff})) == $off)
421: {
422: $FRAGS{$loff} .= $FRAGS{$off};
423: delete $FRAGS{$off};
424: last;
425: }
426: $loff = $off;
427: }
428:
429: ;# return packet if all frags arrived
430: ;# at most two frags with possible padding ???
431: if ($lastseen && defined($FRAGS{0}) &&
432: (((scalar(@x=sort numerical keys(%FRAGS)) == 2) &&
433: (length($FRAGS{0}) + 8) > $x[$[+1]) ||
434: (scalar(@x=sort numerical keys(%FRAGS)) < 2)))
435: {
436: @x=((&pkt_E($r_e_m_op) ? &error_status($status) : ""),
437: $FRAGS{0},@FRAGS);
438: &pkt_E($r_e_m_op) ? $STAT_err_frag++ : $STAT_frag_all++;
439: undef(%FRAGS);
440: undef(@FRAGS);
441: undef($lastseen);
442: delete $ID{$id};
443: &main'clear_timeout($id);
444: return @x;
445: }
446: else
447: {
448: &main'set_timeout($id,time+$timeout,"&ntp'handle_packet_timeout(\"".unpack("H*",$id)."\");"); #'";
449: }
450: }
451: return (undef);
452: }
453: }
454:
455: sub handle_packet_timeout
456: {
457: local($id) = @_;
458: local($r_e_m_op,*FRAGS,*lastseen,@x) = (@FRAGS[$[+5]);
459:
460: *FRAGS = "$id FRAGS";
461: *lastseen = "$id lastseen";
462:
463: @x=((&pkt_E($r_e_m_op) ? &error_status($status) : "TIMEOUT"),
464: $FRAGS{0},@FRAGS[$[ .. $[+4]);
465: $STAT_frag_timeout++;
466: undef(%FRAGS);
467: undef(@FRAGS);
468: undef($lastseen);
469: delete $ID{$id};
470: return @x;
471: }
472:
473:
474: sub pad
475: {
476: return $_[$[+1] * int(($_[$[] + $_[$[+1] - 1) / $_[$[+1]);
477: }
478:
479: 1;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>