/src/tor/src/feature/relay/dns.c
Line | Count | Source |
1 | | /* Copyright (c) 2003-2004, Roger Dingledine. |
2 | | * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. |
3 | | * Copyright (c) 2007-2021, The Tor Project, Inc. */ |
4 | | /* See LICENSE for licensing information */ |
5 | | |
6 | | /** |
7 | | * \file dns.c |
8 | | * \brief Implements a local cache for DNS results for Tor servers. |
9 | | * This is implemented as a wrapper around Adam Langley's eventdns.c code. |
10 | | * (We can't just use gethostbyname() and friends because we really need to |
11 | | * be nonblocking.) |
12 | | * |
13 | | * There are three main cases when a Tor relay uses dns.c to launch a DNS |
14 | | * request: |
15 | | * <ol> |
16 | | * <li>To check whether the DNS server is working more or less correctly. |
17 | | * This happens via dns_launch_correctness_checks(). The answer is |
18 | | * reported in the return value from later calls to |
19 | | * dns_seems_to_be_broken(). |
20 | | * <li>When a client has asked the relay, in a RELAY_BEGIN cell, to connect |
21 | | * to a given server by hostname. This happens via dns_resolve(). |
22 | | * <li>When a client has asked the relay, in a RELAY_RESOLVE cell, to look |
23 | | * up a given server's IP address(es) by hostname. This also happens via |
24 | | * dns_resolve(). |
25 | | * </ol> |
26 | | * |
27 | | * Each of these gets handled a little differently. |
28 | | * |
29 | | * To check for correctness, we look up some hostname we expect to exist and |
30 | | * have real entries, some hostnames which we expect to definitely not exist, |
31 | | * and some hostnames that we expect to probably not exist. If too many of |
32 | | * the hostnames that shouldn't exist do exist, that's a DNS hijacking |
33 | | * attempt. If too many of the hostnames that should exist have the same |
34 | | * addresses as the ones that shouldn't exist, that's a very bad DNS hijacking |
35 | | * attempt, or a very naughty captive portal. And if the hostnames that |
36 | | * should exist simply don't exist, we probably have a broken nameserver. |
37 | | * |
38 | | * To handle client requests, we first check our cache for answers. If there |
39 | | * isn't something up-to-date, we've got to launch A or AAAA requests as |
40 | | * appropriate. How we handle responses to those in particular is a bit |
41 | | * complex; see dns_lookup() and set_exitconn_info_from_resolve(). |
42 | | * |
43 | | * When a lookup is finally complete, the inform_pending_connections() |
44 | | * function will tell all of the streams that have been waiting for the |
45 | | * resolve, by calling connection_exit_connect() if the client sent a |
46 | | * RELAY_BEGIN cell, and by calling send_resolved_cell() or |
47 | | * send_hostname_cell() if the client sent a RELAY_RESOLVE cell. |
48 | | **/ |
49 | | |
50 | | #define DNS_PRIVATE |
51 | | |
52 | | #include "core/or/or.h" |
53 | | #include "app/config/config.h" |
54 | | #include "core/mainloop/connection.h" |
55 | | #include "core/mainloop/mainloop.h" |
56 | | #include "core/mainloop/netstatus.h" |
57 | | #include "core/or/circuitlist.h" |
58 | | #include "core/or/circuituse.h" |
59 | | #include "core/or/connection_edge.h" |
60 | | #include "core/or/policies.h" |
61 | | #include "core/or/relay.h" |
62 | | #include "feature/control/control_events.h" |
63 | | #include "feature/relay/dns.h" |
64 | | #include "feature/nodelist/networkstatus.h" |
65 | | #include "feature/relay/router.h" |
66 | | #include "feature/relay/routermode.h" |
67 | | #include "feature/stats/rephist.h" |
68 | | #include "lib/crypt_ops/crypto_rand.h" |
69 | | #include "lib/evloop/compat_libevent.h" |
70 | | #include "lib/sandbox/sandbox.h" |
71 | | |
72 | | #include "core/or/edge_connection_st.h" |
73 | | #include "core/or/or_circuit_st.h" |
74 | | #include "core/or/conflux_util.h" |
75 | | |
76 | | #include "ht.h" |
77 | | |
78 | | #ifdef HAVE_SYS_STAT_H |
79 | | #include <sys/stat.h> |
80 | | #endif |
81 | | |
82 | | #include <event2/event.h> |
83 | | #include <event2/dns.h> |
84 | | |
85 | | /** How long will we wait for an answer from the resolver before we decide |
86 | | * that the resolver is wedged? */ |
87 | 0 | #define RESOLVE_MAX_TIMEOUT 300 |
88 | | |
89 | | /** The clipped TTL sent back in the RESOLVED cell for every DNS queries. |
90 | | * |
91 | | * See https://gitlab.torproject.org/tpo/core/tor/-/issues/40979 for a thorough |
92 | | * explanation but this is first and foremost a security fix in order to avoid |
93 | | * an exit DNS cache oracle. */ |
94 | 0 | #define RESOLVED_CLIPPED_TTL (60) |
95 | | |
96 | | /** Our evdns_base; this structure handles all our name lookups. */ |
97 | | static struct evdns_base *the_evdns_base = NULL; |
98 | | |
99 | | /** Have we currently configured nameservers with eventdns? */ |
100 | | static int nameservers_configured = 0; |
101 | | /** Did our most recent attempt to configure nameservers with eventdns fail? */ |
102 | | static int nameserver_config_failed = 0; |
103 | | /** What was the resolv_conf fname we last used when configuring the |
104 | | * nameservers? Used to check whether we need to reconfigure. */ |
105 | | static char *resolv_conf_fname = NULL; |
106 | | /** What was the mtime on the resolv.conf file we last used when configuring |
107 | | * the nameservers? Used to check whether we need to reconfigure. */ |
108 | | static time_t resolv_conf_mtime = 0; |
109 | | |
110 | | static void purge_expired_resolves(time_t now); |
111 | | static void dns_found_answer(const char *address, uint8_t query_type, |
112 | | int dns_answer, |
113 | | const tor_addr_t *addr, |
114 | | const char *hostname, |
115 | | uint32_t ttl); |
116 | | static void add_wildcarded_test_address(const char *address); |
117 | | static int configure_nameservers(int force); |
118 | | static int answer_is_wildcarded(const char *ip); |
119 | | static int evdns_err_is_transient(int err); |
120 | | static void inform_pending_connections(cached_resolve_t *resolve); |
121 | | static void make_pending_resolve_cached(cached_resolve_t *cached); |
122 | | static void configure_libevent_options(void); |
123 | | |
124 | | #ifdef DEBUG_DNS_CACHE |
125 | | static void assert_cache_ok_(void); |
126 | | #define assert_cache_ok() assert_cache_ok_() |
127 | | #else |
128 | 0 | #define assert_cache_ok() STMT_NIL |
129 | | #endif /* defined(DEBUG_DNS_CACHE) */ |
130 | | static void assert_resolve_ok(cached_resolve_t *resolve); |
131 | | |
132 | | /** Hash table of cached_resolve objects. */ |
133 | | static HT_HEAD(cache_map, cached_resolve_t) cache_root; |
134 | | |
135 | | /** Global: how many IPv6 requests have we made in all? */ |
136 | | static uint64_t n_ipv6_requests_made = 0; |
137 | | /** Global: how many IPv6 requests have timed out? */ |
138 | | static uint64_t n_ipv6_timeouts = 0; |
139 | | /** Global: Do we think that IPv6 DNS is broken? */ |
140 | | static int dns_is_broken_for_ipv6 = 0; |
141 | | |
142 | | /** Function to compare hashed resolves on their addresses; used to |
143 | | * implement hash tables. */ |
144 | | static inline int |
145 | | cached_resolves_eq(cached_resolve_t *a, cached_resolve_t *b) |
146 | 0 | { |
147 | | /* make this smarter one day? */ |
148 | 0 | assert_resolve_ok(a); // Not b; b may be just a search. |
149 | 0 | return !strncmp(a->address, b->address, MAX_ADDRESSLEN); |
150 | 0 | } |
151 | | |
152 | | /** Hash function for cached_resolve objects */ |
153 | | static inline unsigned int |
154 | | cached_resolve_hash(cached_resolve_t *a) |
155 | 0 | { |
156 | 0 | return (unsigned) siphash24g((const uint8_t*)a->address, strlen(a->address)); |
157 | 0 | } |
158 | | |
159 | 0 | HT_PROTOTYPE(cache_map, cached_resolve_t, node, cached_resolve_hash, Unexecuted instantiation: dns.c:cache_map_HT_INIT Unexecuted instantiation: dns.c:cache_map_HT_START Unexecuted instantiation: dns.c:cache_map_HT_NEXT_RMV Unexecuted instantiation: dns.c:cache_map_HT_FIND Unexecuted instantiation: dns.c:cache_map_HT_FIND_P_ Unexecuted instantiation: dns.c:cache_map_HT_REMOVE |
160 | | cached_resolves_eq); |
161 | 0 | HT_GENERATE2(cache_map, cached_resolve_t, node, cached_resolve_hash, |
162 | | cached_resolves_eq, 0.6, tor_reallocarray_, tor_free_); |
163 | | |
164 | | /** Initialize the DNS cache. */ |
165 | | static void |
166 | | init_cache_map(void) |
167 | 0 | { |
168 | 0 | HT_INIT(cache_map, &cache_root); |
169 | 0 | } |
170 | | |
171 | | /** Helper: called by eventdns when eventdns wants to log something. */ |
172 | | static void |
173 | | evdns_log_cb(int warn, const char *msg) |
174 | 0 | { |
175 | 0 | const char *cp; |
176 | 0 | static int all_down = 0; |
177 | 0 | int severity = warn ? LOG_WARN : LOG_INFO; |
178 | 0 | if (!strcmpstart(msg, "Resolve requested for") && |
179 | 0 | get_options()->SafeLogging) { |
180 | 0 | log_info(LD_EXIT, "eventdns: Resolve requested."); |
181 | 0 | return; |
182 | 0 | } else if (!strcmpstart(msg, "Search: ")) { |
183 | 0 | return; |
184 | 0 | } |
185 | 0 | if (!strcmpstart(msg, "Nameserver ") && (cp=strstr(msg, " has failed: "))) { |
186 | 0 | char *ns = tor_strndup(msg+11, cp-(msg+11)); |
187 | 0 | const char *colon = strchr(cp, ':'); |
188 | 0 | tor_assert(colon); |
189 | 0 | const char *err = colon+2; |
190 | | /* Don't warn about a single failed nameserver; we'll warn with 'all |
191 | | * nameservers have failed' if we're completely out of nameservers; |
192 | | * otherwise, the situation is tolerable. */ |
193 | 0 | severity = LOG_INFO; |
194 | 0 | control_event_server_status(LOG_NOTICE, |
195 | 0 | "NAMESERVER_STATUS NS=%s STATUS=DOWN ERR=%s", |
196 | 0 | ns, escaped(err)); |
197 | 0 | tor_free(ns); |
198 | 0 | } else if (!strcmpstart(msg, "Nameserver ") && |
199 | 0 | (cp=strstr(msg, " is back up"))) { |
200 | 0 | char *ns = tor_strndup(msg+11, cp-(msg+11)); |
201 | 0 | severity = (all_down && warn) ? LOG_NOTICE : LOG_INFO; |
202 | 0 | all_down = 0; |
203 | 0 | control_event_server_status(LOG_NOTICE, |
204 | 0 | "NAMESERVER_STATUS NS=%s STATUS=UP", ns); |
205 | 0 | tor_free(ns); |
206 | 0 | } else if (!strcmp(msg, "All nameservers have failed")) { |
207 | 0 | control_event_server_status(LOG_WARN, "NAMESERVER_ALL_DOWN"); |
208 | 0 | all_down = 1; |
209 | 0 | } else if (!strcmpstart(msg, "Address mismatch on received DNS")) { |
210 | 0 | static ratelim_t mismatch_limit = RATELIM_INIT(3600); |
211 | 0 | const char *src = strstr(msg, " Apparent source"); |
212 | 0 | if (!src || get_options()->SafeLogging) { |
213 | 0 | src = ""; |
214 | 0 | } |
215 | 0 | log_fn_ratelim(&mismatch_limit, severity, LD_EXIT, |
216 | 0 | "eventdns: Received a DNS packet from " |
217 | 0 | "an IP address to which we did not send a request. This " |
218 | 0 | "could be a DNS spoofing attempt, or some kind of " |
219 | 0 | "misconfiguration.%s", src); |
220 | 0 | return; |
221 | 0 | } |
222 | 0 | tor_log(severity, LD_EXIT, "eventdns: %s", msg); |
223 | 0 | } |
224 | | |
225 | | /** New consensus just appeared, take appropriate actions if need be. */ |
226 | | void |
227 | | dns_new_consensus_params(const networkstatus_t *ns) |
228 | 0 | { |
229 | 0 | (void) ns; |
230 | | |
231 | | /* Consensus has parameters for the Exit relay DNS side and so we only reset |
232 | | * the DNS nameservers if we are in server mode. */ |
233 | 0 | if (server_mode(get_options())) { |
234 | 0 | configure_libevent_options(); |
235 | 0 | } |
236 | 0 | } |
237 | | |
238 | | /** Initialize the DNS subsystem; called by the OR process. */ |
239 | | int |
240 | | dns_init(void) |
241 | 0 | { |
242 | 0 | init_cache_map(); |
243 | 0 | if (server_mode(get_options())) { |
244 | 0 | int r = configure_nameservers(1); |
245 | 0 | return r; |
246 | 0 | } |
247 | 0 | return 0; |
248 | 0 | } |
249 | | |
250 | | /** Called when DNS-related options change (or may have changed). Returns -1 |
251 | | * on failure, 0 on success. */ |
252 | | int |
253 | | dns_reset(void) |
254 | 0 | { |
255 | 0 | const or_options_t *options = get_options(); |
256 | 0 | if (! server_mode(options)) { |
257 | |
|
258 | 0 | if (!the_evdns_base) { |
259 | 0 | if (!(the_evdns_base = evdns_base_new(tor_libevent_get_base(), 0))) { |
260 | 0 | log_err(LD_BUG, "Couldn't create an evdns_base"); |
261 | 0 | return -1; |
262 | 0 | } |
263 | 0 | } |
264 | | |
265 | 0 | evdns_base_clear_nameservers_and_suspend(the_evdns_base); |
266 | 0 | evdns_base_search_clear(the_evdns_base); |
267 | 0 | nameservers_configured = 0; |
268 | 0 | tor_free(resolv_conf_fname); |
269 | 0 | resolv_conf_mtime = 0; |
270 | 0 | } else { |
271 | 0 | if (configure_nameservers(0) < 0) { |
272 | 0 | return -1; |
273 | 0 | } |
274 | 0 | } |
275 | 0 | return 0; |
276 | 0 | } |
277 | | |
278 | | /** Return true iff the most recent attempt to initialize the DNS subsystem |
279 | | * failed. */ |
280 | | int |
281 | | has_dns_init_failed(void) |
282 | 0 | { |
283 | 0 | return nameserver_config_failed; |
284 | 0 | } |
285 | | |
286 | | /** Helper: free storage held by an entry in the DNS cache. */ |
287 | | static void |
288 | | free_cached_resolve_(cached_resolve_t *r) |
289 | 0 | { |
290 | 0 | if (!r) |
291 | 0 | return; |
292 | 0 | while (r->pending_connections) { |
293 | 0 | pending_connection_t *victim = r->pending_connections; |
294 | 0 | r->pending_connections = victim->next; |
295 | 0 | tor_free(victim); |
296 | 0 | } |
297 | 0 | if (r->res_status_hostname == RES_STATUS_DONE_OK) |
298 | 0 | tor_free(r->result_ptr.hostname); |
299 | 0 | r->magic = 0xFF00FF00; |
300 | 0 | tor_free(r); |
301 | 0 | } |
302 | | |
303 | | /** Compare two cached_resolve_t pointers by expiry time, and return |
304 | | * less-than-zero, zero, or greater-than-zero as appropriate. Used for |
305 | | * the priority queue implementation. */ |
306 | | static int |
307 | | compare_cached_resolves_by_expiry_(const void *_a, const void *_b) |
308 | 0 | { |
309 | 0 | const cached_resolve_t *a = _a, *b = _b; |
310 | 0 | if (a->expire < b->expire) |
311 | 0 | return -1; |
312 | 0 | else if (a->expire == b->expire) |
313 | 0 | return 0; |
314 | 0 | else |
315 | 0 | return 1; |
316 | 0 | } |
317 | | |
318 | | /** Priority queue of cached_resolve_t objects to let us know when they |
319 | | * will expire. */ |
320 | | static smartlist_t *cached_resolve_pqueue = NULL; |
321 | | |
322 | | static void |
323 | | cached_resolve_add_answer(cached_resolve_t *resolve, |
324 | | int query_type, |
325 | | int dns_result, |
326 | | const tor_addr_t *answer_addr, |
327 | | const char *answer_hostname, |
328 | | uint32_t ttl) |
329 | 0 | { |
330 | 0 | if (query_type == DNS_PTR) { |
331 | 0 | if (resolve->res_status_hostname != RES_STATUS_INFLIGHT) |
332 | 0 | return; |
333 | | |
334 | 0 | if (dns_result == DNS_ERR_NONE && answer_hostname) { |
335 | 0 | resolve->result_ptr.hostname = tor_strdup(answer_hostname); |
336 | 0 | resolve->res_status_hostname = RES_STATUS_DONE_OK; |
337 | 0 | } else { |
338 | 0 | resolve->result_ptr.err_hostname = dns_result; |
339 | 0 | resolve->res_status_hostname = RES_STATUS_DONE_ERR; |
340 | 0 | } |
341 | 0 | resolve->ttl_hostname = ttl; |
342 | 0 | } else if (query_type == DNS_IPv4_A) { |
343 | 0 | if (resolve->res_status_ipv4 != RES_STATUS_INFLIGHT) |
344 | 0 | return; |
345 | | |
346 | 0 | if (dns_result == DNS_ERR_NONE && answer_addr && |
347 | 0 | tor_addr_family(answer_addr) == AF_INET) { |
348 | 0 | resolve->result_ipv4.addr_ipv4 = tor_addr_to_ipv4h(answer_addr); |
349 | 0 | resolve->res_status_ipv4 = RES_STATUS_DONE_OK; |
350 | 0 | } else { |
351 | 0 | resolve->result_ipv4.err_ipv4 = dns_result; |
352 | 0 | resolve->res_status_ipv4 = RES_STATUS_DONE_ERR; |
353 | 0 | } |
354 | 0 | resolve->ttl_ipv4 = ttl; |
355 | 0 | } else if (query_type == DNS_IPv6_AAAA) { |
356 | 0 | if (resolve->res_status_ipv6 != RES_STATUS_INFLIGHT) |
357 | 0 | return; |
358 | | |
359 | 0 | if (dns_result == DNS_ERR_NONE && answer_addr && |
360 | 0 | tor_addr_family(answer_addr) == AF_INET6) { |
361 | 0 | memcpy(&resolve->result_ipv6.addr_ipv6, |
362 | 0 | tor_addr_to_in6(answer_addr), |
363 | 0 | sizeof(struct in6_addr)); |
364 | 0 | resolve->res_status_ipv6 = RES_STATUS_DONE_OK; |
365 | 0 | } else { |
366 | 0 | resolve->result_ipv6.err_ipv6 = dns_result; |
367 | 0 | resolve->res_status_ipv6 = RES_STATUS_DONE_ERR; |
368 | 0 | } |
369 | 0 | resolve->ttl_ipv6 = ttl; |
370 | 0 | } |
371 | 0 | } |
372 | | |
373 | | /** Return true iff there are no in-flight requests for <b>resolve</b>. */ |
374 | | static int |
375 | | cached_resolve_have_all_answers(const cached_resolve_t *resolve) |
376 | 0 | { |
377 | 0 | return (resolve->res_status_ipv4 != RES_STATUS_INFLIGHT && |
378 | 0 | resolve->res_status_ipv6 != RES_STATUS_INFLIGHT && |
379 | 0 | resolve->res_status_hostname != RES_STATUS_INFLIGHT); |
380 | 0 | } |
381 | | |
382 | | /** Set an expiry time for a cached_resolve_t, and add it to the expiry |
383 | | * priority queue */ |
384 | | static void |
385 | | set_expiry(cached_resolve_t *resolve, time_t expires) |
386 | 0 | { |
387 | 0 | tor_assert(resolve && resolve->expire == 0); |
388 | 0 | if (!cached_resolve_pqueue) |
389 | 0 | cached_resolve_pqueue = smartlist_new(); |
390 | 0 | resolve->expire = expires; |
391 | 0 | smartlist_pqueue_add(cached_resolve_pqueue, |
392 | 0 | compare_cached_resolves_by_expiry_, |
393 | 0 | offsetof(cached_resolve_t, minheap_idx), |
394 | 0 | resolve); |
395 | 0 | } |
396 | | |
397 | | /** Free all storage held in the DNS cache and related structures. */ |
398 | | void |
399 | | dns_free_all(void) |
400 | 0 | { |
401 | 0 | cached_resolve_t **ptr, **next, *item; |
402 | 0 | assert_cache_ok(); |
403 | 0 | if (cached_resolve_pqueue) { |
404 | 0 | SMARTLIST_FOREACH(cached_resolve_pqueue, cached_resolve_t *, res, |
405 | 0 | { |
406 | 0 | if (res->state == CACHE_STATE_DONE) |
407 | 0 | free_cached_resolve_(res); |
408 | 0 | }); |
409 | 0 | } |
410 | 0 | for (ptr = HT_START(cache_map, &cache_root); ptr != NULL; ptr = next) { |
411 | 0 | item = *ptr; |
412 | 0 | next = HT_NEXT_RMV(cache_map, &cache_root, ptr); |
413 | 0 | free_cached_resolve_(item); |
414 | 0 | } |
415 | 0 | HT_CLEAR(cache_map, &cache_root); |
416 | 0 | smartlist_free(cached_resolve_pqueue); |
417 | 0 | cached_resolve_pqueue = NULL; |
418 | 0 | tor_free(resolv_conf_fname); |
419 | 0 | } |
420 | | |
421 | | /** Remove every cached_resolve whose <b>expire</b> time is before or |
422 | | * equal to <b>now</b> from the cache. */ |
423 | | static void |
424 | | purge_expired_resolves(time_t now) |
425 | 0 | { |
426 | 0 | cached_resolve_t *resolve, *removed; |
427 | 0 | pending_connection_t *pend; |
428 | 0 | edge_connection_t *pendconn; |
429 | |
|
430 | 0 | assert_cache_ok(); |
431 | 0 | if (!cached_resolve_pqueue) |
432 | 0 | return; |
433 | | |
434 | 0 | while (smartlist_len(cached_resolve_pqueue)) { |
435 | 0 | resolve = smartlist_get(cached_resolve_pqueue, 0); |
436 | 0 | if (resolve->expire > now) |
437 | 0 | break; |
438 | 0 | smartlist_pqueue_pop(cached_resolve_pqueue, |
439 | 0 | compare_cached_resolves_by_expiry_, |
440 | 0 | offsetof(cached_resolve_t, minheap_idx)); |
441 | |
|
442 | 0 | if (resolve->state == CACHE_STATE_PENDING) { |
443 | 0 | log_debug(LD_EXIT, |
444 | 0 | "Expiring a dns resolve %s that's still pending. Forgot to " |
445 | 0 | "cull it? DNS resolve didn't tell us about the timeout?", |
446 | 0 | escaped_safe_str(resolve->address)); |
447 | 0 | } else if (resolve->state == CACHE_STATE_CACHED) { |
448 | 0 | log_debug(LD_EXIT, |
449 | 0 | "Forgetting old cached resolve (address %s, expires %lu)", |
450 | 0 | escaped_safe_str(resolve->address), |
451 | 0 | (unsigned long)resolve->expire); |
452 | 0 | tor_assert(!resolve->pending_connections); |
453 | 0 | } else { |
454 | 0 | tor_assert(resolve->state == CACHE_STATE_DONE); |
455 | 0 | tor_assert(!resolve->pending_connections); |
456 | 0 | } |
457 | |
|
458 | 0 | if (resolve->pending_connections) { |
459 | 0 | log_debug(LD_EXIT, |
460 | 0 | "Closing pending connections on timed-out DNS resolve!"); |
461 | 0 | while (resolve->pending_connections) { |
462 | 0 | pend = resolve->pending_connections; |
463 | 0 | resolve->pending_connections = pend->next; |
464 | | /* Connections should only be pending if they have no socket. */ |
465 | 0 | tor_assert(!SOCKET_OK(pend->conn->base_.s)); |
466 | 0 | pendconn = pend->conn; |
467 | | /* Prevent double-remove */ |
468 | 0 | pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; |
469 | 0 | if (!pendconn->base_.marked_for_close) { |
470 | 0 | connection_edge_end(pendconn, END_STREAM_REASON_TIMEOUT); |
471 | 0 | circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn); |
472 | 0 | connection_free_(TO_CONN(pendconn)); |
473 | 0 | } |
474 | 0 | tor_free(pend); |
475 | 0 | } |
476 | 0 | } |
477 | |
|
478 | 0 | if (resolve->state == CACHE_STATE_CACHED || |
479 | 0 | resolve->state == CACHE_STATE_PENDING) { |
480 | 0 | removed = HT_REMOVE(cache_map, &cache_root, resolve); |
481 | 0 | if (removed != resolve) { |
482 | 0 | log_err(LD_BUG, "The expired resolve we purged didn't match any in" |
483 | 0 | " the cache. Tried to purge %s (%p); instead got %s (%p).", |
484 | 0 | resolve->address, (void*)resolve, |
485 | 0 | removed ? removed->address : "NULL", (void*)removed); |
486 | 0 | } |
487 | 0 | tor_assert(removed == resolve); |
488 | 0 | } else { |
489 | | /* This should be in state DONE. Make sure it's not in the cache. */ |
490 | 0 | cached_resolve_t *tmp = HT_FIND(cache_map, &cache_root, resolve); |
491 | 0 | tor_assert(tmp != resolve); |
492 | 0 | } |
493 | 0 | if (resolve->res_status_hostname == RES_STATUS_DONE_OK) |
494 | 0 | tor_free(resolve->result_ptr.hostname); |
495 | 0 | resolve->magic = 0xF0BBF0BB; |
496 | 0 | tor_free(resolve); |
497 | 0 | } |
498 | | |
499 | 0 | assert_cache_ok(); |
500 | 0 | } |
501 | | |
502 | | /* argument for send_resolved_cell only, meaning "let the answer type be ipv4 |
503 | | * or ipv6 depending on the connection's address". */ |
504 | 0 | #define RESOLVED_TYPE_AUTO 0xff |
505 | | |
506 | | /** Send a response to the RESOLVE request of a connection. |
507 | | * <b>answer_type</b> must be one of |
508 | | * RESOLVED_TYPE_(AUTO|ERROR|ERROR_TRANSIENT|). |
509 | | * |
510 | | * If <b>circ</b> is provided, and we have a cached answer, send the |
511 | | * answer back along circ; otherwise, send the answer back along |
512 | | * <b>conn</b>'s attached circuit. |
513 | | */ |
514 | | MOCK_IMPL(STATIC void, |
515 | | send_resolved_cell,(edge_connection_t *conn, uint8_t answer_type, |
516 | | const cached_resolve_t *resolved)) |
517 | 0 | { |
518 | | // (We use the minimum here to ensure that we never |
519 | | // generate a too-big message.) |
520 | 0 | char buf[RELAY_PAYLOAD_SIZE_MIN], *cp = buf; |
521 | 0 | size_t buflen = 0; |
522 | 0 | uint32_t ttl = RESOLVED_CLIPPED_TTL; |
523 | |
|
524 | 0 | buf[0] = answer_type; |
525 | |
|
526 | 0 | switch (answer_type) |
527 | 0 | { |
528 | 0 | case RESOLVED_TYPE_AUTO: |
529 | 0 | if (resolved && resolved->res_status_ipv4 == RES_STATUS_DONE_OK) { |
530 | 0 | cp[0] = RESOLVED_TYPE_IPV4; |
531 | 0 | cp[1] = 4; |
532 | 0 | set_uint32(cp+2, htonl(resolved->result_ipv4.addr_ipv4)); |
533 | 0 | set_uint32(cp+6, htonl(ttl)); |
534 | 0 | cp += 10; |
535 | 0 | } |
536 | 0 | if (resolved && resolved->res_status_ipv6 == RES_STATUS_DONE_OK) { |
537 | 0 | const uint8_t *bytes = resolved->result_ipv6.addr_ipv6.s6_addr; |
538 | 0 | cp[0] = RESOLVED_TYPE_IPV6; |
539 | 0 | cp[1] = 16; |
540 | 0 | memcpy(cp+2, bytes, 16); |
541 | 0 | set_uint32(cp+18, htonl(ttl)); |
542 | 0 | cp += 22; |
543 | 0 | } |
544 | 0 | if (cp != buf) { |
545 | 0 | buflen = cp - buf; |
546 | 0 | break; |
547 | 0 | } else { |
548 | 0 | answer_type = RESOLVED_TYPE_ERROR; |
549 | | /* We let this fall through and treat it as an error. */ |
550 | 0 | } |
551 | 0 | FALLTHROUGH; |
552 | 0 | case RESOLVED_TYPE_ERROR_TRANSIENT: |
553 | 0 | case RESOLVED_TYPE_ERROR: |
554 | 0 | { |
555 | 0 | const char *errmsg = "Error resolving hostname"; |
556 | 0 | size_t msglen = strlen(errmsg); |
557 | |
|
558 | 0 | buf[0] = answer_type; |
559 | 0 | buf[1] = msglen; |
560 | 0 | strlcpy(buf+2, errmsg, sizeof(buf)-2); |
561 | 0 | set_uint32(buf+2+msglen, htonl(ttl)); |
562 | 0 | buflen = 6+msglen; |
563 | 0 | break; |
564 | 0 | } |
565 | 0 | default: |
566 | 0 | tor_assert(0); |
567 | 0 | return; |
568 | 0 | } |
569 | | // log_notice(LD_EXIT, "Sending a regular RESOLVED reply: "); |
570 | | |
571 | 0 | connection_edge_send_command(conn, RELAY_COMMAND_RESOLVED, buf, buflen); |
572 | 0 | } |
573 | | |
574 | | void |
575 | | dns_send_resolved_error_cell(edge_connection_t *conn, uint8_t answer_type) |
576 | 0 | { |
577 | 0 | send_resolved_cell(conn, answer_type, NULL); |
578 | 0 | } |
579 | | |
580 | | /** Send a response to the RESOLVE request of a connection for an in-addr.arpa |
581 | | * address on connection <b>conn</b> which yielded the result <b>hostname</b>. |
582 | | * The answer type will be RESOLVED_HOSTNAME. |
583 | | * |
584 | | * If <b>circ</b> is provided, and we have a cached answer, send the |
585 | | * answer back along circ; otherwise, send the answer back along |
586 | | * <b>conn</b>'s attached circuit. |
587 | | */ |
588 | | MOCK_IMPL(STATIC void, |
589 | | send_resolved_hostname_cell,(edge_connection_t *conn, |
590 | | const char *hostname)) |
591 | 0 | { |
592 | 0 | char buf[RELAY_PAYLOAD_SIZE_MAX]; |
593 | 0 | size_t buflen; |
594 | 0 | uint32_t ttl = RESOLVED_CLIPPED_TTL; |
595 | |
|
596 | 0 | if (BUG(!hostname)) |
597 | 0 | return; |
598 | | |
599 | 0 | size_t namelen = strlen(hostname); |
600 | |
|
601 | 0 | if (BUG(namelen >= 256)) { |
602 | 0 | return; |
603 | 0 | } |
604 | | |
605 | 0 | buf[0] = RESOLVED_TYPE_HOSTNAME; |
606 | 0 | buf[1] = (uint8_t)namelen; |
607 | 0 | memcpy(buf+2, hostname, namelen); |
608 | 0 | set_uint32(buf+2+namelen, htonl(ttl)); |
609 | 0 | buflen = 2+namelen+4; |
610 | | |
611 | | // log_notice(LD_EXIT, "Sending a reply RESOLVED reply: %s", hostname); |
612 | 0 | connection_edge_send_command(conn, RELAY_COMMAND_RESOLVED, buf, buflen); |
613 | | // log_notice(LD_EXIT, "Sent"); |
614 | 0 | } |
615 | | |
616 | | /** See if we have a cache entry for <b>exitconn</b>-\>address. If so, |
617 | | * if resolve valid, put it into <b>exitconn</b>-\>addr and return 1. |
618 | | * If resolve failed, free exitconn and return -1. |
619 | | * |
620 | | * (For EXIT_PURPOSE_RESOLVE connections, send back a RESOLVED error cell |
621 | | * on returning -1. For EXIT_PURPOSE_CONNECT connections, there's no |
622 | | * need to send back an END cell, since connection_exit_begin_conn will |
623 | | * do that for us.) |
624 | | * |
625 | | * If we have a cached answer, send the answer back along <b>exitconn</b>'s |
626 | | * circuit. |
627 | | * |
628 | | * Else, if seen before and pending, add conn to the pending list, |
629 | | * and return 0. |
630 | | * |
631 | | * Else, if not seen before, add conn to pending list, hand to |
632 | | * dns farm, and return 0. |
633 | | * |
634 | | * Exitconn's on_circuit field must be set, but exitconn should not |
635 | | * yet be linked onto the n_streams/resolving_streams list of that circuit. |
636 | | * On success, link the connection to n_streams if it's an exit connection. |
637 | | * On "pending", link the connection to resolving streams. Otherwise, |
638 | | * clear its on_circuit field. |
639 | | */ |
640 | | int |
641 | | dns_resolve(edge_connection_t *exitconn) |
642 | 0 | { |
643 | 0 | or_circuit_t *oncirc = TO_OR_CIRCUIT(exitconn->on_circuit); |
644 | 0 | int is_resolve, r; |
645 | 0 | int made_connection_pending = 0; |
646 | 0 | char *hostname = NULL; |
647 | 0 | cached_resolve_t *resolve = NULL; |
648 | 0 | is_resolve = exitconn->base_.purpose == EXIT_PURPOSE_RESOLVE; |
649 | |
|
650 | 0 | r = dns_resolve_impl(exitconn, is_resolve, oncirc, &hostname, |
651 | 0 | &made_connection_pending, &resolve); |
652 | |
|
653 | 0 | switch (r) { |
654 | 0 | case 1: |
655 | | /* We got an answer without a lookup -- either the answer was |
656 | | * cached, or it was obvious (like an IP address). */ |
657 | 0 | if (is_resolve) { |
658 | | /* Send the answer back right now, and detach. */ |
659 | 0 | if (hostname) |
660 | 0 | send_resolved_hostname_cell(exitconn, hostname); |
661 | 0 | else |
662 | 0 | send_resolved_cell(exitconn, RESOLVED_TYPE_AUTO, resolve); |
663 | 0 | exitconn->on_circuit = NULL; |
664 | 0 | } else { |
665 | | /* Add to the n_streams list; the calling function will send back a |
666 | | * connected cell. */ |
667 | 0 | exitconn->next_stream = oncirc->n_streams; |
668 | 0 | oncirc->n_streams = exitconn; |
669 | 0 | conflux_update_n_streams(oncirc, exitconn); |
670 | 0 | } |
671 | 0 | break; |
672 | 0 | case 0: |
673 | | /* The request is pending: add the connection into the linked list of |
674 | | * resolving_streams on this circuit. */ |
675 | 0 | exitconn->base_.state = EXIT_CONN_STATE_RESOLVING; |
676 | 0 | exitconn->next_stream = oncirc->resolving_streams; |
677 | 0 | oncirc->resolving_streams = exitconn; |
678 | 0 | conflux_update_resolving_streams(oncirc, exitconn); |
679 | 0 | break; |
680 | 0 | case -2: |
681 | 0 | case -1: |
682 | | /* The request failed before it could start: cancel this connection, |
683 | | * and stop everybody waiting for the same connection. */ |
684 | 0 | if (is_resolve) { |
685 | 0 | send_resolved_cell(exitconn, |
686 | 0 | (r == -1) ? RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT, |
687 | 0 | NULL); |
688 | 0 | } |
689 | |
|
690 | 0 | exitconn->on_circuit = NULL; |
691 | |
|
692 | 0 | dns_cancel_pending_resolve(exitconn->base_.address); |
693 | |
|
694 | 0 | if (!made_connection_pending && !exitconn->base_.marked_for_close) { |
695 | | /* If we made the connection pending, then we freed it already in |
696 | | * dns_cancel_pending_resolve(). If we marked it for close, it'll |
697 | | * get freed from the main loop. Otherwise, can free it now. */ |
698 | 0 | connection_free_(TO_CONN(exitconn)); |
699 | 0 | } |
700 | 0 | break; |
701 | 0 | default: |
702 | 0 | tor_assert(0); |
703 | 0 | } |
704 | | |
705 | 0 | tor_free(hostname); |
706 | 0 | return r; |
707 | 0 | } |
708 | | |
709 | | /** Helper function for dns_resolve: same functionality, but does not handle: |
710 | | * - marking connections on error and clearing their on_circuit |
711 | | * - linking connections to n_streams/resolving_streams, |
712 | | * - sending resolved cells if we have an answer/error right away, |
713 | | * |
714 | | * Return -2 on a transient error. If it's a reverse resolve and it's |
715 | | * successful, sets *<b>hostname_out</b> to a newly allocated string |
716 | | * holding the cached reverse DNS value. |
717 | | * |
718 | | * Set *<b>made_connection_pending_out</b> to true if we have placed |
719 | | * <b>exitconn</b> on the list of pending connections for some resolve; set it |
720 | | * to false otherwise. |
721 | | * |
722 | | * Set *<b>resolve_out</b> to a cached resolve, if we found one. |
723 | | */ |
724 | | MOCK_IMPL(STATIC int, |
725 | | dns_resolve_impl,(edge_connection_t *exitconn, int is_resolve, |
726 | | or_circuit_t *oncirc, char **hostname_out, |
727 | | int *made_connection_pending_out, |
728 | | cached_resolve_t **resolve_out)) |
729 | 0 | { |
730 | 0 | cached_resolve_t *resolve; |
731 | 0 | cached_resolve_t search; |
732 | 0 | pending_connection_t *pending_connection; |
733 | 0 | int is_reverse = 0; |
734 | 0 | tor_addr_t addr; |
735 | 0 | time_t now = time(NULL); |
736 | 0 | int r; |
737 | 0 | assert_connection_ok(TO_CONN(exitconn), 0); |
738 | 0 | tor_assert(!SOCKET_OK(exitconn->base_.s)); |
739 | 0 | assert_cache_ok(); |
740 | 0 | tor_assert(oncirc); |
741 | 0 | *made_connection_pending_out = 0; |
742 | | |
743 | | /* first check if exitconn->base_.address is an IP. If so, we already |
744 | | * know the answer. */ |
745 | 0 | if (tor_addr_parse(&addr, exitconn->base_.address) >= 0) { |
746 | 0 | if (tor_addr_family(&addr) == AF_INET || |
747 | 0 | tor_addr_family(&addr) == AF_INET6) { |
748 | 0 | tor_addr_copy(&exitconn->base_.addr, &addr); |
749 | 0 | exitconn->address_ttl = DEFAULT_DNS_TTL; |
750 | 0 | return 1; |
751 | 0 | } else { |
752 | | /* XXXX unspec? Bogus? */ |
753 | 0 | return -1; |
754 | 0 | } |
755 | 0 | } |
756 | | |
757 | | /* If we're a non-exit, don't even do DNS lookups. */ |
758 | 0 | if (router_my_exit_policy_is_reject_star()) |
759 | 0 | return -1; |
760 | | |
761 | 0 | if (address_is_invalid_destination(exitconn->base_.address, 0)) { |
762 | 0 | tor_log(LOG_PROTOCOL_WARN, LD_EXIT, |
763 | 0 | "Rejecting invalid destination address %s", |
764 | 0 | escaped_safe_str(exitconn->base_.address)); |
765 | 0 | return -1; |
766 | 0 | } |
767 | | |
768 | | /* then take this opportunity to see if there are any expired |
769 | | * resolves in the hash table. */ |
770 | 0 | purge_expired_resolves(now); |
771 | | |
772 | | /* lower-case exitconn->base_.address, so it's in canonical form */ |
773 | 0 | tor_strlower(exitconn->base_.address); |
774 | | |
775 | | /* Check whether this is a reverse lookup. If it's malformed, or it's a |
776 | | * .in-addr.arpa address but this isn't a resolve request, kill the |
777 | | * connection. |
778 | | */ |
779 | 0 | if ((r = tor_addr_parse_PTR_name(&addr, exitconn->base_.address, |
780 | 0 | AF_UNSPEC, 0)) != 0) { |
781 | 0 | if (r == 1) { |
782 | 0 | is_reverse = 1; |
783 | 0 | if (tor_addr_is_internal(&addr, 0)) /* internal address? */ |
784 | 0 | return -1; |
785 | 0 | } |
786 | | |
787 | 0 | if (!is_reverse || !is_resolve) { |
788 | 0 | if (!is_reverse) |
789 | 0 | log_info(LD_EXIT, "Bad .in-addr.arpa address %s; sending error.", |
790 | 0 | escaped_safe_str(exitconn->base_.address)); |
791 | 0 | else if (!is_resolve) |
792 | 0 | log_info(LD_EXIT, |
793 | 0 | "Attempt to connect to a .in-addr.arpa address %s; " |
794 | 0 | "sending error.", |
795 | 0 | escaped_safe_str(exitconn->base_.address)); |
796 | |
|
797 | 0 | return -1; |
798 | 0 | } |
799 | | //log_notice(LD_EXIT, "Looks like an address %s", |
800 | | //exitconn->base_.address); |
801 | 0 | } |
802 | 0 | exitconn->is_reverse_dns_lookup = is_reverse; |
803 | | |
804 | | /* now check the hash table to see if 'address' is already there. */ |
805 | 0 | strlcpy(search.address, exitconn->base_.address, sizeof(search.address)); |
806 | 0 | resolve = HT_FIND(cache_map, &cache_root, &search); |
807 | 0 | if (resolve && resolve->expire > now) { /* already there */ |
808 | 0 | switch (resolve->state) { |
809 | 0 | case CACHE_STATE_PENDING: |
810 | | /* add us to the pending list */ |
811 | 0 | pending_connection = tor_malloc_zero( |
812 | 0 | sizeof(pending_connection_t)); |
813 | 0 | pending_connection->conn = exitconn; |
814 | 0 | pending_connection->next = resolve->pending_connections; |
815 | 0 | resolve->pending_connections = pending_connection; |
816 | 0 | *made_connection_pending_out = 1; |
817 | 0 | log_debug(LD_EXIT,"Connection (fd "TOR_SOCKET_T_FORMAT") waiting " |
818 | 0 | "for pending DNS resolve of %s", exitconn->base_.s, |
819 | 0 | escaped_safe_str(exitconn->base_.address)); |
820 | 0 | return 0; |
821 | 0 | case CACHE_STATE_CACHED: |
822 | 0 | log_debug(LD_EXIT,"Connection (fd "TOR_SOCKET_T_FORMAT") found " |
823 | 0 | "cached answer for %s", |
824 | 0 | exitconn->base_.s, |
825 | 0 | escaped_safe_str(resolve->address)); |
826 | |
|
827 | 0 | *resolve_out = resolve; |
828 | |
|
829 | 0 | return set_exitconn_info_from_resolve(exitconn, resolve, hostname_out); |
830 | 0 | case CACHE_STATE_DONE: |
831 | 0 | log_err(LD_BUG, "Found a 'DONE' dns resolve still in the cache."); |
832 | 0 | tor_fragile_assert(); |
833 | 0 | } |
834 | 0 | tor_assert(0); |
835 | 0 | } |
836 | 0 | tor_assert(!resolve); |
837 | | /* not there, need to add it */ |
838 | 0 | resolve = tor_malloc_zero(sizeof(cached_resolve_t)); |
839 | 0 | resolve->magic = CACHED_RESOLVE_MAGIC; |
840 | 0 | resolve->state = CACHE_STATE_PENDING; |
841 | 0 | resolve->minheap_idx = -1; |
842 | 0 | strlcpy(resolve->address, exitconn->base_.address, sizeof(resolve->address)); |
843 | | |
844 | | /* add this connection to the pending list */ |
845 | 0 | pending_connection = tor_malloc_zero(sizeof(pending_connection_t)); |
846 | 0 | pending_connection->conn = exitconn; |
847 | 0 | resolve->pending_connections = pending_connection; |
848 | 0 | *made_connection_pending_out = 1; |
849 | | |
850 | | /* Add this resolve to the cache and priority queue. */ |
851 | 0 | HT_INSERT(cache_map, &cache_root, resolve); |
852 | 0 | set_expiry(resolve, now + RESOLVE_MAX_TIMEOUT); |
853 | |
|
854 | 0 | log_debug(LD_EXIT,"Launching %s.", |
855 | 0 | escaped_safe_str(exitconn->base_.address)); |
856 | 0 | assert_cache_ok(); |
857 | |
|
858 | 0 | return launch_resolve(resolve); |
859 | 0 | } |
860 | | |
861 | | /** Given an exit connection <b>exitconn</b>, and a cached_resolve_t |
862 | | * <b>resolve</b> whose DNS lookups have all either succeeded or failed, |
863 | | * update the appropriate fields (address_ttl and addr) of <b>exitconn</b>. |
864 | | * |
865 | | * The logic can be complicated here, since we might have launched both |
866 | | * an A lookup and an AAAA lookup, and since either of those might have |
867 | | * succeeded or failed, and since we want to answer a RESOLVE cell with |
868 | | * a full answer but answer a BEGIN cell with whatever answer the client |
869 | | * would accept <i>and</i> we could still connect to. |
870 | | * |
871 | | * If this is a reverse lookup, set *<b>hostname_out</b> to a newly allocated |
872 | | * copy of the name resulting hostname. |
873 | | * |
874 | | * Return -2 on a transient error, -1 on a permenent error, and 1 on |
875 | | * a successful lookup. |
876 | | */ |
877 | | MOCK_IMPL(STATIC int, |
878 | | set_exitconn_info_from_resolve,(edge_connection_t *exitconn, |
879 | | const cached_resolve_t *resolve, |
880 | | char **hostname_out)) |
881 | 0 | { |
882 | 0 | int ipv4_ok, ipv6_ok, answer_with_ipv4, r; |
883 | 0 | uint32_t begincell_flags; |
884 | 0 | const int is_resolve = exitconn->base_.purpose == EXIT_PURPOSE_RESOLVE; |
885 | 0 | tor_assert(exitconn); |
886 | 0 | tor_assert(resolve); |
887 | |
|
888 | 0 | if (exitconn->is_reverse_dns_lookup) { |
889 | 0 | exitconn->address_ttl = resolve->ttl_hostname; |
890 | 0 | if (resolve->res_status_hostname == RES_STATUS_DONE_OK) { |
891 | 0 | *hostname_out = tor_strdup(resolve->result_ptr.hostname); |
892 | 0 | return 1; |
893 | 0 | } else { |
894 | 0 | return -1; |
895 | 0 | } |
896 | 0 | } |
897 | | |
898 | | /* If we're here then the connection wants one or either of ipv4, ipv6, and |
899 | | * we can give it one or both. */ |
900 | 0 | if (is_resolve) { |
901 | 0 | begincell_flags = BEGIN_FLAG_IPV6_OK; |
902 | 0 | } else { |
903 | 0 | begincell_flags = exitconn->begincell_flags; |
904 | 0 | } |
905 | |
|
906 | 0 | ipv4_ok = (resolve->res_status_ipv4 == RES_STATUS_DONE_OK) && |
907 | 0 | ! (begincell_flags & BEGIN_FLAG_IPV4_NOT_OK); |
908 | 0 | ipv6_ok = (resolve->res_status_ipv6 == RES_STATUS_DONE_OK) && |
909 | 0 | (begincell_flags & BEGIN_FLAG_IPV6_OK) && |
910 | 0 | get_options()->IPv6Exit; |
911 | | |
912 | | /* Now decide which one to actually give. */ |
913 | 0 | if (ipv4_ok && ipv6_ok && is_resolve) { |
914 | 0 | answer_with_ipv4 = 1; |
915 | 0 | } else if (ipv4_ok && ipv6_ok) { |
916 | | /* If we have both, see if our exit policy has an opinion. */ |
917 | 0 | const uint16_t port = exitconn->base_.port; |
918 | 0 | int ipv4_allowed, ipv6_allowed; |
919 | 0 | tor_addr_t a4, a6; |
920 | 0 | tor_addr_from_ipv4h(&a4, resolve->result_ipv4.addr_ipv4); |
921 | 0 | tor_addr_from_in6(&a6, &resolve->result_ipv6.addr_ipv6); |
922 | 0 | ipv4_allowed = !router_compare_to_my_exit_policy(&a4, port); |
923 | 0 | ipv6_allowed = !router_compare_to_my_exit_policy(&a6, port); |
924 | 0 | if (ipv4_allowed && !ipv6_allowed) { |
925 | 0 | answer_with_ipv4 = 1; |
926 | 0 | } else if (ipv6_allowed && !ipv4_allowed) { |
927 | 0 | answer_with_ipv4 = 0; |
928 | 0 | } else { |
929 | | /* Our exit policy would permit both. Answer with whichever the user |
930 | | * prefers */ |
931 | 0 | answer_with_ipv4 = !(begincell_flags & |
932 | 0 | BEGIN_FLAG_IPV6_PREFERRED); |
933 | 0 | } |
934 | 0 | } else { |
935 | | /* Otherwise if one is okay, send it back. */ |
936 | 0 | if (ipv4_ok) { |
937 | 0 | answer_with_ipv4 = 1; |
938 | 0 | } else if (ipv6_ok) { |
939 | 0 | answer_with_ipv4 = 0; |
940 | 0 | } else { |
941 | | /* Neither one was okay. Choose based on user preference. */ |
942 | 0 | answer_with_ipv4 = !(begincell_flags & |
943 | 0 | BEGIN_FLAG_IPV6_PREFERRED); |
944 | 0 | } |
945 | 0 | } |
946 | | |
947 | | /* Finally, we write the answer back. */ |
948 | 0 | r = 1; |
949 | 0 | if (answer_with_ipv4) { |
950 | 0 | if (resolve->res_status_ipv4 == RES_STATUS_DONE_OK) { |
951 | 0 | tor_addr_from_ipv4h(&exitconn->base_.addr, |
952 | 0 | resolve->result_ipv4.addr_ipv4); |
953 | 0 | } else { |
954 | 0 | r = evdns_err_is_transient(resolve->result_ipv4.err_ipv4) ? -2 : -1; |
955 | 0 | } |
956 | |
|
957 | 0 | exitconn->address_ttl = resolve->ttl_ipv4; |
958 | 0 | } else { |
959 | 0 | if (resolve->res_status_ipv6 == RES_STATUS_DONE_OK) { |
960 | 0 | tor_addr_from_in6(&exitconn->base_.addr, |
961 | 0 | &resolve->result_ipv6.addr_ipv6); |
962 | 0 | } else { |
963 | 0 | r = evdns_err_is_transient(resolve->result_ipv6.err_ipv6) ? -2 : -1; |
964 | 0 | } |
965 | |
|
966 | 0 | exitconn->address_ttl = resolve->ttl_ipv6; |
967 | 0 | } |
968 | |
|
969 | 0 | return r; |
970 | 0 | } |
971 | | |
972 | | /** Log an error and abort if conn is waiting for a DNS resolve. |
973 | | */ |
974 | | void |
975 | | assert_connection_edge_not_dns_pending(edge_connection_t *conn) |
976 | 0 | { |
977 | 0 | pending_connection_t *pend; |
978 | 0 | cached_resolve_t search; |
979 | |
|
980 | 0 | #if 1 |
981 | 0 | cached_resolve_t *resolve; |
982 | 0 | strlcpy(search.address, conn->base_.address, sizeof(search.address)); |
983 | 0 | resolve = HT_FIND(cache_map, &cache_root, &search); |
984 | 0 | if (!resolve) |
985 | 0 | return; |
986 | 0 | for (pend = resolve->pending_connections; pend; pend = pend->next) { |
987 | 0 | tor_assert(pend->conn != conn); |
988 | 0 | } |
989 | | #else /* !(1) */ |
990 | | cached_resolve_t **resolve; |
991 | | HT_FOREACH(resolve, cache_map, &cache_root) { |
992 | | for (pend = (*resolve)->pending_connections; pend; pend = pend->next) { |
993 | | tor_assert(pend->conn != conn); |
994 | | } |
995 | | } |
996 | | #endif /* 1 */ |
997 | 0 | } |
998 | | |
999 | | /** Remove <b>conn</b> from the list of connections waiting for conn-\>address. |
1000 | | */ |
1001 | | void |
1002 | | connection_dns_remove(edge_connection_t *conn) |
1003 | 0 | { |
1004 | 0 | pending_connection_t *pend, *victim; |
1005 | 0 | cached_resolve_t search; |
1006 | 0 | cached_resolve_t *resolve; |
1007 | |
|
1008 | 0 | tor_assert(conn->base_.type == CONN_TYPE_EXIT); |
1009 | 0 | tor_assert(conn->base_.state == EXIT_CONN_STATE_RESOLVING); |
1010 | |
|
1011 | 0 | strlcpy(search.address, conn->base_.address, sizeof(search.address)); |
1012 | |
|
1013 | 0 | resolve = HT_FIND(cache_map, &cache_root, &search); |
1014 | 0 | if (!resolve) { |
1015 | 0 | log_notice(LD_BUG, "Address %s is not pending. Dropping.", |
1016 | 0 | escaped_safe_str(conn->base_.address)); |
1017 | 0 | return; |
1018 | 0 | } |
1019 | | |
1020 | 0 | tor_assert(resolve->pending_connections); |
1021 | 0 | assert_connection_ok(TO_CONN(conn),0); |
1022 | |
|
1023 | 0 | pend = resolve->pending_connections; |
1024 | |
|
1025 | 0 | if (pend->conn == conn) { |
1026 | 0 | resolve->pending_connections = pend->next; |
1027 | 0 | tor_free(pend); |
1028 | 0 | log_debug(LD_EXIT, "First connection (fd "TOR_SOCKET_T_FORMAT") no " |
1029 | 0 | "longer waiting for resolve of %s", |
1030 | 0 | conn->base_.s, |
1031 | 0 | escaped_safe_str(conn->base_.address)); |
1032 | 0 | return; |
1033 | 0 | } else { |
1034 | 0 | for ( ; pend->next; pend = pend->next) { |
1035 | 0 | if (pend->next->conn == conn) { |
1036 | 0 | victim = pend->next; |
1037 | 0 | pend->next = victim->next; |
1038 | 0 | tor_free(victim); |
1039 | 0 | log_debug(LD_EXIT, |
1040 | 0 | "Connection (fd "TOR_SOCKET_T_FORMAT") no longer waiting " |
1041 | 0 | "for resolve of %s", |
1042 | 0 | conn->base_.s, escaped_safe_str(conn->base_.address)); |
1043 | 0 | return; /* more are pending */ |
1044 | 0 | } |
1045 | 0 | } |
1046 | 0 | log_warn(LD_BUG, "Connection (fd "TOR_SOCKET_T_FORMAT") was not waiting " |
1047 | 0 | "for a resolve of %s, but we tried to remove it.", |
1048 | 0 | conn->base_.s, escaped_safe_str(conn->base_.address)); |
1049 | 0 | } |
1050 | 0 | } |
1051 | | |
1052 | | /** Mark all connections waiting for <b>address</b> for close. Then cancel |
1053 | | * the resolve for <b>address</b> itself, and remove any cached results for |
1054 | | * <b>address</b> from the cache. |
1055 | | */ |
1056 | | MOCK_IMPL(STATIC void, |
1057 | | dns_cancel_pending_resolve,(const char *address)) |
1058 | 0 | { |
1059 | 0 | pending_connection_t *pend; |
1060 | 0 | cached_resolve_t search; |
1061 | 0 | cached_resolve_t *resolve, *tmp; |
1062 | 0 | edge_connection_t *pendconn; |
1063 | 0 | circuit_t *circ; |
1064 | |
|
1065 | 0 | strlcpy(search.address, address, sizeof(search.address)); |
1066 | |
|
1067 | 0 | resolve = HT_FIND(cache_map, &cache_root, &search); |
1068 | 0 | if (!resolve) |
1069 | 0 | return; |
1070 | | |
1071 | 0 | if (resolve->state != CACHE_STATE_PENDING) { |
1072 | | /* We can get into this state if we never actually created the pending |
1073 | | * resolve, due to finding an earlier cached error or something. Just |
1074 | | * ignore it. */ |
1075 | 0 | if (resolve->pending_connections) { |
1076 | 0 | log_warn(LD_BUG, |
1077 | 0 | "Address %s is not pending but has pending connections!", |
1078 | 0 | escaped_safe_str(address)); |
1079 | 0 | tor_fragile_assert(); |
1080 | 0 | } |
1081 | 0 | return; |
1082 | 0 | } |
1083 | | |
1084 | 0 | if (!resolve->pending_connections) { |
1085 | 0 | log_warn(LD_BUG, |
1086 | 0 | "Address %s is pending but has no pending connections!", |
1087 | 0 | escaped_safe_str(address)); |
1088 | 0 | tor_fragile_assert(); |
1089 | 0 | return; |
1090 | 0 | } |
1091 | 0 | tor_assert(resolve->pending_connections); |
1092 | | |
1093 | | /* mark all pending connections to fail */ |
1094 | 0 | log_debug(LD_EXIT, |
1095 | 0 | "Failing all connections waiting on DNS resolve of %s", |
1096 | 0 | escaped_safe_str(address)); |
1097 | 0 | while (resolve->pending_connections) { |
1098 | 0 | pend = resolve->pending_connections; |
1099 | 0 | pend->conn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; |
1100 | 0 | pendconn = pend->conn; |
1101 | 0 | assert_connection_ok(TO_CONN(pendconn), 0); |
1102 | 0 | tor_assert(!SOCKET_OK(pendconn->base_.s)); |
1103 | 0 | if (!pendconn->base_.marked_for_close) { |
1104 | 0 | connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED); |
1105 | 0 | } |
1106 | 0 | circ = circuit_get_by_edge_conn(pendconn); |
1107 | 0 | if (circ) |
1108 | 0 | circuit_detach_stream(circ, pendconn); |
1109 | 0 | if (!pendconn->base_.marked_for_close) |
1110 | 0 | connection_free_(TO_CONN(pendconn)); |
1111 | 0 | resolve->pending_connections = pend->next; |
1112 | 0 | tor_free(pend); |
1113 | 0 | } |
1114 | |
|
1115 | 0 | tmp = HT_REMOVE(cache_map, &cache_root, resolve); |
1116 | 0 | if (tmp != resolve) { |
1117 | 0 | log_err(LD_BUG, "The cancelled resolve we purged didn't match any in" |
1118 | 0 | " the cache. Tried to purge %s (%p); instead got %s (%p).", |
1119 | 0 | resolve->address, (void*)resolve, |
1120 | 0 | tmp ? tmp->address : "NULL", (void*)tmp); |
1121 | 0 | } |
1122 | 0 | tor_assert(tmp == resolve); |
1123 | |
|
1124 | 0 | resolve->state = CACHE_STATE_DONE; |
1125 | 0 | } |
1126 | | |
1127 | | /** Return true iff <b>address</b> is one of the addresses we use to verify |
1128 | | * that well-known sites aren't being hijacked by our DNS servers. */ |
1129 | | static inline int |
1130 | | is_test_address(const char *address) |
1131 | 0 | { |
1132 | 0 | const or_options_t *options = get_options(); |
1133 | 0 | return options->ServerDNSTestAddresses && |
1134 | 0 | smartlist_contains_string_case(options->ServerDNSTestAddresses, address); |
1135 | 0 | } |
1136 | | |
1137 | | /** Called on the OR side when the eventdns library tells us the outcome of a |
1138 | | * single DNS resolve: remember the answer, and tell all pending connections |
1139 | | * about the result of the lookup if the lookup is now done. (<b>address</b> |
1140 | | * is a NUL-terminated string containing the address to look up; |
1141 | | * <b>query_type</b> is one of DNS_{IPv4_A,IPv6_AAAA,PTR}; <b>dns_answer</b> |
1142 | | * is DNS_OK or one of DNS_ERR_*, <b>addr</b> is an IPv4 or IPv6 address if we |
1143 | | * got one; <b>hostname</b> is a hostname fora PTR request if we got one, and |
1144 | | * <b>ttl</b> is the time-to-live of this answer, in seconds.) |
1145 | | */ |
1146 | | static void |
1147 | | dns_found_answer(const char *address, uint8_t query_type, |
1148 | | int dns_answer, |
1149 | | const tor_addr_t *addr, |
1150 | | const char *hostname, uint32_t ttl) |
1151 | 0 | { |
1152 | 0 | cached_resolve_t search; |
1153 | 0 | cached_resolve_t *resolve; |
1154 | |
|
1155 | 0 | assert_cache_ok(); |
1156 | |
|
1157 | 0 | strlcpy(search.address, address, sizeof(search.address)); |
1158 | |
|
1159 | 0 | resolve = HT_FIND(cache_map, &cache_root, &search); |
1160 | 0 | if (!resolve) { |
1161 | 0 | int is_test_addr = is_test_address(address); |
1162 | 0 | if (!is_test_addr) |
1163 | 0 | log_info(LD_EXIT,"Resolved unasked address %s; ignoring.", |
1164 | 0 | escaped_safe_str(address)); |
1165 | 0 | return; |
1166 | 0 | } |
1167 | 0 | assert_resolve_ok(resolve); |
1168 | |
|
1169 | 0 | if (resolve->state != CACHE_STATE_PENDING) { |
1170 | | /* XXXX Maybe update addr? or check addr for consistency? Or let |
1171 | | * VALID replace FAILED? */ |
1172 | 0 | int is_test_addr = is_test_address(address); |
1173 | 0 | if (!is_test_addr) |
1174 | 0 | log_notice(LD_EXIT, |
1175 | 0 | "Resolved %s which was already resolved; ignoring", |
1176 | 0 | escaped_safe_str(address)); |
1177 | 0 | tor_assert(resolve->pending_connections == NULL); |
1178 | 0 | return; |
1179 | 0 | } |
1180 | | |
1181 | 0 | cached_resolve_add_answer(resolve, query_type, dns_answer, |
1182 | 0 | addr, hostname, ttl); |
1183 | |
|
1184 | 0 | if (cached_resolve_have_all_answers(resolve)) { |
1185 | 0 | inform_pending_connections(resolve); |
1186 | |
|
1187 | 0 | make_pending_resolve_cached(resolve); |
1188 | 0 | } |
1189 | 0 | } |
1190 | | |
1191 | | /** Given a pending cached_resolve_t that we just finished resolving, |
1192 | | * inform every connection that was waiting for the outcome of that |
1193 | | * resolution. |
1194 | | * |
1195 | | * Do this by sending a RELAY_RESOLVED cell (if the pending stream had sent us |
1196 | | * a RELAY_RESOLVE cell), or by launching an exit connection (if the pending |
1197 | | * stream had sent us a RELAY_BEGIN cell). |
1198 | | */ |
1199 | | static void |
1200 | | inform_pending_connections(cached_resolve_t *resolve) |
1201 | 0 | { |
1202 | 0 | pending_connection_t *pend; |
1203 | 0 | edge_connection_t *pendconn; |
1204 | 0 | int r; |
1205 | |
|
1206 | 0 | while (resolve->pending_connections) { |
1207 | 0 | char *hostname = NULL; |
1208 | 0 | pend = resolve->pending_connections; |
1209 | 0 | pendconn = pend->conn; /* don't pass complex things to the |
1210 | | connection_mark_for_close macro */ |
1211 | 0 | assert_connection_ok(TO_CONN(pendconn),time(NULL)); |
1212 | |
|
1213 | 0 | if (pendconn->base_.marked_for_close) { |
1214 | | /* prevent double-remove. */ |
1215 | 0 | pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; |
1216 | 0 | resolve->pending_connections = pend->next; |
1217 | 0 | tor_free(pend); |
1218 | 0 | continue; |
1219 | 0 | } |
1220 | | |
1221 | 0 | r = set_exitconn_info_from_resolve(pendconn, |
1222 | 0 | resolve, |
1223 | 0 | &hostname); |
1224 | |
|
1225 | 0 | if (r < 0) { |
1226 | | /* prevent double-remove. */ |
1227 | 0 | pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; |
1228 | 0 | if (pendconn->base_.purpose == EXIT_PURPOSE_CONNECT) { |
1229 | 0 | connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED); |
1230 | | /* This detach must happen after we send the end cell. */ |
1231 | 0 | circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn); |
1232 | 0 | } else { |
1233 | 0 | send_resolved_cell(pendconn, r == -1 ? |
1234 | 0 | RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT, |
1235 | 0 | NULL); |
1236 | | /* This detach must happen after we send the resolved cell. */ |
1237 | 0 | circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn); |
1238 | 0 | } |
1239 | 0 | connection_free_(TO_CONN(pendconn)); |
1240 | 0 | } else { |
1241 | 0 | circuit_t *circ; |
1242 | 0 | if (pendconn->base_.purpose == EXIT_PURPOSE_CONNECT) { |
1243 | | /* prevent double-remove. */ |
1244 | 0 | pend->conn->base_.state = EXIT_CONN_STATE_CONNECTING; |
1245 | |
|
1246 | 0 | circ = circuit_get_by_edge_conn(pend->conn); |
1247 | 0 | tor_assert(circ); |
1248 | 0 | tor_assert(!CIRCUIT_IS_ORIGIN(circ)); |
1249 | | /* unlink pend->conn from resolving_streams, */ |
1250 | 0 | circuit_detach_stream(circ, pend->conn); |
1251 | | /* and link it to n_streams */ |
1252 | 0 | pend->conn->next_stream = TO_OR_CIRCUIT(circ)->n_streams; |
1253 | 0 | pend->conn->on_circuit = circ; |
1254 | 0 | TO_OR_CIRCUIT(circ)->n_streams = pend->conn; |
1255 | 0 | conflux_update_n_streams(TO_OR_CIRCUIT(circ), pend->conn); |
1256 | |
|
1257 | 0 | connection_exit_connect(pend->conn); |
1258 | 0 | } else { |
1259 | | /* prevent double-remove. This isn't really an accurate state, |
1260 | | * but it does the right thing. */ |
1261 | 0 | pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; |
1262 | 0 | if (pendconn->is_reverse_dns_lookup) |
1263 | 0 | send_resolved_hostname_cell(pendconn, hostname); |
1264 | 0 | else |
1265 | 0 | send_resolved_cell(pendconn, RESOLVED_TYPE_AUTO, resolve); |
1266 | 0 | circ = circuit_get_by_edge_conn(pendconn); |
1267 | 0 | tor_assert(circ); |
1268 | 0 | circuit_detach_stream(circ, pendconn); |
1269 | 0 | connection_free_(TO_CONN(pendconn)); |
1270 | 0 | } |
1271 | 0 | } |
1272 | 0 | resolve->pending_connections = pend->next; |
1273 | 0 | tor_free(pend); |
1274 | 0 | tor_free(hostname); |
1275 | 0 | } |
1276 | 0 | } |
1277 | | |
1278 | | /** Remove a pending cached_resolve_t from the hashtable, and add a |
1279 | | * corresponding cached cached_resolve_t. |
1280 | | * |
1281 | | * This function is only necessary because of the perversity of our |
1282 | | * cache timeout code; see inline comment for ideas on eliminating it. |
1283 | | **/ |
1284 | | static void |
1285 | | make_pending_resolve_cached(cached_resolve_t *resolve) |
1286 | 0 | { |
1287 | 0 | cached_resolve_t *removed; |
1288 | |
|
1289 | 0 | resolve->state = CACHE_STATE_DONE; |
1290 | 0 | removed = HT_REMOVE(cache_map, &cache_root, resolve); |
1291 | 0 | if (removed != resolve) { |
1292 | 0 | log_err(LD_BUG, "The pending resolve we found wasn't removable from" |
1293 | 0 | " the cache. Tried to purge %s (%p); instead got %s (%p).", |
1294 | 0 | resolve->address, (void*)resolve, |
1295 | 0 | removed ? removed->address : "NULL", (void*)removed); |
1296 | 0 | } |
1297 | 0 | assert_resolve_ok(resolve); |
1298 | 0 | assert_cache_ok(); |
1299 | | /* The resolve will eventually just hit the time-out in the expiry queue and |
1300 | | * expire. See fd0bafb0dedc7e2 for a brief explanation of how this got that |
1301 | | * way. XXXXX we could do better!*/ |
1302 | |
|
1303 | 0 | { |
1304 | 0 | cached_resolve_t *new_resolve = tor_memdup(resolve, |
1305 | 0 | sizeof(cached_resolve_t)); |
1306 | 0 | uint32_t ttl = UINT32_MAX; |
1307 | 0 | new_resolve->expire = 0; /* So that set_expiry won't croak. */ |
1308 | 0 | if (resolve->res_status_hostname == RES_STATUS_DONE_OK) |
1309 | 0 | new_resolve->result_ptr.hostname = |
1310 | 0 | tor_strdup(resolve->result_ptr.hostname); |
1311 | |
|
1312 | 0 | new_resolve->state = CACHE_STATE_CACHED; |
1313 | |
|
1314 | 0 | assert_resolve_ok(new_resolve); |
1315 | 0 | HT_INSERT(cache_map, &cache_root, new_resolve); |
1316 | |
|
1317 | 0 | if ((resolve->res_status_ipv4 == RES_STATUS_DONE_OK || |
1318 | 0 | resolve->res_status_ipv4 == RES_STATUS_DONE_ERR) && |
1319 | 0 | resolve->ttl_ipv4 < ttl) |
1320 | 0 | ttl = resolve->ttl_ipv4; |
1321 | |
|
1322 | 0 | if ((resolve->res_status_ipv6 == RES_STATUS_DONE_OK || |
1323 | 0 | resolve->res_status_ipv6 == RES_STATUS_DONE_ERR) && |
1324 | 0 | resolve->ttl_ipv6 < ttl) |
1325 | 0 | ttl = resolve->ttl_ipv6; |
1326 | |
|
1327 | 0 | if ((resolve->res_status_hostname == RES_STATUS_DONE_OK || |
1328 | 0 | resolve->res_status_hostname == RES_STATUS_DONE_ERR) && |
1329 | 0 | resolve->ttl_hostname < ttl) |
1330 | 0 | ttl = resolve->ttl_hostname; |
1331 | |
|
1332 | 0 | set_expiry(new_resolve, time(NULL) + ttl); |
1333 | 0 | } |
1334 | |
|
1335 | 0 | assert_cache_ok(); |
1336 | 0 | } |
1337 | | |
1338 | | /** Eventdns helper: return true iff the eventdns result <b>err</b> is |
1339 | | * a transient failure. */ |
1340 | | static int |
1341 | | evdns_err_is_transient(int err) |
1342 | 0 | { |
1343 | 0 | switch (err) |
1344 | 0 | { |
1345 | 0 | case DNS_ERR_SERVERFAILED: |
1346 | 0 | case DNS_ERR_TRUNCATED: |
1347 | 0 | case DNS_ERR_TIMEOUT: |
1348 | 0 | return 1; |
1349 | 0 | default: |
1350 | 0 | return 0; |
1351 | 0 | } |
1352 | 0 | } |
1353 | | |
1354 | | /** |
1355 | | * Return number of configured nameservers in <b>the_evdns_base</b>. |
1356 | | */ |
1357 | | size_t |
1358 | | number_of_configured_nameservers(void) |
1359 | 0 | { |
1360 | 0 | return evdns_base_count_nameservers(the_evdns_base); |
1361 | 0 | } |
1362 | | |
1363 | | #ifdef HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR |
1364 | | /** |
1365 | | * Return address of configured nameserver in <b>the_evdns_base</b> |
1366 | | * at index <b>idx</b>. |
1367 | | */ |
1368 | | tor_addr_t * |
1369 | | configured_nameserver_address(const size_t idx) |
1370 | 0 | { |
1371 | 0 | struct sockaddr_storage sa; |
1372 | 0 | ev_socklen_t sa_len = sizeof(sa); |
1373 | |
|
1374 | 0 | if (evdns_base_get_nameserver_addr(the_evdns_base, (int)idx, |
1375 | 0 | (struct sockaddr *)&sa, |
1376 | 0 | sa_len) > 0) { |
1377 | 0 | tor_addr_t *tor_addr = tor_malloc(sizeof(tor_addr_t)); |
1378 | 0 | if (tor_addr_from_sockaddr(tor_addr, |
1379 | 0 | (const struct sockaddr *)&sa, |
1380 | 0 | NULL) == 0) { |
1381 | 0 | return tor_addr; |
1382 | 0 | } |
1383 | 0 | tor_free(tor_addr); |
1384 | 0 | } |
1385 | | |
1386 | 0 | return NULL; |
1387 | 0 | } |
1388 | | #endif /* defined(HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR) */ |
1389 | | |
1390 | | /** Return a pointer to a stack allocated buffer containing the string |
1391 | | * representation of the exit_dns_timeout consensus parameter. */ |
1392 | | static const char * |
1393 | | get_consensus_param_exit_dns_timeout(void) |
1394 | 0 | { |
1395 | 0 | static char str[4]; |
1396 | | |
1397 | | /* Get the Exit DNS timeout value from the consensus or default. This is in |
1398 | | * milliseconds. */ |
1399 | 0 | #define EXIT_DNS_TIMEOUT_DEFAULT (1000) |
1400 | 0 | #define EXIT_DNS_TIMEOUT_MIN (1) |
1401 | 0 | #define EXIT_DNS_TIMEOUT_MAX (120000) |
1402 | 0 | int32_t val = networkstatus_get_param(NULL, "exit_dns_timeout", |
1403 | 0 | EXIT_DNS_TIMEOUT_DEFAULT, |
1404 | 0 | EXIT_DNS_TIMEOUT_MIN, |
1405 | 0 | EXIT_DNS_TIMEOUT_MAX); |
1406 | | /* NOTE: We convert it to seconds because libevent only supports that. In the |
1407 | | * future, if we support different resolver(s), we might want to specialize |
1408 | | * this call. */ |
1409 | | |
1410 | | /* NOTE: We also don't allow 0 and so we must cap the division to 1 second |
1411 | | * else all DNS request would fail if the consensus would ever tell us a |
1412 | | * value below 1000 (1 sec). */ |
1413 | 0 | val = MAX(1, val / 1000); |
1414 | |
|
1415 | 0 | tor_snprintf(str, sizeof(str), "%d", val); |
1416 | 0 | return str; |
1417 | 0 | } |
1418 | | |
1419 | | /** Return a pointer to a stack allocated buffer containing the string |
1420 | | * representation of the exit_dns_num_attempts consensus parameter. */ |
1421 | | static const char * |
1422 | | get_consensus_param_exit_dns_attempts(void) |
1423 | 0 | { |
1424 | 0 | static char str[4]; |
1425 | | |
1426 | | /* Get the Exit DNS number of attempt value from the consensus or default. */ |
1427 | 0 | #define EXIT_DNS_NUM_ATTEMPTS_DEFAULT (2) |
1428 | 0 | #define EXIT_DNS_NUM_ATTEMPTS_MIN (0) |
1429 | 0 | #define EXIT_DNS_NUM_ATTEMPTS_MAX (255) |
1430 | 0 | int32_t val = networkstatus_get_param(NULL, "exit_dns_num_attempts", |
1431 | 0 | EXIT_DNS_NUM_ATTEMPTS_DEFAULT, |
1432 | 0 | EXIT_DNS_NUM_ATTEMPTS_MIN, |
1433 | 0 | EXIT_DNS_NUM_ATTEMPTS_MAX); |
1434 | 0 | tor_snprintf(str, sizeof(str), "%d", val); |
1435 | 0 | return str; |
1436 | 0 | } |
1437 | | |
1438 | | /** Configure the libevent options. This can safely be called after |
1439 | | * initialization or even if the evdns base is not set. */ |
1440 | | static void |
1441 | | configure_libevent_options(void) |
1442 | 0 | { |
1443 | | /* This is possible because we can get called when a new consensus is set |
1444 | | * while the DNS subsystem is not initialized just yet. It should be |
1445 | | * harmless. */ |
1446 | 0 | if (!the_evdns_base) { |
1447 | 0 | return; |
1448 | 0 | } |
1449 | | |
1450 | 0 | #define SET(k,v) evdns_base_set_option(the_evdns_base, (k), (v)) |
1451 | | |
1452 | | // If we only have one nameserver, it does not make sense to back off |
1453 | | // from it for a timeout. Unfortunately, the value for max-timeouts is |
1454 | | // currently clamped by libevent to 255, but it does not hurt to set |
1455 | | // it higher in case libevent gets a patch for this. Higher-than- |
1456 | | // default maximum of 3 with multiple nameservers to avoid spuriously |
1457 | | // marking one down on bursts of timeouts resulting from scans/attacks |
1458 | | // against non-responding authoritative DNS servers. |
1459 | 0 | if (evdns_base_count_nameservers(the_evdns_base) == 1) { |
1460 | 0 | SET("max-timeouts:", "1000000"); |
1461 | 0 | } else { |
1462 | 0 | SET("max-timeouts:", "10"); |
1463 | 0 | } |
1464 | | |
1465 | | // Elongate the queue of maximum inflight dns requests, so if a bunch |
1466 | | // remain pending at the resolver (happens commonly with Unbound) we won't |
1467 | | // stall every other DNS request. This potentially means some wasted |
1468 | | // CPU as there's a walk over a linear queue involved, but this is a |
1469 | | // much better tradeoff compared to just failing DNS requests because |
1470 | | // of a full queue. |
1471 | 0 | SET("max-inflight:", "8192"); |
1472 | | |
1473 | | /* Set timeout to be 1 second. This tells libevent that it shouldn't wait |
1474 | | * more than N second to drop a DNS query and consider it "timed out". It is |
1475 | | * very important to differentiate here a libevent timeout and a DNS server |
1476 | | * timeout. And so, by setting this to N second, libevent sends back |
1477 | | * "DNS_ERR_TIMEOUT" if that N second is reached which does NOT indicate that |
1478 | | * the query itself timed out in transit. */ |
1479 | 0 | SET("timeout:", get_consensus_param_exit_dns_timeout()); |
1480 | | |
1481 | | /* This tells libevent to attempt up to X times a DNS query if the previous |
1482 | | * one failed to complete within N second. We believe that this should be |
1483 | | * enough to catch temporary hiccups on the first query. But after that, it |
1484 | | * should signal us that it won't be able to resolve it. */ |
1485 | 0 | SET("attempts:", get_consensus_param_exit_dns_attempts()); |
1486 | |
|
1487 | 0 | if (get_options()->ServerDNSRandomizeCase) |
1488 | 0 | SET("randomize-case:", "1"); |
1489 | 0 | else |
1490 | 0 | SET("randomize-case:", "0"); |
1491 | |
|
1492 | 0 | #undef SET |
1493 | 0 | } |
1494 | | |
1495 | | /** Configure eventdns nameservers if force is true, or if the configuration |
1496 | | * has changed since the last time we called this function, or if we failed on |
1497 | | * our last attempt. On Unix, this reads from /etc/resolv.conf or |
1498 | | * options->ServerDNSResolvConfFile; on Windows, this reads from |
1499 | | * options->ServerDNSResolvConfFile or the registry. Return 0 on success or |
1500 | | * -1 on failure. */ |
1501 | | static int |
1502 | | configure_nameservers(int force) |
1503 | 0 | { |
1504 | 0 | const or_options_t *options; |
1505 | 0 | const char *conf_fname; |
1506 | 0 | struct stat st; |
1507 | 0 | int r, flags; |
1508 | 0 | options = get_options(); |
1509 | 0 | conf_fname = options->ServerDNSResolvConfFile; |
1510 | 0 | #ifndef _WIN32 |
1511 | 0 | if (!conf_fname) |
1512 | 0 | conf_fname = "/etc/resolv.conf"; |
1513 | 0 | #endif |
1514 | 0 | flags = DNS_OPTIONS_ALL; |
1515 | |
|
1516 | 0 | if (!the_evdns_base) { |
1517 | 0 | if (!(the_evdns_base = evdns_base_new(tor_libevent_get_base(), 0))) { |
1518 | 0 | log_err(LD_BUG, "Couldn't create an evdns_base"); |
1519 | 0 | return -1; |
1520 | 0 | } |
1521 | 0 | } |
1522 | | |
1523 | 0 | evdns_set_log_fn(evdns_log_cb); |
1524 | 0 | if (conf_fname) { |
1525 | 0 | log_debug(LD_FS, "stat()ing %s", conf_fname); |
1526 | 0 | int missing_resolv_conf = 0; |
1527 | 0 | int stat_res = stat(sandbox_intern_string(conf_fname), &st); |
1528 | |
|
1529 | 0 | if (stat_res) { |
1530 | 0 | log_warn(LD_EXIT, "Unable to stat resolver configuration in '%s': %s", |
1531 | 0 | conf_fname, strerror(errno)); |
1532 | 0 | missing_resolv_conf = 1; |
1533 | 0 | } else if (!force && resolv_conf_fname && |
1534 | 0 | !strcmp(conf_fname,resolv_conf_fname) |
1535 | 0 | && st.st_mtime == resolv_conf_mtime) { |
1536 | 0 | log_info(LD_EXIT, "No change to '%s'", conf_fname); |
1537 | 0 | return 0; |
1538 | 0 | } |
1539 | | |
1540 | 0 | if (stat_res == 0 && st.st_size == 0) |
1541 | 0 | missing_resolv_conf = 1; |
1542 | |
|
1543 | 0 | if (nameservers_configured) { |
1544 | 0 | evdns_base_search_clear(the_evdns_base); |
1545 | 0 | evdns_base_clear_nameservers_and_suspend(the_evdns_base); |
1546 | 0 | } |
1547 | | #if defined(DNS_OPTION_HOSTSFILE) && defined(USE_LIBSECCOMP) |
1548 | | if (flags & DNS_OPTION_HOSTSFILE) { |
1549 | | flags ^= DNS_OPTION_HOSTSFILE; |
1550 | | log_debug(LD_FS, "Loading /etc/hosts"); |
1551 | | evdns_base_load_hosts(the_evdns_base, |
1552 | | sandbox_intern_string("/etc/hosts")); |
1553 | | } |
1554 | | #endif /* defined(DNS_OPTION_HOSTSFILE) && defined(USE_LIBSECCOMP) */ |
1555 | |
|
1556 | 0 | if (!missing_resolv_conf) { |
1557 | 0 | log_info(LD_EXIT, "Parsing resolver configuration in '%s'", conf_fname); |
1558 | 0 | if ((r = evdns_base_resolv_conf_parse(the_evdns_base, flags, |
1559 | 0 | sandbox_intern_string(conf_fname)))) { |
1560 | 0 | log_warn(LD_EXIT, "Unable to parse '%s', or no nameservers " |
1561 | 0 | "in '%s' (%d)", conf_fname, conf_fname, r); |
1562 | |
|
1563 | 0 | if (r != 6) // "r = 6" means "no DNS servers were in resolv.conf" - |
1564 | 0 | goto err; // in which case we expect libevent to add 127.0.0.1 as |
1565 | | // fallback. |
1566 | 0 | } |
1567 | 0 | if (evdns_base_count_nameservers(the_evdns_base) == 0) { |
1568 | 0 | log_warn(LD_EXIT, "Unable to find any nameservers in '%s'.", |
1569 | 0 | conf_fname); |
1570 | 0 | } |
1571 | |
|
1572 | 0 | tor_free(resolv_conf_fname); |
1573 | 0 | resolv_conf_fname = tor_strdup(conf_fname); |
1574 | 0 | resolv_conf_mtime = st.st_mtime; |
1575 | 0 | } else { |
1576 | 0 | log_warn(LD_EXIT, "Could not read your DNS config from '%s' - " |
1577 | 0 | "please investigate your DNS configuration. " |
1578 | 0 | "This is possibly a problem. Meanwhile, falling" |
1579 | 0 | " back to local DNS at 127.0.0.1.", conf_fname); |
1580 | 0 | evdns_base_nameserver_ip_add(the_evdns_base, "127.0.0.1"); |
1581 | 0 | } |
1582 | | |
1583 | 0 | if (nameservers_configured) |
1584 | 0 | evdns_base_resume(the_evdns_base); |
1585 | 0 | } |
1586 | | #ifdef _WIN32 |
1587 | | else { |
1588 | | if (nameservers_configured) { |
1589 | | evdns_base_search_clear(the_evdns_base); |
1590 | | evdns_base_clear_nameservers_and_suspend(the_evdns_base); |
1591 | | } |
1592 | | if (evdns_base_config_windows_nameservers(the_evdns_base)) { |
1593 | | log_warn(LD_EXIT,"Could not config nameservers."); |
1594 | | goto err; |
1595 | | } |
1596 | | if (evdns_base_count_nameservers(the_evdns_base) == 0) { |
1597 | | log_warn(LD_EXIT, "Unable to find any platform nameservers in " |
1598 | | "your Windows configuration."); |
1599 | | goto err; |
1600 | | } |
1601 | | if (nameservers_configured) |
1602 | | evdns_base_resume(the_evdns_base); |
1603 | | tor_free(resolv_conf_fname); |
1604 | | resolv_conf_mtime = 0; |
1605 | | } |
1606 | | #endif /* defined(_WIN32) */ |
1607 | | |
1608 | | /* Setup libevent options. */ |
1609 | 0 | configure_libevent_options(); |
1610 | | |
1611 | | /* Relaunch periodical DNS check event. */ |
1612 | 0 | dns_servers_relaunch_checks(); |
1613 | |
|
1614 | 0 | nameservers_configured = 1; |
1615 | 0 | if (nameserver_config_failed) { |
1616 | 0 | nameserver_config_failed = 0; |
1617 | | /* XXX the three calls to republish the descriptor might be producing |
1618 | | * descriptors that are only cosmetically different, especially on |
1619 | | * non-exit relays! -RD */ |
1620 | 0 | mark_my_descriptor_dirty("dns resolvers back"); |
1621 | 0 | } |
1622 | 0 | return 0; |
1623 | 0 | err: |
1624 | 0 | nameservers_configured = 0; |
1625 | 0 | if (! nameserver_config_failed) { |
1626 | 0 | nameserver_config_failed = 1; |
1627 | 0 | mark_my_descriptor_dirty("dns resolvers failed"); |
1628 | 0 | } |
1629 | 0 | return -1; |
1630 | 0 | } |
1631 | | |
1632 | | /** For eventdns: Called when we get an answer for a request we launched. |
1633 | | * See eventdns.h for arguments; 'arg' holds the address we tried to resolve. |
1634 | | */ |
1635 | | static void |
1636 | | evdns_callback(int result, char type, int count, int ttl, void *addresses, |
1637 | | void *arg) |
1638 | 0 | { |
1639 | 0 | char *arg_ = arg; |
1640 | 0 | uint8_t orig_query_type = arg_[0]; |
1641 | 0 | char *string_address = arg_ + 1; |
1642 | 0 | tor_addr_t addr; |
1643 | 0 | const char *hostname = NULL; |
1644 | 0 | int was_wildcarded = 0; |
1645 | |
|
1646 | 0 | tor_addr_make_unspec(&addr); |
1647 | | |
1648 | | /* Keep track of whether IPv6 is working */ |
1649 | 0 | if (type == DNS_IPv6_AAAA) { |
1650 | 0 | if (result == DNS_ERR_TIMEOUT) { |
1651 | 0 | ++n_ipv6_timeouts; |
1652 | 0 | } |
1653 | |
|
1654 | 0 | if (n_ipv6_timeouts > 10 && |
1655 | 0 | n_ipv6_timeouts > n_ipv6_requests_made / 2) { |
1656 | 0 | if (! dns_is_broken_for_ipv6) { |
1657 | 0 | log_notice(LD_EXIT, "More than half of our IPv6 requests seem to " |
1658 | 0 | "have timed out. I'm going to assume I can't get AAAA " |
1659 | 0 | "responses."); |
1660 | 0 | dns_is_broken_for_ipv6 = 1; |
1661 | 0 | } |
1662 | 0 | } |
1663 | 0 | } |
1664 | |
|
1665 | 0 | if (result == DNS_ERR_NONE) { |
1666 | 0 | if (type == DNS_IPv4_A && count) { |
1667 | 0 | char answer_buf[INET_NTOA_BUF_LEN+1]; |
1668 | 0 | char *escaped_address; |
1669 | 0 | uint32_t *addrs = addresses; |
1670 | 0 | tor_addr_from_ipv4n(&addr, addrs[0]); |
1671 | |
|
1672 | 0 | tor_addr_to_str(answer_buf, &addr, sizeof(answer_buf), 0); |
1673 | 0 | escaped_address = esc_for_log(string_address); |
1674 | |
|
1675 | 0 | if (answer_is_wildcarded(answer_buf)) { |
1676 | 0 | log_debug(LD_EXIT, "eventdns said that %s resolves to ISP-hijacked " |
1677 | 0 | "address %s; treating as a failure.", |
1678 | 0 | safe_str(escaped_address), |
1679 | 0 | escaped_safe_str(answer_buf)); |
1680 | 0 | was_wildcarded = 1; |
1681 | 0 | tor_addr_make_unspec(&addr); |
1682 | 0 | result = DNS_ERR_NOTEXIST; |
1683 | 0 | } else { |
1684 | 0 | log_debug(LD_EXIT, "eventdns said that %s resolves to %s", |
1685 | 0 | safe_str(escaped_address), |
1686 | 0 | escaped_safe_str(answer_buf)); |
1687 | 0 | } |
1688 | 0 | tor_free(escaped_address); |
1689 | 0 | } else if (type == DNS_IPv6_AAAA && count) { |
1690 | 0 | char answer_buf[TOR_ADDR_BUF_LEN]; |
1691 | 0 | char *escaped_address; |
1692 | 0 | const char *ip_str; |
1693 | 0 | struct in6_addr *addrs = addresses; |
1694 | 0 | tor_addr_from_in6(&addr, &addrs[0]); |
1695 | 0 | ip_str = tor_inet_ntop(AF_INET6, &addrs[0], answer_buf, |
1696 | 0 | sizeof(answer_buf)); |
1697 | 0 | escaped_address = esc_for_log(string_address); |
1698 | |
|
1699 | 0 | if (BUG(ip_str == NULL)) { |
1700 | 0 | log_warn(LD_EXIT, "tor_inet_ntop() failed!"); |
1701 | 0 | result = DNS_ERR_NOTEXIST; |
1702 | 0 | } else if (answer_is_wildcarded(answer_buf)) { |
1703 | 0 | log_debug(LD_EXIT, "eventdns said that %s resolves to ISP-hijacked " |
1704 | 0 | "address %s; treating as a failure.", |
1705 | 0 | safe_str(escaped_address), |
1706 | 0 | escaped_safe_str(answer_buf)); |
1707 | 0 | was_wildcarded = 1; |
1708 | 0 | tor_addr_make_unspec(&addr); |
1709 | 0 | result = DNS_ERR_NOTEXIST; |
1710 | 0 | } else { |
1711 | 0 | log_debug(LD_EXIT, "eventdns said that %s resolves to %s", |
1712 | 0 | safe_str(escaped_address), |
1713 | 0 | escaped_safe_str(answer_buf)); |
1714 | 0 | } |
1715 | 0 | tor_free(escaped_address); |
1716 | 0 | } else if (type == DNS_PTR && count) { |
1717 | 0 | char *escaped_address; |
1718 | 0 | hostname = ((char**)addresses)[0]; |
1719 | 0 | escaped_address = esc_for_log(string_address); |
1720 | 0 | log_debug(LD_EXIT, "eventdns said that %s resolves to %s", |
1721 | 0 | safe_str(escaped_address), |
1722 | 0 | escaped_safe_str(hostname)); |
1723 | 0 | tor_free(escaped_address); |
1724 | 0 | } else if (count) { |
1725 | 0 | log_info(LD_EXIT, "eventdns returned only unrecognized answer types " |
1726 | 0 | " for %s.", |
1727 | 0 | escaped_safe_str(string_address)); |
1728 | 0 | } else { |
1729 | 0 | log_info(LD_EXIT, "eventdns returned no addresses or error for %s.", |
1730 | 0 | escaped_safe_str(string_address)); |
1731 | 0 | } |
1732 | 0 | } |
1733 | 0 | if (was_wildcarded) { |
1734 | 0 | if (is_test_address(string_address)) { |
1735 | | /* Ick. We're getting redirected on known-good addresses. Our DNS |
1736 | | * server must really hate us. */ |
1737 | 0 | add_wildcarded_test_address(string_address); |
1738 | 0 | } |
1739 | 0 | } |
1740 | |
|
1741 | 0 | if (orig_query_type && type && orig_query_type != type) { |
1742 | 0 | log_warn(LD_BUG, "Weird; orig_query_type == %d but type == %d", |
1743 | 0 | (int)orig_query_type, (int)type); |
1744 | 0 | } |
1745 | 0 | if (result != DNS_ERR_SHUTDOWN) |
1746 | 0 | dns_found_answer(string_address, orig_query_type, |
1747 | 0 | result, &addr, hostname, clip_dns_fuzzy_ttl(ttl)); |
1748 | | |
1749 | | /* The result can be changed within this function thus why we note the result |
1750 | | * at the end. */ |
1751 | 0 | rep_hist_note_dns_error(type, result); |
1752 | |
|
1753 | 0 | tor_free(arg_); |
1754 | 0 | } |
1755 | | |
1756 | | /** Start a single DNS resolve for <b>address</b> (if <b>query_type</b> is |
1757 | | * DNS_IPv4_A or DNS_IPv6_AAAA) <b>ptr_address</b> (if <b>query_type</b> is |
1758 | | * DNS_PTR). Return 0 if we launched the request, -1 otherwise. */ |
1759 | | static int |
1760 | | launch_one_resolve(const char *address, uint8_t query_type, |
1761 | | const tor_addr_t *ptr_address) |
1762 | 0 | { |
1763 | 0 | const int options = get_options()->ServerDNSSearchDomains ? 0 |
1764 | 0 | : DNS_QUERY_NO_SEARCH; |
1765 | 0 | const size_t addr_len = strlen(address); |
1766 | 0 | struct evdns_request *req = 0; |
1767 | 0 | char *addr = tor_malloc(addr_len + 2); |
1768 | 0 | addr[0] = (char) query_type; |
1769 | 0 | memcpy(addr+1, address, addr_len + 1); |
1770 | | |
1771 | | /* Note the query for our statistics. */ |
1772 | 0 | rep_hist_note_dns_request(query_type); |
1773 | |
|
1774 | 0 | switch (query_type) { |
1775 | 0 | case DNS_IPv4_A: |
1776 | 0 | req = evdns_base_resolve_ipv4(the_evdns_base, |
1777 | 0 | address, options, evdns_callback, addr); |
1778 | 0 | break; |
1779 | 0 | case DNS_IPv6_AAAA: |
1780 | 0 | req = evdns_base_resolve_ipv6(the_evdns_base, |
1781 | 0 | address, options, evdns_callback, addr); |
1782 | 0 | ++n_ipv6_requests_made; |
1783 | 0 | break; |
1784 | 0 | case DNS_PTR: |
1785 | 0 | if (tor_addr_family(ptr_address) == AF_INET) |
1786 | 0 | req = evdns_base_resolve_reverse(the_evdns_base, |
1787 | 0 | tor_addr_to_in(ptr_address), |
1788 | 0 | DNS_QUERY_NO_SEARCH, |
1789 | 0 | evdns_callback, addr); |
1790 | 0 | else if (tor_addr_family(ptr_address) == AF_INET6) |
1791 | 0 | req = evdns_base_resolve_reverse_ipv6(the_evdns_base, |
1792 | 0 | tor_addr_to_in6(ptr_address), |
1793 | 0 | DNS_QUERY_NO_SEARCH, |
1794 | 0 | evdns_callback, addr); |
1795 | 0 | else |
1796 | 0 | log_warn(LD_BUG, "Called with PTR query and unexpected address family"); |
1797 | 0 | break; |
1798 | 0 | default: |
1799 | 0 | log_warn(LD_BUG, "Called with unexpected query type %d", (int)query_type); |
1800 | 0 | break; |
1801 | 0 | } |
1802 | | |
1803 | 0 | if (req) { |
1804 | 0 | return 0; |
1805 | 0 | } else { |
1806 | 0 | tor_free(addr); |
1807 | 0 | return -1; |
1808 | 0 | } |
1809 | 0 | } |
1810 | | |
1811 | | /** For eventdns: start resolving as necessary to find the target for |
1812 | | * <b>exitconn</b>. Returns -1 on error, -2 on transient error, |
1813 | | * 0 on "resolve launched." */ |
1814 | | MOCK_IMPL(STATIC int, |
1815 | | launch_resolve,(cached_resolve_t *resolve)) |
1816 | 0 | { |
1817 | 0 | tor_addr_t a; |
1818 | 0 | int r; |
1819 | |
|
1820 | 0 | if (net_is_disabled()) |
1821 | 0 | return -1; |
1822 | | |
1823 | | /* What? Nameservers not configured? Sounds like a bug. */ |
1824 | 0 | if (!nameservers_configured) { |
1825 | 0 | log_warn(LD_EXIT, "(Harmless.) Nameservers not configured, but resolve " |
1826 | 0 | "launched. Configuring."); |
1827 | 0 | if (configure_nameservers(1) < 0) { |
1828 | 0 | return -1; |
1829 | 0 | } |
1830 | 0 | } |
1831 | | |
1832 | 0 | r = tor_addr_parse_PTR_name( |
1833 | 0 | &a, resolve->address, AF_UNSPEC, 0); |
1834 | |
|
1835 | 0 | tor_assert(the_evdns_base); |
1836 | 0 | if (r == 0) { |
1837 | 0 | log_info(LD_EXIT, "Launching eventdns request for %s", |
1838 | 0 | escaped_safe_str(resolve->address)); |
1839 | 0 | resolve->res_status_ipv4 = RES_STATUS_INFLIGHT; |
1840 | 0 | if (get_options()->IPv6Exit) |
1841 | 0 | resolve->res_status_ipv6 = RES_STATUS_INFLIGHT; |
1842 | |
|
1843 | 0 | if (launch_one_resolve(resolve->address, DNS_IPv4_A, NULL) < 0) { |
1844 | 0 | resolve->res_status_ipv4 = 0; |
1845 | 0 | r = -1; |
1846 | 0 | } |
1847 | |
|
1848 | 0 | if (r==0 && get_options()->IPv6Exit) { |
1849 | | /* We ask for an IPv6 address for *everything*. */ |
1850 | 0 | if (launch_one_resolve(resolve->address, DNS_IPv6_AAAA, NULL) < 0) { |
1851 | 0 | resolve->res_status_ipv6 = 0; |
1852 | 0 | r = -1; |
1853 | 0 | } |
1854 | 0 | } |
1855 | 0 | } else if (r == 1) { |
1856 | 0 | r = 0; |
1857 | 0 | log_info(LD_EXIT, "Launching eventdns reverse request for %s", |
1858 | 0 | escaped_safe_str(resolve->address)); |
1859 | 0 | resolve->res_status_hostname = RES_STATUS_INFLIGHT; |
1860 | 0 | if (launch_one_resolve(resolve->address, DNS_PTR, &a) < 0) { |
1861 | 0 | resolve->res_status_hostname = 0; |
1862 | 0 | r = -1; |
1863 | 0 | } |
1864 | 0 | } else if (r == -1) { |
1865 | 0 | log_warn(LD_BUG, "Somehow a malformed in-addr.arpa address reached here."); |
1866 | 0 | } |
1867 | |
|
1868 | 0 | if (r < 0) { |
1869 | 0 | log_fn(LOG_PROTOCOL_WARN, LD_EXIT, "eventdns rejected address %s.", |
1870 | 0 | escaped_safe_str(resolve->address)); |
1871 | 0 | } |
1872 | 0 | return r; |
1873 | 0 | } |
1874 | | |
1875 | | /** How many requests for bogus addresses have we launched so far? */ |
1876 | | static int n_wildcard_requests = 0; |
1877 | | |
1878 | | /** Map from dotted-quad IP address in response to an int holding how many |
1879 | | * times we've seen it for a randomly generated (hopefully bogus) address. It |
1880 | | * would be easier to use definitely-invalid addresses (as specified by |
1881 | | * RFC2606), but see comment in dns_launch_wildcard_checks(). */ |
1882 | | static strmap_t *dns_wildcard_response_count = NULL; |
1883 | | |
1884 | | /** If present, a list of dotted-quad IP addresses that we are pretty sure our |
1885 | | * nameserver wants to return in response to requests for nonexistent domains. |
1886 | | */ |
1887 | | static smartlist_t *dns_wildcard_list = NULL; |
1888 | | /** True iff we've logged about a single address getting wildcarded. |
1889 | | * Subsequent warnings will be less severe. */ |
1890 | | static int dns_wildcard_one_notice_given = 0; |
1891 | | /** True iff we've warned that our DNS server is wildcarding too many failures. |
1892 | | */ |
1893 | | static int dns_wildcard_notice_given = 0; |
1894 | | |
1895 | | /** List of supposedly good addresses that are getting wildcarded to the |
1896 | | * same addresses as nonexistent addresses. */ |
1897 | | static smartlist_t *dns_wildcarded_test_address_list = NULL; |
1898 | | /** True iff we've warned about a test address getting wildcarded */ |
1899 | | static int dns_wildcarded_test_address_notice_given = 0; |
1900 | | /** True iff all addresses seem to be getting wildcarded. */ |
1901 | | static int dns_is_completely_invalid = 0; |
1902 | | |
1903 | | /** Called when we see <b>id</b> (a dotted quad or IPv6 address) in response |
1904 | | * to a request for a hopefully bogus address. */ |
1905 | | static void |
1906 | | wildcard_increment_answer(const char *id) |
1907 | 0 | { |
1908 | 0 | int *ip; |
1909 | 0 | if (!dns_wildcard_response_count) |
1910 | 0 | dns_wildcard_response_count = strmap_new(); |
1911 | |
|
1912 | 0 | ip = strmap_get(dns_wildcard_response_count, id); // may be null (0) |
1913 | 0 | if (!ip) { |
1914 | 0 | ip = tor_malloc_zero(sizeof(int)); |
1915 | 0 | strmap_set(dns_wildcard_response_count, id, ip); |
1916 | 0 | } |
1917 | 0 | ++*ip; |
1918 | |
|
1919 | 0 | if (*ip > 5 && n_wildcard_requests > 10) { |
1920 | 0 | if (!dns_wildcard_list) dns_wildcard_list = smartlist_new(); |
1921 | 0 | if (!smartlist_contains_string(dns_wildcard_list, id)) { |
1922 | 0 | tor_log(dns_wildcard_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT, |
1923 | 0 | "Your DNS provider has given \"%s\" as an answer for %d different " |
1924 | 0 | "invalid addresses. Apparently they are hijacking DNS failures. " |
1925 | 0 | "I'll try to correct for this by treating future occurrences of " |
1926 | 0 | "\"%s\" as 'not found'.", id, *ip, id); |
1927 | 0 | smartlist_add_strdup(dns_wildcard_list, id); |
1928 | 0 | } |
1929 | 0 | if (!dns_wildcard_notice_given) |
1930 | 0 | control_event_server_status(LOG_NOTICE, "DNS_HIJACKED"); |
1931 | 0 | dns_wildcard_notice_given = 1; |
1932 | 0 | } |
1933 | 0 | } |
1934 | | |
1935 | | /** Note that a single test address (one believed to be good) seems to be |
1936 | | * getting redirected to the same IP as failures are. */ |
1937 | | static void |
1938 | | add_wildcarded_test_address(const char *address) |
1939 | 0 | { |
1940 | 0 | int n, n_test_addrs; |
1941 | 0 | if (!dns_wildcarded_test_address_list) |
1942 | 0 | dns_wildcarded_test_address_list = smartlist_new(); |
1943 | |
|
1944 | 0 | if (smartlist_contains_string_case(dns_wildcarded_test_address_list, |
1945 | 0 | address)) |
1946 | 0 | return; |
1947 | | |
1948 | 0 | n_test_addrs = get_options()->ServerDNSTestAddresses ? |
1949 | 0 | smartlist_len(get_options()->ServerDNSTestAddresses) : 0; |
1950 | |
|
1951 | 0 | smartlist_add_strdup(dns_wildcarded_test_address_list, address); |
1952 | 0 | n = smartlist_len(dns_wildcarded_test_address_list); |
1953 | 0 | if (n > n_test_addrs/2) { |
1954 | 0 | tor_log(dns_wildcarded_test_address_notice_given ? LOG_INFO : LOG_NOTICE, |
1955 | 0 | LD_EXIT, "Your DNS provider tried to redirect \"%s\" to a junk " |
1956 | 0 | "address. It has done this with %d test addresses so far. I'm " |
1957 | 0 | "going to stop being an exit node for now, since our DNS seems so " |
1958 | 0 | "broken.", address, n); |
1959 | 0 | if (!dns_is_completely_invalid) { |
1960 | 0 | dns_is_completely_invalid = 1; |
1961 | 0 | mark_my_descriptor_dirty("dns hijacking confirmed"); |
1962 | 0 | } |
1963 | 0 | if (!dns_wildcarded_test_address_notice_given) |
1964 | 0 | control_event_server_status(LOG_WARN, "DNS_USELESS"); |
1965 | 0 | dns_wildcarded_test_address_notice_given = 1; |
1966 | 0 | } |
1967 | 0 | } |
1968 | | |
1969 | | /** Callback function when we get an answer (possibly failing) for a request |
1970 | | * for a (hopefully) nonexistent domain. */ |
1971 | | static void |
1972 | | evdns_wildcard_check_callback(int result, char type, int count, int ttl, |
1973 | | void *addresses, void *arg) |
1974 | 0 | { |
1975 | 0 | (void)ttl; |
1976 | 0 | const char *ip_str; |
1977 | 0 | ++n_wildcard_requests; |
1978 | 0 | if (result == DNS_ERR_NONE && count) { |
1979 | 0 | char *string_address = arg; |
1980 | 0 | int i; |
1981 | 0 | if (type == DNS_IPv4_A) { |
1982 | 0 | const uint32_t *addrs = addresses; |
1983 | 0 | for (i = 0; i < count; ++i) { |
1984 | 0 | char answer_buf[INET_NTOA_BUF_LEN+1]; |
1985 | 0 | struct in_addr in; |
1986 | 0 | int ntoa_res; |
1987 | 0 | in.s_addr = addrs[i]; |
1988 | 0 | ntoa_res = tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf)); |
1989 | 0 | tor_assert_nonfatal(ntoa_res >= 0); |
1990 | 0 | if (ntoa_res > 0) |
1991 | 0 | wildcard_increment_answer(answer_buf); |
1992 | 0 | } |
1993 | 0 | } else if (type == DNS_IPv6_AAAA) { |
1994 | 0 | const struct in6_addr *addrs = addresses; |
1995 | 0 | for (i = 0; i < count; ++i) { |
1996 | 0 | char answer_buf[TOR_ADDR_BUF_LEN+1]; |
1997 | 0 | ip_str = tor_inet_ntop(AF_INET6, &addrs[i], answer_buf, |
1998 | 0 | sizeof(answer_buf)); |
1999 | 0 | tor_assert_nonfatal(ip_str); |
2000 | 0 | if (ip_str) |
2001 | 0 | wildcard_increment_answer(answer_buf); |
2002 | 0 | } |
2003 | 0 | } |
2004 | |
|
2005 | 0 | tor_log(dns_wildcard_one_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT, |
2006 | 0 | "Your DNS provider gave an answer for \"%s\", which " |
2007 | 0 | "is not supposed to exist. Apparently they are hijacking " |
2008 | 0 | "DNS failures. Trying to correct for this. We've noticed %d " |
2009 | 0 | "possibly bad address%s so far.", |
2010 | 0 | string_address, strmap_size(dns_wildcard_response_count), |
2011 | 0 | (strmap_size(dns_wildcard_response_count) == 1) ? "" : "es"); |
2012 | 0 | dns_wildcard_one_notice_given = 1; |
2013 | 0 | } |
2014 | 0 | tor_free(arg); |
2015 | 0 | } |
2016 | | |
2017 | | /** Launch a single request for a nonexistent hostname consisting of between |
2018 | | * <b>min_len</b> and <b>max_len</b> random (plausible) characters followed by |
2019 | | * <b>suffix</b> */ |
2020 | | static void |
2021 | | launch_wildcard_check(int min_len, int max_len, int is_ipv6, |
2022 | | const char *suffix) |
2023 | 0 | { |
2024 | 0 | char *addr; |
2025 | 0 | struct evdns_request *req; |
2026 | |
|
2027 | 0 | addr = crypto_random_hostname(min_len, max_len, "", suffix); |
2028 | 0 | log_info(LD_EXIT, "Testing whether our DNS server is hijacking nonexistent " |
2029 | 0 | "domains with request for bogus hostname \"%s\"", addr); |
2030 | |
|
2031 | 0 | tor_assert(the_evdns_base); |
2032 | 0 | if (is_ipv6) |
2033 | 0 | req = evdns_base_resolve_ipv6( |
2034 | 0 | the_evdns_base, |
2035 | | /* This "addr" tells us which address to resolve */ |
2036 | 0 | addr, |
2037 | 0 | DNS_QUERY_NO_SEARCH, evdns_wildcard_check_callback, |
2038 | 0 | /* This "addr" is an argument to the callback*/ addr); |
2039 | 0 | else |
2040 | 0 | req = evdns_base_resolve_ipv4( |
2041 | 0 | the_evdns_base, |
2042 | | /* This "addr" tells us which address to resolve */ |
2043 | 0 | addr, |
2044 | 0 | DNS_QUERY_NO_SEARCH, evdns_wildcard_check_callback, |
2045 | 0 | /* This "addr" is an argument to the callback*/ addr); |
2046 | 0 | if (!req) { |
2047 | | /* There is no evdns request in progress; stop addr from getting leaked */ |
2048 | 0 | tor_free(addr); |
2049 | 0 | } |
2050 | 0 | } |
2051 | | |
2052 | | /** Launch attempts to resolve a bunch of known-good addresses (configured in |
2053 | | * ServerDNSTestAddresses). [Callback for a libevent timer] */ |
2054 | | static void |
2055 | | launch_test_addresses(evutil_socket_t fd, short event, void *args) |
2056 | 0 | { |
2057 | 0 | const or_options_t *options = get_options(); |
2058 | 0 | (void)fd; |
2059 | 0 | (void)event; |
2060 | 0 | (void)args; |
2061 | |
|
2062 | 0 | if (net_is_disabled()) |
2063 | 0 | return; |
2064 | | |
2065 | 0 | log_info(LD_EXIT, "Launching checks to see whether our nameservers like to " |
2066 | 0 | "hijack *everything*."); |
2067 | | /* This situation is worse than the failure-hijacking situation. When this |
2068 | | * happens, we're no good for DNS requests at all, and we shouldn't really |
2069 | | * be an exit server.*/ |
2070 | 0 | if (options->ServerDNSTestAddresses) { |
2071 | |
|
2072 | 0 | tor_assert(the_evdns_base); |
2073 | 0 | SMARTLIST_FOREACH_BEGIN(options->ServerDNSTestAddresses, |
2074 | 0 | const char *, address) { |
2075 | 0 | if (launch_one_resolve(address, DNS_IPv4_A, NULL) < 0) { |
2076 | 0 | log_info(LD_EXIT, "eventdns rejected test address %s", |
2077 | 0 | escaped_safe_str(address)); |
2078 | 0 | } |
2079 | |
|
2080 | 0 | if (launch_one_resolve(address, DNS_IPv6_AAAA, NULL) < 0) { |
2081 | 0 | log_info(LD_EXIT, "eventdns rejected test address %s", |
2082 | 0 | escaped_safe_str(address)); |
2083 | 0 | } |
2084 | 0 | } SMARTLIST_FOREACH_END(address); |
2085 | 0 | } |
2086 | 0 | } |
2087 | | |
2088 | 0 | #define N_WILDCARD_CHECKS 2 |
2089 | | |
2090 | | /** Launch DNS requests for a few nonexistent hostnames and a few well-known |
2091 | | * hostnames, and see if we can catch our nameserver trying to hijack them and |
2092 | | * map them to a stupid "I couldn't find ggoogle.com but maybe you'd like to |
2093 | | * buy these lovely encyclopedias" page. */ |
2094 | | static void |
2095 | | dns_launch_wildcard_checks(void) |
2096 | 0 | { |
2097 | 0 | int i, ipv6; |
2098 | 0 | log_info(LD_EXIT, "Launching checks to see whether our nameservers like " |
2099 | 0 | "to hijack DNS failures."); |
2100 | 0 | for (ipv6 = 0; ipv6 <= 1; ++ipv6) { |
2101 | 0 | for (i = 0; i < N_WILDCARD_CHECKS; ++i) { |
2102 | | /* RFC2606 reserves these. Sadly, some DNS hijackers, in a silly |
2103 | | * attempt to 'comply' with rfc2606, refrain from giving A records for |
2104 | | * these. This is the standards-compliance equivalent of making sure |
2105 | | * that your crackhouse's elevator inspection certificate is up to date. |
2106 | | */ |
2107 | 0 | launch_wildcard_check(2, 16, ipv6, ".invalid"); |
2108 | 0 | launch_wildcard_check(2, 16, ipv6, ".test"); |
2109 | | |
2110 | | /* These will break specs if there are ever any number of |
2111 | | * 8+-character top-level domains. */ |
2112 | 0 | launch_wildcard_check(8, 16, ipv6, ""); |
2113 | | |
2114 | | /* Try some random .com/org/net domains. This will work fine so long as |
2115 | | * not too many resolve to the same place. */ |
2116 | 0 | launch_wildcard_check(8, 16, ipv6, ".com"); |
2117 | 0 | launch_wildcard_check(8, 16, ipv6, ".org"); |
2118 | 0 | launch_wildcard_check(8, 16, ipv6, ".net"); |
2119 | 0 | } |
2120 | 0 | } |
2121 | 0 | } |
2122 | | |
2123 | | /** If appropriate, start testing whether our DNS servers tend to lie to |
2124 | | * us. */ |
2125 | | void |
2126 | | dns_launch_correctness_checks(void) |
2127 | 0 | { |
2128 | 0 | static struct event *launch_event = NULL; |
2129 | 0 | struct timeval timeout; |
2130 | 0 | if (!get_options()->ServerDNSDetectHijacking) |
2131 | 0 | return; |
2132 | 0 | dns_launch_wildcard_checks(); |
2133 | | |
2134 | | /* Wait a while before launching requests for test addresses, so we can |
2135 | | * get the results from checking for wildcarding. */ |
2136 | 0 | if (!launch_event) |
2137 | 0 | launch_event = tor_evtimer_new(tor_libevent_get_base(), |
2138 | 0 | launch_test_addresses, NULL); |
2139 | 0 | timeout.tv_sec = 30; |
2140 | 0 | timeout.tv_usec = 0; |
2141 | 0 | if (evtimer_add(launch_event, &timeout) < 0) { |
2142 | 0 | log_warn(LD_BUG, "Couldn't add timer for checking for dns hijacking"); |
2143 | 0 | } |
2144 | 0 | } |
2145 | | |
2146 | | /** Return true iff our DNS servers lie to us too much to be trusted. */ |
2147 | | int |
2148 | | dns_seems_to_be_broken(void) |
2149 | 0 | { |
2150 | 0 | return dns_is_completely_invalid; |
2151 | 0 | } |
2152 | | |
2153 | | /** Return true iff we think that IPv6 hostname lookup is broken */ |
2154 | | int |
2155 | | dns_seems_to_be_broken_for_ipv6(void) |
2156 | 0 | { |
2157 | 0 | return dns_is_broken_for_ipv6; |
2158 | 0 | } |
2159 | | |
2160 | | /** Forget what we've previously learned about our DNS servers' correctness. */ |
2161 | | void |
2162 | | dns_reset_correctness_checks(void) |
2163 | 0 | { |
2164 | 0 | strmap_free(dns_wildcard_response_count, tor_free_); |
2165 | 0 | dns_wildcard_response_count = NULL; |
2166 | |
|
2167 | 0 | n_wildcard_requests = 0; |
2168 | |
|
2169 | 0 | n_ipv6_requests_made = n_ipv6_timeouts = 0; |
2170 | |
|
2171 | 0 | if (dns_wildcard_list) { |
2172 | 0 | SMARTLIST_FOREACH(dns_wildcard_list, char *, cp, tor_free(cp)); |
2173 | 0 | smartlist_clear(dns_wildcard_list); |
2174 | 0 | } |
2175 | 0 | if (dns_wildcarded_test_address_list) { |
2176 | 0 | SMARTLIST_FOREACH(dns_wildcarded_test_address_list, char *, cp, |
2177 | 0 | tor_free(cp)); |
2178 | 0 | smartlist_clear(dns_wildcarded_test_address_list); |
2179 | 0 | } |
2180 | 0 | dns_wildcard_one_notice_given = dns_wildcard_notice_given = |
2181 | 0 | dns_wildcarded_test_address_notice_given = dns_is_completely_invalid = |
2182 | 0 | dns_is_broken_for_ipv6 = 0; |
2183 | 0 | } |
2184 | | |
2185 | | /** Return true iff we have noticed that the dotted-quad <b>ip</b> has been |
2186 | | * returned in response to requests for nonexistent hostnames. */ |
2187 | | static int |
2188 | | answer_is_wildcarded(const char *ip) |
2189 | 0 | { |
2190 | 0 | return dns_wildcard_list && smartlist_contains_string(dns_wildcard_list, ip); |
2191 | 0 | } |
2192 | | |
2193 | | /** Exit with an assertion if <b>resolve</b> is corrupt. */ |
2194 | | static void |
2195 | | assert_resolve_ok(cached_resolve_t *resolve) |
2196 | 0 | { |
2197 | 0 | tor_assert(resolve); |
2198 | 0 | tor_assert(resolve->magic == CACHED_RESOLVE_MAGIC); |
2199 | 0 | tor_assert(strlen(resolve->address) < MAX_ADDRESSLEN); |
2200 | 0 | tor_assert(tor_strisnonupper(resolve->address)); |
2201 | 0 | if (resolve->state != CACHE_STATE_PENDING) { |
2202 | 0 | tor_assert(!resolve->pending_connections); |
2203 | 0 | } |
2204 | 0 | if (resolve->state == CACHE_STATE_PENDING || |
2205 | 0 | resolve->state == CACHE_STATE_DONE) { |
2206 | | #if 0 |
2207 | | tor_assert(!resolve->ttl); |
2208 | | if (resolve->is_reverse) |
2209 | | tor_assert(!resolve->hostname); |
2210 | | else |
2211 | | tor_assert(!resolve->result_ipv4.addr_ipv4); |
2212 | | #endif /* 0 */ |
2213 | | /*XXXXX ADD MORE */ |
2214 | 0 | } |
2215 | 0 | } |
2216 | | |
2217 | | /** Return the number of DNS cache entries as an int */ |
2218 | | static int |
2219 | | dns_cache_entry_count(void) |
2220 | 0 | { |
2221 | 0 | return HT_SIZE(&cache_root); |
2222 | 0 | } |
2223 | | |
2224 | | /* Return the total size in bytes of the DNS cache. */ |
2225 | | size_t |
2226 | | dns_cache_total_allocation(void) |
2227 | 0 | { |
2228 | 0 | return sizeof(struct cached_resolve_t) * dns_cache_entry_count() + |
2229 | 0 | HT_MEM_USAGE(&cache_root); |
2230 | 0 | } |
2231 | | |
2232 | | /** Log memory information about our internal DNS cache at level 'severity'. */ |
2233 | | void |
2234 | | dump_dns_mem_usage(int severity) |
2235 | 0 | { |
2236 | | /* This should never be larger than INT_MAX. */ |
2237 | 0 | int hash_count = dns_cache_entry_count(); |
2238 | 0 | size_t hash_mem = dns_cache_total_allocation(); |
2239 | | |
2240 | | /* Print out the count and estimated size of our &cache_root. It undercounts |
2241 | | hostnames in cached reverse resolves. |
2242 | | */ |
2243 | 0 | tor_log(severity, LD_MM, "Our DNS cache has %d entries.", hash_count); |
2244 | 0 | tor_log(severity, LD_MM, "Our DNS cache size is approximately %u bytes.", |
2245 | 0 | (unsigned)hash_mem); |
2246 | 0 | } |
2247 | | |
2248 | | /* Do a round of OOM cleanup on all DNS entries. Return the amount of removed |
2249 | | * bytes. It is possible that the returned value is lower than min_remove_bytes |
2250 | | * if the caches get emptied out so the caller should be aware of this. */ |
2251 | | size_t |
2252 | | dns_cache_handle_oom(time_t now, size_t min_remove_bytes) |
2253 | 0 | { |
2254 | 0 | time_t time_inc = 0; |
2255 | 0 | size_t total_bytes_removed = 0; |
2256 | 0 | size_t current_size = dns_cache_total_allocation(); |
2257 | |
|
2258 | 0 | do { |
2259 | | /* If no DNS entries left, break loop. */ |
2260 | 0 | if (!dns_cache_entry_count()) |
2261 | 0 | break; |
2262 | | |
2263 | | /* Get cutoff interval and remove entries. */ |
2264 | 0 | time_t cutoff = now + time_inc; |
2265 | 0 | purge_expired_resolves(cutoff); |
2266 | | |
2267 | | /* Update amount of bytes removed and array size. */ |
2268 | 0 | size_t bytes_removed = current_size - dns_cache_total_allocation(); |
2269 | 0 | current_size -= bytes_removed; |
2270 | 0 | total_bytes_removed += bytes_removed; |
2271 | | |
2272 | | /* Increase time_inc by a reasonable fraction. */ |
2273 | 0 | time_inc += (MAX_DNS_TTL / 4); |
2274 | 0 | } while (total_bytes_removed < min_remove_bytes); |
2275 | |
|
2276 | 0 | return total_bytes_removed; |
2277 | 0 | } |
2278 | | |
2279 | | #ifdef DEBUG_DNS_CACHE |
2280 | | /** Exit with an assertion if the DNS cache is corrupt. */ |
2281 | | static void |
2282 | | assert_cache_ok_(void) |
2283 | | { |
2284 | | cached_resolve_t **resolve; |
2285 | | int bad_rep = HT_REP_IS_BAD_(cache_map, &cache_root); |
2286 | | if (bad_rep) { |
2287 | | log_err(LD_BUG, "Bad rep type %d on dns cache hash table", bad_rep); |
2288 | | tor_assert(!bad_rep); |
2289 | | } |
2290 | | |
2291 | | HT_FOREACH(resolve, cache_map, &cache_root) { |
2292 | | assert_resolve_ok(*resolve); |
2293 | | tor_assert((*resolve)->state != CACHE_STATE_DONE); |
2294 | | } |
2295 | | if (!cached_resolve_pqueue) |
2296 | | return; |
2297 | | |
2298 | | smartlist_pqueue_assert_ok(cached_resolve_pqueue, |
2299 | | compare_cached_resolves_by_expiry_, |
2300 | | offsetof(cached_resolve_t, minheap_idx)); |
2301 | | |
2302 | | SMARTLIST_FOREACH(cached_resolve_pqueue, cached_resolve_t *, res, |
2303 | | { |
2304 | | if (res->state == CACHE_STATE_DONE) { |
2305 | | cached_resolve_t *found = HT_FIND(cache_map, &cache_root, res); |
2306 | | tor_assert(!found || found != res); |
2307 | | } else { |
2308 | | cached_resolve_t *found = HT_FIND(cache_map, &cache_root, res); |
2309 | | tor_assert(found); |
2310 | | } |
2311 | | }); |
2312 | | } |
2313 | | |
2314 | | #endif /* defined(DEBUG_DNS_CACHE) */ |
2315 | | |
2316 | | cached_resolve_t * |
2317 | | dns_get_cache_entry(cached_resolve_t *query) |
2318 | 0 | { |
2319 | 0 | return HT_FIND(cache_map, &cache_root, query); |
2320 | 0 | } |
2321 | | |
2322 | | void |
2323 | | dns_insert_cache_entry(cached_resolve_t *new_entry) |
2324 | 0 | { |
2325 | 0 | HT_INSERT(cache_map, &cache_root, new_entry); |
2326 | 0 | } |