[Git][NTPsec/ntpsec][master] Refactor aurgentication in pyntpq. Begin implementation of mrulist.
Eric S. Raymond
gitlab at mg.gitlab.com
Tue Nov 1 15:28:34 UTC 2016
Eric S. Raymond pushed to branch master at NTPsec / ntpsec
Commits:
aaa15862 by Eric S. Raymond at 2016-11-01T11:27:50-04:00
Refactor aurgentication in pyntpq. Begin implementation of mrulist.
- - - - -
2 changed files:
- ntpq/pyntpq
- pylib/packet.py
Changes:
=====================================
ntpq/pyntpq
=====================================
--- a/ntpq/pyntpq
+++ b/ntpq/pyntpq
@@ -591,7 +591,10 @@ usage: poll [ n ] [ verbose ]
def do_passwd(self, line):
"specify a password to use for authenticated requests"
- self.warn("Authentication is not yet implemented\n")
+ try:
+ self.session.password()
+ except Mode6Exception as e:
+ print(e.message)
def help_passwd(self):
self.say("""\
@@ -1138,6 +1141,11 @@ usage: lopeers
def do_config(self, line):
"send a remote configuration command to ntpd"
+ try:
+ self.session.password()
+ except Mode6Exception as e:
+ print(e.message)
+ return
if self.debug > 2:
self.warn("In Config\nKeyword = :config\nCommand = %s\n" % line)
try:
@@ -1178,7 +1186,8 @@ usage: config_from_file <configuration filename>
def do_mrulist(self, line):
"display the list of most recently seen source addresses, tags mincount=... resall=0x... resany=0x..."
- pass
+ self.say("Ctrl-C will stop MRU retrieval and display partial results.\n")
+ self.session.mrulist()
def help_mrulist(self):
self.say("""\
@@ -1188,6 +1197,11 @@ usage: mrulist [ tag=value ] [ tag=value ] [ tag=value ] [ tag=value ]
def do_ifstats(self, line):
"show statistics for each local address ntpd is using"
+ try:
+ self.session.password()
+ except Mode6Exception as e:
+ print(e.message)
+ return
pass
def help_ifstats(self):
@@ -1198,6 +1212,11 @@ usage: ifstats
def do_reslist(self, line):
"show ntpd access control list"
+ try:
+ self.session.password()
+ except Mode6Exception as e:
+ print(e.message)
+ return
pass
def help_reslist(self):
=====================================
pylib/packet.py
=====================================
--- a/pylib/packet.py
+++ b/pylib/packet.py
@@ -5,7 +5,8 @@
#
# SPDX-License-Identifier: BSD-2-clause
from __future__ import print_function, division
-import sys, socket, select, struct, curses.ascii, collections, getpass, hashlib
+import sys, socket, select, struct, curses.ascii, collections
+import getpass, hashlib, time
# General notes on Python 2/3 compatibility:
#
@@ -113,18 +114,7 @@ from ntp_control import *
# of requests and multipacket responses to each.
MAXFRAGS = 32
-# These things are ours. They shadow the CERR_* definitions in ntp_control.h
-
-NERR_UNSPEC = 0
-NERR_PERMISSION = 1
-NERR_BADFMT = 2
-NERR_BADOP = 3
-NERR_BADASSOC = 4
-NERR_UNKNOWNVAR = 5
-NERR_BADVALUE = 6
-NERR_RESTRICT = 7
-
-NERR_NORESOURCE = NERR_PERMISSION # wish there was a different code
+MRU_REPORT_SECS = 5
class Packet:
"Encapsulate an NTP fragment"
@@ -251,7 +241,9 @@ SERR_BADLENGTH = "***Response length should have been a multiple of 4"
SERR_BADKEY = "***Invalid key identifier"
SERR_INVPASS = "***Invalid password"
SERR_NOKEY = "***Key not found"
-SERR_AUTH = "***Server disallowed request (authentication?)"
+SERR_BADNONCE = "***Unexpected nonce response format"
+SERR_BADPARM = "***Unknown parameter %s"
+SERR_NOCRED = "***No credentials"
def dump_hex_printable(xdata):
"Dump a packet in hex, in a familiar hex format"
@@ -282,6 +274,7 @@ class Mode6Exception(BaseException):
class Mode6Session:
"A session to a host"
+ MRU_ROW_LIMIT = 256
def __init__(self):
self.debug = 0
@@ -292,7 +285,7 @@ class Mode6Session:
self.always_auth = False # Always send authenticated requests
self.keytype = "MD5"
self.keyid = None
- self.password = None
+ self.passwd = None
self.hostname = None
self.isnum = False
self.sock = None
@@ -300,6 +293,8 @@ class Mode6Session:
self.sequence = 0
self.response = ""
self.rstatus = 0
+ self.mrustats = []
+ self.ntpd_row_limit = Mode6Session.MRU_ROW_LIMIT
def close(self):
if self.sock:
@@ -382,6 +377,24 @@ class Mode6Session:
return False
return True
+ def password(self):
+ "Get a keyid and the password if we don't have one."
+ if self.keyid is None:
+ try:
+ key_id = int(input("Keyid: "))
+ # FIXME: Magic number, yuck
+ if key_id == 0 or key_id > 65535:
+ raise Mode6Exception(SERR_BADKEY)
+ except ValueError:
+ raise Mode6Exception(SERR_BADKEY)
+ self.keyid = key_id
+
+ if self.passwd is None:
+ passwd = getpass.getpass("%s Password: " % self.keytype)
+ if passwd is None:
+ raise Mode6Exception(SERR_INVPASS)
+ self.passwd = passwd
+
def sendpkt(self, xdata):
"Send a packet to the host."
while len(xdata) % 4:
@@ -412,6 +425,7 @@ class Mode6Session:
pkt = Mode6Packet(self, opcode, associd, qdata)
# If we have data, pad it out to a 32-bit boundary.
+ # Do not include these in the payload count.
if pkt.extension:
pkt.extension = polybytes(pkt.extension)
while ((Packet.HEADER_LEN + len(pkt.extension)) & 3):
@@ -423,6 +437,9 @@ class Mode6Session:
if not auth and not self.always_auth:
return pkt.send()
+ if self.keyid is None or self.passwd is None:
+ raise Mode6Exception(SERR_NOCRED)
+
# Pad out packet to a multiple of 8 octets to be sure
# receiver can handle it. Note: these pad bytes should
# *not* be counted in the header count field.
@@ -431,22 +448,6 @@ class Mode6Session:
pkt.extension += b"\x00"
pkt.extension = polystr(pkt.extension)
- # Get the keyid and the password if we don't have one.
- if self.keyid is None:
- try:
- key_id = int(input("Keyid: "))
- # FIXME: Magic number, yuck
- if key_id == 0 or key_id > 65535:
- raise Mode6Exception(SERR_BADKEY)
- except ValueError:
- raise Mode6Exception(SERR_BADKEY)
- self.keyid = key_id
-
- passwd = getpass.getpass("%s Password: " % self.keytype)
- if passwd is None:
- raise Mode6Exception(SERR_INVPASS)
- self.passwd = passwd
-
# Do the encryption.
hasher = hashlib.new(self.keytype)
hasher.update(self.passwd)
@@ -697,10 +698,44 @@ class Mode6Session:
# Copes with an implementation error - ntpd uses putdata without
# setting the size correctly.
if not self.response:
- raise Mode6Exception(SERR_AUTH)
+ raise Mode6Exception(SERR_PERMISSION)
elif b"\x00" in self.response:
self.response = self.response[:self.response.index(b"\x00")]
self.response = self.response.rstrip()
return self.response == "Config Succeeded"
+ def mrulist(self, variables):
+ "Retrieve MRU list data"
+ self.doquery(opcode=CTL_OP_REQ_NONCE)
+ if not self.response.startswith("nonce="):
+ raise Mode6Exception(SERR_BADNONCE)
+ nonce = self.response
+ nonce_uses = 0
+ restarted_count = 0
+ mru_count = 0
+ c_mru_l_rc = False
+ list_complete = False
+ have_now = False
+ cap_frags = True
+ got = 0
+ ri = 0
+
+ for k in list(variables.keys()):
+ if k in ("mincount","resall","resany","maxlstint","laddr","sort"):
+ continue
+ else:
+ raise Mode6Exception(SERR_BADPARAM % k)
+ mrulist_interrupted = False
+ try:
+ next_report = time.time() + MRU_REPORT_SECS
+ limit = min(3 * MAXFRAGS, self.ntpd_row_limit)
+ frags = MAXFRAGS;
+ req_buf = "nonce=%s, frags=%d" % (nonce, frags)
+ if varlist:
+ req_buf += ", " + ",".join([("%s=%s" % it) for it in list(variables.items())])
+ while True:
+ self.doquery(opcode=CTL_OP_REQ_NONCE, qdata=req_buf)
+ except KeyboardInterrupt:
+ mrulist_interrupted = True
+
# end
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/commit/aaa15862988fa24906be1e6103d1530caa4de2f3
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ntpsec.org/pipermail/vc/attachments/20161101/0cf443a6/attachment.html>
More information about the vc
mailing list