diff --git a/doc/TODO b/doc/TODO
index b61304dd80..09f8319d16 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -71,7 +71,7 @@ Things we'd like to do in 0.2.0.x:
- Dump certificates with the wrong time. Or just warn?
- Warn authority ops when their certs are nearly invalid.
- When checking a consensus, make sure that its times are plausible.
- - Add a function that will eventually tell us about our clock skew.
+ o Add a function that will eventually tell us about our clock skew.
For now, just require that authorities not be skewed.
- Start caching consensus documents once authorities make them
- Start downloading and using consensus documents once caches serve them
diff --git a/src/common/util.c b/src/common/util.c
index d8e89395ad..e0eeee282a 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -1250,6 +1250,70 @@ parse_http_time(const char *date, struct tm *tm)
return 0;
}
+/* =====
+ * Fuzzy time
+ * ===== */
+
+/* In a perfect world, everybody would run ntp, and ntp would be perfect, so
+ * if we wanted to know "Is the current time before time X?" we could just say
+ * "time(NULL) < X".
+ *
+ * But unfortunately, many users are running Tor in an imperfect world, on
+ * even more imperfect computers. Hence, we need to track time oddly. We
+ * model the user's computer as being "skewed" from accurate time by
+ * -ftime_skew seconds, such that our best guess of the current time is
+ * time(NULL)+ftime_skew. We also assume that our measurements of time may
+ * have up to ftime_slop seconds of inaccuracy; hence, the
+ * measurements;
+ */
+static int ftime_skew = 0;
+static int ftime_slop = 60;
+void
+ftime_set_maximum_sloppiness(int seconds)
+{
+ tor_assert(seconds >= 0);
+ ftime_slop = seconds;
+}
+void
+ftime_set_estimated_skew(int seconds)
+{
+ ftime_skew = seconds;
+}
+#if 0
+void
+ftime_get_window(time_t now, ftime_t *ft_out)
+{
+ ft_out->earliest = now + ftime_skew - ftime_slop;
+ ft_out->latest = now + ftime_skew + ftime_slop;
+}
+#endif
+int
+ftime_maybe_after(time_t now, time_t when)
+{
+ /* It may be after when iff the latest possible current time is after when. */
+ return (now + ftime_skew + ftime_slop) >= when;
+}
+int
+ftime_maybe_before(time_t now, time_t when)
+{
+ /* It may be before when iff the earliest possible current time is before. */
+ return (now + ftime_skew - ftime_slop) < when;
+}
+int
+ftime_definitely_after(time_t now, time_t when)
+{
+ /* It is definitely after when if the earliest time it could be is still
+ * after when. */
+ return (now + ftime_skew - ftime_slop) >= when;
+}
+int
+ftime_definitely_before(time_t now, time_t when)
+{
+ /* It is definitely before when if the latest time it could be is still
+ * before when. */
+ return (now + ftime_skew + ftime_slop) < when;
+}
+
/* =====
* File helpers
* ===== */
diff --git a/src/common/util.h b/src/common/util.h
index d973948c50..950de9bacc 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -206,6 +206,15 @@ void format_local_iso_time(char *buf, time_t t);
void format_iso_time(char *buf, time_t t);
int parse_iso_time(const char *buf, time_t *t);
int parse_http_time(const char *buf, struct tm *tm);
+/* Fuzzy time. */
+void ftime_set_maximum_sloppiness(int seconds);
+void ftime_set_estimated_skew(int seconds);
+/* typedef struct ftime_t { time_t earliest; time_t latest; } ftime_t; */
+/* void ftime_get_window(time_t now, ftime_t *ft_out); */
+int ftime_maybe_after(time_t now, time_t when);
+int ftime_maybe_before(time_t now, time_t when);
+int ftime_definitely_after(time_t now, time_t when);
+int ftime_definitely_before(time_t now, time_t when);
/* File helpers */
int write_all(int fd, const char *buf, size_t count, int isSocket);