Annotation of embedaddon/ntp/scripts/monitoring/ntp.pl, revision 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>