[Git][NTPsec/ntpsec][master] 6 commits: Rate limiting cleanup

Hal Murray gitlab at mg.gitlab.com
Fri Mar 13 18:28:21 UTC 2020



Hal Murray pushed to branch master at NTPsec / ntpsec


Commits:
4ac74571 by Hal Murray at 2020-03-09T21:02:45-07:00
Rate limiting cleanup

The old rate limiting scheme was carefully tuned to work with
a single copy of the same code.  That doesn't work if you have
several clients behind a NAT box.

That chunk of code now uses a simple exponential decay (aka
leaky bucket) to keep track of recent traffic.  The time constant
is 20 seconds and the rate limit is 1 packet per second.  There is
no config option to change them.  (yet?)  The "score" is scaled
such that the units are packets/second.

That pair of parameters means that a client can start with a burst
of 20 packets but over the long term, but can only sustain 1 packet
per second.

ntpq/mru now displays the score and the number of packets
from that IP Address that were dropped.

- - - - -
4cbab792 by Hal Murray at 2020-03-10T19:19:44-07:00
seccomp: Add comment about systemd to catchTrap

- - - - -
6fa76a4d by Hal Murray at 2020-03-12T16:31:20-07:00
Add KoD limiting

- - - - -
0093b02b by Hal Murray at 2020-03-12T18:20:41-07:00
Add sorting by score and drop to ntpq/mrulist

- - - - -
0e0e4db4 by Hal Murray at 2020-03-12T23:36:19-07:00
Add filtering by mindrop and minscore to ntpq/mrulist

- - - - -
f67f8bf1 by Hal Murray at 2020-03-13T02:04:25-07:00
Add minlstint and doc for maxlstint for ntpq/mrulist

- - - - -


11 changed files:

- docs/includes/mrufmt.adoc
- docs/includes/ntpq-body.adoc
- docs/mode6.adoc
- include/ntp.h
- ntpd/ntp_control.c
- ntpd/ntp_monitor.c
- ntpd/ntp_sandbox.c
- pylib/packet.py
- pylib/util.py
- tests/pylib/test_packet.py
- tests/pylib/test_util.py


Changes:

=====================================
docs/includes/mrufmt.adoc
=====================================
@@ -19,6 +19,8 @@ KoD response, respectively.
 |+m+             |Packet mode.
 |+v+             |Packet version number.
 |+count+         |Packets received from this address.
+|+score+         |Packets per second with 20 second decay time.
+|+drop+          |Packets dropped (or KoDed) from this address.
 |+rport+         |Source port of last packet from this address.
 |+remote address+|
 DNS name, numeric address, or address followed by claimed DNS name


=====================================
docs/includes/ntpq-body.adoc
=====================================
@@ -295,7 +295,7 @@ ind assid status conf reach auth condition last_event cnt
   server so loaded that none of its MRU entries age out before they
   are shipped. With this option, each segment is reported as it arrives.
 
-+mrulist+ [+limited+ | +kod+ | +mincount=+'count' | +laddr=+'localaddr' | +sort=+'sortorder' | +resany=+'hexmask' | +resall=+'hexmask']::
++mrulist+ [+limited+ | +kod+ | +mincount=+'count' | +mindrop=+'drop' | +minscore=+'score' | +maxlstint=+'seconds' | +minlstint=+'seconds' | +laddr=+'localaddr' | +sort=+'sortorder' | +resany=+'hexmask' | +resall=+'hexmask']::
   Obtain and print traffic counts collected and maintained by the
   monitor facility. This is useful for tracking who _uses_ or
   _abuses_ your server.
@@ -303,16 +303,26 @@ ind assid status conf reach auth condition last_event cnt
 With the exception of +sort=+'sortorder', the options
 filter the list returned by +ntpd+. The +limited+ and +kod+ options
 return only entries representing client addresses from which the last
