[tor-commits] [depictor/master] Add Clock Skew. Closes #25767

tom at torproject.org tom at torproject.org
Fri Apr 20 15:31:10 UTC 2018


commit a91384c90639c71dad3486813f85b9bbf79bf2c4
Author: Tom Ritter <tom at ritter.vg>
Date:   Fri Apr 20 10:30:59 2018 -0500

    Add Clock Skew. Closes #25767
---
 data/consensus.cfg |  3 +++
 utility.py         | 28 +++++++++++++++++++++++++++
 website.py         | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 write_website.py   |  5 ++++-
 4 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/data/consensus.cfg b/data/consensus.cfg
index 02f39b1..e4af54a 100644
--- a/data/consensus.cfg
+++ b/data/consensus.cfg
@@ -9,6 +9,9 @@ graph_logical_min 125
 # do not show values values greater than this on the graph. You can leave this high
 graph_logical_max 25000
 
+# we highlight clockskew that is 20 seconds or greater
+clockskew_threshold 20
+
 # recognized tor consensus parameters
 
 known_params bwweightscale
diff --git a/utility.py b/utility.py
old mode 100644
new mode 100755
index 6b2cfae..d4f9a68
--- a/utility.py
+++ b/utility.py
@@ -1,4 +1,7 @@
+#!/usr/bin/env python
+
 import time
+import urllib
 import datetime
 
 import stem.descriptor
@@ -81,6 +84,26 @@ def _get_documents(label, resource):
 
 	return documents, issues, runtimes
 
+def get_clockskew():
+	clockskew = {}
+	for (nickname, authority) in get_dirauths().items():
+		authority_address = "http://" + str(authority.address) + ":" + str(authority.dir_port)
+		try:
+			startTimeStamp = datetime.datetime.utcnow()
+			startTime = time.time()
+			f = urllib.urlopen(authority_address)
+			for h in f.info().headers:
+				if h.upper().startswith('DATE:'):
+					clockskew[nickname] = datetime.datetime.strptime(h[6:].strip(), '%a, %d %b %Y %H:%M:%S %Z')
+			processing = time.time() - startTime
+			if processing > 5:
+				clockskew[nickname] -= datetime.timedelta(seconds=(processing / 2))
+			clockskew[nickname] -= startTimeStamp
+			clockskew[nickname] = clockskew[nickname].total_seconds()
+		except:
+			continue
+	return clockskew
+
 def unix_time(dt):
     return (dt - datetime.datetime.utcfromtimestamp(0)).total_seconds() * 1000.0
 
@@ -98,3 +121,8 @@ class FileMock():
 		pass
 	def write(self, str):
 		pass
+
+if __name__ == "__main__":
+	skew = get_clockskew()
+	for c in skew:
+		print c, skew[c]
\ No newline at end of file
diff --git a/website.py b/website.py
index 02fbdce..d3fa842 100755
--- a/website.py
+++ b/website.py
@@ -24,6 +24,7 @@ class WebsiteWriter:
 	consensus = None
 	votes = None
 	fallback_dirs = None
+	clockskew = None
 	known_authorities = []
 	bandwidth_authorities = []
 	consensus_expiry = datetime.timedelta(hours=3)
@@ -51,6 +52,7 @@ class WebsiteWriter:
 		self._write_recommended_versions()
 		self._write_consensus_parameters()
 		self._write_authority_keys()
+		self._write_authority_clocks()
 		self._write_shared_random()
 		self._write_protocols()
 		self._write_bandwidth_weights()
@@ -82,6 +84,8 @@ class WebsiteWriter:
 		self.known_params = config['known_params']
 	def set_fallback_dirs(self, fallback_dirs):
 		self.fallback_dirs = fallback_dirs
+	def set_clockskew(self, clockskew):
+		self.clockskew = clockskew
 	def get_consensus_time(self):
 		return self.consensus.valid_after
 	def all_votes_present(self):
@@ -691,6 +695,55 @@ class WebsiteWriter:
 			+ "</p>\n")
 
 	#-----------------------------------------------------------------------------------------
