|drXdZddlmZmZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl Z ddlZddlZddlZddlZddlZdZdZdZdZdZd Zd Zd Zd ZGd dZGddeZGddeZ GddeZ!GddZ"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 j<fd0Z=Gd1d2Z>Gd3d4Z?Gd5d6eZ@Gd7d8ZAd9ZBd:ZCd;ZDd<ZEd=ZFGd>d?ZGdS)@a( 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 ceZdZdZedZedZejj ejj dfdZ e dZ e jdZ dZd Zd ZdS) PacketzEncapsulate an NTP fragmentc|dzdz|dzzS)N)vms ,/usr/lib/python3/dist-packages/ntp/packet.pyVN_MODEzPacket.VN_MODE sa%A!c'*+cJ|dzdzt||zS)Nr)r r)lrrs rPKT_LI_VN_MODEzPacket.PKT_LI_VN_MODEs#a%A1!5!556rNc||_d|_d|_tt jj|||_dS)Nrr)session li_vn_mode extensionr rntpmagicLEAP_NOTINSYNC)selfmodeversionrs r__init__zPacket.__init__s>  // 0H07??rc|jSN)_Packet__extensionr!s rrzPacket.extensions rcNtj||_dSr&)rpoly polybytesr')r!xs rrzPacket.extension"s 8--a00rcVdtj|jS)N)zno-leapzadd-leapzdel-leapunsync)rrPKT_LEAPrr(s rleapz Packet.leap&s&),,T_==? ?rc|jdz dzS)Nrrrr(s rr#zPacket.version*s1$++rc|jdzS)Nrr2r(s rr"z Packet.mode-s$$r)__name__ __module__ __qualname____doc__ staticmethodrrrr MODE_CLIENT NTP_VERSIONr$propertyrsetterr0r#r"rrrr r s!!,,\,77\7 I1.????  X 111???,,,%%%%%rr ceZdZddZdZdS) SyncExceptionrc"||_||_dSr&message errorcoder!rArBs rr$zSyncException.__init__2 "rc|jSr&rAr(s r__str__zSyncException.__str__6 |rNrr4r5r6r$rGrrrr>r>1s7####rr>ceZdZdZdZdZdZdZddZdZ e d Z e d Z d Z d Zd ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdS) SyncPacketz5Mode 1-5 time-synchronization packet, including SNTP.z !BBBbIIIQQQQ0l~TghUMu>ct|d|_d|_d|_d|_d|_d|_d|_d|_ d|_ d|_ d|_ d|_ g|_d|_d|_d|_t$t)j|_d|_d|_|r4|t2j|dSdS)NrrNTF)r r$statusstratumpoll precision root_delayroot_dispersionrefidreference_timestamporigin_timestampreceive_timestamptransmit_timestampr extfieldsmachostnameresolvedrL posix_to_ntptimereceivedtrustedrescaledanalyzerr*r+)r!datas rr$zSyncPacket.__init__As     #$ !!""#  "// <<    3 LL++D11 2 2 2 2 2 3 3rc t|}|tjks |dzdkrtdt jtj|dtj\ |_|_|_ |_ |_ |_ |_ |_|_|_|_|tjd|_|j}t|dkrgt jd|dd\}}|j||dd|zf|d|zd}t|dkgt|dkr ||_dSt|dkrtd t|d vrtd t|d vr ||_dSdS) Nrrzimpossible packet lengthz!IIr rrzUnsupported DES authentication)r rzPacket is a runt)r rg)lenrL HEADER_LENr>structunpackformatrrQrRrSrTrUrVrWrXrYrZrr[appendr\)r!redatalenpayloadftypeflens rrdzSyncPacket.analyzeYsd)) Z* * *w{q.@.@ :;; ;%+M  t$:Z%:$:;%=%= "       !   j3445.'llR"M%!==MUD N ! !5'!AdF(*;"< = = =afgg&G'llR w<<1  DHHH \\R   @AA A \\W $ $ 233 3 \\X % %DHHH& %rc&|dz tjz S)z!Scale from NTP time to POSIX time)rL UNIX_EPOCHts r ntp_to_posixzSyncPacket.ntp_to_posixsU z444rc@t|tjzdzS)z!Scale from POSIX time to NTP timers)intrLrtrus rr_zSyncPacket.posix_to_ntps A --6777rc|jsd|_|xjdzc_|xjdzc_t|j|_t|j|_t|j|_t|j|_t|j |_ dSdS)z%Rescale all timestamps to POSIX time.TrN) rcrTrUrLrwrWrXrYrZrar(s rposixizezSyncPacket.posixizes} C DM OO "OO  R ' '1'>'>((*(*D $$.$;$;%%'%'D !%/%<%<&&(&(D "&0&=&='')')D #&33DMBBDMMM C Crc|jSr&)rXr(s rt1z SyncPacket.t1s $$rc|jSr&)rYr(s rt2z SyncPacket.t2s %%rc|jSr&)rZr(s rt3z SyncPacket.t3s &&rc|jSr&)rar(s rt4z SyncPacket.t4s }rc||z ||z z S)zPacket flight time)rr}rrr(s rdeltazSyncPacket.deltas7 DGGII%$''))dggii*?@@rctj||z zd|jzzS)z(Residual error due to clock imprecision.)rLPHIrr}rSr(s repsilonzSyncPacket.epsilons2~TWWYY!67!T^:KKKrctt|dz |zS)z?Synchronization distance, estimates worst-case error in secondsr)absrrr(s rsynchdzSyncPacket.synchds+4::<<>DLLNN2333rc||z ||z zdz S)z9Adjustment implied by this packet - 'theta' in NTP-speak.r)rr}rrr(s radjustzSyncPacket.adjusts<47799$twwyy':;Q>>rctjtj|j|j|j|j|j|j |j |j |j |j |j }||jzSz*Flatten the packet into an octet sequence.)rjpackrLrlrrQrRrSrTrUrVrWrXrYrZrr!bodys rflattenzSyncPacket.flattensc{:,?<9>?/:3012 4 4dn$$rc`|jdz dz|jdz dz|jdz dz|jdzfS)zAnalyze refid into octets.rgrr )rVr(s r refid_octetszSyncPacket.refid_octetssBr!T)r!T)qD( T!# #rctjtjd|zS)z'Sometimes it's a clock name or KOD type)BBBB)rr*polystrrjrrr(s rrefid_as_stringzSyncPacket.refid_as_strings0x i$:K:K:M:M.M OPPPrcjtjd|zS)zSometimes it's an IPV4 address.z %d.%d.%d.%d)rr*rrr(s rrefid_as_addresszSyncPacket.refid_as_addresss)x 0A0A0C0C CDDDrc2t|jdkS)Nrrhr\r(s r is_crypto_nakzSyncPacket.is_crypto_naks48}}!!rc2t|jdkS)Nr rr(s rhas_MD5zSyncPacket.has_MD548}}""rc2t|jdkS)Nrgrr(s rhas_SHA1zSyncPacket.has_SHA1rrcd|||fz}|d|j|jfzz }|}t d|Ds|}|d|zz }|dtj t |j zz }|dtj t |jzz }|dtj t |jzz }|dtj t |jzz }|jr|dt%|jzz }|jr"|dt%|jddzz }|dz }|S)z@Represent a posixized sync packet in an eyeball-friendly format.zz&SyncPacket.__repr__..s*55Q1((555555r:>)r0r#r"rTrUrallrrutilrfc3339rLrwrWrXrYrZr[reprr\)r!rrss r__repr__zSyncPacket.__repr__s  T\\^^TYY[[I I W)=> >>  ! ! # #55"55555 )&&((B S2X  S38##  # #D$< = =??? ? S38##  # #D$9 : :<<< < S38##  # #D$: ; ;=== = S38##  # #D$; < <>>> > > , tDN+++ +A 8 , tDH~~ad++ +A SrN)rN)r4r5r6r7rlrirtrr$rdr8rwr_r{r}rrrrrrrrrrrrrrrrrrrLrL:s;; FJJ C33330'''R55\5 88\8 CCC %%%&&&'''AAALLL 444 ???%%% ###QQQEEE"""######rrLc^eZdZdZddZdZdZdZdZd Z d Z d Z d Z d Z dZdZdZdS) ControlPacketzMode 6 request/response.rrNct|tjj|j|||_d|_d|_||_ d|_ ||_ t||_ dS)N)r"r#rrr)r r$rr MODE_CONTROL pktversionr_e_m_opsequencerPassocidoffsetrrhcount)r!ropcoderqdatas rr$zControlPacket.__init__sl39#9 ' 2 '  ) ) )     ZZ rz!BBHHHHHrc|jdzrdndS)NTFrr(s r is_responsezControlPacket.is_response}t+6tt6rc|jdzrdndS)N@TFrr(s ris_errorzControlPacket.is_errorrrc|jdzrdndS)NrTFrr(s rmorezControlPacket.morerrc|jdzS)Nrr(s rrzControlPacket.opcodes}t##rc|jdz dzS)Nr r)rPr(s rerrcodezControlPacket.errcodes q D((rc |j|jzSr&)rrr(s rendzControlPacket.endszDK''rcJd|j||jfzS)z Return statistics on a fragment.z%5d %5d %3d octets )rrrr(s rstatszControlPacket.stats s &$+txxzz4:)NNNrc^tj|}tjt j|dt j\|_|_ |_ |_ |_ |_ |_|t jd|_|j |j |j |j fSr&)rr*r+rjrkrrlrirrrrPrrrr)r!rawdatas rrdzControlPacket.analyze$s($$W--}]%9%,-Fm.F-F%GII         !9!:!:; t{DL$+FFrc tjtj|j|j|j|j|j|j |j }||j zSr) rjrrrlrrrrPrrrrrs rrzControlPacket.flatten1sJ{=/?==;<;:''dn$$rc^|j|dSr&)rsendpktrr(s rsendzControlPacket.send=s& T\\^^,,,,,rN)rrrN)r4r5r6r7r$rlrirrrrrrrrdrrrrrrrs     FJ777777777$$$)))(((OOO G G G % % %-----rrc(eZdZdZdZdZdZeZdS)Peerz*The information we have about an NTP peer.c>||_||_||_i|_dSr&)rrrP variables)r!rrrPs rr$z Peer.__init__Ds"   rcB|j|_dSr&)rreadvarrr(s rreadvarsz Peer.readvarsJs--//rc$d|j|jfzS)Nz)rrPr(s rrGz Peer.__str__Ms.$, 1LLLrN)r4r5r6r7r$rrGrrrrrrAsI00 000MMMHHHrrz.***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 declaredcZd}|rtj||\}}t|}d|z}d|D}|t |z}||kr |d||z zz }d|D}|d|dzz }|||dSdS) z.Dump a packet in hex, in a familiar hex formatrz%02x cLg|]!}tj|"Sr)rr*polyordrr,s r z&dump_hex_printable..ws(:::ACH$$Q'':::rz cPg|]#}d|cxkrdkrnnt|nd$S)r.)chrrs rrz&dump_hex_printable..|s:III1rQ}}}}}}}}}CFFF3IIIrrN N)rr slicedatarhtuplejoinwrite)xdataoutfprowsizelinedatalinelenlines rdump_hex_printablermsG (,,UG<<%h-- ::::: h W   EWw./ /DIIIII !!D(( D rc*eZdZdZdZdZdZdZdS)MRUEntryz A traffic entry for an MRU list.cvd|_d|_d|_d|_d|_d|_d|_d|_dS)Nr)addrlastfirstmvrctscdrr(s rr$zMRUEntry.__init__s>   rctj|j}tj|j}||z |jz Sr&)rntpc lfptofloatrrr)r!rrs ravgintzMRUEntry.avgintsAx""49--##DJ//u ''rch|j}|ddkra|d|d}|d}|dkr |d|}tjtj|S|d|d}dtjtj|zS)Nr[r]%rs)rfindsocket inet_ptonAF_INET6AF_INET)r!rpcts rsortaddrzMRUEntry.sortaddrsy 7c>>$))C..()D))C..CQwwDSDz#FOT:: :3(Df.v~tDDD DrcFdt|jddzdzS)Nz >rN)r4r5r6r7r$rrrrrrrrsY&&((( EEE$?????rrc$eZdZdZdZdZdZdS)MRUListzFA sequence of address-timespan pairs returned by ntpd in one response.c"g|_d|_dSr&entriesnowr(s rr$zMRUList.__init__s rc|jduS)z2Is the server done shipping entries for this span?N)rr(s r is_completezMRUList.is_completesxt##rc(d|jd|jdS)Nz.hinted_lookups/%eT4>&,&7&,&8&+-- -rr)r=rWzntpq: numeric-mode lookup of z failed, rNrzntpq: standard-mode lookup of r EAI_NODATAzntpq: ndp lookup failed, %s z+ntpq: API error, missing socket attributes ) startswithr AI_NUMERICHOSTgaierrorrrrJrDstrerrorr.r AI_CANONNAME AI_ADDRCONFIGAttributeErrorhasattr EAI_NONAMErZerrno) r!rXfamrYee1fallback_hintserrliste2s `` r __lookuphostzControlSession.__lookuphosts   C  !B$KE - - - - - -  A =e63HIII I A A A HNN4::#eeQZZ126*a A A A A A A A A A H =e1555 5 H H Hz%    $)EE2;;;"8999$0N &"66!     H6<003%0&2CDGG%02G8w&&<,}%qAAAAAAAAA!?<<<:1 J,,-L/1{.;<<<<" H H H:)J$$FHHH H7 H>tsAB7B  B B!!G$19G+C;:G; DGDG AF) E#G$#F%2)F F) F%%F)(G)+GGGGG$c|||}|dS|d\}}}}}|(tj|d||_d|_n|p||_d|_t j|jd|jz|j d|d|_ tj||||_ n6#tj $r$} td|| j| jfzd} ~ wwxYw |j |n6#tj $r$} td || j| jfzd} ~ wwxYwdS) z"openhost - open a socket to a hostNFrTzOpening host %srrzError opening %s: %s [%d]zError connecting to %s: %s [%d])_ControlSession__lookuphostr  inet_ntopr]r;rrrJrDr.r=r<errorrr^rdconnect) r!rXreresfamilysocktypeprotocol canonnamesockaddrrfs ropenhostzControlSession.openhost.ss++ ;5&+QZ%A$BCC C C C I  h ' ' ' '| C C C"#D&+QZ%A$BCC C Cts0%CC4C//C48DE"EEc|j0|j, t|_n#ttf$rYnwxYw|jr\|jdkrQ |j\|_|_|_dS#t$rttwxYw tj dr-ttjd}nd}|dks |t$krtt&n)#t(tf$rtt&wxYw||_|j |j|j\|_}n{#t*t,f$rgt/jd|jz}|tt0t3|dkrtj|}YnwxYw||_dSdS)z2Get a keyid and the password if we don't have one.N localhostrzKeyid: z %s Password: r )r8r: AuthenticatorOSErrorIOErrorr]controlr7r9 ValueErrorr SERR_NOTRUSTosisattyryrr* polyinput MAX_KEYID SERR_BADKEY SyntaxError IndexError TypeErrorgetpass SERR_INVPASSrhr hexstr2octets)r!key_idr9s rpasswordzControlSession.passwordJs : y  -DII)Dy 9T]k999)++--!>??FFFQ;;&9"4"4*;777#5, 4 4 4&{333 4DJ ;  <'+y'<$ ff * < < < 4<)GHH>*<888v;;## X33F;;F <!DKKK  s8%99,A==B A(D &D/EA5GGcPt|dzr|dz }t|dztj|jdt||jfz|jd |jtj |n?#tj $r-|j"|j d|jzYdSwxYw|jdkr6|j/|j d t||jd S) zSend a packet to the host.rzSending %d octets. seq=%drNzWrite to %s failed rzRequest packet: r)rhrrrJrDrr.r<sendallr*r+r rorr]r)r!rs rrzControlSession.sendpktss*%jj1n  W E%jj1n  tz3e**dm456:j! E E E  I  ch0077 8 8 8 8|   z%   !7$-!GHHH22   J!OO$*"8 J  0 1 1 1 udj 1 1 1qs.7B&&8C"!C"Fc>|jdkrL|jE|jdkr|jd|jd|||fzt|tjjkr3|j*|jdt|zdSt||||}|xjdz c_|xjdzc_|j|_|j rtj |j |_ tj t|j zdzr4|xj d z c_ tj t|j zdz4|s|j s|S|j|jt#t$tj t|j zd zr4|xj d z c_ tj t|j zd z4t&||j|j|j}|t#t.|xj tj |z c_ |S) z(Ship an ntpq request packet to a server.rNrrz-sendrequest: opcode=%d, associd=%d, qdata=%s z'***Internal error! Data too large (%d) rirr)r.rDrrhrr}CTL_MAX_DATA_LENrrrr*r+rir6rr8r9r SERR_NOCREDrz compute_macrr7 SERR_NOKEY)r!rrrr:pktr\s r sendrequestzControlSession.sendrequestsf J!OO$*"8zQ   &&& J  M &78 9 9 9 u:: 4 4 4z%   !K!$U",---2D&'599    }  = )H..s}==CM!,s3=/A/AAQF ) ( ",s3=/A/AAQF )  D, 88::  : !4";// / (3s}+=+==B % MMW $MM(3s}+=+==B %'' (, DL$+OO ;":.. . MMSX//44 4MMxxzzrc g}d_d}d}j jj}nd}fd}|dd |dz }|d tzkrt t |s jd z } n jd z } |d tj | fzd  tj j ggg| \} } } n'#tj $rt twxYw|dtj | fzd | s|s|rt t|rjdkrjjdt!|D]9\} } jd| dz| fz:jdd|zt t$|dtj zd t&jj d}n'#t.j $rt t0wxYwjr*jt5jkr|ddd}|dt7|zdt9 |n'#t<j $rt t>wxYw |||}|sˉj!rj"rj#tHz}|| tJzz }t7||tLztNzkrDjdt7||tLztNzfzd_!n$j"(|||sd_!j)dj#_)j#dkr!*r |d|r!*r |dfd|D}|r@|d}|j+j+kr(|dj#j+|j#|j+fz9|rG|d}|,j+kr"|d j+|j#|j+fz|r?,|j+kr"|d!j#j+|j+fz|d"t7|dzj#j+,*fzd|-|.d#$*sd }j/_0|r|dj+dkrtcdt7|D]O}||dz ,||j+kr!|d%|t7|fzdn"Pd&|D}t&jd2|_|d't7jt7|fzdjd kr&|d(tgjjn{jdkr!|d)tijznOjd krDj5d*}jd|}|d+ti|zdSnj!s |d,dSdS)-zz,ControlSession.getresponse..arc\tjj|j|Sr&rItxtthr!s rrz,ControlSession.getresponse..&38>>$*c26*b$B$BrzFragment collection beginsrTriz$At %s, select with timeout %d beginsrz"At %s, select with timeout %d endsz$ERR_INCOMPLETE: Received fragments: z%d: %szlast fragment %sreceived )znot rNzAt %s, socket read beginsriz'Flaky: I deliberately dropped a packet.zReceived %d octetsrz(AUTH - packet too short for MAC %d < %d ) packet_end mac_beginz*Received count of 0 in non-final fragment zReceived second last fragment c4g|]}|jjk|Srr)rfragrpkts rrz.ControlSession.getresponse..*s1:::D"kT[88 888rz3duplicate %d octets at %d ignored, prior %d at %d rz6received 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=%sc|jSr&r)rs rrz,ControlSession.getresponse..JsDKrkeyz#Hole in fragment sequence, %d of %dcVg|]&}tj|j'Sr)rr*rr)rfs rrz.ControlSession.getresponse..[s:$8$8$8()%(H$4$4Q[$A$A$8$8$8rz3Fragment collection ends. %d bytes in %d fragmentszResponse packet: zResponse packet: %s  zFirst line: %s z7AUTH: Content untrusted due to authentication failure! )6r>rDrMAXFRAGSr SERR_TOOMUCHr2r4r`asctimeselectr<ro SERR_SELECT SERR_TIMEOUTr. enumeraterSERR_INCOMPLETErr*r+recvr  SERR_SOCKETrGrandomrhrrdrj SERR_UNSPEC _ControlSession__validate_packet _authpassr:rMODE_SIX_HEADER_LENGTHMODE_SIX_ALIGNMENT KEYID_LENGTHMINIMUM_MAC_LENGTH verify_macrrrrrmsortrPr?rangerrrr )r!rrtimeo fragments seenlastfragbailwarnrMtvord_irrvalid_pend not_earlierrr tempfraglisteol firstliners` @r getresponsezControlSession.getresponses    : !:#DDKDBBBB ,a000\  AID( ##&|444 4*T1,t3 G:|~~s+,-. 0 0 0 4#]DI;BDD Q< 4 4 4&{333 4 G8|~~s+,-. 0 0 0 8 ==.|<<< G a . ((CEEE)29)=)=MMIQ J,,X1djjll8K-KLLLL (()E+7 +E*FGGG&777 G/$,..@! D D D 4(,,TY^^D-A-ABB< 4 4 4&{333 4{ t{fmoo==A1EEE G(3w<<7 ; ; ; &&D 4 W%%%%< 4 4 4&{333 4**4&'JJE ~ +$) + %;;556w<<5<#7:L#LMMJ$$%P&)'llU\5IL^5^%`&abbb%*DNN--g%6;.==+%*DN"^KTZK8DNzQ499;;BCCC   6777::::I:::K )!n %44D' J '-{/ACCDDD  }88:: ++D( KT[ABCCC txxzzK,>>>$ DK1CDEFFF G)9~~a'{DHHJJ ==?@ A A A   T " " " NN77N 8 8 899;; +# #{   ! 3q 8 8q#i..11  A 1~))++y|/BBB E#$c)nn"5!678:::C $8$8-6$8$8$8L$'H$6$6rww|7L7L$M$MDMG/"4=113y>>BCDEGGGzQ1222*4=$*EEEEq5T]8K8KKLLLLq"m0077$(M$3$$7 04 ??BCCC4y\ z~ M DK L L L L L M Ms$!B<<$C .7H&&$I *K$K$cj jj}nd}fd}|tjjks'|tjjkr#|d|zddS|tjjkr#|d|zddS| s|dddS|j j kr|d|j j fzddS| |kr%|d | |fzddS| r| r |d |zdx__t#t$t&j|z||j|kr|d |j|fzt-|d zr|d t-|zdSt.j|jzd zdz}t-||krC|d|jt-|t.jz fzt#t4dS)Nc|Sr&rrs rrz2ControlSession.__validate_packet..wrrc\tjj|j|Sr&rIrs rrz2ControlSession.__validate_packet..xrrz!Fragment received with version %drFzFragment 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 rz(Response fragment not padded, size = %d z>Response fragment claims %u octets payload, above %d received T)rDrr#rrr:r5r"rrrrrrrr8r9r SERR_SERVERr" server_errorsrrhrrirr)r!rrrrrrM shouldbesizes` r__validate_packetz ControlSession.__validate_packetrs : !:#DDKDBBBB\\^^ci3 3 3 LLNNSY5 5 5 G7llnn%&' ) ) )5 99;;#)0 0 0 G4tyy{{BA F F F5!!  G7 ; ; ;5 =DM ) ) G<]DM2345 7 7 75 ;;==F " " G3[[]]F+,-. 0 0 05 ==?? yy{{ '@||~~&''''+ +DJ" .t||~~>?    <7 " " D@L'*+ , , , w<<#   D<w<<  ! ! !5%04:=ARG w<<, & & D'JG }/G GHI J J J#?33 3trrrNc&|sttd} ||||| |||| }n2#t$r%}|r|jt tfvrd}Yd}~[|d}~wwxYw |S)z$send a request and save the responseTFN)rQr SERR_NOHOSTrrrArr)r!rrrr:retryrqrfs rdoqueryzControlSession.doquerys}} 0";// /    VWeT : : : &&vwE BB#   QY<*III!EHHHHG    sA B (BBB c|tjj|t |jdzrt tg}|dkr{tt |jdzD]V}|jd|zd|zdz}tj d|\}}| t|||W| d|S)z(Read peer status, or throw an exception.)rrrrz!HHc|jSr&)r)as rrz)ControlSession.readstat..s!)rr)rrr}CTL_OP_READSTATrhr>rSERR_BADLENGTHrrjrkrmrr)r!ridlistrrerPs rreadstatzControlSession.readstats CK7 III t}   ! 3">22 2 a<<3t}--q011 ; ;}QqS1QY/$*M%$>$>!& d4&99:::: ++ ,,, rc^g}d}d}tj|j|_|jD]w}tj|}|dkr ||z }| }0|s0|dkr*||d}bd|cxkrdkrnr||z }x|r'||g}|D]2}d|vrAtj|| d\} } | dd } n|d} } | | } } | r t| d} nv#t$rg t| } | d kr|s|d | fn4#t$r'| ddkr| d dkr | dd } | } YnwxYwYnwxYw| } |r|| | | ff|| | f4tj |S) z&Parse a response as a textual varlist.FrN",rr=rNdelayzdelay-sr)rr*rr>rrmstriprrindexryr~float OrderedDict) r!rawkvpairsinstringr>rcorditemspairrvalue castedvalues r__parse_varlistzControlSession.__parse_varlistsr ((77   A8##A&&DCxxA '< !s((x~~//000TCA   - NN8>>++ , , , 1 1Dd{{ X//djjooFF Uabb !2UekkmmC $ ,"%eQ--KK! , , ,,&+Ell '>>#>!LL)U);<<<%,,,!!HOO%)s2B2B$)!B$KE&+ , ,$  1 cK#789999 c;/0000x##E***s6E$$ G/.FG.G GGGGNc|d}nd|}||||||S)z@Read system vars from the host as a dict, or throw an exception.NrNr)rr)rr_ControlSession__parse_varlist)r!rvarlistrrrs rrzControlSession.readvar sM ?EEHHW%%E VWE :::##C(((rc||tjj|d|jst t d|jvr,|jd|jd|_|j|_|jtj dkS)z?Send configuration text to the daemon. Return True if accepted.Trrr:rNzConfig Succeeded) rrr}CTL_OP_CONFIGUREr>rSERR_PERMISSIONrrstripr*r+)r! configtexts rconfigzControlSession.configs CK8%D  2 2 2} I"?33 3  % % M*G4=+>+>w+G+G*GHDM ,,.. } 2 23E F FFFrc>tdD]}|tjjt j|_|jtj dr8tj |j cSttur|j}n|j}|jd|zt%t&)zV Ask for, and get, a nonce that can be replayed. This combats source address spoofing r)rznonce=z## Nonce expected: %s)rrrr}CTL_OP_REQ_NONCEr`rEr>r[r*r+rrstrbytesdecoderDrr SERR_BADNONCE)r!rresps r fetch_noncezControlSession.fetch_nonce!s q ? ?A LL >>>> ? %<<=DD=''))D 047888}---rc (d}d}t|}g}i}|r|t|D]\} } |d| d| d| dkr| d| }n| dkr7| d kr>| d kr%t j| |_i| d krpd D]} | | d zr| d \} } t| } n%#t$rtt| zwxYw| |vr'i|t| <|| | |t| | < ||D]} t#}|xjdz c_d D]C} | |t| vr*t'|| |t| | D|j||||j|S)z=Extracts data from the key/value list into a more useful formNrztag=z, val=rnoncerz last.olderz addr.olderrz last.newest)rrrrrrrrrr)listrr mru_kv_keyrMrrrrr[splitryr~r SERR_BADTAGrrmrrFsetattrr)r!rspandirectmrur r fake_list fake_dicttagvalprefixmemberidxs r __mru_analyzezControlSession.__mru_analyze7slY__&&''   ' JJ:J & & & 6 6JS# LLLSSS##6 : : :g~~#&33, $$ $$e||8..s33 %%Q 6 6>>&3,// 6$'IIcNNMVSB!#hh%BBB.{S/@AAAB)++.0 #c((+!((---25Ic#hh'/ 6  % %C**C JJ!OJJR F FYs3xx000C3s88)>"D c|j||jtjjkrO|dd|dz }|dkrt t |d|zdn|jtjjkrZ|rd}|ddn|xjdzc_t||j}|d|zdnz|jttfvr\|r-td|dz }|d |zdn6td|dz }|d |zdn |jr|||||fS) Nz4no overlap between prior entries and server MRU listrr z/---> Restarting from the beginning, retry #%uFz+Reverted to row limit from fragments limit.z0Row limit reduced to %d following CERR_BADVALUE.rz7Frag limit reduced to %d following incomplete response.z7Row limit reduced to %d following incomplete response.) rBrr}CERR_UNKNOWNVARrMr SERR_STALL CERR_BADVALUErAminrrmax)r!rfrestarted_count cap_fragslimitfragss r__mru_query_errorz ControlSession.__mru_query_errorjs ; G [CK7 7 7 LL+,- / / / q O""&z222 LL%'6789 ; ; ; ; [CK5 5 5 :!  0124444##q(##E4#677 .05678:::: [_l; ; ; AAuqy)) 46;<=>@@@@Auqy)) 57<=>?AAAA [ G 5%77rc d}d}d}d}t}|i}|rt|\}}}|} t} t dtz|j} d| |fz} |r8d|vrt |d|d<d|vrt |d|d<t|\} }| |z } |tj j | d }n9#t$r,}d}| |||| |}|\}}} }Yd}~nd}~wwxYw|}|r ||||| |}|r|} | rn|sP|rt t|d z}n5t dtz|jt#| d z| d zd z } t%j|jz tj jkr|} d | |rdnd|r|n| | fz} | t+| t-| z } |g| _n#t0$rYnwxYwt3| ||| S)zRetrieve MRU list datarTNrz %s, frags=%dresallresany)rrFr!rz %s, %s=%d%sr%r$)rparse_mru_variablesr rr rAhexgenerate_mru_parmsrrr}CTL_OP_READ_MRUr _ControlSession__mru_query_errorr_ControlSession__mru_analyzerr!r`rE NONCE_TIMEOUTgenerate_mru_lastseenrhrKeyboardInterrupt stitch_mru)r!rrawhookrr"r#sortersortkeyr%r rr$req_bufparms firstParmsrecoverable_read_errorsrfrqnewNonces rmrulistzControlSession.mrulists)   I  D%8%C%C "FGU  ""yyU H d&9::E$u~5G Cy((*-i.A*B*BIh'y((*-i.A*B*BIh' 29 = = E: z !GG &CLL (C'.!000.3++'CCC.2+00O1:E5JJC?B A6I(C,+I, D"6"DID""D$I IIc$|tjj|dg}|D]\}}|drd|vr|d\}}t|}|t|dz krTtt||dzD]3}| tj 4||||<|S)zRetrieve ordered-list data.Trrrr)rrr}CTL_OP_READ_ORDLIST_Arrisdigitrryrhrrmrr)r!listtypestanzasrrstemstanzars r __ordlistzControlSession.__ordlists CK=#$  0 0 0 002288:: . .LS%2w   .SCZZ!$3vVCLL1,,,"3w<<!<<??sx';';'='=>>>>(-%rc,|dS)zRetrieve reslist data.addr_restrictions_ControlSession__ordlistr(s rreslistzControlSession.reslist s~~1222rc,|dS)zRetrieve ifstats data.ifstatsrHr(s rrLzControlSession.ifstatss~~i(((r)F)rrNFrI)NNN)+r4r5r6r7r@rrr} CERR_UNSPECCERR_PERMISSION CERR_BADFMT CERR_BADOP CERR_BADASSOCrr CERR_RESTRICTrr$rMrOrQrmr r/rwrrrrrrrrCTL_OP_READVARrrr r0r/r=rIrJrLrrrr"r"s)MI  #\   !: #\ !: !:  M2@@@ %%%666p#)"28'!'!'!R(3333jtMtMtMl>>>@*    3+3+3+3+j {1u)))) G G G...,111f%8%8%8NhhhhT   333)))))rr"c d}d}t}d|vr^|d}|d=dddddddd d d d d d }|dkrd}|.||}|tt|zt |D]}|dvr|ds|drw|d}t|dks7|dttt tdvrtt|ztt|zd|vr%t|d}|d=d|vr.|ddtjjz|d<|d=d|vr.|ddtjjz|d<|d=|||fS)NrcJtj|jSr&rrrrrfs rrz%parse_mru_variables.."s 3 3AF ; ;rcLtj|j Sr&rVrWs rrz%parse_mru_variables..$s#("5"5af"="=!=rc,| Sr&rrWs rrz%parse_mru_variables..&s rc*|Sr&rZrWs rrz%parse_mru_variables..(src*|Sr&rrWs rrz%parse_mru_variables..*sajjllrc*|Sr&r]rWs rrz%parse_mru_variables..,sqzz||rc|j Sr&rrWs rrz%parse_mru_variables... urc|jSr&r`rWs rrz%parse_mru_variables..0rc|j Sr&rrWs rrz%parse_mru_variables..2rarc|jSr&rerWs rrz%parse_mru_variables..4rcrc|j Sr&rrWs rrz%parse_mru_variables..6s qterc|jSr&rhrWs rrz%parse_mru_variables..8sqtr) lstintz-lstintrz-avgintrz-addrrz-countscorez-scoredropz-droprj)mincountmindropminscorer(r)kodlimited maxlstint minlstintladdrrecentrr%r$zaddr.zlast.rrrrr%rpr)rrq)rgetr SERR_BADSORTr keysr[rrhmaprr SERR_BADPARAMryrrRES_KOD RES_LIMITED)rr6r7r%sortdictkkns rr+r+s2 FG E F# f <;==++++**++$_$n$_$n#O#^1  4 h  G  \\'**F~&|g'=>>> ).."" # # 6 6 + + +  \\' " " 6all7&;&; 6B2ww!||r!uCT%))__,E,EEE&}q'8999 "=1#455 5)IMM'**++ g  'mmHa88 # 12 ( e I'mmHa88 # 56 ( i 7E !!rci}g}t|jD]?\}}|j|vr g||j<||j||jf@|D]%}|t ||dddz }&d|D}|d|D]}|j||r<|j||dkr|jdSdSdS)Nc|dS)Nrrrs rrzstitch_mru..is !rrrcg|] }|d SrIrrs rrzstitch_mru..js%%%qt%%%rT)reverser) rrrrmrsortedrpopr)rr6r7addrdictdeletiarentryrs rr4r4[sHHG --55 E :X % %#%HUZ ##Q O4444CC6(4.nn===crcBB%%W%%%G LLL  # f%%% f   L " " " " " ##  rc|sdSdt|D}dd|z}d|vrd|dz}||z }n|}||fS)N)rNrNc0g|]}|ddkd|zS)rruz%s=%sr)rits rrz&generate_mru_parms..{s7JJJbex6G6G26G6G6Grz, ruz , recent=%s)r rr)rparmStrsr9r:s rr-r-ws vJJy0011JJJH 499X&& &E9"Yx%88 e  * rc:d}tt|jD]v}|jt|j|z dz }d||j||jfz}|t|zt|zt jjkrn||z }w|S)NrNrz, addr.%d=%s, last.%d=%s)rrhrrrrr}r)rexistingBufferSizebufrrfincrs rr2r2s C 3t|$$ % % LT\**Q.2 3)Q16,BB S )CII 5 , - - E 4KCC Jrc|dd}t|dkrdS t|dS#t$rYdSwxYw)Nrrrr)rrhryr~)tokenbitss rr r sb 8>>#  D 4yyA~~r47|| rrsA AAcbeZdZdZd dZdZdZd dZedZ edZ d d Z dS) rzz+MAC authentication manager for NTP packets.Nci|_|t|D]}d|vr|d|d}|}|s:|\}}}|dvrd}t |dkr'tj |dd}||f|jt|<dSdS)N#)AES AES128CMACzAES-128r r) passwordsopenrrrupperrhrrrry)r!keyfilerr8r7r9s rr$zAuthenticator.__init__s  W ? ?$;; 0C 01Dzz||+/::<<(==??&;;;'Gv;;##!X33F3B3K@@F.5v->s5zz**   ? ?rc*t|jS)z1return the number of keytype/passwd tuples stored)rhrr(s r__len__zAuthenticator.__len__s4>"""rc6|j|S)z#get a keytype/passwd tuple by keyid)rrv)r!r8s r __getitem__zAuthenticator.__getitem__s~!!%(((rc|||jvr|f|j|zS|ddfStdD]}|dryt|d}|j|\}}|t t |dkrtj |}|||fcSt )z?Get the keytype/passwd tuple that controls localhost and its idNz/etc/ntpsec/ntp.confr}rr ) rrr[ryrr~rhrrr)r!r8rr7r9s rr}zAuthenticator.controls  &&x$."777tT**/00 0 0Dy)) 0DJJLLO,,$(N5$9!&>$$v;;## X33F;;Fw//// 0rcXtj|sdStjtj|tj||}|rt |dkrdStjd||zS)z)Create the authentication payload to sendFrr!I) rr checknamer\r*r+rhrjr)ror8r7r9mac2s rrzAuthenticator.compute_macsx!!'** 5x||CH..w77H..v66AA s4yyA~~3{4''$..rcFt|tjjkS)zDoes this packet have a MAC?)rhrr LEN_PKT_NOMAC)packets rhave_maczAuthenticator.have_macs 6{{SY444rrMc|d|}|||tz}||tzd}tjd|\}||jvrdS|j|\}}tj|sdStjtj |tj ||} | sdS tj || S#t$r || kcYSwxYw)zDDoes the MAC on this packet verify according to credentials we have?NrF) rrjrkrrrrr\r*r+hmaccompare_digestra) r!rrrror8r\r7r9rs rrzAuthenticator.verify_macs*%yrLrr SERR_BADFMTr SERR_BADOP SERR_BADASSOCSERR_UNKNOWNVAR SERR_BADVALUErrrrrrrrrrrrrzrrrrrwrrCrrrrr"r+r4r-r2r rzrrrrsIIV0/////// (      %%%%%%%%%%%%%%%%PM@@@@@@@@FA-A-A-A-A-FA-A-A-H"@ D : ; AB 9 ? ' << ' ! F) $  5 + ! ' N ! 4 6 %(J(%?%?%?%?%?%?%?%?P I I I I I I I I}N )N )N )N )N )N )N )N )bE"E"E"P###8      YYYYYYYYYYr