1 /* Copyright 2003-2004 Roger Dingledine.
2 * Copyright 2004-2005 Roger Dingledine, Nick Mathewson. */
3 /* See LICENSE for licensing information */
5 const char dns_c_id
[] = "$Id$";
9 * \brief Implements a farm of 'DNS worker' threads or processes to
10 * perform DNS lookups for onion routers and cache the results.
11 * [This needs to be done in the background because of the lack of a
12 * good, ubiquitous asynchronous DNS implementation.]
15 /* See http://elvin.dstc.com/ListArchive/elvin-dev/archive/2001/09/msg00027.html
16 * for some approaches to asynchronous dns. We will want to switch once one of
17 * them becomes more commonly available.
23 /** Longest hostname we're willing to resolve. */
24 #define MAX_ADDRESSLEN 256
26 /** Maximum DNS processes to spawn. */
27 #define MAX_DNSWORKERS 100
28 /** Minimum DNS processes to spawn. */
29 #define MIN_DNSWORKERS 3
31 /** If more than this many processes are idle, shut down the extras. */
32 #define MAX_IDLE_DNSWORKERS 10
34 /** Possible outcomes from hostname lookup: permanent failure,
35 * transient (retryable) failure, and success. */
36 #define DNS_RESOLVE_FAILED_TRANSIENT 1
37 #define DNS_RESOLVE_FAILED_PERMANENT 2
38 #define DNS_RESOLVE_SUCCEEDED 3
40 /** How many dnsworkers we have running right now. */
41 static int num_dnsworkers
=0;
42 /** How many of the running dnsworkers have an assigned task right now. */
43 static int num_dnsworkers_busy
=0;
44 /** When did we last rotate the dnsworkers? */
45 static time_t last_rotation_time
=0;
47 /** Linked list of connections waiting for a DNS answer. */
48 typedef struct pending_connection_t
{
50 struct pending_connection_t
*next
;
51 } pending_connection_t
;
53 /** A DNS request: possibly completed, possibly pending; cached_resolve
54 * structs are stored at the OR side in a splay tree, and as a linked
55 * list from oldest to newest.
57 typedef struct cached_resolve_t
{
58 SPLAY_ENTRY(cached_resolve_t
) node
;
59 char address
[MAX_ADDRESSLEN
]; /**< The hostname to be resolved. */
60 uint32_t addr
; /**< IPv4 addr for <b>address</b>. */
61 char state
; /**< 0 is pending; 1 means answer is valid; 2 means resolve failed. */
62 #define CACHE_STATE_PENDING 0
63 #define CACHE_STATE_VALID 1
64 #define CACHE_STATE_FAILED 2
65 uint32_t expire
; /**< Remove items from cache after this time. */
66 pending_connection_t
*pending_connections
;
67 struct cached_resolve_t
*next
;
70 static void purge_expired_resolves(uint32_t now
);
71 static int assign_to_dnsworker(connection_t
*exitconn
);
72 static void dns_purge_resolve(cached_resolve_t
*resolve
);
73 static void dns_found_answer(char *address
, uint32_t addr
, char outcome
);
74 static int dnsworker_main(void *data
);
75 static int spawn_dnsworker(void);
76 static int spawn_enough_dnsworkers(void);
77 static void send_resolved_cell(connection_t
*conn
, uint8_t answer_type
);
79 /** Splay tree of cached_resolve objects. */
80 static SPLAY_HEAD(cache_tree
, cached_resolve_t
) cache_root
;
82 /** Function to compare hashed resolves on their addresses; used to
83 * implement splay trees. */
85 compare_cached_resolves(cached_resolve_t
*a
,
88 /* make this smarter one day? */
89 return strncmp(a
->address
, b
->address
, MAX_ADDRESSLEN
);
92 SPLAY_PROTOTYPE(cache_tree
, cached_resolve_t
, node
, compare_cached_resolves
);
93 SPLAY_GENERATE(cache_tree
, cached_resolve_t
, node
, compare_cached_resolves
);
95 /** Initialize the DNS cache. */
99 SPLAY_INIT(&cache_root
);
102 /** Initialize the DNS subsystem; called by the OR process. */
110 /** Helper: free storage held by an entry in the DNS cache. */
112 _free_cached_resolve(cached_resolve_t
*r
)
114 while (r
->pending_connections
) {
115 pending_connection_t
*victim
= r
->pending_connections
;
116 r
->pending_connections
= victim
->next
;
122 /** Free all storage held in the DNS cache */
126 cached_resolve_t
*ptr
, *next
;
127 for (ptr
= SPLAY_MIN(cache_tree
, &cache_root
); ptr
!= NULL
; ptr
= next
) {
128 next
= SPLAY_NEXT(cache_tree
, &cache_root
, ptr
);
129 SPLAY_REMOVE(cache_tree
, &cache_root
, ptr
);
130 _free_cached_resolve(ptr
);
134 /** Linked list of resolved addresses, oldest to newest. */
135 static cached_resolve_t
*oldest_cached_resolve
= NULL
;
136 static cached_resolve_t
*newest_cached_resolve
= NULL
;
138 /** Remove every cached_resolve whose <b>expire</b> time is before <b>now</b>
141 purge_expired_resolves(uint32_t now
)
143 cached_resolve_t
*resolve
;
144 pending_connection_t
*pend
;
145 connection_t
*pendconn
;
147 /* this is fast because the linked list
148 * oldest_cached_resolve is ordered by when they came in.
150 while (oldest_cached_resolve
&& (oldest_cached_resolve
->expire
< now
)) {
151 resolve
= oldest_cached_resolve
;
152 log(LOG_DEBUG
,"Forgetting old cached resolve (address %s, expires %lu)",
153 safe_str(resolve
->address
), (unsigned long)resolve
->expire
);
154 if (resolve
->state
== CACHE_STATE_PENDING
) {
155 log_fn(LOG_WARN
,"Bug: Expiring a dns resolve ('%s') that's still pending. Forgot to cull it?", safe_str(resolve
->address
));
156 tor_fragile_assert();
158 if (resolve
->pending_connections
) {
159 log_fn(LOG_WARN
, "Closing pending connections on expiring DNS resolve!");
160 tor_fragile_assert();
161 while (resolve
->pending_connections
) {
162 pend
= resolve
->pending_connections
;
163 resolve
->pending_connections
= pend
->next
;
164 /* Connections should only be pending if they have no socket. */
165 tor_assert(pend
->conn
->s
== -1);
166 pendconn
= pend
->conn
;
167 connection_edge_end(pendconn
, END_STREAM_REASON_TIMEOUT
,
168 pendconn
->cpath_layer
);
169 circuit_detach_stream(circuit_get_by_edge_conn(pendconn
), pendconn
);
170 connection_free(pendconn
);
174 oldest_cached_resolve
= resolve
->next
;
175 if (!oldest_cached_resolve
) /* if there are no more, */
176 newest_cached_resolve
= NULL
; /* then make sure the list's tail knows that too */
177 SPLAY_REMOVE(cache_tree
, &cache_root
, resolve
);
182 /** Send a response to the RESOVLE request of a connection. answer_type must
183 * be one of RESOLVED_TYPE_(IPV4|ERROR|ERROR_TRANSIENT) */
185 send_resolved_cell(connection_t
*conn
, uint8_t answer_type
)
187 char buf
[RELAY_PAYLOAD_SIZE
];
190 buf
[0] = answer_type
;
194 case RESOLVED_TYPE_IPV4
:
196 set_uint32(buf
+2, htonl(conn
->addr
));
197 set_uint32(buf
+6, htonl(MAX_DNS_ENTRY_AGE
)); /*XXXX send a real TTL*/
200 case RESOLVED_TYPE_ERROR_TRANSIENT
:
201 case RESOLVED_TYPE_ERROR
:
203 const char *errmsg
= "Error resolving hostname";
204 int msglen
= strlen(errmsg
);
205 int ttl
= (answer_type
== RESOLVED_TYPE_ERROR
? MAX_DNS_ENTRY_AGE
: 0);
207 strlcpy(buf
+2, errmsg
, sizeof(buf
)-2);
208 set_uint32(buf
+2+msglen
, htonl((uint32_t)ttl
));
215 connection_edge_send_command(conn
, circuit_get_by_edge_conn(conn
),
216 RELAY_COMMAND_RESOLVED
, buf
, buflen
,
220 /** Link <b>r</b> into the tree of address-to-result mappings, and add it to
221 * the linked list of resolves-by-age. */
223 insert_resolve(cached_resolve_t
*r
)
225 /* add us to the linked list of resolves */
226 if (!oldest_cached_resolve
) {
227 oldest_cached_resolve
= r
;
229 newest_cached_resolve
->next
= r
;
231 newest_cached_resolve
= r
;
233 SPLAY_INSERT(cache_tree
, &cache_root
, r
);
236 /** See if we have a cache entry for <b>exitconn</b>-\>address. if so,
237 * if resolve valid, put it into <b>exitconn</b>-\>addr and return 1.
238 * If resolve failed, unlink exitconn if needed, free it, and return -1.
240 * Else, if seen before and pending, add conn to the pending list,
243 * Else, if not seen before, add conn to pending list, hand to
244 * dns farm, and return 0.
247 dns_resolve(connection_t
*exitconn
)
249 cached_resolve_t
*resolve
;
250 cached_resolve_t search
;
251 pending_connection_t
*pending_connection
;
254 uint32_t now
= time(NULL
);
255 assert_connection_ok(exitconn
, 0);
256 tor_assert(exitconn
->s
== -1);
258 /* first check if exitconn->address is an IP. If so, we already
259 * know the answer. */
260 if (tor_inet_aton(exitconn
->address
, &in
) != 0) {
261 exitconn
->addr
= ntohl(in
.s_addr
);
262 if (exitconn
->purpose
== EXIT_PURPOSE_RESOLVE
)
263 send_resolved_cell(exitconn
, RESOLVED_TYPE_IPV4
);
267 /* then take this opportunity to see if there are any expired
268 * resolves in the tree. */
269 purge_expired_resolves(now
);
271 /* lower-case exitconn->address, so it's in canonical form */
272 tor_strlower(exitconn
->address
);
274 /* now check the tree to see if 'address' is already there. */
275 strlcpy(search
.address
, exitconn
->address
, sizeof(search
.address
));
276 resolve
= SPLAY_FIND(cache_tree
, &cache_root
, &search
);
277 if (resolve
) { /* already there */
278 switch (resolve
->state
) {
279 case CACHE_STATE_PENDING
:
280 /* add us to the pending list */
281 pending_connection
= tor_malloc_zero(
282 sizeof(pending_connection_t
));
283 pending_connection
->conn
= exitconn
;
284 pending_connection
->next
= resolve
->pending_connections
;
285 resolve
->pending_connections
= pending_connection
;
286 log_fn(LOG_DEBUG
,"Connection (fd %d) waiting for pending DNS resolve of '%s'",
287 exitconn
->s
, safe_str(exitconn
->address
));
288 exitconn
->state
= EXIT_CONN_STATE_RESOLVING
;
290 case CACHE_STATE_VALID
:
291 exitconn
->addr
= resolve
->addr
;
292 log_fn(LOG_DEBUG
,"Connection (fd %d) found cached answer for '%s'",
293 exitconn
->s
, safe_str(exitconn
->address
));
294 if (exitconn
->purpose
== EXIT_PURPOSE_RESOLVE
)
295 send_resolved_cell(exitconn
, RESOLVED_TYPE_IPV4
);
297 case CACHE_STATE_FAILED
:
298 log_fn(LOG_DEBUG
,"Connection (fd %d) found cached error for '%s'",
299 exitconn
->s
, safe_str(exitconn
->address
));
300 if (exitconn
->purpose
== EXIT_PURPOSE_RESOLVE
)
301 send_resolved_cell(exitconn
, RESOLVED_TYPE_ERROR
);
302 circ
= circuit_get_by_edge_conn(exitconn
);
304 circuit_detach_stream(circ
, exitconn
);
305 if (!exitconn
->marked_for_close
)
306 connection_free(exitconn
);
311 /* not there, need to add it */
312 resolve
= tor_malloc_zero(sizeof(cached_resolve_t
));
313 resolve
->state
= CACHE_STATE_PENDING
;
314 resolve
->expire
= now
+ MAX_DNS_ENTRY_AGE
;
315 strlcpy(resolve
->address
, exitconn
->address
, sizeof(resolve
->address
));
317 /* add us to the pending list */
318 pending_connection
= tor_malloc_zero(sizeof(pending_connection_t
));
319 pending_connection
->conn
= exitconn
;
320 resolve
->pending_connections
= pending_connection
;
321 exitconn
->state
= EXIT_CONN_STATE_RESOLVING
;
323 insert_resolve(resolve
);
324 return assign_to_dnsworker(exitconn
);
327 /** Find or spawn a dns worker process to handle resolving
328 * <b>exitconn</b>-\>address; tell that dns worker to begin resolving.
331 assign_to_dnsworker(connection_t
*exitconn
)
333 connection_t
*dnsconn
;
336 tor_assert(exitconn
->state
== EXIT_CONN_STATE_RESOLVING
);
337 tor_assert(exitconn
->s
== -1);
339 /* respawn here, to be sure there are enough */
340 if (spawn_enough_dnsworkers() < 0) {
344 dnsconn
= connection_get_by_type_state(CONN_TYPE_DNSWORKER
, DNSWORKER_STATE_IDLE
);
347 log_fn(LOG_WARN
,"no idle dns workers. Failing.");
348 if (exitconn
->purpose
== EXIT_PURPOSE_RESOLVE
)
349 send_resolved_cell(exitconn
, RESOLVED_TYPE_ERROR_TRANSIENT
);
353 log_fn(LOG_DEBUG
, "Connection (fd %d) needs to resolve '%s'; assigning to DNSWorker (fd %d)",
354 exitconn
->s
, safe_str(exitconn
->address
), dnsconn
->s
);
356 tor_free(dnsconn
->address
);
357 dnsconn
->address
= tor_strdup(exitconn
->address
);
358 dnsconn
->state
= DNSWORKER_STATE_BUSY
;
359 num_dnsworkers_busy
++;
361 len
= strlen(dnsconn
->address
);
362 connection_write_to_buf((char*)&len
, 1, dnsconn
);
363 connection_write_to_buf(dnsconn
->address
, len
, dnsconn
);
367 dns_cancel_pending_resolve(exitconn
->address
); /* also sends end and frees! */
371 /** Remove <b>conn</b> from the list of connections waiting for conn-\>address.
374 connection_dns_remove(connection_t
*conn
)
376 pending_connection_t
*pend
, *victim
;
377 cached_resolve_t search
;
378 cached_resolve_t
*resolve
;
380 tor_assert(conn
->type
== CONN_TYPE_EXIT
);
381 tor_assert(conn
->state
== EXIT_CONN_STATE_RESOLVING
);
383 strlcpy(search
.address
, conn
->address
, sizeof(search
.address
));
385 resolve
= SPLAY_FIND(cache_tree
, &cache_root
, &search
);
387 log_fn(LOG_NOTICE
,"Address '%s' is not pending. Dropping.", safe_str(conn
->address
));
391 tor_assert(resolve
->pending_connections
);
392 assert_connection_ok(conn
,0);
394 pend
= resolve
->pending_connections
;
396 if (pend
->conn
== conn
) {
397 resolve
->pending_connections
= pend
->next
;
399 log_fn(LOG_DEBUG
, "First connection (fd %d) no longer waiting for resolve of '%s'",
400 conn
->s
, safe_str(conn
->address
));
403 for ( ; pend
->next
; pend
= pend
->next
) {
404 if (pend
->next
->conn
== conn
) {
406 pend
->next
= victim
->next
;
408 log_fn(LOG_DEBUG
, "Connection (fd %d) no longer waiting for resolve of '%s'",
409 conn
->s
, safe_str(conn
->address
));
410 return; /* more are pending */
413 tor_assert(0); /* not reachable unless onlyconn not in pending list */
417 /** Log an error and abort if conn is waiting for a DNS resolve.
420 assert_connection_edge_not_dns_pending(connection_t
*conn
)
422 pending_connection_t
*pend
;
423 cached_resolve_t
*resolve
;
425 SPLAY_FOREACH(resolve
, cache_tree
, &cache_root
) {
426 for (pend
= resolve
->pending_connections
;
429 tor_assert(pend
->conn
!= conn
);
434 /** Log an error and abort if any connection waiting for a DNS resolve is
437 assert_all_pending_dns_resolves_ok(void)
439 pending_connection_t
*pend
;
440 cached_resolve_t
*resolve
;
442 SPLAY_FOREACH(resolve
, cache_tree
, &cache_root
) {
443 for (pend
= resolve
->pending_connections
;
446 assert_connection_ok(pend
->conn
, 0);
447 tor_assert(pend
->conn
->s
== -1);
448 tor_assert(!connection_in_array(pend
->conn
));
453 /** Mark all connections waiting for <b>address</b> for close. Then cancel
454 * the resolve for <b>address</b> itself, and remove any cached results for
455 * <b>address</b> from the cache.
458 dns_cancel_pending_resolve(char *address
)
460 pending_connection_t
*pend
;
461 cached_resolve_t search
;
462 cached_resolve_t
*resolve
;
463 connection_t
*pendconn
;
466 strlcpy(search
.address
, address
, sizeof(search
.address
));
468 resolve
= SPLAY_FIND(cache_tree
, &cache_root
, &search
);
470 log_fn(LOG_NOTICE
,"Address '%s' is not pending. Dropping.", safe_str(address
));
474 if (!resolve
->pending_connections
) {
475 /* XXX this should never trigger, but sometimes it does */
476 log_fn(LOG_WARN
,"Bug: Address '%s' is pending but has no pending connections!",
478 tor_fragile_assert();
481 tor_assert(resolve
->pending_connections
);
483 /* mark all pending connections to fail */
484 log_fn(LOG_DEBUG
, "Failing all connections waiting on DNS resolve of '%s'",
486 while (resolve
->pending_connections
) {
487 pend
= resolve
->pending_connections
;
488 pend
->conn
->state
= EXIT_CONN_STATE_RESOLVEFAILED
;
489 pendconn
= pend
->conn
;
490 tor_assert(pendconn
->s
== -1);
491 if (!pendconn
->marked_for_close
) {
492 connection_edge_end(pendconn
, END_STREAM_REASON_RESOURCELIMIT
,
493 pendconn
->cpath_layer
);
495 circ
= circuit_get_by_edge_conn(pendconn
);
497 circuit_detach_stream(circ
, pendconn
);
498 connection_free(pendconn
);
499 resolve
->pending_connections
= pend
->next
;
503 dns_purge_resolve(resolve
);
506 /** Remove <b>resolve</b> from the cache.
509 dns_purge_resolve(cached_resolve_t
*resolve
)
511 cached_resolve_t
*tmp
;
513 /* remove resolve from the linked list */
514 if (resolve
== oldest_cached_resolve
) {
515 oldest_cached_resolve
= resolve
->next
;
516 if (oldest_cached_resolve
== NULL
)
517 newest_cached_resolve
= NULL
;
519 /* FFFF make it a doubly linked list if this becomes too slow */
520 for (tmp
=oldest_cached_resolve
; tmp
&& tmp
->next
!= resolve
; tmp
=tmp
->next
) ;
521 tor_assert(tmp
); /* it's got to be in the list, or we screwed up somewhere else */
522 tmp
->next
= resolve
->next
; /* unlink it */
524 if (newest_cached_resolve
== resolve
)
525 newest_cached_resolve
= tmp
;
528 /* remove resolve from the tree */
529 SPLAY_REMOVE(cache_tree
, &cache_root
, resolve
);
534 /** Called on the OR side when a DNS worker tells us the outcome of a DNS
535 * resolve: tell all pending connections about the result of the lookup, and
536 * cache the value. (<b>address</b> is a NUL-terminated string containing the
537 * address to look up; <b>addr</b> is an IPv4 address in host order;
538 * <b>outcome</b> is one of
539 * DNS_RESOLVE_{FAILED_TRANSIENT|FAILED_PERMANENT|SUCCEEDED}.
542 dns_found_answer(char *address
, uint32_t addr
, char outcome
)
544 pending_connection_t
*pend
;
545 cached_resolve_t search
;
546 cached_resolve_t
*resolve
;
547 connection_t
*pendconn
;
550 strlcpy(search
.address
, address
, sizeof(search
.address
));
552 resolve
= SPLAY_FIND(cache_tree
, &cache_root
, &search
);
554 log_fn(LOG_INFO
,"Resolved unasked address '%s'; caching anyway.",
556 resolve
= tor_malloc_zero(sizeof(cached_resolve_t
));
557 resolve
->state
= (outcome
== DNS_RESOLVE_SUCCEEDED
) ?
558 CACHE_STATE_VALID
: CACHE_STATE_FAILED
;
559 resolve
->addr
= addr
;
560 resolve
->expire
= time(NULL
) + MAX_DNS_ENTRY_AGE
;
561 insert_resolve(resolve
);
565 if (resolve
->state
!= CACHE_STATE_PENDING
) {
566 /* XXXX Maybe update addr? or check addr for consistency? Or let
567 * VALID replace FAILED? */
568 log_fn(LOG_NOTICE
, "Resolved '%s' which was already resolved; ignoring",
570 tor_assert(resolve
->pending_connections
== NULL
);
573 /* Removed this assertion: in fact, we'll sometimes get a double answer
574 * to the same question. This can happen when we ask one worker to resolve
575 * X.Y.Z., then we cancel the request, and then we ask another worker to
577 /* tor_assert(resolve->state == CACHE_STATE_PENDING); */
579 resolve
->addr
= addr
;
580 if (outcome
== DNS_RESOLVE_SUCCEEDED
)
581 resolve
->state
= CACHE_STATE_VALID
;
583 resolve
->state
= CACHE_STATE_FAILED
;
585 while (resolve
->pending_connections
) {
586 pend
= resolve
->pending_connections
;
587 assert_connection_ok(pend
->conn
,time(NULL
));
588 pend
->conn
->addr
= resolve
->addr
;
589 pendconn
= pend
->conn
; /* don't pass complex things to the
590 connection_mark_for_close macro */
592 if (resolve
->state
== CACHE_STATE_FAILED
) {
593 /* prevent double-remove. */
594 pendconn
->state
= EXIT_CONN_STATE_RESOLVEFAILED
;
595 if (pendconn
->purpose
== EXIT_PURPOSE_CONNECT
) {
596 connection_edge_end(pendconn
, END_STREAM_REASON_RESOLVEFAILED
, pendconn
->cpath_layer
);
597 /* This detach must happen after we send the end cell. */
598 circuit_detach_stream(circuit_get_by_edge_conn(pendconn
), pendconn
);
600 send_resolved_cell(pendconn
, RESOLVED_TYPE_ERROR
);
601 /* This detach must happen after we send the resolved cell. */
602 circuit_detach_stream(circuit_get_by_edge_conn(pendconn
), pendconn
);
604 connection_free(pendconn
);
606 if (pendconn
->purpose
== EXIT_PURPOSE_CONNECT
) {
607 /* prevent double-remove. */
608 pend
->conn
->state
= EXIT_CONN_STATE_CONNECTING
;
610 circ
= circuit_get_by_edge_conn(pend
->conn
);
612 /* unlink pend->conn from resolving_streams, */
613 circuit_detach_stream(circ
, pend
->conn
);
614 /* and link it to n_streams */
615 pend
->conn
->next_stream
= circ
->n_streams
;
616 pend
->conn
->on_circuit
= circ
;
617 circ
->n_streams
= pend
->conn
;
619 connection_exit_connect(pend
->conn
);
621 /* prevent double-remove. This isn't really an accurate state,
622 * but it does the right thing. */
623 pendconn
->state
= EXIT_CONN_STATE_RESOLVEFAILED
;
624 send_resolved_cell(pendconn
, RESOLVED_TYPE_IPV4
);
625 circ
= circuit_get_by_edge_conn(pendconn
);
627 circuit_detach_stream(circ
, pendconn
);
628 connection_free(pendconn
);
631 resolve
->pending_connections
= pend
->next
;
635 if (outcome
== DNS_RESOLVE_FAILED_TRANSIENT
) { /* remove from cache */
636 dns_purge_resolve(resolve
);
640 /******************************************************************/
643 * Connection between OR and dnsworker
646 /** Write handler: called when we've pushed a request to a dnsworker. */
648 connection_dns_finished_flushing(connection_t
*conn
)
651 tor_assert(conn
->type
== CONN_TYPE_DNSWORKER
);
652 connection_stop_writing(conn
);
657 connection_dns_reached_eof(connection_t
*conn
)
659 log_fn(LOG_WARN
,"Read eof. Worker died unexpectedly.");
660 if (conn
->state
== DNSWORKER_STATE_BUSY
) {
661 /* don't cancel the resolve here -- it would be cancelled in
662 * connection_about_to_close_connection(), since conn is still
665 num_dnsworkers_busy
--;
668 connection_mark_for_close(conn
);
672 /** Read handler: called when we get data from a dnsworker. See
673 * if we have a complete answer. If so, call dns_found_answer on the
674 * result. If not, wait. Returns 0. */
676 connection_dns_process_inbuf(connection_t
*conn
)
682 tor_assert(conn
->type
== CONN_TYPE_DNSWORKER
);
684 if (conn
->state
!= DNSWORKER_STATE_BUSY
&& buf_datalen(conn
->inbuf
)) {
685 log_fn(LOG_WARN
,"Bug: read data (%d bytes) from an idle dns worker (fd %d, address '%s'). Please report.",
686 (int)buf_datalen(conn
->inbuf
), conn
->s
, safe_str(conn
->address
));
687 tor_fragile_assert();
689 /* Pull it off the buffer anyway, or it will just stay there.
690 * Keep pulling things off because sometimes we get several
691 * answers at once (!). */
692 while (buf_datalen(conn
->inbuf
)) {
693 connection_fetch_from_buf(&success
,1,conn
);
694 connection_fetch_from_buf((char *)&addr
,sizeof(uint32_t),conn
);
695 log_fn(LOG_WARN
,"Discarding idle dns answer (success %d, addr %d.)",
696 success
, addr
); // XXX safe_str
700 if (buf_datalen(conn
->inbuf
) < 5) /* entire answer available? */
701 return 0; /* not yet */
702 tor_assert(conn
->state
== DNSWORKER_STATE_BUSY
);
703 tor_assert(buf_datalen(conn
->inbuf
) == 5);
705 connection_fetch_from_buf(&success
,1,conn
);
706 connection_fetch_from_buf((char *)&addr
,sizeof(uint32_t),conn
);
708 log_fn(LOG_DEBUG
, "DNSWorker (fd %d) returned answer for '%s'",
709 conn
->s
, safe_str(conn
->address
));
711 tor_assert(success
>= DNS_RESOLVE_FAILED_TRANSIENT
);
712 tor_assert(success
<= DNS_RESOLVE_SUCCEEDED
);
713 dns_found_answer(conn
->address
, ntohl(addr
), success
);
715 tor_free(conn
->address
);
716 conn
->address
= tor_strdup("<idle>");
717 conn
->state
= DNSWORKER_STATE_IDLE
;
718 num_dnsworkers_busy
--;
719 if (conn
->timestamp_created
< last_rotation_time
) {
720 connection_mark_for_close(conn
);
722 spawn_enough_dnsworkers();
727 /** Close and re-open all idle dnsworkers; schedule busy ones to be closed
728 * and re-opened once they're no longer busy.
731 dnsworkers_rotate(void)
733 connection_t
*dnsconn
;
734 while ((dnsconn
= connection_get_by_type_state(CONN_TYPE_DNSWORKER
,
735 DNSWORKER_STATE_IDLE
))) {
736 connection_mark_for_close(dnsconn
);
739 last_rotation_time
= time(NULL
);
740 if (server_mode(get_options()))
741 spawn_enough_dnsworkers();
744 /** Implementation for DNS workers; this code runs in a separate
745 * execution context. It takes as its argument an fdarray as returned
746 * by socketpair(), and communicates via fdarray[1]. The protocol is
749 * - ADDRESSLEN [1 byte]
750 * - ADDRESS [ADDRESSLEN bytes]
751 * - The DNS worker does the lookup, and replies:
755 * OUTCOME is one of DNS_RESOLVE_{FAILED_TRANSIENT|FAILED_PERMANENT|SUCCEEDED}.
756 * IP is in host order.
758 * The dnsworker runs indefinitely, until its connection is closed or an error
762 dnsworker_main(void *data
)
764 char address
[MAX_ADDRESSLEN
];
765 unsigned char address_len
;
772 /* log_fn(LOG_NOTICE,"After spawn: fdarray @%d has %d:%d", (int)fdarray, fdarray[0],fdarray[1]); */
774 fd
= fdarray
[1]; /* this side is ours */
775 #ifndef TOR_IS_MULTITHREADED
776 tor_close_socket(fdarray
[0]); /* this is the side of the socketpair the parent uses */
777 tor_free_all(1); /* so the child doesn't hold the parent's fd's open */
778 handle_signals(0); /* ignore interrupts from the keyboard, etc */
785 if ((r
= recv(fd
, &address_len
, 1, 0)) != 1) {
787 log_fn(LOG_INFO
,"DNS worker exiting because Tor process closed connection (either pruned idle dnsworker or died).");
789 log_fn(LOG_INFO
,"DNS worker exiting because of error on connection to Tor process.");
790 log_fn(LOG_INFO
,"(Error on %d was %s)", fd
, tor_socket_strerror(tor_socket_errno(fd
)));
792 tor_close_socket(fd
);
796 if (address_len
&& read_all(fd
, address
, address_len
, 1) != address_len
) {
797 log_fn(LOG_ERR
,"read hostname failed. Child exiting.");
798 tor_close_socket(fd
);
801 address
[address_len
] = 0; /* null terminate it */
803 result
= tor_lookup_hostname(address
, &ip
);
804 /* Make 0.0.0.0 an error, so that we can use "0" to mean "no addr") */
809 /* XXX result can never be 1, because we set it to -1 above on error */
810 log_fn(LOG_INFO
,"Could not resolve dest addr %s (transient).",safe_str(address
));
811 answer
[0] = DNS_RESOLVE_FAILED_TRANSIENT
;
814 log_fn(LOG_INFO
,"Could not resolve dest addr %s (permanent).",safe_str(address
));
815 answer
[0] = DNS_RESOLVE_FAILED_PERMANENT
;
818 log_fn(LOG_INFO
,"Resolved address '%s'.",safe_str(address
));
819 answer
[0] = DNS_RESOLVE_SUCCEEDED
;
822 set_uint32(answer
+1, ip
);
823 if (write_all(fd
, answer
, 5, 1) != 5) {
824 log_fn(LOG_ERR
,"writing answer failed. Child exiting.");
825 tor_close_socket(fd
);
829 return 0; /* windows wants this function to return an int */
832 /** Launch a new DNS worker; return 0 on success, -1 on failure.
835 spawn_dnsworker(void)
842 fdarray
= tor_malloc(sizeof(int)*2);
843 if ((err
= tor_socketpair(AF_UNIX
, SOCK_STREAM
, 0, fdarray
)) < 0) {
844 log(LOG_WARN
, "Couldn't construct socketpair: %s", tor_socket_strerror(-err
));
849 /* log_fn(LOG_NOTICE,"Before spawn: fdarray @%d has %d:%d", (int)fdarray, fdarray[0],fdarray[1]); */
851 fd
= fdarray
[0]; /* We copy this out here, since dnsworker_main may free fdarray */
852 spawn_func(dnsworker_main
, (void*)fdarray
);
853 log_fn(LOG_DEBUG
,"just spawned a worker.");
854 #ifndef TOR_IS_MULTITHREADED
855 tor_close_socket(fdarray
[1]); /* we don't need the worker's side of the pipe */
859 conn
= connection_new(CONN_TYPE_DNSWORKER
);
861 set_socket_nonblocking(fd
);
863 /* set up conn so it's got all the data we need to remember */
865 conn
->address
= tor_strdup("<unused>");
867 if (connection_add(conn
) < 0) { /* no space, forget it */
868 log_fn(LOG_WARN
,"connection_add failed. Giving up.");
869 connection_free(conn
); /* this closes fd */
873 conn
->state
= DNSWORKER_STATE_IDLE
;
874 connection_start_reading(conn
);
876 return 0; /* success */
879 /** If we have too many or too few DNS workers, spawn or kill some.
880 * Return 0 if we are happy, return -1 if we tried to spawn more but
884 spawn_enough_dnsworkers(void)
886 int num_dnsworkers_needed
; /* aim to have 1 more than needed,
887 * but no less than min and no more than max */
888 connection_t
*dnsconn
;
890 /* XXX This may not be the best strategy. Maybe we should queue pending
891 * requests until the old ones finish or time out: otherwise, if
892 * the connection requests come fast enough, we never get any DNS done. -NM
893 * XXX But if we queue them, then the adversary can pile even more
894 * queries onto us, blocking legitimate requests for even longer.
895 * Maybe we should compromise and only kill if it's been at it for
896 * more than, e.g., 2 seconds. -RD
898 if (num_dnsworkers_busy
== MAX_DNSWORKERS
) {
899 /* We always want at least one worker idle.
900 * So find the oldest busy worker and kill it.
902 dnsconn
= connection_get_by_type_state_lastwritten(CONN_TYPE_DNSWORKER
,
903 DNSWORKER_STATE_BUSY
);
906 log_fn(LOG_WARN
, "%d DNS workers are spawned; all are busy. Killing one.",
909 connection_mark_for_close(dnsconn
);
910 num_dnsworkers_busy
--;
914 if (num_dnsworkers_busy
>= MIN_DNSWORKERS
)
915 num_dnsworkers_needed
= num_dnsworkers_busy
+1;
917 num_dnsworkers_needed
= MIN_DNSWORKERS
;
919 while (num_dnsworkers
< num_dnsworkers_needed
) {
920 if (spawn_dnsworker() < 0) {
921 log_fn(LOG_WARN
,"Spawn failed. Will try again later.");
927 while (num_dnsworkers
> num_dnsworkers_busy
+MAX_IDLE_DNSWORKERS
) {
929 /* cull excess workers */
930 log_fn(LOG_INFO
,"%d of %d dnsworkers are idle. Killing one.",
931 num_dnsworkers
-num_dnsworkers_busy
, num_dnsworkers
);
932 dnsconn
= connection_get_by_type_state(CONN_TYPE_DNSWORKER
, DNSWORKER_STATE_IDLE
);
934 connection_mark_for_close(dnsconn
);