+	def _write_authority_clocks(self):
+		"""
+		Write authority clock skew
+		"""
+		self.site.write("<br>\n\n\n"
+		+ " <!-- ================================================================= -->"
+		+ "<a name=\"authorityclocks\">\n"
+		+ "<h3><a href=\"#authorityclocks\" class=\"anchor\">"
+		+ "Authority Clock Skew</a></h3>\n"
+		+ "<br>\n"
+		+ "<table border=\"0\" cellpadding=\"4\" cellspacing=\"0\" summary=\"\">\n"
+		+ "  <colgroup>\n"
+		+ "    <col width=\"160\">\n"
+		+ "    <col width=\"640\">\n"
+		+ "  </colgroup>\n"
+		+ "  <tr>\n"
+		+ "    <th>Name</th>"
+		+ "    <th>Approximate Clock Skew</th>"
+		+ "  </tr>\n")
+
+		if not self.clockskew:
+			self.site.write("  <tr><td>(No clock skew data.)</td><td></td></tr>\n")
+		else:
+			for dirauth_nickname in self.known_authorities:
+				if dirauth_nickname in self.clockskew:
+					clock = self.clockskew[dirauth_nickname]
+
+					if clock > self.config['clockskew_threshold']:
+						self.site.write("  <tr>\n"
+						+ "    <td class=\"oiv\">" + dirauth_nickname + "</td>\n"
+						+ "    <td class=\"oiv\">"
+						+ str(clock) + " seconds</td>\n  </tr>\n")
+					else:
+						self.site.write("  <tr>\n"
+						+ "    <td>" + dirauth_nickname + "</td>\n"
+						+ "    <td>"
+						+ str(clock) + " seconds</td>\n  </tr>\n")
+				else:
+					self.site.write("  <tr>\n"
+					+ "    <td>" + dirauth_nickname + "</td>\n"
+					+ "    <td><span class=\"oiv\">Could not query authority<span></td>\n"
+					+ "  </tr>\n")
+
+			self.site.write("</table>\n"
+			+ "<br>\n"
+			+ "<p><i>Times are roughly accurate, anything below a couple seconds should be fine. Please use this table as a guide rather than an authoritative source.</i>"
+			+ "</p>\n")
+
+	#-----------------------------------------------------------------------------------------
 	def sharedRandomToStr(self, sr):
 		s = "["
 		s += "V:" + str(sr.version) + " "
@@ -1632,7 +1685,8 @@ if __name__ == '__main__':
                                     'known_params': [],
                                     'ignore_fallback_authorities': False,
                                     'graph_logical_min': 125,
-                                    'graph_logical_max': 25000
+                                    'graph_logical_max': 25000,
+                                    'clockskew_threshold': 0,
                                     })
 	config = stem.util.conf.get_config("consensus")
 	config.load(os.path.join(os.path.dirname(__file__), 'data', 'consensus.cfg'))
diff --git a/write_website.py b/write_website.py
index d8d3e3f..f79e2c3 100755
--- a/write_website.py
+++ b/write_website.py
@@ -48,7 +48,8 @@ CONFIG = stem.util.conf.config_dict('consensus', {
 	'known_params': [],
 	'ignore_fallback_authorities' : False,
 	'graph_logical_min' : 125,
-	'graph_logical_max' : 25000
+	'graph_logical_max' : 25000,
+	'clockskew_threshold': 0,
 })
 
 def main():
@@ -58,6 +59,7 @@ def main():
 
 	consensuses, consensus_fetching_issues, consensus_fetching_runtimes = get_consensuses()
 	votes, vote_fetching_issues, vote_fetching_runtimes = get_votes()
+	clockskew = get_clockskew()
 
 	# updates the download statistics file
 	f = open(os.path.join(os.path.dirname(__file__), 'out', 'download-stats.csv'), 'a')
@@ -299,6 +301,7 @@ def main():
 	w.set_consensuses(consensuses)
 	w.set_votes(votes)
 	w.set_fallback_dirs(fallback_dirs)
+	w.set_clockskew(clockskew)
 	w.write_website(os.path.join(os.path.dirname(__file__), 'out', 'consensus-health.html'), \
 		True, os.path.join(os.path.dirname(__file__), 'out', 'relay-indexes.txt'))
 	w.write_website(os.path.join(os.path.dirname(__file__), 'out', 'index.html'), False)



More information about the tor-commits mailing list