[Git][NTPsec/ntpsec][master] 4 commits: First cut at pyntpdig with authentication.
Eric S. Raymond
gitlab at mg.gitlab.com
Tue Nov 8 12:46:34 UTC 2016
Eric S. Raymond pushed to branch master at NTPsec / ntpsec
Commits:
951af89b by Eric S. Raymond at 2016-11-08T06:22:45-05:00
First cut at pyntpdig with authentication.
- - - - -
b06f19f3 by Eric S. Raymond at 2016-11-08T06:43:18-05:00
In pyntpdig, implement packet hex dumping at debug >= 2.
- - - - -
1f3e43af by Eric S. Raymond at 2016-11-08T06:53:58-05:00
Standardize the way we dump the codebase version.
- - - - -
3578cbe1 by Eric S. Raymond at 2016-11-08T07:45:49-05:00
Authenticated send works in pyntdig.
- - - - -
5 changed files:
- ntpdig/pyntpdig
- ntpq/ntpq
- ntpstats/ntpviz
- pylib/packet.py
- pylib/util.py
Changes:
=====================================
ntpdig/pyntpdig
=====================================
--- a/ntpdig/pyntpdig
+++ b/ntpdig/pyntpdig
@@ -35,6 +35,26 @@ from __future__ import print_function, division
import sys, socket, select, struct, time, getopt, datetime
+# This code can run with a large subset of its capabilities
+# even when the ntp library is not available.
+try:
+ import ntp.packet
+ import ntp.util
+ standalone = False
+except:
+ standalone = True
+
+if standalone:
+ version = "ntpsec ntpdig (running standalone)"
+else:
+ version = ntp.util.stdversion()
+
+def standalone_bailout(switch):
+ if standalone:
+ sys.stderr.write("ntpdig: %s is not available running standalone\n." \
+ % switch)
+ raise SystemExit(1)
+
class SNTPPacket:
@staticmethod
def rescale(t):
@@ -93,10 +113,26 @@ def queryhost(server, concurrent, timeout=5, port=123):
if debug:
log("querying %s (%s)" % (sockaddr[0], server))
s = socket.socket(family, socktype)
- d = b'\xe3' + b'\0' * 47
- s.sendto(d, sockaddr)
+ packet = b'\xe3' + b'\0' * 47
+ if keyid and keytype and passwd:
+ if debug:
+ log("authenticating with %s key %d" % (keytype, keyid))
+ mac = ntp.packet.Authenticator.compute_mac(packet,
+ keyid, keytype, passwd)
+ if mac is None:
+ log("MAC generation failed while querying %s" % server)
+ raise SystemExit(1)
+ else:
+ packet += mac
+ s.sendto(packet, sockaddr)
+ if debug >= 2:
+ print("Sent to %s:" % (sockaddr[0],))
+ ntp.packet.dump_hex_printable(packet)
def read_append(s, packets):
d, a = s.recvfrom(1024)
+ if debug >= 2:
+ print("Received:")
+ ntp.packet.dump_hex_printable(d)
pkt = SNTPPacket(d)
pkt.hostname = server
pkt.resolved = sockaddr[0]
@@ -204,8 +240,8 @@ USAGE: sntp [ -<flag> [<val>] | --<name>[{=| }<val>] ]...
- prohibits the option 'ipv4'
-a Num authentication Enable authentication with the numbered key
-c yes concurrent Hosts to be queried concurrently
- -d no debug Normal verbose
- -D yes set-debug-level Normal verbose
+ -d no debug Increase debug verbosity
+ -D yes set-debug-level Set debug verbosity
-g yes gap Set gap between requests
-j no json Use JSON output format
-l Str logfile Log to specified logfile
@@ -262,7 +298,8 @@ if __name__ == '__main__':
af = socket.AF_INET
elif switch in ("-6", "--ipv6"):
af = socket.AF_INET6
- elif switch in ("-a", "--authentication"): # Not implemented yet
+ elif switch in ("-a", "--authentication"):
+ standalone_bailout(switch)
authkey = int(val)
elif switch in ("-c", "--concurrent"):
concurrent_hosts.append(val)
@@ -272,21 +309,25 @@ if __name__ == '__main__':
debug = int(val)
elif switch in ("-j", "--json"):
json = True
- elif switch in ("-k", "--keyfile"): # Not implemented yet
+ elif switch in ("-k", "--keyfile"):
+ standalone_bailout(switch)
keyfile = val
elif switch in ("-l", "--logfile"):
try:
logfp = open(val, "w")
except OSError:
- self.warn("logfile open of %s failed.\n" % val)
+ sys.stderr.write("logfile open of %s failed.\n" % val)
raise SystemExit(1)
elif switch in ("-M", "--steplimit"): # Not implemented yet
+ standalone_bailout(switch)
steplimit = int(val)
elif switch in ("-p", "--samples"):
samples = int(val)
elif switch in ("-S", "--step"): # Not implemented yet
+ standalone_bailout(switch)
step = True
elif switch in ("-s", "--slew"): # Not implemented yet
+ standalone_bailout(switch)
slew = True
elif switch in ("-t", "--timeout"):
timeout = int(val)
@@ -294,18 +335,31 @@ if __name__ == '__main__':
print(usage)
raise SystemExit(0)
elif switch in ("-V", "--version"):
- print("ntpdig 0.1\n") # FIXME: Use the version module
+ print(version)
raise SystemExit(0)
else:
- self.warn("Unknown command line switch or missing argument.\n")
- self.warn(usage)
+ sys.stderr.write("Unknown command line switch or missing argument.\n")
+ sys.stderr.write(usage)
raise SystemExit(1)
except ValueError:
- self.warn("Invalid argument.\n")
- self.warn(usage)
+ sys.stderr.write("Invalid argument.\n")
+ sys.stderr.write(usage)
raise SystemExit(1)
- if authkey and keyfile is None:
+ credentials = keyid = keytype = passwd = None
+ try:
+ credentials = ntp.packet.Authenticator(keyfile)
+ except (OSError, IOError):
+ pass
+ if credentials:
+ try:
+ (keyid, keytype, passwd) = credentials.control(authkey)
+ except ValueError:
+ # There are no trusted keys. Barf.
+ log("cannot get authentication key")
+ raise SystemExit(1)
+
+ if not credentials and authkey and keyfile is None:
self.warn("-a option requires -k.\n")
raise SystemExit(1)
=====================================
ntpq/ntpq
=====================================
--- a/ntpq/ntpq
+++ b/ntpq/ntpq
@@ -30,7 +30,7 @@ try:
except ImportError:
pass
-version = ntp.version.BASENAME + " " + ntp.version.VERSION
+version = stdversion()
# General notes on Python 2/3 compatibility:
#
=====================================
ntpstats/ntpviz
=====================================
--- a/ntpstats/ntpviz
+++ b/ntpstats/ntpviz
@@ -42,7 +42,7 @@ import tempfile
try:
from ntp.statfiles import *
- import ntp.version
+ import ntp.util
except ImportError:
sys.stderr.write("ntpviz: can't find Python NTP library -- check PYTHONPATH.\n")
sys.exit(1)
@@ -1283,8 +1283,7 @@ Python by ESR, concept and GNUPLOT code by Dan Drown.
args = parser.parse_args()
- version = "%s %s+%s" % ( ntp.version.BASENAME, ntp.version.VERSION, \
- ntp.version.TICK)
+ version = ntp.util.stdversion()
if args.version:
print(version)
=====================================
pylib/packet.py
=====================================
--- a/pylib/packet.py
+++ b/pylib/packet.py
@@ -1040,9 +1040,11 @@ DEFAULT_KEYFILE = "/usr/local/etc/ntp.keys"
class Authenticator:
"MAC authentication manager for NTP packets."
- def __init__(self, keyfile=DEFAULT_KEYFILE):
+ def __init__(self, keyfile=None):
# We allow I/O and permission errors upward deliberately
self.passwords = {}
+ if keyfile is None:
+ keyfile = DEFAULT_KEYFILE
for line in open(keyfile):
if '#' in line:
line = line[:line.index("#")]
@@ -1055,8 +1057,13 @@ class Authenticator:
return len(self.passwords)
def __getitem__(self, keyid):
return self.passwords.get(keyid)
- def control(self):
+ def control(self, keyid=None):
"Get a keyid/passwd pair that is trusted on localhost"
+ if keyid is not None:
+ if keyid in self.passwords:
+ return (keyid) + self.passwords[keyid]
+ else:
+ return (keyid, None, None)
for line in open("/etc/ntp.conf"):
if line.startswith("control"):
keyid = int(line.split()[1])
=====================================
pylib/util.py
=====================================
--- a/pylib/util.py
+++ b/pylib/util.py
@@ -10,6 +10,10 @@ import ntp.ntpc
import re
from ntp.packet import *
+from ntp.version import *
+
+def stdversion():
+ return "%s %s+%s" % (BASENAME, VERSION, ntp.version.TICK)
def portsplit(hostname):
portsuffix = ""
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/compare/5877d463b16fe3a852029a1edf22df1638abbc29...3578cbe19b9da920cc6d76bba0cf3a08816f602d
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ntpsec.org/pipermail/vc/attachments/20161108/f80b62cf/attachment.html>
More information about the vc
mailing list