-packet received triggered either discarding or a KoD response. The
-+mincount=+'count' option filters entries representing less than 'count'
-packets. The +laddr=+'localaddr' option filters entries for packets
+packet received triggered either discarding or a KoD response.
+The +mincount=+'count' option filters entries that have received less
+than 'count' packets.
+The +mindrop=+'drop' option filters entries that have dropped less
+than 'drop' packets.
+The +minscore=+'score' option filters entries with a score less
+than 'score'.
+The +maxlstint=+'seconds' option filters entries where no packets have
+arrived within 'seconds'.
+The +minlstint=+'seconds' option filters entries with a packet has
+arrived within 'seconds'.
+The +laddr=+'localaddr' option filters entries for packets
 received on any local address other than 'localaddr'. +resany=+'hexmask'
 and +resall=+'hexmask' filter entries containing none or less than all,
 respectively, of the bits in 'hexmask', which must begin with +0x+.
 +
 The _sortorder_ defaults to +lstint+ and may be any of +addr+,
-+count+, +avgint+, +lstint+, or any of those preceded by a minus sign
-(hyphen) to reverse the sort order. The output columns are:
++count+, +avgint+, +lstint+, +score+, +drop+ or any of those
+preceded by a minus sign (hyphen) to reverse the sort order.
+The output columns are:
 +
 include::mrufmt.adoc[]
 


=====================================
docs/mode6.adoc
=====================================
@@ -302,7 +302,14 @@ limit::		Limit on MRU entries returned.  One of frags= or limit=
 
 mincount::	(decimal) Return entries with packet count >= mincount.
 
-maxlstint::	(decimal) Return entries with lstint <= maxlstint.
+mindrop::	(decimal) Return entries with drop count >= mindrop.
+
+minscore::	(float) Return entries with score >= minscore.
+
+maxlstint::	(decimal seconds) Return entries with lstint <= maxlstint.
+		(lstint is now-time of most recent packet)
+
+minlstint::	(decimal seconds) Return entries with lstint >= minlstint.
 		(lstint is now-time of most recent packet)
 
 laddr::		Return entries associated with the server's IP


