a \dk@sdZddlmZmZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl Z ddlZddlZddlZddlZddlZdZdZdZdZdZd Zd Zd Zd ZGd ddZGdddeZGdddeZ GdddeZ!GdddZ"dZ#dZ$dZ%dZ&dZ'dZ(dZ)dZ*dZ+d Z,d!Z-d"Z.d#Z/d$Z0d%Z1d&Z2d'Z3d(Z4d)Z5d*Z6d+Z7d,Z8d-Z9d.Z:d/Z;e jGd4d5d5Z?Gd6d7d7eZ@Gd8d9d9ZAd:d;ZBdd?ZDd@dAZEdBdCZFGdDdEdEZGdS)Fa( packet.py - definitions and classes for Python querying of NTP Freely translated from the old C ntpq code by ESR, with comments preserved. The idea was to cleanly separate ntpq-that-was into a thin front-end layer handling mainly command interpretation and a back-end that presents the take from ntpd as objects that can be re-used by other front ends. Other reusable pieces live in util.py. This code should be Python2-vs-Python-3 agnostic. Keep it that way! Here are some pictures to help make sense of this code. First, from RFC 5905, the general structure of an NTP packet (Figure 8): 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |LI | VN |Mode | Stratum | Poll | Precision | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Root Delay | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Root Dispersion | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Reference ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + Reference Timestamp (64) + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + Origin Timestamp (64) + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + Receive Timestamp (64) + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + Transmit Timestamp (64) + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | . . . Extension Field 1 (variable) . . . | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | . . . Extension Field 2 (variable) . . . | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Key Identifier | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | digest (128) | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ The fixed header is 48 bytes long. The simplest possible case of an NTP packet is the minimal SNTP request, a mode 3 packet with the Stratum and all following fields zeroed out to byte 47. How to interpret these fields: The modes are as follows: +-------+--------------------------+ | Value | Meaning | +-------+--------------------------+ | 0 | reserved | | 1 | symmetric active | | 2 | symmetric passive | | 3 | client | | 4 | server | | 5 | broadcast | | 6 | NTP control message | | 7 | reserved for private use | +-------+--------------------------+ While the Stratum field has 8 bytes, only values 0-16 (low 5 bits) are legal. Value 16 means 'unsynchronized' Values 17-255 are reserved. LI (Leap Indicator), Version, Poll, and Precision are not described here; see RFC 5905. t_1, the origin timestamp, is the time according to the client at which the request was sent. t_2, the receive timestamp, is the time according to the server at which the request was received. t_3, the transmit timestamp, is the time according to the server at which the reply was sent. You also need t_4, the destination timestamp, which is the time according to the client at which the reply was received. This is not in the reply packet, it's the packet receipt time collected by the client. The 'Reference timestamp' is an unused historical relic. It's supposed to be copied unchanged from upstream in the stratum hierarchy. Normal practice has been for Stratum 1 servers to fill it in with the raw timestamp from the most recent reference-clock. Theta is the thing we want to estimate: the offset between the server clock and the client clock. The sign convention is that theta is positive if the server is ahead of the client. Theta is estimated by [(t_2-t_1)+(t_3-t_4)]/2. The accuracy of this estimate is predicated upon network latency being symmetrical. Delta is the network round trip time, i.e. (t_4-t_1)-(t_3-t_2). Here's how the terms work: (t_4-t_1) is the total time that the request was in flight, and (t_3-t_2) is the time that the server spent processing it; when you subtract that out you're left with just network delays. Lambda nominally represents the maximum amount by which theta could be off. It's computed as delta/2 + epsilon. The delta/2 term usually dominates and represents the maximum amount by which network asymmetry could be throwing off the calculation. Epsilon is the sum of three other sources of error: rho_r: the (im)precision field from response packet, representing the server's inherent error in clock measurement. rho_s: the client's own (im)precision. PHI*(t_4-t_1): The amount by which the client's clock may plausibly have drifted while the packet was in flight. PHI is taken to be a constant of 15ppm. rho_r and rho_s are estimated by making back-to-back calls to clock_gettime() (or similar) and taking their difference. They're encoded on the wire as an eight-bit two's complement integer representing, to the nearest integer, log_2 of the value in seconds. If you look at the raw data, there are 3 unknowns: * transit time client to server * transit time server to client * clock offset but there are only two equations, so you can't solve it. NTP gets the 3rd equation by assuming the transit times are equal. That lets it solve for the clock offset. If you assume that both clocks are accurate which is reasonable if you have GPS at both ends, then you can easily solve for the transit times in each direction. The RFC 5905 diagram is slightly out of date in that the digest header assumes a 128-bit (16-octet) MD5 hash, but it is also possible for the field to be a 128-bit AES_CMAC hash or 160-bit (20-octet) SHA-1 hash. NTPsec will support any 128- or 160-bit MAC type in libcrypto. An extension field consists of a 16-bit network-order type field length, followed by a 16-bit network-order payload length in octets, followed by the payload (which must be padded to a 4-octet boundary). 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type field | Payload length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | Payload (variable) | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Here's what a Mode 6 packet looks like: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |LI | VN | 6 |R|E|M| Opcode | Sequence | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Status | Association ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Offset | Count | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | . . . Payload (variable) . . . | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Key Identifier | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | digest (128) | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ In this case, the fixed header is 24 bytes long. R = Response bit E = Error bit M = More bit. A Mode 6 packet cannot have extension fields. )print_functiondivisionN ii i c@sreZdZdZeddZeddZejj ejj dfddZ e d d Z e jd d Z d d ZddZddZdS)PacketzEncapsulate an NTP fragmentcCs|d@d>|d@BS)N)vmr r 0/usr/lib64/python3.9/site-packages/ntp/packet.pyVN_MODE szPacket.VN_MODEcCs|d@d>t||BS)Nr )r r)lrrr r rPKT_LI_VN_MODEszPacket.PKT_LI_VN_MODENcCs*||_d|_d|_ttjj|||_dS)Nr)session li_vn_mode extensionr rntpmagicZLEAP_NOTINSYNC)selfmodeversionrr r r__init__s  zPacket.__init__cCs|jSN)_Packet__extensionrr r rrszPacket.extensioncCstj||_dSr)rpoly polybytesr )rxr r rr"scCsdtj|jS)N)zno-leapzadd-leapzdel-leapZunsync)rrZPKT_LEAPrr!r r rleap&s z Packet.leapcCs|jd?d@S)Nr r rr!r r rr*szPacket.versioncCs |jd@S)Nr r&r!r r rr-sz Packet.mode)__name__ __module__ __qualname____doc__ staticmethodrrrrZ MODE_CLIENT NTP_VERSIONrpropertyrsetterr%rrr r r rr s     r c@seZdZdddZddZdS) SyncExceptionrcCs||_||_dSrmessage errorcoderr1r2r r rr2szSyncException.__init__cCs|jSrr1r!r r r__str__6szSyncException.__str__N)rr'r(r)rr5r r r rr/1s r/c@seZdZdZdZdZdZdZd2ddZd d Z e d d Z e d dZ ddZ ddZddZddZddZddZddZddZdd Zd!d"Zd#d$Zd%d&Zd'd(Zd)d*Zd+d,Zd-d.Zd/d0Zd1S)3 SyncPacketz5Mode 1-5 time-synchronization packet, including SNTP.z !BBBbIIIQQQQ0l~TghUMu>cCst|d|_d|_d|_d|_d|_d|_d|_d|_ d|_ d|_ d|_ d|_ g|_d|_d|_d|_tt|_d|_d|_|r|tj|dS)Nrr9TF)r rstatusstratumpoll precision root_delayroot_dispersionrefidreference_timestamporigin_timestampreceive_timestamptransmit_timestampr extfieldsmachostnameZresolvedr7 posix_to_ntptimereceivedZtrustedrescaledanalyzerr"r#)rdatar r rrAs, zSyncPacket.__init__c Cs,t|}|tjks|d@dkr&tdttj|dtj\ |_|_|_ |_ |_ |_ |_ |_|_|_|_|tjd|_|j}t|dkrtd|dd\}}|j||dd|f|d|d}qt|dkr||_nBt|dkrtd n,t|d vrtd nt|d vr(||_dS) Nr rzimpossible packet lengthz!IIrrrzUnsupported DES authentication)rrzPacket is a runt)r rN)lenr7 HEADER_LENr/structunpackformatrr;r<r=r>r?r@rArBrCrDrrEappendrF)rrMZdatalenpayloadZftypeZflenr r rrLYs>       zSyncPacket.analyzecCs|dtjS)z!Scale from NTP time to POSIX time)r7 UNIX_EPOCHtr r r ntp_to_posixszSyncPacket.ntp_to_posixcCst|tjdS)z!Scale from POSIX time to NTP timerV)intr7rWrXr r rrHszSyncPacket.posix_to_ntpcCsr|jsnd|_|jdL_|jdL_t|j|_t|j|_t|j|_t|j|_t|j |_ dS)z%Rescale all timestamps to POSIX time.TrN) rKr>r?r7rZrArBrCrDrJr!r r rposixizes"zSyncPacket.posixizecCs|jSr)rBr!r r rt1sz SyncPacket.t1cCs|jSr)rCr!r r rt2sz SyncPacket.t2cCs|jSr)rDr!r r rt3sz SyncPacket.t3cCs|jSr)rJr!r r rt4sz SyncPacket.t4cCs ||||S)zPacket flight time)r`r]r_r^r!r r rdeltaszSyncPacket.deltacCs tj||d|jS)z(Residual error due to clock imprecision.)r7PHIr`r]r=r!r r repsilonszSyncPacket.epsiloncCst|d|S)z?Synchronization distance, estimates worst-case error in secondsrb)absrardr!r r rsynchdszSyncPacket.synchdcCs$||||dS)z9Adjustment implied by this packet - 'theta' in NTP-speak.rb)r^r]r_r`r!r r radjustszSyncPacket.adjustcCsBttj|j|j|j|j|j|j |j |j |j |j |j }||jSz*Flatten the packet into an octet sequence.)rQpackr7rSrr;r<r=r>r?r@rArBrCrDrrbodyr r rflattens zSyncPacket.flattencCs0|jd?d@|jd?d@|jd?d@|jd@fS)zAnalyze refid into octets.rNrr)r@r!r r r refid_octetss    zSyncPacket.refid_octetscCstjtjd|S)z'Sometimes it's a clock name or KOD type)ZBBBB)rr"polystrrQrirnr!r r rrefid_as_stringszSyncPacket.refid_as_stringcCstjd|S)zSometimes it's an IPV4 address.z %d.%d.%d.%d)rr"rornr!r r rrefid_as_addressszSyncPacket.refid_as_addresscCst|jdkS)NrrOrFr!r r r is_crypto_nakszSyncPacket.is_crypto_nakcCst|jdkS)Nr rrr!r r rhas_MD5szSyncPacket.has_MD5cCst|jdkS)NrNrrr!r r rhas_SHA1szSyncPacket.has_SHA1cCsd|||f}|d|j|jf7}|}tdd|DsP|}|d|7}|dtj t |j 7}|dtj t |j7}|dtj t |j7}|dtj t |j7}|jr|dt|j7}|jr|dt|jdd7}|d7}|S) z@Represent a posixized sync packet in an eyeball-friendly format.zrz&SyncPacket.__repr__..:>)r%rrr>r?rpallrqrutilZrfc3339r7rZrArBrCrDrEreprrF)rrrsr r r__repr__s0         zSyncPacket.__repr__N)r9)r'r(r)r*rSrPrWrcrrLr+rZrHr\r]r^r_r`rardrfrgrlrnrprqrsrtrurr r r rr7:s8 )  r7c@sreZdZdZdddZdZdZdd Zd d Zd d Z ddZ ddZ ddZ ddZ ddZddZddZdS) ControlPacketzMode 6 request/response.rr9cCsJtj|tjj|j|d||_d|_d|_||_ d|_ ||_ t ||_ dS)N)rrrr{r)r rrr MODE_CONTROL pktversionr_e_m_opsequencer:associdoffsetrrOcount)rropcoderqdatar r rrs zControlPacket.__init__z!BBHHHHHrcCs|jd@rdSdS)NTFrr!r r r is_responseszControlPacket.is_responsecCs|jd@rdSdS)N@TFrr!r r ris_errorszControlPacket.is_errorcCs|jd@rdSdS)NrTFrr!r r rmoreszControlPacket.morecCs |jd@S)Nrr!r r rrszControlPacket.opcodecCs|jd?d@S)Nrrm)r:r!r r rerrcodeszControlPacket.errcodecCs |j|jSr)rrr!r r rendszControlPacket.endcCsd|j||jfS)z Return statistics on a fragment.z%5d %5d %3d octets )rrrr!r r rstats szControlPacket.statscCsdtj|}ttj|dtj\|_|_ |_ |_ |_ |_ |_|tjd|_|j |j |j |j fSr)rr"r#rQrRrrSrPrrrr:rrrr)rrawdatar r rrL$s  zControlPacket.analyzec Cs2ttj|j|j|j|j|j|j |j }||j Srh) rQrirrSrrrr:rrrrrjr r rrl1szControlPacket.flattencCs|j|dSr)rsendpktrlr!r r rsend=szControlPacket.sendN)rrr9)r'r(r)r*rrSrPrrrrrrrrLrlrr r r rrs   rc@s,eZdZdZddZddZddZeZdS) Peerz*The information we have about an NTP peer.cCs||_||_||_i|_dSr)rrr: variables)rrrr:r r rrDsz Peer.__init__cCs|j|_dSr)rreadvarrr!r r rreadvarsJsz Peer.readvarscCsd|j|jfS)Nz)rr:r!r r rr5Msz Peer.__str__N)r'r(r)r*rrr5rr r r rrAs rz.***Server reports a bad format request packet z/***Server disallowed request (authentication?) z****Server reports a bad opcode in request z(***Association ID {0} unknown to server z,***A request variable unknown to the server z/***Server indicates a request variable was bad z(***Server returned an unspecified error z.***Socket error; probably ntpd is not running z***Request timed out z'***Response from server was incomplete z****Buffer size exceeded for returned data z***Select call failed z***No host open z3***Response length should have been a multiple of 4z***Invalid key identifierz***Invalid passwordz***Key not foundz#***Unexpected nonce response formatz***Unknown parameter '%s'z***No credentialsz***Server error code %sz?***No response, probably high-traffic server with low MRU limitz***Bad MRU tag %sz#***Sort order %s is not implementedz%***No trusted keys have been declaredcCsd}|rtj||\}}t|}d|}dd|D}|t|;}||kr\|d||7}dd|D}|d|d7}||qd S) z.Dump a packet in hex, in a familiar hex formatrz%02x cSsg|]}tj|qSr )rr"polyordrwr$r r r wrz&dump_hex_printable..z cSs0g|](}d|krdkr(nnt|ndqS)r.)chrrr r rr|rr9 N)rr slicedatarOtuplejoinwrite)xdataZoutfpZrowsizeZlinedataZlinelenliner r rdump_hex_printablems rc@s0eZdZdZddZddZddZdd Zd S) MRUEntryz A traffic entry for an MRU list.cCs4d|_d|_d|_d|_d|_d|_d|_d|_dS)Nr)addrlastfirstmvrctscdrr!r r rrszMRUEntry.__init__cCs*tj|j}tj|j}|||jSr)rntpc lfptofloatrrr)rrrr r ravgintszMRUEntry.avgintcCsx|j}|ddkrP|d|d}|d}|dkrB|d|}ttj|S|d|d}dttj|SdS)Nr[r{]%rzs)rfindsocketZ inet_ptonZAF_INET6ZAF_INET)rrZpctr r rsortaddrs   zMRUEntry.sortaddrcCsdt|jdddS)Nz rr!r r rrszMRUList.__repr__N)r'r(r)r*rrrr r r rrsrc@seZdZdddZddZdS)ControlExceptionrcCs||_||_dSrr0r3r r rrszControlException.__init__cCs|jSrr4r!r r rr5szControlException.__str__N)rr6r r r rrs rc@s2eZdZdZdZdZejjdejj dejj dejj dejj dejj d ejjd ejjd iZd d ZddZddZddZddZejfddZddZddZd>ddZdd Zd!d"Zd?d%d&Zd@d'd(ZdAd)d*Z d#d+ejj!dfd,d-Z"d.d/Z#d0d1Z$d2d3Z%d4d5Z&dBd6d7Z'd8d9Z(d:d;Z)d.hinted_lookuprrz*ntpq: numeric-mode lookup of %s failed, %sr Nrz,ntpq: standard-mode lookup of %s failed, %s EAI_NODATAzntpq: ndp lookup failed, %s z+ntpq: API error, missing socket attributes ) startswithrZAI_NUMERICHOSTZgaierrorrrrrstrerrorrrZ AI_CANONNAMEZ AI_ADDRCONFIGAttributeErrorhasattrZ EAI_NONAMErerrno) rrfamreZe1Zfallback_hintsZerrlistZe2r rrZ __lookuphostsT           zControlSession.__lookuphostc Cs(|||}|durdS|d\}}}}}|durLt|d||_d|_n|pR||_d|_tj|jd|j|j d|d|_ zt||||_ Wn<tj y} z"t d|| j| jfWYd} ~ n d} ~ 00z|j |Wn>tj y"} z"t d || j| jfWYd} ~ n d} ~ 00dS) z"openhost - open a socket to a hostNFrTzOpening host %sr r{zError opening %s: %s [%d]zError connecting to %s: %s [%d])_ControlSession__lookuphostrZ inet_ntoprGrrrrrrrrerrorrrrZconnect) rrrresZfamilyZsocktypeZprotocolZ canonnameZsockaddrrr r ropenhost.s4     zControlSession.openhostc Csd|jdur|jdur8z t|_Wnttfy6Yn0|jr|jdkrz|j\|_|_|_WdSt y~t t Yn0zqDj!rj"rj#t$}|| t%7}t||t&t'krjdt||t&t'fd_!nj"j(|||dsd_!j)dj#_)j#dkr*r|dqD|r *r |dqDfdd|D}|rV|d}|j+j+krV|dj#j+|j#|j+fqD|r|d }|,j+kr|d!j+|j#|j+fqD|r,|j+kr|d"j#j+|j+fqD|d#t|d j#j+,*fd|-|j.d$dd%*sd&}j/_0|rD|dj+dkrDt1d t|D]>}||d ,||j+kr:|d'|t|fd q<q:d(d|D}tjd2|_|d)tjt|fd jd kr|d*t3jjnVjdkr|d+t4jn6jd kr2j5d,}jd|}|d-t4|dSqrz,ControlSession.getresponse..cstjj|j|SrrZtxtZthr!r rrs zFragment collection beginsr{rbiz$At %s, select with timeout %d beginsr z"At %s, select with timeout %d endsz$ERR_INCOMPLETE: Received fragments: z%d: %szlast fragment %sreceived )znot r9zAt %s, socket read beginsriz'Flaky: I deliberately dropped a packet.zReceived %d octetsr z(AUTH - packet too short for MAC %d < %d ) packet_end mac_beginz*Received count of 0 in non-final fragment zReceived second last fragment csg|]}|jjkr|qSr r)rwfrag)rpktr rr*s z.ControlSession.getresponse..z3duplicate %d octets at %d ignored, prior %d at %d r|z6received frag at %d overlaps with %d octet frag at %d z6received %d octet frag at %d overlaps with frag at %d z@Recording fragment %d, size = %d offset = %d, end = %d, more=%scSs|jSrr)rr r rrJrkeyTz#Hole in fragment sequence, %d of %dcSsg|]}tj|jqSr )rr"ror)rwfr r rr[sz3Fragment collection ends. %d bytes in %d fragmentszResponse packet: zResponse packet: %s  zFirst line: %s z7AUTH: Content untrusted due to authentication failure! )6rrrMAXFRAGSr SERR_TOOMUCHrrrIasctimeselectrr SERR_SELECT SERR_TIMEOUTr enumeraterSERR_INCOMPLETErr"r#Zrecvr SERR_SOCKETrrandomrOrrLrQ SERR_UNSPEC _ControlSession__validate_packet _authpassrrMODE_SIX_HEADER_LENGTHMODE_SIX_ALIGNMENT KEYID_LENGTHMINIMUM_MAC_LENGTH verify_macrrrrrTsortr:rrangerrrr)rrrZtimeoZ fragmentsZ seenlastfragZbailwarnrZtvoZrd_irrZvalidZ_pendZ not_earlierrrZ tempfraglistZeol firstliner )rrr getresponses&                      zControlSession.getresponsecsjdurjj}ndd}fdd}|tjjksH|tjjkr^|d|ddS|tjjkr|d|ddS| s|dddS|j j kr|d |j j fddS| |kr|d | |fddS| r2| r |d |d__tttj|||j|krP|d |j|ft|d @rr|dt|dStj|jd d@}t||kr|d|jt|tjfttdS)NcSs|Srr rr r rrwrz2ControlSession.__validate_packet..cstjj|j|Srrrr!r rrxs z!Fragment received with version %dr{FzFragment received with mode %dz!Received request, wanted responsez&Received sequence number %d, wanted %dzReceived opcode %d, wanted %dz(Error %d received on non-final fragment z,Association ID %d doesn't match expected %d r z(Response fragment not padded, size = %d z>Response fragment claims %u octets payload, above %d received T)rrrrrr,rrrrrrrrrrrr SERR_SERVERr server_errorsrrOrrPrr#)rrrrrr0rZ shouldbesizer r!rZ__validate_packetrsz             z ControlSession.__validate_packetrr9c Cs|sttd}|||||z|||| }Wqty}z4|rl|jttfvrld}WYd}~qn|WYd}~qd}~00qq|S)z$send a request and save the responseTFN)rr SERR_NOHOSTrr4r1r!r#)rrrrrZretryrrr r rdoqueryszControlSession.doquerycCs|jtjj|dt|jdr(ttg}|dkrtt|jdD]@}|jd|d|d}t d|\}}| t |||qF|j ddd|S)z(Read peer status, or throw an exception.)rrrrz!HHcSs|jSr)r)ar r rrrz)ControlSession.readstat..r)r9rrZCTL_OP_READSTATrOrrSERR_BADLENGTHr/rQrRrTrr.)rrZidlistr2rMr:r r rreadstatszControlSession.readstatc Csg}d}d}tj|j|_|jD]h}tj|}|dkrJ||7}| }q"|sj|dkrj||d}q"d|kr~dkr"nq"||7}q"|r||g}|D]}d|vrtj|| d\} } | dd } n |d} } | | } } | rzt | d} Wnt yz*t | } | d krB|sB|d | fWn@t y| ddkr|| d dkr|| dd } | } Yn0Yn0n| } |r|| | | ffq|| | fqtj |S) z&Parse a response as a textual varlist.Fr9",rr=r{NZdelayzdelay-sr|)rr"rorrrTstriprrindexr[rfloat OrderedDict) rrawZkvpairsZinstringrrxZcorditemsZpairrvalueZ castedvaluer r rZ__parse_varlistsP       zControlSession.__parse_varlistNcCs2|durd}n d|}|j|||d||S)z@Read system vars from the host as a dict, or throw an exception.Nr9r>)rr)rr9_ControlSession__parse_varlist)rrZvarlistrrDrr r rr s  zControlSession.readvarcCsd|jtjj|dd|js$ttn"d|jvrF|jd|jd|_|j|_|jtj dkS)z?Send configuration text to the daemon. Return True if accepted.Trrrr NzConfig Succeeded) r9rrZCTL_OP_CONFIGURErrSERR_PERMISSIONrArstripr"r#)rZ configtextr r rconfigs    zControlSession.configcCstdD]H}|jtjjdt|_|jtj drtj |j Sqt turb|j}n |j}|jd|ttdS)zV Ask for, and get, a nonce that can be replayed. This combats source address spoofing r)rznonce=z## Nonce expected: %sN)r/r9rrZCTL_OP_REQ_NONCErIrrrr"r#ror@strbytesdecoderrr SERR_BADNONCE)rr2Zrespr r r fetch_nonce!s   zControlSession.fetch_noncec Csd}d}t|}g}i}|r,|jtd|D]\} } |d| | fd| dkrbd| | f}n| dkrnq0n | dkrxq0| d krtj| |_q0n | d krq0d D]|} | | d r| d \} } z t | } Wnt yt t| Yn0| |vr i|t| <|| | |t| | <qq0||D]\} t}|jd 7_d D]0} | |t| vrHt|| |t| | qH|j|q,|dur||j|S)z=Extracts data from the key/value list into a more useful formNrztag=%s, val=%srnonce%s=%sz last.olderz addr.olderrz last.newest)rrrrrrrrrr{)listrEr. mru_kv_keyrrrrrrsplitr[rr SERR_BADTAGrLrTrrsetattrr)rrspandirectZmrurQrEZ fake_listZ fake_dicttagvalprefixmemberidxr r rZ __mru_analyze7sT          zControlSession.__mru_analyzecCs|jdur|n|jtjjkrT|dd|d7}|dkrBtt|d|dn|jtjjkr|rxd}|ddn*|jd8_t ||j}|d|dn^|jt t fvr|rt d|d}|d |dnt d|d}|d |dn |jr|||||fS) Nz4no overlap between prior entries and server MRU listr{rz/---> Restarting from the beginning, retry #%uFz+Reverted to row limit from fragments limit.z0Row limit reduced to %d following CERR_BADVALUE.rbz7Frag limit reduced to %d following incomplete response.z7Row limit reduced to %d following incomplete response.) r2rrCERR_UNKNOWNVARrr SERR_STALL CERR_BADVALUErminr#r!max)rrrestarted_count cap_fragslimitfragsr r rZ__mru_query_errorjsX  z ControlSession.__mru_query_errorc Csd}d}d}d}t}|dur i}|r2t|\}}}|} t} ztdt|j} d| |f} |rd|vr|t|d|d<d|vrt|d|d<t|\} }| |7} z|jt j j | dd }WnHt y }z.d}| |||| |}|\}}} }WYd}~n d}~00|}|r"||||| |}|r:|} | rHq|s|rdtt|d }n$tdt|jt| d | d d } t|jt j jkr|} d | |rdnd|r|n| | f} | t| t| 7} |durg| _qWntyYn0t| ||| S)zRetrieve MRU list datarTNr z %s, frags=%dresallresany)rrFr{!rz %s, %s=%d%srgrf)rparse_mru_variablesrPrrbrhexgenerate_mru_parmsr9rrZCTL_OP_READ_MRUr _ControlSession__mru_query_errorrG_ControlSession__mru_analyzerrcrIrZ NONCE_TIMEOUTgenerate_mru_lastseenrOrKeyboardInterrupt stitch_mru)rrZrawhookrYrdresortersortkeyrgrQrXrfZreq_bufparms firstParmsZrecoverable_read_errorsrrZnewNoncer r rmrulists   "       zControlSession.mrulistcCs|jtjj|ddg}|D]v\}}|dr$d|vr$|d\}}t|}|t |dkrt t ||dD]}| tj qx||||<q$|S)zRetrieve ordered-list data.TrHr|rr{)r9rrZCTL_OP_READ_ORDLIST_ArGrEisdigitrUr[rOr/rTrrC)rZlisttypeZstanzasrrFZstemZstanzar2r r rZ __ordlists zControlSession.__ordlistcCs |dS)zRetrieve reslist data.Zaddr_restrictions_ControlSession__ordlistr!r r rreslist szControlSession.reslistcCs |dS)zRetrieve ifstats data.ifstatsryr!r r rr|szControlSession.ifstats)F)rr9F)r)F)NNN)+r'r(r)r*rr(rrZ CERR_UNSPECZCERR_PERMISSIONZ CERR_BADFMTZ CERR_BADOPZ CERR_BADASSOCr_raZ CERR_RESTRICTr7rrrrrrrrrrrr4r'r9r<rGZCTL_OP_READVARrrKrPrornrwrzr{r|r r r rrsL 8) 57@   5  3' jrc Csd}d}t}d|vr|d}|d=ddddddddddddd dd dd dd dd dddd }|dkr|d}|dur||}|durtt|t|D]t}|dvrqq|ds|dr|d}t|dks|dt t tt dvrtt |qqtt |qd|vrBt |d}|d=d|vrj|ddtjjB|d<|d=d|vr|ddtjjB|d<|d=|||fS)Nr.cSstj|jSrrrrrrr r rr"rz%parse_mru_variables..cSstj|j Srr}r~r r rr$rcSs | Srrr~r r rr&rcSs|Srrr~r r rr(rcSs|Srrr~r r rr*rcSs|Srrr~r r rr,rcSs|j Srrr~r r rr.rcSs|jSrrr~r r rr0rcSs|j Srrr~r r rr2rcSs|jSrrr~r r rr4rcSs|j Srrr~r r rr6rcSs|jSrrr~r r rr8r) lstintz-lstintrz-avgintrz-addrrz-countZscorez-scoreZdropz-dropr)ZmincountZmindropZminscorerhrikodlimitedZ maxlstintZ minlstintZladdrrecentr.rgrfzaddr.zlast.rrbr{rrgrrirr)rgetr SERR_BADSORTrSkeysrrUrOmaprLr/ SERR_BADPARAMr[rrZRES_KODZ RES_LIMITED)rrsrtrgZsortdictkZknr r rrks`    (      rkcCsi}g}t|jD]2\}}|j|vr.g||j<||j||jfq|D]$}|t||ddddd7}qJdd|D}|jdd|D]}|j|q|r|jj|d|d kr|jdS) NcSs|dS)Nr{r rr r rrirzstitch_mru..rr|cSsg|] }|dqS)rr rr r rrjrzstitch_mru..T)reverser) r"rrrTrsortedr.popr)rXrsrtZaddrdictZdeletiar2entryrr r rrr[s   " rrcCsV|sdSddt|D}dd|}d|vrJd|d}||7}n|}||fS)N)r9r9cSs g|]}|ddkrd|qS)rrrRr )rwitr r rr{sz&generate_mru_parms..z, rz , recent=%s)rSrEr)rZparmStrsrurvr r rrmws   rmcCsrd}tt|jD]Z}|jt|j|d}d||j||jf}|t|t|tjjkrdqnq||7}q|S)Nr9r{z, addr.%d=%s, last.%d=%s)r/rOrrrrrr )rXZexistingBufferSizeZbufr2rZincrr r rrps rpcCsF|dd}t|dkrdSzt|dWSty@YdS0dS)Nrrr{r|)rUrOr[r)tokenbitsr r rrTs  rTc@sVeZdZdZdddZddZddZdd d Zed d Z ed dZ dddZ dS)rz+MAC authentication manager for NTP packets.NcCsi|_|durt|D]|}d|vr4|d|d}|}|sBq|\}}}|dvr`d}t|dkrtj |dd}||f|jt |<qdS)N#)ZAESZ AES128CMACzAES-128r r) passwordsopenrAr@rUupperrOrrrr[)rZkeyfilerrrrr r rrs   zAuthenticator.__init__cCs t|jS)z1return the number of keytype/passwd tuples stored)rOrr!r r r__len__szAuthenticator.__len__cCs |j|S)z#get a keytype/passwd tuple by keyid)rr)rrr r r __getitem__szAuthenticator.__getitem__cCs|dur,||jvr"|f|j|S|ddfStdD]^}|dr4t|d}|j|\}}|durltt|dkrtj |}|||fSq4tdS)z?Get the keytype/passwd tuple that controls localhost and its idNz /etc/ntp.confrr{r ) rrrr[rUrrOrrr)rrrrrr r rrs      zAuthenticator.controlcCsTtj|sdStjtj|tj||}|r@t|dkrDdStd||S)z)Create the authentication payload to sendFrr!I) rr checknamerFr"r#rOrQri)rUrrrmac2r r rr s  zAuthenticator.compute_maccCst|tjjkS)zDoes this packet have a MAC?)rOrrZ LEN_PKT_NOMAC)packetr r rhave_macszAuthenticator.have_macr8c Cs|d|}|||t}||td}td|\}||jvrHdS|j|\}}tj|sfdStjtj |tj ||} | sdSzt || WSt y|| kYS0dS)zDDoes the MAC on this packet verify according to credentials we have?NrF) r+rQrRrrrrrFr"r#hmaccompare_digestr) rrrrrUrrFrrrr r rr-s$     zAuthenticator.verify_mac)N)N)r8r8) r'r(r)r*rrrrr+r rr-r r r rrs    r)Hr*Z __future__rrrrrr%rrrvrQrrIZ ntp.controlrZ ntp.magicZntp.ntpcZntp.utilZntp.polyrrrrr)r,r+r*ZMAX_BARE_MAC_LENGTHr BaseExceptionr/r7rrZ SERR_BADFMTrIZ SERR_BADOPZ SERR_BADASSOCZSERR_UNKNOWNVARZ SERR_BADVALUEr&r$r!r#rr r8r;rrrrOrr r6r`rVrrrrrrrrrkrrrmrprTrr r r rsL ( DD( WH