fix typo
[tor.git] / src / or / replaycache.c
blob23a1737b185b1f1c6040250e944a4392a9533bf4
1 /* Copyright (c) 2012-2016, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 /*
5 * \file replaycache.c
7 * \brief Self-scrubbing replay cache for rendservice.c
8 */
10 #define REPLAYCACHE_PRIVATE
12 #include "or.h"
13 #include "replaycache.h"
15 /** Free the replaycache r and all of its entries.
18 void
19 replaycache_free(replaycache_t *r)
21 if (!r) {
22 log_info(LD_BUG, "replaycache_free() called on NULL");
23 return;
26 if (r->digests_seen) digest256map_free(r->digests_seen, tor_free_);
28 tor_free(r);
31 /** Allocate a new, empty replay detection cache, where horizon is the time
32 * for entries to age out and interval is the time after which the cache
33 * should be scrubbed for old entries.
36 replaycache_t *
37 replaycache_new(time_t horizon, time_t interval)
39 replaycache_t *r = NULL;
41 if (horizon < 0) {
42 log_info(LD_BUG, "replaycache_new() called with negative"
43 " horizon parameter");
44 goto err;
47 if (interval < 0) {
48 log_info(LD_BUG, "replaycache_new() called with negative interval"
49 " parameter");
50 interval = 0;
53 r = tor_malloc(sizeof(*r));
54 r->scrub_interval = interval;
55 r->scrubbed = 0;
56 r->horizon = horizon;
57 r->digests_seen = digest256map_new();
59 err:
60 return r;
63 /** See documentation for replaycache_add_and_test()
66 STATIC int
67 replaycache_add_and_test_internal(
68 time_t present, replaycache_t *r, const void *data, size_t len,
69 time_t *elapsed)
71 int rv = 0;
72 uint8_t digest[DIGEST256_LEN];
73 time_t *access_time;
75 /* sanity check */
76 if (present <= 0 || !r || !data || len == 0) {
77 log_info(LD_BUG, "replaycache_add_and_test_internal() called with stupid"
78 " parameters; please fix this.");
79 goto done;
82 /* compute digest */
83 crypto_digest256((char *)digest, (const char *)data, len, DIGEST_SHA256);
85 /* check map */
86 access_time = digest256map_get(r->digests_seen, digest);
88 /* seen before? */
89 if (access_time != NULL) {
91 * If it's far enough in the past, no hit. If the horizon is zero, we
92 * never expire.
94 if (*access_time >= present - r->horizon || r->horizon == 0) {
95 /* replay cache hit, return 1 */
96 rv = 1;
97 /* If we want to output an elapsed time, do so */
98 if (elapsed) {
99 if (present >= *access_time) {
100 *elapsed = present - *access_time;
101 } else {
102 /* We shouldn't really be seeing hits from the future, but... */
103 *elapsed = 0;
108 * If it's ahead of the cached time, update
110 if (*access_time < present) {
111 *access_time = present;
113 } else {
114 /* No, so no hit and update the digest map with the current time */
115 access_time = tor_malloc(sizeof(*access_time));
116 *access_time = present;
117 digest256map_set(r->digests_seen, digest, access_time);
120 /* now scrub the cache if it's time */
121 replaycache_scrub_if_needed_internal(present, r);
123 done:
124 return rv;
127 /** See documentation for replaycache_scrub_if_needed()
130 STATIC void
131 replaycache_scrub_if_needed_internal(time_t present, replaycache_t *r)
133 digest256map_iter_t *itr = NULL;
134 const uint8_t *digest;
135 void *valp;
136 time_t *access_time;
138 /* sanity check */
139 if (!r || !(r->digests_seen)) {
140 log_info(LD_BUG, "replaycache_scrub_if_needed_internal() called with"
141 " stupid parameters; please fix this.");
142 return;
145 /* scrub time yet? (scrubbed == 0 indicates never scrubbed before) */
146 if (present - r->scrubbed < r->scrub_interval && r->scrubbed > 0) return;
148 /* if we're never expiring, don't bother scrubbing */
149 if (r->horizon == 0) return;
151 /* okay, scrub time */
152 itr = digest256map_iter_init(r->digests_seen);
153 while (!digest256map_iter_done(itr)) {
154 digest256map_iter_get(itr, &digest, &valp);
155 access_time = (time_t *)valp;
156 /* aged out yet? */
157 if (*access_time < present - r->horizon) {
158 /* Advance the iterator and remove this one */
159 itr = digest256map_iter_next_rmv(r->digests_seen, itr);
160 /* Free the value removed */
161 tor_free(access_time);
162 } else {
163 /* Just advance the iterator */
164 itr = digest256map_iter_next(r->digests_seen, itr);
168 /* update scrubbed timestamp */
169 if (present > r->scrubbed) r->scrubbed = present;
172 /** Test the buffer of length len point to by data against the replay cache r;
173 * the digest of the buffer will be added to the cache at the current time,
174 * and the function will return 1 if it was already seen within the cache's
175 * horizon, or 0 otherwise.
179 replaycache_add_and_test(replaycache_t *r, const void *data, size_t len)
181 return replaycache_add_and_test_internal(time(NULL), r, data, len, NULL);
184 /** Like replaycache_add_and_test(), but if it's a hit also return the time
185 * elapsed since this digest was last seen.
189 replaycache_add_test_and_elapsed(
190 replaycache_t *r, const void *data, size_t len, time_t *elapsed)
192 return replaycache_add_and_test_internal(time(NULL), r, data, len, elapsed);
195 /** Scrub aged entries out of r if sufficiently long has elapsed since r was
196 * last scrubbed.
199 void
200 replaycache_scrub_if_needed(replaycache_t *r)
202 replaycache_scrub_if_needed_internal(time(NULL), r);