=====================================
include/ntp.h
=====================================
@@ -613,8 +613,9 @@ struct mon_data {
 	endpt *		lcladr;		/* address on which this arrived */
 	l_fp		first;		/* first time seen */
 	l_fp		last;		/* last time seen */
-	int		leak;		/* leaky bucket accumulator */
 	int		count;		/* total packet count */
+	unsigned int	dropped;	/* packets dropped */
+	float		score;		/* recent packets/second */
 	unsigned short	flags;		/* restrict flags */
 	uint8_t		vn_mode;	/* packet mode & version */
 	sockaddr_u	rmtadr;		/* address of remote host */


=====================================
ntpd/ntp_control.c
=====================================
@@ -3227,8 +3227,10 @@ send_mru_entry(
 	const char ct_fmt[] =		"ct.%d";
 	const char mv_fmt[] =		"mv.%d";
 	const char rs_fmt[] =		"rs.%d";
+	const char sc_fmt[] =		"sc.%d";
+	const char dr_fmt[] =		"dr.%d";
 	char	tag[32];
-	bool	sent[6]; /* 6 tag=value pairs */
+	bool	sent[8]; /* 8 tag=value pairs */
 	uint32_t noise;
 	unsigned int	which = 0;
 	unsigned int	remaining;
@@ -3278,6 +3280,16 @@ send_mru_entry(
 			ctl_puthex(tag, mon->flags);
 			break;
 
+		case 6:
+			snprintf(tag, sizeof(tag), sc_fmt, count);
+			ctl_putdblf(tag, true, 3, mon->score);
+			break;
+
+		case 7:
+			snprintf(tag, sizeof(tag), dr_fmt, count);
+			ctl_putuint(tag, mon->dropped);
+			break;
+
 		default:
 			/* huh? */
 			break;
@@ -3331,6 +3343,8 @@ send_mru_entry(
  *			address.  When limit is not one and frags= is
  *			provided, the fragment limit controls.
  *	mincount=	(decimal) Return entries with count >= mincount.
+ *	mindrop=	(decimal) Return entries with drop >= mindrop.
+ *	minscore=	(float) Return entries with score >= minscore.
  *	laddr=		Return entries associated with the server's IP
  *			address given.  No port specification is needed,
  *			and any supplied is ignored.
@@ -3414,9 +3428,12 @@ static void read_mru_list(
 	static const char	frags_text[] =		"frags";
 	static const char	limit_text[] =		"limit";
 	static const char	mincount_text[] =	"mincount";
+	static const char	mindrop_text[] =	"mindrop";
+	static const char	minscore_text[] =	"minscore";
 	static const char	resall_text[] =		"resall";
 	static const char	resany_text[] =		"resany";
 	static const char	maxlstint_text[] =	"maxlstint";
+	static const char	minlstint_text[] =	"minlstint";
 	static const char	laddr_text[] =		"laddr";
 	static const char	recent_text[] =		"recent";
 	static const char	resaxx_fmt[] =		"0x%hx";
@@ -3426,7 +3443,10 @@ static void read_mru_list(
 	unsigned short		resall;
 	unsigned short		resany;
 	int			mincount;
+	unsigned int		mindrop;
+	float			minscore;
 	unsigned int		maxlstint;
+	unsigned int		minlstint;
 	sockaddr_u		laddr;
 	unsigned int		recent;
 	endpt *                 lcladr;
@@ -3467,9 +3487,12 @@ static void read_mru_list(
 	set_var(&in_parms, frags_text, sizeof(frags_text), 0);
 	set_var(&in_parms, limit_text, sizeof(limit_text), 0);
 	set_var(&in_parms, mincount_text, sizeof(mincount_text), 0);
+	set_var(&in_parms, mindrop_text, sizeof(mindrop_text), 0);
+	set_var(&in_parms, minscore_text, sizeof(minscore_text), 0);
 	set_var(&in_parms, resall_text, sizeof(resall_text), 0);
 	set_var(&in_parms, resany_text, sizeof(resany_text), 0);
 	set_var(&in_parms, maxlstint_text, sizeof(maxlstint_text), 0);
+	set_var(&in_parms, minlstint_text, sizeof(minlstint_text), 0);
 	set_var(&in_parms, laddr_text, sizeof(laddr_text), 0);
 	set_var(&in_parms, recent_text, sizeof(recent_text), 0);
 	for (i = 0; i < COUNTOF(last); i++) {
@@ -3484,9 +3507,12 @@ static void read_mru_list(
 	frags = 0;
 	limit = 0;
 	mincount = 0;
+	mindrop = 0;
+	minscore = 0.0;
 	resall = 0;
 	resany = 0;
 	maxlstint = 0;
+	minlstint = 0;
 	recent = 0;
 	lcladr = NULL;
 	priors = 0;
@@ -3517,6 +3543,14 @@ static void read_mru_list(
 				goto blooper;
 			if (mincount < 0)
 				mincount = 0;
+		} else if (!strcmp(mindrop_text, v->text)) {
+			if (1 != sscanf(val, "%u", &mindrop))
+				goto blooper;
+		} else if (!strcmp(minscore_text, v->text)) {
+			if (1 != sscanf(val, "%f", &minscore))
+				goto blooper;
+			if (minscore < 0)
+				minscore = 0.0;
 		} else if (!strcmp(resall_text, v->text)) {
 			if (1 != sscanf(val, resaxx_fmt, &resall))
 				goto blooper;
@@ -3526,6 +3560,9 @@ static void read_mru_list(
 		} else if (!strcmp(maxlstint_text, v->text)) {
 			if (1 != sscanf(val, "%u", &maxlstint))
 				goto blooper;
+		} else if (!strcmp(minlstint_text, v->text)) {
+			if (1 != sscanf(val, "%u", &minlstint))
+				goto blooper;
 		} else if (!strcmp(laddr_text, v->text)) {
 			if (decodenetnum(val, &laddr))
 				goto blooper;
@@ -3639,6 +3676,10 @@ static void read_mru_list(
 
 		if (mon->count < mincount)
 			continue;
+		if (mon->dropped < mindrop)
+			continue;
+		if (mon->score < minscore)
+			continue;
 		if (resall && resall != (resall & mon->flags))
 			continue;
 		if (resany && !(resany & mon->flags))
@@ -3646,6 +3687,9 @@ static void read_mru_list(
 		if (maxlstint > 0 && lfpuint(now) - lfpuint(mon->last) >
 		    maxlstint)
 			continue;
+		if (minlstint > 0 && lfpuint(now) - lfpuint(mon->last) <
+		    minlstint)
+			continue;
 		if (lcladr != NULL && mon->lcladr != lcladr)
 			continue;
 		if (recent != 0 && countdown-- > recent)


=====================================
ntpd/ntp_monitor.c
=====================================
@@ -4,6 +4,9 @@
 
 #include "config.h"
 
+#include <math.h>
+#include <stdlib.h>
+
 #include "ntpd.h"
 #include "ntp_io.h"
 #include "ntp_lists.h"
@@ -54,14 +57,14 @@ struct monitor_data mon_data = {
 	.mru_maxage = 3600,	/* recycle if older than this */
 	.mru_minage = 64,	/* recycle if full and older than this */
 	.mru_maxdepth = MRU_MAXDEPTH_DEF,	/* MRU count hard limit */
-	.mon_age = 3000,		/* preemption limit */
 	.mru_initalloc = INIT_MONLIST, /* entries to preallocate */
 	.mru_incalloc = INC_MONLIST, /* allocation batch factor */
 	.mru_exists = 0,	/* slot already exists */
 	.mru_new = 0,		/* allocate a new slot (2 cases) */
 	.mru_recycleold = 0,	/* recycle slot: age > mru_maxage */
 	.mru_recyclefull = 0,	/* recycle slot: full and age > mru_minage */
-	.mru_none = 0		/* couldn't get one */
+	.mru_none = 0,		/* couldn't get one */
+	.mon_age = 3000		/* preemption limit */
 };
 
 /*
@@ -77,6 +80,12 @@ static	void	remove_from_hash(mon_entry *);
 static	void	mon_free_entry(mon_entry *);
 static	void	mon_reclaim_entry(mon_entry *);
 
+/* Rate limiting */
+float rate_limit = 1.0;		/* packets per second */
+float kod_limit = 0.1;		/* KOD per second - see comments below */
+float decay_time = 20;		/* seconds, exponential decay time */
+
+
 /*
  * init_mon - initialize monitoring global data
  */
@@ -319,11 +328,8 @@ ntp_monitor(
 	unsigned short	restrict_mask;
 	uint8_t		mode;
 	uint8_t		version;
-	uint8_t     li_vn_mode;
-	int		interval;
-	int		head;		/* headway increment */
-	int		leak;		/* new headway */
-	int		limit;		/* average threshold */
+	uint8_t		li_vn_mode;
+	float		since_last;	/* seconds since last packet */
 
 	if (mon_data.mon_enabled == MON_OFF)
 		return ~(RES_LIMITED | RES_KOD) & flags;
@@ -346,9 +352,6 @@ ntp_monitor(
 		mon_data.mru_exists++;
 		interval_fp = rbufp->recv_time;
 		interval_fp -= mon->last;
-		/* add one-half second to round up */
-		interval_fp += 0x80000000;
-		interval = lfpsint(interval_fp);
 		mon->last = rbufp->recv_time;
 		NSRCPORT(&mon->rmtadr) = NSRCPORT(&rbufp->recv_srcadr);
 		mon->count++;
@@ -359,44 +362,35 @@ ntp_monitor(
 		UNLINK_DLIST(mon, mru);
 		LINK_DLIST(mon_data.mon_mru_list, mon, mru);
 
-		/*
-		 * At this point the most recent arrival is first in the
-		 * MRU list.  Decrease the counter by the headway, but
-		 * not less than zero.
-		 */
-		mon->leak -= interval;
-		mon->leak = max(0, mon->leak);
-		head = 1 << rstrct.ntp_minpoll;
-		leak = mon->leak + head;
-		limit = NTP_SHIFT * head;
-
-		DPRINT(2, ("MRU: interval %d headway %d limit %d\n",
-			   interval, leak, limit));
-
-		/*
-		 * If the minimum and average thresholds are not
-		 * exceeded, douse the RES_LIMITED and RES_KOD bits and
-		 * increase the counter by the headway increment.  Note
-		 * that we give a 1-s grace for the minimum threshold
-		 * and a 2-s grace for the headway increment.  If one or
-		 * both thresholds are exceeded and the old counter is
-		 * less than the average threshold, set the counter to
-		 * the average threshold plus the increment and leave
-		 * the RES_LIMITED and RES_KOD bits lit. Otherwise,
-		 * leave the counter alone and douse the RES_KOD bit.
-		 * This rate-limits the KoDs to no less than the average
-		 * headway.
+		/* Keep score:
+		 * if packets arrive at 1/second,
+		 * score will build up to (almost) 1.0
 		 */
-		if (interval + 1 >= rstrct.ntp_minpkt && leak < limit) {
-			mon->leak = leak - 2;
+		since_last = ldexpf(interval_fp, -32);
+		mon->score *= expf(-since_last/decay_time);
+		mon->score += 1.0/decay_time;
+		if (mon->score < rate_limit) {
+			/* low score, turn off reject bits */
 			restrict_mask &= ~(RES_LIMITED | RES_KOD);
-		} else if (mon->leak < limit)
-			mon->leak = limit + head;
-		else
-			restrict_mask &= ~RES_KOD;
+		}
 
-		mon->flags = restrict_mask;
+		if (RES_LIMITED & restrict_mask)
+			mon->dropped++;
+		if (RES_KOD & restrict_mask) {
+			/* We need rate limiting on KoD too.
+			 * Note that DDoS attackers often send
+			 * >1000 packets/second.  A simple fraction
+			 * would turn into lots of KoDs.
+			 * So we try 1/score-squared.
+			 * kod_limit is roughly packets/second when
+			 * score is close to 1.
+			 */
+			float rand = random()*1.0/RAND_MAX;
+			if (rand > kod_limit/(mon->score*mon->score))
+				restrict_mask &= ~RES_KOD;
+		}
 
+		mon->flags = restrict_mask;
 		return mon->flags;
 	}
 
@@ -471,8 +465,9 @@ ntp_monitor(
 	mon->last = rbufp->recv_time;
 	mon->first = mon->last;
 	mon->count = 1;
+	mon->dropped = 0;
+	mon->score = 1.0/decay_time;
 	mon->flags = ~(RES_LIMITED | RES_KOD) & flags;
-	mon->leak = 0;
 	memcpy(&mon->rmtadr, &rbufp->recv_srcadr, sizeof(mon->rmtadr));
 	mon->vn_mode = VN_MODE(version, mode);
 	mon->lcladr = rbufp->dstadr;


=====================================
ntpd/ntp_sandbox.c
=====================================
@@ -493,6 +493,11 @@ int scmp_sc[] = {
  *  You will get several hits for various architures/modes.
  *  You can probably guess the right one.
  *
+ *  If this trap doesn't work, systemd may print out the
+ *  critical info.  Look for something like this:
+ *    Main process exited, code=killed, status=31/SYS
+ *  See above for decoding that number.
+ *
  * Option two:
  *  use strace
  *  sudo strace -t -f -o<filename> <path-to-ntpd> <args>


=====================================
pylib/packet.py
=====================================
@@ -637,9 +637,11 @@ class MRUEntry:
         self.addr = None        # text of IPv4 or IPv6 address and port
         self.last = None        # timestamp of last receipt
         self.first = None       # timestamp of first receipt
-        self.ct = 0             # count of packets received
         self.mv = None          # mode and version
         self.rs = None          # restriction mask (RES_* bits)
+        self.ct = 0             # count of packets received
+        self.sc = None          # score
+        self.dr = None          # dropped packets
 
     def avgint(self):
         last = ntp.ntpc.lfptofloat(self.last)
@@ -1329,7 +1331,7 @@ This combats source address spoofing
             elif tag == "last.newest":
                 # more finished
                 continue
-            for prefix in ("addr", "last", "first", "ct", "mv", "rs"):
+            for prefix in ("addr", "last", "first", "ct", "mv", "rs", "sc", "dr"):
                 if tag.startswith(prefix + "."):
                     (member, idx) = tag.split(".")
                     try:
@@ -1344,10 +1346,11 @@ This combats source address spoofing
         fake_list.sort()
         for idx in fake_list:
             mru = MRUEntry()
+            self.slots += 1
             # Always 6 in practice, in the tests not so much
 #            if len(fake_dict[str(idx)]) != 6:
 #                continue
-            for prefix in ("addr", "last", "first", "ct", "mv", "rs"):
+            for prefix in ("addr", "last", "first", "ct", "mv", "rs", "sc", "dr"):
                 if prefix in fake_dict[str(idx)]:  # dodgy test needs this line
                     setattr(mru, prefix, fake_dict[str(idx)][prefix])
             span.entries.append(mru)
@@ -1550,10 +1553,18 @@ def parse_mru_variables(variables):
             "addr": lambda e: e.sortaddr(),
             # IPv6 desc. then IPv4 desc.
             "-addr": lambda e: e.sortaddr(),
-            # hit count ascending
+            # hit count ascending 
             "count": lambda e: -e.ct,
             # hit count descending
             "-count": lambda e: e.ct,
+            # score ascending 
+            "score": lambda e: -e.sc,
+            # score descending
+            "-score": lambda e: e.sc,
+            # drop count ascending 
+            "drop": lambda e: -e.dr,
+            # drop count descending
+            "-drop": lambda e: e.dr,
         }
         if sortkey == "lstint":
             sortkey = None   # normal/default case, no need to sort
@@ -1562,8 +1573,10 @@ def parse_mru_variables(variables):
             if sorter is None:
                 raise ControlException(SERR_BADSORT % sortkey)
     for k in list(variables.keys()):
-        if k in ("mincount", "resall", "resany", "kod", "limited",
-                 "maxlstint", "laddr", "recent", "sort", "frags", "limit"):
+        if k in ("mincount", "mindrop", "minscore",
+                 "resall", "resany", "kod", "limited",
+                 "maxlstint", "minlstint", "laddr", "recent",
+                 "sort", "frags", "limit"):
             continue
         else:
             raise ControlException(SERR_BADPARAM % k)


=====================================
pylib/util.py
=====================================
@@ -1235,7 +1235,7 @@ class MRUSummary:
         self.showhostnames = showhostnames      # If false, display numeric IPs
         self.wideremote = wideremote
 
-    header = " lstint avgint rstr r m v  count rport remote address"
+    header = " lstint avgint rstr r m v  count    score   drop rport remote address"
 
     def summary(self, entry):
         last = ntp.ntpc.lfptofloat(entry.last)
@@ -1290,11 +1290,25 @@ class MRUSummary:
             if not self.wideremote:
                 # truncate for narrow display
                 dns = dns[:40]
-            stats += " %4hx %c %d %d %6d %5s %s" % \
+            if entry.sc:
+                score = float(entry.sc)
+                if score > 100000.0:
+                  score = "%8.1f" % score
+                elif score > 10000.0:
+                  score = "%8.2f" % score
+                else:
+                  score = "%8.3f" % score
+            else:
+                score = "-"
+            if entry.dr!= None:     # 0 is valid
+                drop = "%4d" % entry.dr
+            else:
+                drop = "-"
+            stats += " %4hx %c %d %d %6d %8s %6s %5s %s" % \
                      (entry.rs, rscode,
                       ntp.magic.PKT_MODE(entry.mv),
                       ntp.magic.PKT_VERSION(entry.mv),
-                      entry.ct, port[1:], dns)
+                      entry.ct, score, drop, port[1:], dns)
             return stats
         except ValueError:
             # This can happen when ntpd ships a corrupt varlist


=====================================
tests/pylib/test_packet.py
=====================================
@@ -599,6 +599,7 @@ class TestMisc(unittest.TestCase):
         cls.last = "0x00000200.00000000"
         cls.first = "0x00000100.00000000"
         cls.ct = 4
+        cls.sc = "0.12345"
         self.assertEqual(cls.avgint(), 64)
         if socket.has_ipv6:
             # Test sortaddr, ipv6
@@ -624,15 +625,17 @@ class TestMisc(unittest.TestCase):
                              "<MRUEntry: "
                              "'last': '0x00000200.00000000', "
                              "'addr': '11.22.33.44:23', 'rs': None, "
-                             "'mv': None, 'first': '0x00000100.00000000', "
-                             "'ct': 4>")
+                             "'mv': None, 'sc': '0.12345', "
+                             "'first': '0x00000100.00000000', "
+                             "'dr': None, 'ct': 4>")
         elif sys.version_info[1] >= 6:  # Already know it is 3.something
             # Python 3.6+, dicts enumerate in assignment order
             self.assertEqual(cls.__repr__(),
                              "<MRUEntry: 'addr': '11.22.33.44:23', "
                              "'last': '0x00000200.00000000', "
-                             "'first': '0x00000100.00000000', 'ct': 4, "
-                             "'mv': None, 'rs': None>")
+                             "'first': '0x00000100.00000000', "
+                             "'mv': None, 'rs': None, 'ct': 4, "
+                             "'sc': '0.12345', 'dr': None>")
         else:
             # Python 3.x < 3.6, dicts enumerate randomly
             # I can not test randomness of this type


=====================================
tests/pylib/test_util.py
=====================================
@@ -939,7 +939,7 @@ class TestPylibUtilMethods(unittest.TestCase):
                                         "foo.bar.com", "1.2.3.4")]
             self.assertEqual(cls.summary(ent),
                              "64730 23296      0  400 K 7 2"
-                             "      1    42 1.2.3.4")
+                             "      1        -      -    42 1.2.3.4")
             # Test summary, second options
             mycache._cache = {}
             cls.now = 0x00000000
@@ -953,7 +953,7 @@ class TestPylibUtilMethods(unittest.TestCase):
             cdns_jig_returns = ["foo.com"]
             self.assertEqual(cls.summary(ent),
                              "64730 23808   4.00   20 L 7 2     65"
-                             "    42 foo.com")
+                             "        -      -    42 foo.com")
             # Test summary, third options
             mycache._cache = {}
             ent.ct = 2
@@ -961,7 +961,7 @@ class TestPylibUtilMethods(unittest.TestCase):
             fakesockmod.gai_error_count = 1
             cdns_jig_returns = ["foobarbaz" * 5]  # 45 chars, will be cropped
             self.assertEqual(cls.summary(ent),
-                             "64730 23808    256    0 . 7 2      2    42"
+                             "64730 23808    256    0 . 7 2      2        -      -    42"
                              " 1.2.3.4 (foobarbazfoobarbazfoobarbazfoob")
             # Test summary, wide
             mycache._cache = {}
@@ -970,7 +970,7 @@ class TestPylibUtilMethods(unittest.TestCase):
             cdns_jig_returns = ["foobarbaz" * 5]  # 45 chars, will be cropped
             self.assertEqual(cls.summary(ent),
                              "64730 23808    256    0 . 7 2      2"
-                             "    42 1.2.3.4 "
+                             "        -      -    42 1.2.3.4 "
                              "(foobarbazfoobarbazfoobarbazfoobarbazfoobarbaz)")
         finally:
             ntp.util.socket = socktemp



View it on GitLab: https://gitlab.com/NTPsec/ntpsec/-/compare/51f41df59751ce28aab12e999ba3e6472e573756...f67f8bf19f58e8736a7882eab03003bb1ed96a41

-- 
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/-/compare/51f41df59751ce28aab12e999ba3e6472e573756...f67f8bf19f58e8736a7882eab03003bb1ed96a41
You're receiving this email because of your account on gitlab.com.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ntpsec.org/pipermail/vc/attachments/20200313/8a329c14/attachment-0001.htm>


More information about the vc mailing list