[Git][NTPsec/ntpsec][master] Repair a problem in Mode 6 protocol handling.
Eric S. Raymond
gitlab at mg.gitlab.com
Mon Dec 19 20:05:07 UTC 2016
Eric S. Raymond pushed to branch master at NTPsec / ntpsec
Commits:
48d07be8 by Eric S. Raymond at 2016-12-19T15:04:32-05:00
Repair a problem in Mode 6 protocol handling.
The old C ntpq code was, as it turns out, broken. It assumed that a nonce
issued by ntpd was good for 4 succeeding requests when, in fact, the server
would consider it invalid 16 seconds after the receipt time of the request
for the nonce.
The Python Mode 6 protocol code inherited this bug. This commit fixes
the problem.
- - - - -
4 changed files:
- docs/mode6.txt
- include/ntp_control.h
- ntpd/ntp_control.c
- pylib/packet.py
Changes:
=====================================
docs/mode6.txt
=====================================
--- a/docs/mode6.txt
+++ b/docs/mode6.txt
@@ -482,6 +482,12 @@ containing one string-valued variable, "nonce". The value need not by
interpreted by the client, only replayed as part of a following MRU-list
request.
+Each nonce becomes invalid 16 seconds after the request for it was
+received by ntpd. While the issue time is encoded in the nonce, it
+is safer practice not to rely on the nonce format but instead to track
+the last nonce transmission time in your client and re-request based
+on that.
+
[[auth]]
== Authentication ==
=====================================
include/ntp_control.h
=====================================
--- a/include/ntp_control.h
+++ b/include/ntp_control.h
@@ -160,4 +160,13 @@ struct ntp_control {
#define IFSTATS_FIELDS 12
#define RESLIST_FIELDS 4
+/*
+ * To prevent replay attacks, MRU list nonces age out. Time is in seconds.
+ *
+ * Don't change this value casually. Lengthening it might extend an
+ * attack window for DDoS amplification. Shortening it might make your
+ * server (or client) incompatible with older versions.
+ */
+#define NONCE_TIMEOUT 16
+
#endif /* GUARD_NTP_CONTROL_H */
=====================================
ntpd/ntp_control.c
=====================================
--- a/ntpd/ntp_control.c
+++ b/ntpd/ntp_control.c
@@ -3051,7 +3051,7 @@ static int validate_nonce(
get_systime(&now_delta);
L_SUB(&now_delta, &ts);
- return (supposed == derived && now_delta.l_ui < 16);
+ return (supposed == derived && now_delta.l_ui < NONCE_TIMEOUT);
}
=====================================
pylib/packet.py
=====================================
--- a/pylib/packet.py
+++ b/pylib/packet.py
@@ -727,6 +727,7 @@ class ControlSession:
self.rstatus = 0
self.ntpd_row_limit = ControlSession.MRU_ROW_LIMIT
self.logfp = sys.stdout
+ self.nonce_xmit = 0
def close(self):
if self.sock:
@@ -1191,13 +1192,13 @@ class ControlSession:
def fetch_nonce(self):
"Receive a nonce that can be replayed - combats source address spoofing"
self.doquery(opcode=ntp.control.CTL_OP_REQ_NONCE)
+ self.nonce_xmit = time.time()
if not self.response.startswith(polybytes("nonce=")):
raise ControlException(SERR_BADNONCE)
return polystr(self.response.strip())
def mrulist(self, variables=None, rawhook=None, recent=None):
"Retrieve MRU list data"
- nonce_uses = 0
restarted_count = 0
cap_frags = True
warn = self.logfp.write
@@ -1363,10 +1364,8 @@ class ControlSession:
"frags" if cap_frags else "limit",
frags if cap_frags else limit,
parms)
- nonce_uses += 1
- if nonce_uses >= 4:
+ if time.time() - self.nonce_xmit >= ntp.control.NONCE_TIMEOUT:
nonce = self.fetch_nonce()
- nonce_uses = 0
for i in range(len(span.entries)):
e = span.entries[len(span.entries) - i - 1]
incr = ", addr.%d=%s, last.%d=%s" % (i, e.addr, i, e.last)
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/commit/48d07be80284fa790ff62a1aaf9a23de7e2be817
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ntpsec.org/pipermail/vc/attachments/20161219/91b92544/attachment.html>
More information about the vc
mailing list