Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright 2006-2007 Niels Provos |
2 | | * Copyright 2007-2012 Nick Mathewson and Niels Provos |
3 | | * |
4 | | * Redistribution and use in source and binary forms, with or without |
5 | | * modification, are permitted provided that the following conditions |
6 | | * are met: |
7 | | * 1. Redistributions of source code must retain the above copyright |
8 | | * notice, this list of conditions and the following disclaimer. |
9 | | * 2. Redistributions in binary form must reproduce the above copyright |
10 | | * notice, this list of conditions and the following disclaimer in the |
11 | | * documentation and/or other materials provided with the distribution. |
12 | | * 3. The name of the author may not be used to endorse or promote products |
13 | | * derived from this software without specific prior written permission. |
14 | | * |
15 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
16 | | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
17 | | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
18 | | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
19 | | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
20 | | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
21 | | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
22 | | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
23 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
24 | | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 | | */ |
26 | | |
27 | | /* Based on software by Adam Langly. Adam's original message: |
28 | | * |
29 | | * Async DNS Library |
30 | | * Adam Langley <agl@imperialviolet.org> |
31 | | * http://www.imperialviolet.org/eventdns.html |
32 | | * Public Domain code |
33 | | * |
34 | | * This software is Public Domain. To view a copy of the public domain dedication, |
35 | | * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to |
36 | | * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. |
37 | | * |
38 | | * I ask and expect, but do not require, that all derivative works contain an |
39 | | * attribution similar to: |
40 | | * Parts developed by Adam Langley <agl@imperialviolet.org> |
41 | | * |
42 | | * You may wish to replace the word "Parts" with something else depending on |
43 | | * the amount of original code. |
44 | | * |
45 | | * (Derivative works does not include programs which link against, run or include |
46 | | * the source verbatim in their source distributions) |
47 | | * |
48 | | * Version: 0.1b |
49 | | */ |
50 | | |
51 | | #include "event2/event-config.h" |
52 | | #include "evconfig-private.h" |
53 | | |
54 | | #include <sys/types.h> |
55 | | |
56 | | #ifndef _FORTIFY_SOURCE |
57 | | #define _FORTIFY_SOURCE 3 |
58 | | #endif |
59 | | |
60 | | #include <string.h> |
61 | | #include <fcntl.h> |
62 | | #ifdef EVENT__HAVE_SYS_TIME_H |
63 | | #include <sys/time.h> |
64 | | #endif |
65 | | #ifdef EVENT__HAVE_STDINT_H |
66 | | #include <stdint.h> |
67 | | #endif |
68 | | #include <stdlib.h> |
69 | | #include <string.h> |
70 | | #include <errno.h> |
71 | | #ifdef EVENT__HAVE_UNISTD_H |
72 | | #include <unistd.h> |
73 | | #endif |
74 | | #include <limits.h> |
75 | | #include <sys/stat.h> |
76 | | #include <stdio.h> |
77 | | #include <stdarg.h> |
78 | | #ifdef _WIN32 |
79 | | #include <winsock2.h> |
80 | | #include <ws2tcpip.h> |
81 | | #ifndef _WIN32_IE |
82 | | #define _WIN32_IE 0x400 |
83 | | #endif |
84 | | #include <shlobj.h> |
85 | | #endif |
86 | | |
87 | | #include "event2/dns.h" |
88 | | #include "event2/dns_struct.h" |
89 | | #include "event2/dns_compat.h" |
90 | | #include "event2/util.h" |
91 | | #include "event2/event.h" |
92 | | #include "event2/event_struct.h" |
93 | | #include "event2/thread.h" |
94 | | |
95 | | #include "defer-internal.h" |
96 | | #include "log-internal.h" |
97 | | #include "mm-internal.h" |
98 | | #include "strlcpy-internal.h" |
99 | | #include "ipv6-internal.h" |
100 | | #include "util-internal.h" |
101 | | #include "evthread-internal.h" |
102 | | #ifdef _WIN32 |
103 | | #include <ctype.h> |
104 | | #include <winsock2.h> |
105 | | #include <windows.h> |
106 | | #include <iphlpapi.h> |
107 | | #include <io.h> |
108 | | #else |
109 | | #include <sys/socket.h> |
110 | | #include <netinet/in.h> |
111 | | #include <arpa/inet.h> |
112 | | #endif |
113 | | |
114 | | #ifdef EVENT__HAVE_NETINET_IN6_H |
115 | | #include <netinet/in6.h> |
116 | | #endif |
117 | | |
118 | 0 | #define EVDNS_LOG_DEBUG EVENT_LOG_DEBUG |
119 | 0 | #define EVDNS_LOG_WARN EVENT_LOG_WARN |
120 | 0 | #define EVDNS_LOG_MSG EVENT_LOG_MSG |
121 | | |
122 | | #ifndef HOST_NAME_MAX |
123 | | #define HOST_NAME_MAX 255 |
124 | | #endif |
125 | | |
126 | | #include <stdio.h> |
127 | | |
128 | | #undef MIN |
129 | 0 | #define MIN(a,b) ((a)<(b)?(a):(b)) |
130 | | |
131 | | #define ASSERT_VALID_REQUEST(req) \ |
132 | 0 | EVUTIL_ASSERT((req)->handle && (req)->handle->current_req == (req)) |
133 | | |
134 | | #define u64 ev_uint64_t |
135 | 0 | #define u32 ev_uint32_t |
136 | 0 | #define u16 ev_uint16_t |
137 | 0 | #define u8 ev_uint8_t |
138 | | |
139 | | /* maximum number of addresses from a single packet */ |
140 | | /* that we bother recording */ |
141 | 0 | #define MAX_V4_ADDRS 32 |
142 | 0 | #define MAX_V6_ADDRS 32 |
143 | | |
144 | | |
145 | 0 | #define TYPE_A EVDNS_TYPE_A |
146 | 0 | #define TYPE_CNAME 5 |
147 | 0 | #define TYPE_PTR EVDNS_TYPE_PTR |
148 | 0 | #define TYPE_SOA EVDNS_TYPE_SOA |
149 | 0 | #define TYPE_AAAA EVDNS_TYPE_AAAA |
150 | | |
151 | 0 | #define CLASS_INET EVDNS_CLASS_INET |
152 | | |
153 | | /* Persistent handle. We keep this separate from 'struct request' since we |
154 | | * need some object to last for as long as an evdns_request is outstanding so |
155 | | * that it can be canceled, whereas a search request can lead to multiple |
156 | | * 'struct request' instances being created over its lifetime. */ |
157 | | struct evdns_request { |
158 | | struct request *current_req; |
159 | | struct evdns_base *base; |
160 | | |
161 | | int pending_cb; /* Waiting for its callback to be invoked; not |
162 | | * owned by event base any more. */ |
163 | | |
164 | | /* elements used by the searching code */ |
165 | | int search_index; |
166 | | struct search_state *search_state; |
167 | | char *search_origname; /* needs to be free()ed */ |
168 | | int search_flags; |
169 | | }; |
170 | | |
171 | | struct request { |
172 | | u8 *request; /* the dns packet data */ |
173 | | u8 request_type; /* TYPE_PTR or TYPE_A or TYPE_AAAA */ |
174 | | unsigned int request_len; |
175 | | int reissue_count; |
176 | | int tx_count; /* the number of times that this packet has been sent */ |
177 | | void *user_pointer; /* the pointer given to us for this request */ |
178 | | evdns_callback_type user_callback; |
179 | | struct nameserver *ns; /* the server which we last sent it */ |
180 | | |
181 | | /* these objects are kept in a circular list */ |
182 | | /* XXX We could turn this into a CIRCLEQ. */ |
183 | | struct request *next, *prev; |
184 | | |
185 | | struct event timeout_event; |
186 | | |
187 | | u16 trans_id; /* the transaction id */ |
188 | | unsigned request_appended :1; /* true if the request pointer is data which follows this struct */ |
189 | | unsigned transmit_me :1; /* needs to be transmitted */ |
190 | | |
191 | | /* XXXX This is a horrible hack. */ |
192 | | char **put_cname_in_ptr; /* store the cname here if we get one. */ |
193 | | |
194 | | struct evdns_base *base; |
195 | | |
196 | | struct evdns_request *handle; |
197 | | }; |
198 | | |
199 | | struct reply { |
200 | | unsigned int type; |
201 | | unsigned int have_answer : 1; |
202 | | union { |
203 | | struct { |
204 | | u32 addrcount; |
205 | | u32 addresses[MAX_V4_ADDRS]; |
206 | | } a; |
207 | | struct { |
208 | | u32 addrcount; |
209 | | struct in6_addr addresses[MAX_V6_ADDRS]; |
210 | | } aaaa; |
211 | | struct { |
212 | | char name[HOST_NAME_MAX]; |
213 | | } ptr; |
214 | | } data; |
215 | | }; |
216 | | |
217 | | struct nameserver { |
218 | | evutil_socket_t socket; /* a connected UDP socket */ |
219 | | struct sockaddr_storage address; |
220 | | ev_socklen_t addrlen; |
221 | | int failed_times; /* number of times which we have given this server a chance */ |
222 | | int timedout; /* number of times in a row a request has timed out */ |
223 | | struct event event; |
224 | | /* these objects are kept in a circular list */ |
225 | | struct nameserver *next, *prev; |
226 | | struct event timeout_event; /* used to keep the timeout for */ |
227 | | /* when we next probe this server. */ |
228 | | /* Valid if state == 0 */ |
229 | | /* Outstanding probe request for this nameserver, if any */ |
230 | | struct evdns_request *probe_request; |
231 | | char state; /* zero if we think that this server is down */ |
232 | | char choked; /* true if we have an EAGAIN from this server's socket */ |
233 | | char write_waiting; /* true if we are waiting for EV_WRITE events */ |
234 | | struct evdns_base *base; |
235 | | |
236 | | /* Number of currently inflight requests: used |
237 | | * to track when we should add/del the event. */ |
238 | | int requests_inflight; |
239 | | }; |
240 | | |
241 | | |
242 | | /* Represents a local port where we're listening for DNS requests. Right now, */ |
243 | | /* only UDP is supported. */ |
244 | | struct evdns_server_port { |
245 | | evutil_socket_t socket; /* socket we use to read queries and write replies. */ |
246 | | int refcnt; /* reference count. */ |
247 | | char choked; /* Are we currently blocked from writing? */ |
248 | | char closing; /* Are we trying to close this port, pending writes? */ |
249 | | evdns_request_callback_fn_type user_callback; /* Fn to handle requests */ |
250 | | void *user_data; /* Opaque pointer passed to user_callback */ |
251 | | struct event event; /* Read/write event */ |
252 | | /* circular list of replies that we want to write. */ |
253 | | struct server_request *pending_replies; |
254 | | struct event_base *event_base; |
255 | | |
256 | | #ifndef EVENT__DISABLE_THREAD_SUPPORT |
257 | | void *lock; |
258 | | #endif |
259 | | }; |
260 | | |
261 | | /* Represents part of a reply being built. (That is, a single RR.) */ |
262 | | struct server_reply_item { |
263 | | struct server_reply_item *next; /* next item in sequence. */ |
264 | | char *name; /* name part of the RR */ |
265 | | u16 type; /* The RR type */ |
266 | | u16 class; /* The RR class (usually CLASS_INET) */ |
267 | | u32 ttl; /* The RR TTL */ |
268 | | char is_name; /* True iff data is a label */ |
269 | | u16 datalen; /* Length of data; -1 if data is a label */ |
270 | | void *data; /* The contents of the RR */ |
271 | | }; |
272 | | |
273 | | /* Represents a request that we've received as a DNS server, and holds */ |
274 | | /* the components of the reply as we're constructing it. */ |
275 | | struct server_request { |
276 | | /* Pointers to the next and previous entries on the list of replies */ |
277 | | /* that we're waiting to write. Only set if we have tried to respond */ |
278 | | /* and gotten EAGAIN. */ |
279 | | struct server_request *next_pending; |
280 | | struct server_request *prev_pending; |
281 | | |
282 | | u16 trans_id; /* Transaction id. */ |
283 | | struct evdns_server_port *port; /* Which port received this request on? */ |
284 | | struct sockaddr_storage addr; /* Where to send the response */ |
285 | | ev_socklen_t addrlen; /* length of addr */ |
286 | | |
287 | | int n_answer; /* how many answer RRs have been set? */ |
288 | | int n_authority; /* how many authority RRs have been set? */ |
289 | | int n_additional; /* how many additional RRs have been set? */ |
290 | | |
291 | | struct server_reply_item *answer; /* linked list of answer RRs */ |
292 | | struct server_reply_item *authority; /* linked list of authority RRs */ |
293 | | struct server_reply_item *additional; /* linked list of additional RRs */ |
294 | | |
295 | | /* Constructed response. Only set once we're ready to send a reply. */ |
296 | | /* Once this is set, the RR fields are cleared, and no more should be set. */ |
297 | | char *response; |
298 | | size_t response_len; |
299 | | |
300 | | /* Caller-visible fields: flags, questions. */ |
301 | | struct evdns_server_request base; |
302 | | }; |
303 | | |
304 | | struct evdns_base { |
305 | | /* An array of n_req_heads circular lists for inflight requests. |
306 | | * Each inflight request req is in req_heads[req->trans_id % n_req_heads]. |
307 | | */ |
308 | | struct request **req_heads; |
309 | | /* A circular list of requests that we're waiting to send, but haven't |
310 | | * sent yet because there are too many requests inflight */ |
311 | | struct request *req_waiting_head; |
312 | | /* A circular list of nameservers. */ |
313 | | struct nameserver *server_head; |
314 | | int n_req_heads; |
315 | | |
316 | | struct event_base *event_base; |
317 | | |
318 | | /* The number of good nameservers that we have */ |
319 | | int global_good_nameservers; |
320 | | |
321 | | /* inflight requests are contained in the req_head list */ |
322 | | /* and are actually going out across the network */ |
323 | | int global_requests_inflight; |
324 | | /* requests which aren't inflight are in the waiting list */ |
325 | | /* and are counted here */ |
326 | | int global_requests_waiting; |
327 | | |
328 | | int global_max_requests_inflight; |
329 | | |
330 | | struct timeval global_timeout; /* 5 seconds by default */ |
331 | | int global_max_reissues; /* a reissue occurs when we get some errors from the server */ |
332 | | int global_max_retransmits; /* number of times we'll retransmit a request which timed out */ |
333 | | /* number of timeouts in a row before we consider this server to be down */ |
334 | | int global_max_nameserver_timeout; |
335 | | /* true iff we will use the 0x20 hack to prevent poisoning attacks. */ |
336 | | int global_randomize_case; |
337 | | |
338 | | /* The first time that a nameserver fails, how long do we wait before |
339 | | * probing to see if it has returned? */ |
340 | | struct timeval global_nameserver_probe_initial_timeout; |
341 | | |
342 | | /** Port to bind to for outgoing DNS packets. */ |
343 | | struct sockaddr_storage global_outgoing_address; |
344 | | /** ev_socklen_t for global_outgoing_address. 0 if it isn't set. */ |
345 | | ev_socklen_t global_outgoing_addrlen; |
346 | | |
347 | | struct timeval global_getaddrinfo_allow_skew; |
348 | | |
349 | | int getaddrinfo_ipv4_timeouts; |
350 | | int getaddrinfo_ipv6_timeouts; |
351 | | int getaddrinfo_ipv4_answered; |
352 | | int getaddrinfo_ipv6_answered; |
353 | | |
354 | | struct search_state *global_search_state; |
355 | | |
356 | | TAILQ_HEAD(hosts_list, hosts_entry) hostsdb; |
357 | | |
358 | | #ifndef EVENT__DISABLE_THREAD_SUPPORT |
359 | | void *lock; |
360 | | #endif |
361 | | |
362 | | int disable_when_inactive; |
363 | | }; |
364 | | |
365 | | struct hosts_entry { |
366 | | TAILQ_ENTRY(hosts_entry) next; |
367 | | union { |
368 | | struct sockaddr sa; |
369 | | struct sockaddr_in sin; |
370 | | struct sockaddr_in6 sin6; |
371 | | } addr; |
372 | | int addrlen; |
373 | | char hostname[1]; |
374 | | }; |
375 | | |
376 | | static struct evdns_base *current_base = NULL; |
377 | | |
378 | | struct evdns_base * |
379 | | evdns_get_global_base(void) |
380 | 0 | { |
381 | 0 | return current_base; |
382 | 0 | } |
383 | | |
384 | | /* Given a pointer to an evdns_server_request, get the corresponding */ |
385 | | /* server_request. */ |
386 | | #define TO_SERVER_REQUEST(base_ptr) \ |
387 | 0 | ((struct server_request*) \ |
388 | 0 | (((char*)(base_ptr) - evutil_offsetof(struct server_request, base)))) |
389 | | |
390 | 0 | #define REQ_HEAD(base, id) ((base)->req_heads[id % (base)->n_req_heads]) |
391 | | |
392 | | static struct nameserver *nameserver_pick(struct evdns_base *base); |
393 | | static void evdns_request_insert(struct request *req, struct request **head); |
394 | | static void evdns_request_remove(struct request *req, struct request **head); |
395 | | static void nameserver_ready_callback(evutil_socket_t fd, short events, void *arg); |
396 | | static int evdns_transmit(struct evdns_base *base); |
397 | | static int evdns_request_transmit(struct request *req); |
398 | | static void nameserver_send_probe(struct nameserver *const ns); |
399 | | static void search_request_finished(struct evdns_request *const); |
400 | | static int search_try_next(struct evdns_request *const req); |
401 | | static struct request *search_request_new(struct evdns_base *base, struct evdns_request *handle, int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg); |
402 | | static void evdns_requests_pump_waiting_queue(struct evdns_base *base); |
403 | | static u16 transaction_id_pick(struct evdns_base *base); |
404 | | static struct request *request_new(struct evdns_base *base, struct evdns_request *handle, int type, const char *name, int flags, evdns_callback_type callback, void *ptr); |
405 | | static void request_submit(struct request *const req); |
406 | | |
407 | | static int server_request_free(struct server_request *req); |
408 | | static void server_request_free_answers(struct server_request *req); |
409 | | static void server_port_free(struct evdns_server_port *port); |
410 | | static void server_port_ready_callback(evutil_socket_t fd, short events, void *arg); |
411 | | static int evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename); |
412 | | static int evdns_base_set_option_impl(struct evdns_base *base, |
413 | | const char *option, const char *val, int flags); |
414 | | static void evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests); |
415 | | static void evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg); |
416 | | |
417 | | static int strtoint(const char *const str); |
418 | | |
419 | | #ifdef EVENT__DISABLE_THREAD_SUPPORT |
420 | | #define EVDNS_LOCK(base) EVUTIL_NIL_STMT_ |
421 | | #define EVDNS_UNLOCK(base) EVUTIL_NIL_STMT_ |
422 | | #define ASSERT_LOCKED(base) EVUTIL_NIL_STMT_ |
423 | | #else |
424 | | #define EVDNS_LOCK(base) \ |
425 | 0 | EVLOCK_LOCK((base)->lock, 0) |
426 | | #define EVDNS_UNLOCK(base) \ |
427 | 0 | EVLOCK_UNLOCK((base)->lock, 0) |
428 | | #define ASSERT_LOCKED(base) \ |
429 | 0 | EVLOCK_ASSERT_LOCKED((base)->lock) |
430 | | #endif |
431 | | |
432 | | static evdns_debug_log_fn_type evdns_log_fn = NULL; |
433 | | |
434 | | void |
435 | | evdns_set_log_fn(evdns_debug_log_fn_type fn) |
436 | 0 | { |
437 | 0 | evdns_log_fn = fn; |
438 | 0 | } |
439 | | |
440 | | #ifdef __GNUC__ |
441 | | #define EVDNS_LOG_CHECK __attribute__ ((format(printf, 2, 3))) |
442 | | #else |
443 | | #define EVDNS_LOG_CHECK |
444 | | #endif |
445 | | |
446 | | static void evdns_log_(int severity, const char *fmt, ...) EVDNS_LOG_CHECK; |
447 | | static void |
448 | | evdns_log_(int severity, const char *fmt, ...) |
449 | 0 | { |
450 | 0 | va_list args; |
451 | 0 | va_start(args,fmt); |
452 | 0 | if (evdns_log_fn) { |
453 | 0 | char buf[512]; |
454 | 0 | int is_warn = (severity == EVDNS_LOG_WARN); |
455 | 0 | evutil_vsnprintf(buf, sizeof(buf), fmt, args); |
456 | 0 | evdns_log_fn(is_warn, buf); |
457 | 0 | } else { |
458 | 0 | event_logv_(severity, NULL, fmt, args); |
459 | 0 | } |
460 | 0 | va_end(args); |
461 | 0 | } |
462 | | |
463 | 0 | #define log evdns_log_ |
464 | | |
465 | | /* This walks the list of inflight requests to find the */ |
466 | | /* one with a matching transaction id. Returns NULL on */ |
467 | | /* failure */ |
468 | | static struct request * |
469 | 0 | request_find_from_trans_id(struct evdns_base *base, u16 trans_id) { |
470 | 0 | struct request *req = REQ_HEAD(base, trans_id); |
471 | 0 | struct request *const started_at = req; |
472 | 0 |
|
473 | 0 | ASSERT_LOCKED(base); |
474 | 0 |
|
475 | 0 | if (req) { |
476 | 0 | do { |
477 | 0 | if (req->trans_id == trans_id) return req; |
478 | 0 | req = req->next; |
479 | 0 | } while (req != started_at); |
480 | 0 | } |
481 | 0 |
|
482 | 0 | return NULL; |
483 | 0 | } |
484 | | |
485 | | /* a libevent callback function which is called when a nameserver */ |
486 | | /* has gone down and we want to test if it has came back to life yet */ |
487 | | static void |
488 | 0 | nameserver_prod_callback(evutil_socket_t fd, short events, void *arg) { |
489 | 0 | struct nameserver *const ns = (struct nameserver *) arg; |
490 | 0 | (void)fd; |
491 | 0 | (void)events; |
492 | 0 |
|
493 | 0 | EVDNS_LOCK(ns->base); |
494 | 0 | nameserver_send_probe(ns); |
495 | 0 | EVDNS_UNLOCK(ns->base); |
496 | 0 | } |
497 | | |
498 | | /* a libevent callback which is called when a nameserver probe (to see if */ |
499 | | /* it has come back to life) times out. We increment the count of failed_times */ |
500 | | /* and wait longer to send the next probe packet. */ |
501 | | static void |
502 | 0 | nameserver_probe_failed(struct nameserver *const ns) { |
503 | 0 | struct timeval timeout; |
504 | 0 | int i; |
505 | 0 |
|
506 | 0 | ASSERT_LOCKED(ns->base); |
507 | 0 | (void) evtimer_del(&ns->timeout_event); |
508 | 0 | if (ns->state == 1) { |
509 | 0 | /* This can happen if the nameserver acts in a way which makes us mark */ |
510 | 0 | /* it as bad and then starts sending good replies. */ |
511 | 0 | return; |
512 | 0 | } |
513 | 0 | |
514 | 0 | #define MAX_PROBE_TIMEOUT 3600 |
515 | 0 | #define TIMEOUT_BACKOFF_FACTOR 3 |
516 | 0 | |
517 | 0 | memcpy(&timeout, &ns->base->global_nameserver_probe_initial_timeout, |
518 | 0 | sizeof(struct timeval)); |
519 | 0 | for (i=ns->failed_times; i > 0 && timeout.tv_sec < MAX_PROBE_TIMEOUT; --i) { |
520 | 0 | timeout.tv_sec *= TIMEOUT_BACKOFF_FACTOR; |
521 | 0 | timeout.tv_usec *= TIMEOUT_BACKOFF_FACTOR; |
522 | 0 | if (timeout.tv_usec > 1000000) { |
523 | 0 | timeout.tv_sec += timeout.tv_usec / 1000000; |
524 | 0 | timeout.tv_usec %= 1000000; |
525 | 0 | } |
526 | 0 | } |
527 | 0 | if (timeout.tv_sec > MAX_PROBE_TIMEOUT) { |
528 | 0 | timeout.tv_sec = MAX_PROBE_TIMEOUT; |
529 | 0 | timeout.tv_usec = 0; |
530 | 0 | } |
531 | 0 |
|
532 | 0 | ns->failed_times++; |
533 | 0 |
|
534 | 0 | if (evtimer_add(&ns->timeout_event, &timeout) < 0) { |
535 | 0 | char addrbuf[128]; |
536 | 0 | log(EVDNS_LOG_WARN, |
537 | 0 | "Error from libevent when adding timer event for %s", |
538 | 0 | evutil_format_sockaddr_port_( |
539 | 0 | (struct sockaddr *)&ns->address, |
540 | 0 | addrbuf, sizeof(addrbuf))); |
541 | 0 | } |
542 | 0 | } |
543 | | |
544 | | static void |
545 | 0 | request_swap_ns(struct request *req, struct nameserver *ns) { |
546 | 0 | if (ns && req->ns != ns) { |
547 | 0 | EVUTIL_ASSERT(req->ns->requests_inflight > 0); |
548 | 0 | req->ns->requests_inflight--; |
549 | 0 | ns->requests_inflight++; |
550 | 0 |
|
551 | 0 | req->ns = ns; |
552 | 0 | } |
553 | 0 | } |
554 | | |
555 | | /* called when a nameserver has been deemed to have failed. For example, too */ |
556 | | /* many packets have timed out etc */ |
557 | | static void |
558 | 0 | nameserver_failed(struct nameserver *const ns, const char *msg) { |
559 | 0 | struct request *req, *started_at; |
560 | 0 | struct evdns_base *base = ns->base; |
561 | 0 | int i; |
562 | 0 | char addrbuf[128]; |
563 | 0 |
|
564 | 0 | ASSERT_LOCKED(base); |
565 | 0 | /* if this nameserver has already been marked as failed */ |
566 | 0 | /* then don't do anything */ |
567 | 0 | if (!ns->state) return; |
568 | 0 | |
569 | 0 | log(EVDNS_LOG_MSG, "Nameserver %s has failed: %s", |
570 | 0 | evutil_format_sockaddr_port_( |
571 | 0 | (struct sockaddr *)&ns->address, |
572 | 0 | addrbuf, sizeof(addrbuf)), |
573 | 0 | msg); |
574 | 0 |
|
575 | 0 | base->global_good_nameservers--; |
576 | 0 | EVUTIL_ASSERT(base->global_good_nameservers >= 0); |
577 | 0 | if (base->global_good_nameservers == 0) { |
578 | 0 | log(EVDNS_LOG_MSG, "All nameservers have failed"); |
579 | 0 | } |
580 | 0 |
|
581 | 0 | ns->state = 0; |
582 | 0 | ns->failed_times = 1; |
583 | 0 |
|
584 | 0 | if (evtimer_add(&ns->timeout_event, |
585 | 0 | &base->global_nameserver_probe_initial_timeout) < 0) { |
586 | 0 | log(EVDNS_LOG_WARN, |
587 | 0 | "Error from libevent when adding timer event for %s", |
588 | 0 | evutil_format_sockaddr_port_( |
589 | 0 | (struct sockaddr *)&ns->address, |
590 | 0 | addrbuf, sizeof(addrbuf))); |
591 | 0 | /* ???? Do more? */ |
592 | 0 | } |
593 | 0 |
|
594 | 0 | /* walk the list of inflight requests to see if any can be reassigned to */ |
595 | 0 | /* a different server. Requests in the waiting queue don't have a */ |
596 | 0 | /* nameserver assigned yet */ |
597 | 0 |
|
598 | 0 | /* if we don't have *any* good nameservers then there's no point */ |
599 | 0 | /* trying to reassign requests to one */ |
600 | 0 | if (!base->global_good_nameservers) return; |
601 | 0 | |
602 | 0 | for (i = 0; i < base->n_req_heads; ++i) { |
603 | 0 | req = started_at = base->req_heads[i]; |
604 | 0 | if (req) { |
605 | 0 | do { |
606 | 0 | if (req->tx_count == 0 && req->ns == ns) { |
607 | 0 | /* still waiting to go out, can be moved */ |
608 | 0 | /* to another server */ |
609 | 0 | request_swap_ns(req, nameserver_pick(base)); |
610 | 0 | } |
611 | 0 | req = req->next; |
612 | 0 | } while (req != started_at); |
613 | 0 | } |
614 | 0 | } |
615 | 0 | } |
616 | | |
617 | | static void |
618 | | nameserver_up(struct nameserver *const ns) |
619 | 0 | { |
620 | 0 | char addrbuf[128]; |
621 | 0 | ASSERT_LOCKED(ns->base); |
622 | 0 | if (ns->state) return; |
623 | 0 | log(EVDNS_LOG_MSG, "Nameserver %s is back up", |
624 | 0 | evutil_format_sockaddr_port_( |
625 | 0 | (struct sockaddr *)&ns->address, |
626 | 0 | addrbuf, sizeof(addrbuf))); |
627 | 0 | evtimer_del(&ns->timeout_event); |
628 | 0 | if (ns->probe_request) { |
629 | 0 | evdns_cancel_request(ns->base, ns->probe_request); |
630 | 0 | ns->probe_request = NULL; |
631 | 0 | } |
632 | 0 | ns->state = 1; |
633 | 0 | ns->failed_times = 0; |
634 | 0 | ns->timedout = 0; |
635 | 0 | ns->base->global_good_nameservers++; |
636 | 0 | } |
637 | | |
638 | | static void |
639 | 0 | request_trans_id_set(struct request *const req, const u16 trans_id) { |
640 | 0 | req->trans_id = trans_id; |
641 | 0 | *((u16 *) req->request) = htons(trans_id); |
642 | 0 | } |
643 | | |
644 | | /* Called to remove a request from a list and dealloc it. */ |
645 | | /* head is a pointer to the head of the list it should be */ |
646 | | /* removed from or NULL if the request isn't in a list. */ |
647 | | /* when free_handle is one, free the handle as well. */ |
648 | | static void |
649 | 0 | request_finished(struct request *const req, struct request **head, int free_handle) { |
650 | 0 | struct evdns_base *base = req->base; |
651 | 0 | int was_inflight = (head != &base->req_waiting_head); |
652 | 0 | EVDNS_LOCK(base); |
653 | 0 | ASSERT_VALID_REQUEST(req); |
654 | 0 |
|
655 | 0 | if (head) |
656 | 0 | evdns_request_remove(req, head); |
657 | 0 |
|
658 | 0 | log(EVDNS_LOG_DEBUG, "Removing timeout for request %p", req); |
659 | 0 | if (was_inflight) { |
660 | 0 | evtimer_del(&req->timeout_event); |
661 | 0 | base->global_requests_inflight--; |
662 | 0 | req->ns->requests_inflight--; |
663 | 0 | } else { |
664 | 0 | base->global_requests_waiting--; |
665 | 0 | } |
666 | 0 | /* it was initialized during request_new / evtimer_assign */ |
667 | 0 | event_debug_unassign(&req->timeout_event); |
668 | 0 |
|
669 | 0 | if (req->ns && |
670 | 0 | req->ns->requests_inflight == 0 && |
671 | 0 | req->base->disable_when_inactive) { |
672 | 0 | event_del(&req->ns->event); |
673 | 0 | evtimer_del(&req->ns->timeout_event); |
674 | 0 | } |
675 | 0 |
|
676 | 0 | if (!req->request_appended) { |
677 | 0 | /* need to free the request data on it's own */ |
678 | 0 | mm_free(req->request); |
679 | 0 | } else { |
680 | 0 | /* the request data is appended onto the header */ |
681 | 0 | /* so everything gets free()ed when we: */ |
682 | 0 | } |
683 | 0 |
|
684 | 0 | if (req->handle) { |
685 | 0 | EVUTIL_ASSERT(req->handle->current_req == req); |
686 | 0 |
|
687 | 0 | if (free_handle) { |
688 | 0 | search_request_finished(req->handle); |
689 | 0 | req->handle->current_req = NULL; |
690 | 0 | if (! req->handle->pending_cb) { |
691 | 0 | /* If we're planning to run the callback, |
692 | 0 | * don't free the handle until later. */ |
693 | 0 | mm_free(req->handle); |
694 | 0 | } |
695 | 0 | req->handle = NULL; /* If we have a bug, let's crash |
696 | 0 | * early */ |
697 | 0 | } else { |
698 | 0 | req->handle->current_req = NULL; |
699 | 0 | } |
700 | 0 | } |
701 | 0 |
|
702 | 0 | mm_free(req); |
703 | 0 |
|
704 | 0 | evdns_requests_pump_waiting_queue(base); |
705 | 0 | EVDNS_UNLOCK(base); |
706 | 0 | } |
707 | | |
708 | | /* This is called when a server returns a funny error code. */ |
709 | | /* We try the request again with another server. */ |
710 | | /* */ |
711 | | /* return: */ |
712 | | /* 0 ok */ |
713 | | /* 1 failed/reissue is pointless */ |
714 | | static int |
715 | 0 | request_reissue(struct request *req) { |
716 | 0 | const struct nameserver *const last_ns = req->ns; |
717 | 0 | ASSERT_LOCKED(req->base); |
718 | 0 | ASSERT_VALID_REQUEST(req); |
719 | 0 | /* the last nameserver should have been marked as failing */ |
720 | 0 | /* by the caller of this function, therefore pick will try */ |
721 | 0 | /* not to return it */ |
722 | 0 | request_swap_ns(req, nameserver_pick(req->base)); |
723 | 0 | if (req->ns == last_ns) { |
724 | 0 | /* ... but pick did return it */ |
725 | 0 | /* not a lot of point in trying again with the */ |
726 | 0 | /* same server */ |
727 | 0 | return 1; |
728 | 0 | } |
729 | 0 | |
730 | 0 | req->reissue_count++; |
731 | 0 | req->tx_count = 0; |
732 | 0 | req->transmit_me = 1; |
733 | 0 |
|
734 | 0 | return 0; |
735 | 0 | } |
736 | | |
737 | | /* this function looks for space on the inflight queue and promotes */ |
738 | | /* requests from the waiting queue if it can. */ |
739 | | /* */ |
740 | | /* TODO: */ |
741 | | /* add return code, see at nameserver_pick() and other functions. */ |
742 | | static void |
743 | 0 | evdns_requests_pump_waiting_queue(struct evdns_base *base) { |
744 | 0 | ASSERT_LOCKED(base); |
745 | 0 | while (base->global_requests_inflight < base->global_max_requests_inflight && |
746 | 0 | base->global_requests_waiting) { |
747 | 0 | struct request *req; |
748 | 0 |
|
749 | 0 | EVUTIL_ASSERT(base->req_waiting_head); |
750 | 0 | req = base->req_waiting_head; |
751 | 0 |
|
752 | 0 | req->ns = nameserver_pick(base); |
753 | 0 | if (!req->ns) |
754 | 0 | return; |
755 | 0 | |
756 | 0 | /* move a request from the waiting queue to the inflight queue */ |
757 | 0 | req->ns->requests_inflight++; |
758 | 0 |
|
759 | 0 | evdns_request_remove(req, &base->req_waiting_head); |
760 | 0 |
|
761 | 0 | base->global_requests_waiting--; |
762 | 0 | base->global_requests_inflight++; |
763 | 0 |
|
764 | 0 | request_trans_id_set(req, transaction_id_pick(base)); |
765 | 0 |
|
766 | 0 | evdns_request_insert(req, &REQ_HEAD(base, req->trans_id)); |
767 | 0 | evdns_request_transmit(req); |
768 | 0 | evdns_transmit(base); |
769 | 0 | } |
770 | 0 | } |
771 | | |
772 | | /* TODO(nickm) document */ |
773 | | struct deferred_reply_callback { |
774 | | struct event_callback deferred; |
775 | | struct evdns_request *handle; |
776 | | u8 request_type; |
777 | | u8 have_reply; |
778 | | u32 ttl; |
779 | | u32 err; |
780 | | evdns_callback_type user_callback; |
781 | | struct reply reply; |
782 | | }; |
783 | | |
784 | | static void |
785 | | reply_run_callback(struct event_callback *d, void *user_pointer) |
786 | 0 | { |
787 | 0 | struct deferred_reply_callback *cb = |
788 | 0 | EVUTIL_UPCAST(d, struct deferred_reply_callback, deferred); |
789 | 0 |
|
790 | 0 | switch (cb->request_type) { |
791 | 0 | case TYPE_A: |
792 | 0 | if (cb->have_reply) |
793 | 0 | cb->user_callback(DNS_ERR_NONE, DNS_IPv4_A, |
794 | 0 | cb->reply.data.a.addrcount, cb->ttl, |
795 | 0 | cb->reply.data.a.addresses, |
796 | 0 | user_pointer); |
797 | 0 | else |
798 | 0 | cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer); |
799 | 0 | break; |
800 | 0 | case TYPE_PTR: |
801 | 0 | if (cb->have_reply) { |
802 | 0 | char *name = cb->reply.data.ptr.name; |
803 | 0 | cb->user_callback(DNS_ERR_NONE, DNS_PTR, 1, cb->ttl, |
804 | 0 | &name, user_pointer); |
805 | 0 | } else { |
806 | 0 | cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer); |
807 | 0 | } |
808 | 0 | break; |
809 | 0 | case TYPE_AAAA: |
810 | 0 | if (cb->have_reply) |
811 | 0 | cb->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA, |
812 | 0 | cb->reply.data.aaaa.addrcount, cb->ttl, |
813 | 0 | cb->reply.data.aaaa.addresses, |
814 | 0 | user_pointer); |
815 | 0 | else |
816 | 0 | cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer); |
817 | 0 | break; |
818 | 0 | default: |
819 | 0 | EVUTIL_ASSERT(0); |
820 | 0 | } |
821 | 0 |
|
822 | 0 | if (cb->handle && cb->handle->pending_cb) { |
823 | 0 | mm_free(cb->handle); |
824 | 0 | } |
825 | 0 |
|
826 | 0 | mm_free(cb); |
827 | 0 | } |
828 | | |
829 | | static void |
830 | | reply_schedule_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply) |
831 | 0 | { |
832 | 0 | struct deferred_reply_callback *d = mm_calloc(1, sizeof(*d)); |
833 | 0 |
|
834 | 0 | if (!d) { |
835 | 0 | event_warn("%s: Couldn't allocate space for deferred callback.", |
836 | 0 | __func__); |
837 | 0 | return; |
838 | 0 | } |
839 | 0 |
|
840 | 0 | ASSERT_LOCKED(req->base); |
841 | 0 |
|
842 | 0 | d->request_type = req->request_type; |
843 | 0 | d->user_callback = req->user_callback; |
844 | 0 | d->ttl = ttl; |
845 | 0 | d->err = err; |
846 | 0 | if (reply) { |
847 | 0 | d->have_reply = 1; |
848 | 0 | memcpy(&d->reply, reply, sizeof(struct reply)); |
849 | 0 | } |
850 | 0 |
|
851 | 0 | if (req->handle) { |
852 | 0 | req->handle->pending_cb = 1; |
853 | 0 | d->handle = req->handle; |
854 | 0 | } |
855 | 0 |
|
856 | 0 | event_deferred_cb_init_( |
857 | 0 | &d->deferred, |
858 | 0 | event_get_priority(&req->timeout_event), |
859 | 0 | reply_run_callback, |
860 | 0 | req->user_pointer); |
861 | 0 | event_deferred_cb_schedule_( |
862 | 0 | req->base->event_base, |
863 | 0 | &d->deferred); |
864 | 0 | } |
865 | | |
866 | | /* this processes a parsed reply packet */ |
867 | | static void |
868 | 0 | reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) { |
869 | 0 | int error; |
870 | 0 | char addrbuf[128]; |
871 | 0 | static const int error_codes[] = { |
872 | 0 | DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST, |
873 | 0 | DNS_ERR_NOTIMPL, DNS_ERR_REFUSED |
874 | 0 | }; |
875 | 0 |
|
876 | 0 | ASSERT_LOCKED(req->base); |
877 | 0 | ASSERT_VALID_REQUEST(req); |
878 | 0 |
|
879 | 0 | if (flags & 0x020f || !reply || !reply->have_answer) { |
880 | 0 | /* there was an error */ |
881 | 0 | if (flags & 0x0200) { |
882 | 0 | error = DNS_ERR_TRUNCATED; |
883 | 0 | } else if (flags & 0x000f) { |
884 | 0 | u16 error_code = (flags & 0x000f) - 1; |
885 | 0 | if (error_code > 4) { |
886 | 0 | error = DNS_ERR_UNKNOWN; |
887 | 0 | } else { |
888 | 0 | error = error_codes[error_code]; |
889 | 0 | } |
890 | 0 | } else if (reply && !reply->have_answer) { |
891 | 0 | error = DNS_ERR_NODATA; |
892 | 0 | } else { |
893 | 0 | error = DNS_ERR_UNKNOWN; |
894 | 0 | } |
895 | 0 |
|
896 | 0 | switch (error) { |
897 | 0 | case DNS_ERR_NOTIMPL: |
898 | 0 | case DNS_ERR_REFUSED: |
899 | 0 | /* we regard these errors as marking a bad nameserver */ |
900 | 0 | if (req->reissue_count < req->base->global_max_reissues) { |
901 | 0 | char msg[64]; |
902 | 0 | evutil_snprintf(msg, sizeof(msg), "Bad response %d (%s)", |
903 | 0 | error, evdns_err_to_string(error)); |
904 | 0 | nameserver_failed(req->ns, msg); |
905 | 0 | if (!request_reissue(req)) return; |
906 | 0 | } |
907 | 0 | break; |
908 | 0 | case DNS_ERR_SERVERFAILED: |
909 | 0 | /* rcode 2 (servfailed) sometimes means "we |
910 | 0 | * are broken" and sometimes (with some binds) |
911 | 0 | * means "that request was very confusing." |
912 | 0 | * Treat this as a timeout, not a failure. |
913 | 0 | */ |
914 | 0 | log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver" |
915 | 0 | "at %s; will allow the request to time out.", |
916 | 0 | evutil_format_sockaddr_port_( |
917 | 0 | (struct sockaddr *)&req->ns->address, |
918 | 0 | addrbuf, sizeof(addrbuf))); |
919 | 0 | /* Call the timeout function */ |
920 | 0 | evdns_request_timeout_callback(0, 0, req); |
921 | 0 | return; |
922 | 0 | default: |
923 | 0 | /* we got a good reply from the nameserver: it is up. */ |
924 | 0 | if (req->handle == req->ns->probe_request) { |
925 | 0 | /* Avoid double-free */ |
926 | 0 | req->ns->probe_request = NULL; |
927 | 0 | } |
928 | 0 |
|
929 | 0 | nameserver_up(req->ns); |
930 | 0 | } |
931 | 0 |
|
932 | 0 | if (req->handle->search_state && |
933 | 0 | req->request_type != TYPE_PTR) { |
934 | 0 | /* if we have a list of domains to search in, |
935 | 0 | * try the next one */ |
936 | 0 | if (!search_try_next(req->handle)) { |
937 | 0 | /* a new request was issued so this |
938 | 0 | * request is finished and */ |
939 | 0 | /* the user callback will be made when |
940 | 0 | * that request (or a */ |
941 | 0 | /* child of it) finishes. */ |
942 | 0 | return; |
943 | 0 | } |
944 | 0 | } |
945 | 0 | |
946 | 0 | /* all else failed. Pass the failure up */ |
947 | 0 | reply_schedule_callback(req, ttl, error, NULL); |
948 | 0 | request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1); |
949 | 0 | } else { |
950 | 0 | /* all ok, tell the user */ |
951 | 0 | reply_schedule_callback(req, ttl, 0, reply); |
952 | 0 | if (req->handle == req->ns->probe_request) |
953 | 0 | req->ns->probe_request = NULL; /* Avoid double-free */ |
954 | 0 | nameserver_up(req->ns); |
955 | 0 | request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1); |
956 | 0 | } |
957 | 0 | } |
958 | | |
959 | | static int |
960 | 0 | name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) { |
961 | 0 | int name_end = -1; |
962 | 0 | int j = *idx; |
963 | 0 | int ptr_count = 0; |
964 | 0 | #define GET32(x) do { if (j + 4 > length) goto err; memcpy(&t32_, packet + j, 4); j += 4; x = ntohl(t32_); } while (0) |
965 | 0 | #define GET16(x) do { if (j + 2 > length) goto err; memcpy(&t_, packet + j, 2); j += 2; x = ntohs(t_); } while (0) |
966 | 0 | #define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while (0) |
967 | 0 |
|
968 | 0 | char *cp = name_out; |
969 | 0 | const char *const end = name_out + name_out_len; |
970 | 0 |
|
971 | 0 | /* Normally, names are a series of length prefixed strings terminated */ |
972 | 0 | /* with a length of 0 (the lengths are u8's < 63). */ |
973 | 0 | /* However, the length can start with a pair of 1 bits and that */ |
974 | 0 | /* means that the next 14 bits are a pointer within the current */ |
975 | 0 | /* packet. */ |
976 | 0 |
|
977 | 0 | for (;;) { |
978 | 0 | u8 label_len; |
979 | 0 | GET8(label_len); |
980 | 0 | if (!label_len) break; |
981 | 0 | if (label_len & 0xc0) { |
982 | 0 | u8 ptr_low; |
983 | 0 | GET8(ptr_low); |
984 | 0 | if (name_end < 0) name_end = j; |
985 | 0 | j = (((int)label_len & 0x3f) << 8) + ptr_low; |
986 | 0 | /* Make sure that the target offset is in-bounds. */ |
987 | 0 | if (j < 0 || j >= length) return -1; |
988 | 0 | /* If we've jumped more times than there are characters in the |
989 | 0 | * message, we must have a loop. */ |
990 | 0 | if (++ptr_count > length) return -1; |
991 | 0 | continue; |
992 | 0 | } |
993 | 0 | if (label_len > 63) return -1; |
994 | 0 | if (cp != name_out) { |
995 | 0 | if (cp + 1 >= end) return -1; |
996 | 0 | *cp++ = '.'; |
997 | 0 | } |
998 | 0 | if (cp + label_len >= end) return -1; |
999 | 0 | if (j + label_len > length) return -1; |
1000 | 0 | memcpy(cp, packet + j, label_len); |
1001 | 0 | cp += label_len; |
1002 | 0 | j += label_len; |
1003 | 0 | } |
1004 | 0 | if (cp >= end) return -1; |
1005 | 0 | *cp = '\0'; |
1006 | 0 | if (name_end < 0) |
1007 | 0 | *idx = j; |
1008 | 0 | else |
1009 | 0 | *idx = name_end; |
1010 | 0 | return 0; |
1011 | 0 | err: |
1012 | 0 | return -1; |
1013 | 0 | } |
1014 | | |
1015 | | /* parses a raw request from a nameserver */ |
1016 | | static int |
1017 | 0 | reply_parse(struct evdns_base *base, u8 *packet, int length) { |
1018 | 0 | int j = 0, k = 0; /* index into packet */ |
1019 | 0 | u16 t_; /* used by the macros */ |
1020 | 0 | u32 t32_; /* used by the macros */ |
1021 | 0 | char tmp_name[256], cmp_name[256]; /* used by the macros */ |
1022 | 0 | int name_matches = 0; |
1023 | 0 |
|
1024 | 0 | u16 trans_id, questions, answers, authority, additional, datalength; |
1025 | 0 | u16 flags = 0; |
1026 | 0 | u32 ttl, ttl_r = 0xffffffff; |
1027 | 0 | struct reply reply; |
1028 | 0 | struct request *req = NULL; |
1029 | 0 | unsigned int i; |
1030 | 0 |
|
1031 | 0 | ASSERT_LOCKED(base); |
1032 | 0 |
|
1033 | 0 | GET16(trans_id); |
1034 | 0 | GET16(flags); |
1035 | 0 | GET16(questions); |
1036 | 0 | GET16(answers); |
1037 | 0 | GET16(authority); |
1038 | 0 | GET16(additional); |
1039 | 0 | (void) authority; /* suppress "unused variable" warnings. */ |
1040 | 0 | (void) additional; /* suppress "unused variable" warnings. */ |
1041 | 0 |
|
1042 | 0 | req = request_find_from_trans_id(base, trans_id); |
1043 | 0 | if (!req) return -1; |
1044 | 0 | EVUTIL_ASSERT(req->base == base); |
1045 | 0 |
|
1046 | 0 | memset(&reply, 0, sizeof(reply)); |
1047 | 0 |
|
1048 | 0 | /* If it's not an answer, it doesn't correspond to any request. */ |
1049 | 0 | if (!(flags & 0x8000)) return -1; /* must be an answer */ |
1050 | 0 | if ((flags & 0x020f) && (flags & 0x020f) != DNS_ERR_NOTEXIST) { |
1051 | 0 | /* there was an error and it's not NXDOMAIN */ |
1052 | 0 | goto err; |
1053 | 0 | } |
1054 | 0 | /* if (!answers) return; */ /* must have an answer of some form */ |
1055 | 0 | |
1056 | 0 | /* This macro skips a name in the DNS reply. */ |
1057 | 0 | #define SKIP_NAME \ |
1058 | 0 | do { tmp_name[0] = '\0'; \ |
1059 | 0 | if (name_parse(packet, length, &j, tmp_name, \ |
1060 | 0 | sizeof(tmp_name))<0) \ |
1061 | 0 | goto err; \ |
1062 | 0 | } while (0) |
1063 | 0 |
|
1064 | 0 | reply.type = req->request_type; |
1065 | 0 |
|
1066 | 0 | /* skip over each question in the reply */ |
1067 | 0 | for (i = 0; i < questions; ++i) { |
1068 | 0 | /* the question looks like |
1069 | 0 | * <label:name><u16:type><u16:class> |
1070 | 0 | */ |
1071 | 0 | tmp_name[0] = '\0'; |
1072 | 0 | cmp_name[0] = '\0'; |
1073 | 0 | k = j; |
1074 | 0 | if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name)) < 0) |
1075 | 0 | goto err; |
1076 | 0 | if (name_parse(req->request, req->request_len, &k, |
1077 | 0 | cmp_name, sizeof(cmp_name))<0) |
1078 | 0 | goto err; |
1079 | 0 | if (!base->global_randomize_case) { |
1080 | 0 | if (strcmp(tmp_name, cmp_name) == 0) |
1081 | 0 | name_matches = 1; |
1082 | 0 | } else { |
1083 | 0 | if (evutil_ascii_strcasecmp(tmp_name, cmp_name) == 0) |
1084 | 0 | name_matches = 1; |
1085 | 0 | } |
1086 | 0 |
|
1087 | 0 | j += 4; |
1088 | 0 | if (j > length) |
1089 | 0 | goto err; |
1090 | 0 | } |
1091 | 0 |
|
1092 | 0 | if (!name_matches) |
1093 | 0 | goto err; |
1094 | 0 | |
1095 | 0 | /* now we have the answer section which looks like |
1096 | 0 | * <label:name><u16:type><u16:class><u32:ttl><u16:len><data...> |
1097 | 0 | */ |
1098 | 0 | |
1099 | 0 | for (i = 0; i < answers; ++i) { |
1100 | 0 | u16 type, class; |
1101 | 0 |
|
1102 | 0 | SKIP_NAME; |
1103 | 0 | GET16(type); |
1104 | 0 | GET16(class); |
1105 | 0 | GET32(ttl); |
1106 | 0 | GET16(datalength); |
1107 | 0 |
|
1108 | 0 | if (type == TYPE_A && class == CLASS_INET) { |
1109 | 0 | int addrcount, addrtocopy; |
1110 | 0 | if (req->request_type != TYPE_A) { |
1111 | 0 | j += datalength; continue; |
1112 | 0 | } |
1113 | 0 | if ((datalength & 3) != 0) /* not an even number of As. */ |
1114 | 0 | goto err; |
1115 | 0 | addrcount = datalength >> 2; |
1116 | 0 | addrtocopy = MIN(MAX_V4_ADDRS - reply.data.a.addrcount, (unsigned)addrcount); |
1117 | 0 |
|
1118 | 0 | ttl_r = MIN(ttl_r, ttl); |
1119 | 0 | /* we only bother with the first four addresses. */ |
1120 | 0 | if (j + 4*addrtocopy > length) goto err; |
1121 | 0 | memcpy(&reply.data.a.addresses[reply.data.a.addrcount], |
1122 | 0 | packet + j, 4*addrtocopy); |
1123 | 0 | j += 4*addrtocopy; |
1124 | 0 | reply.data.a.addrcount += addrtocopy; |
1125 | 0 | reply.have_answer = 1; |
1126 | 0 | if (reply.data.a.addrcount == MAX_V4_ADDRS) break; |
1127 | 0 | } else if (type == TYPE_PTR && class == CLASS_INET) { |
1128 | 0 | if (req->request_type != TYPE_PTR) { |
1129 | 0 | j += datalength; continue; |
1130 | 0 | } |
1131 | 0 | if (name_parse(packet, length, &j, reply.data.ptr.name, |
1132 | 0 | sizeof(reply.data.ptr.name))<0) |
1133 | 0 | goto err; |
1134 | 0 | ttl_r = MIN(ttl_r, ttl); |
1135 | 0 | reply.have_answer = 1; |
1136 | 0 | break; |
1137 | 0 | } else if (type == TYPE_CNAME) { |
1138 | 0 | char cname[HOST_NAME_MAX]; |
1139 | 0 | if (!req->put_cname_in_ptr || *req->put_cname_in_ptr) { |
1140 | 0 | j += datalength; continue; |
1141 | 0 | } |
1142 | 0 | if (name_parse(packet, length, &j, cname, |
1143 | 0 | sizeof(cname))<0) |
1144 | 0 | goto err; |
1145 | 0 | *req->put_cname_in_ptr = mm_strdup(cname); |
1146 | 0 | } else if (type == TYPE_AAAA && class == CLASS_INET) { |
1147 | 0 | int addrcount, addrtocopy; |
1148 | 0 | if (req->request_type != TYPE_AAAA) { |
1149 | 0 | j += datalength; continue; |
1150 | 0 | } |
1151 | 0 | if ((datalength & 15) != 0) /* not an even number of AAAAs. */ |
1152 | 0 | goto err; |
1153 | 0 | addrcount = datalength >> 4; /* each address is 16 bytes long */ |
1154 | 0 | addrtocopy = MIN(MAX_V6_ADDRS - reply.data.aaaa.addrcount, (unsigned)addrcount); |
1155 | 0 | ttl_r = MIN(ttl_r, ttl); |
1156 | 0 |
|
1157 | 0 | /* we only bother with the first four addresses. */ |
1158 | 0 | if (j + 16*addrtocopy > length) goto err; |
1159 | 0 | memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount], |
1160 | 0 | packet + j, 16*addrtocopy); |
1161 | 0 | reply.data.aaaa.addrcount += addrtocopy; |
1162 | 0 | j += 16*addrtocopy; |
1163 | 0 | reply.have_answer = 1; |
1164 | 0 | if (reply.data.aaaa.addrcount == MAX_V6_ADDRS) break; |
1165 | 0 | } else { |
1166 | 0 | /* skip over any other type of resource */ |
1167 | 0 | j += datalength; |
1168 | 0 | } |
1169 | 0 | } |
1170 | 0 |
|
1171 | 0 | if (!reply.have_answer) { |
1172 | 0 | for (i = 0; i < authority; ++i) { |
1173 | 0 | u16 type, class; |
1174 | 0 | SKIP_NAME; |
1175 | 0 | GET16(type); |
1176 | 0 | GET16(class); |
1177 | 0 | GET32(ttl); |
1178 | 0 | GET16(datalength); |
1179 | 0 | if (type == TYPE_SOA && class == CLASS_INET) { |
1180 | 0 | u32 serial, refresh, retry, expire, minimum; |
1181 | 0 | SKIP_NAME; |
1182 | 0 | SKIP_NAME; |
1183 | 0 | GET32(serial); |
1184 | 0 | GET32(refresh); |
1185 | 0 | GET32(retry); |
1186 | 0 | GET32(expire); |
1187 | 0 | GET32(minimum); |
1188 | 0 | (void)expire; |
1189 | 0 | (void)retry; |
1190 | 0 | (void)refresh; |
1191 | 0 | (void)serial; |
1192 | 0 | ttl_r = MIN(ttl_r, ttl); |
1193 | 0 | ttl_r = MIN(ttl_r, minimum); |
1194 | 0 | } else { |
1195 | 0 | /* skip over any other type of resource */ |
1196 | 0 | j += datalength; |
1197 | 0 | } |
1198 | 0 | } |
1199 | 0 | } |
1200 | 0 |
|
1201 | 0 | if (ttl_r == 0xffffffff) |
1202 | 0 | ttl_r = 0; |
1203 | 0 |
|
1204 | 0 | reply_handle(req, flags, ttl_r, &reply); |
1205 | 0 | return 0; |
1206 | 0 | err: |
1207 | 0 | if (req) |
1208 | 0 | reply_handle(req, flags, 0, NULL); |
1209 | 0 | return -1; |
1210 | 0 | } |
1211 | | |
1212 | | /* Parse a raw request (packet,length) sent to a nameserver port (port) from */ |
1213 | | /* a DNS client (addr,addrlen), and if it's well-formed, call the corresponding */ |
1214 | | /* callback. */ |
1215 | | static int |
1216 | | request_parse(u8 *packet, int length, struct evdns_server_port *port, struct sockaddr *addr, ev_socklen_t addrlen) |
1217 | 0 | { |
1218 | 0 | int j = 0; /* index into packet */ |
1219 | 0 | u16 t_; /* used by the macros */ |
1220 | 0 | char tmp_name[256]; /* used by the macros */ |
1221 | 0 |
|
1222 | 0 | int i; |
1223 | 0 | u16 trans_id, flags, questions, answers, authority, additional; |
1224 | 0 | struct server_request *server_req = NULL; |
1225 | 0 |
|
1226 | 0 | ASSERT_LOCKED(port); |
1227 | 0 |
|
1228 | 0 | /* Get the header fields */ |
1229 | 0 | GET16(trans_id); |
1230 | 0 | GET16(flags); |
1231 | 0 | GET16(questions); |
1232 | 0 | GET16(answers); |
1233 | 0 | GET16(authority); |
1234 | 0 | GET16(additional); |
1235 | 0 | (void)answers; |
1236 | 0 | (void)additional; |
1237 | 0 | (void)authority; |
1238 | 0 |
|
1239 | 0 | if (flags & 0x8000) return -1; /* Must not be an answer. */ |
1240 | 0 | flags &= 0x0110; /* Only RD and CD get preserved. */ |
1241 | 0 |
|
1242 | 0 | server_req = mm_malloc(sizeof(struct server_request)); |
1243 | 0 | if (server_req == NULL) return -1; |
1244 | 0 | memset(server_req, 0, sizeof(struct server_request)); |
1245 | 0 |
|
1246 | 0 | server_req->trans_id = trans_id; |
1247 | 0 | memcpy(&server_req->addr, addr, addrlen); |
1248 | 0 | server_req->addrlen = addrlen; |
1249 | 0 |
|
1250 | 0 | server_req->base.flags = flags; |
1251 | 0 | server_req->base.nquestions = 0; |
1252 | 0 | server_req->base.questions = mm_calloc(sizeof(struct evdns_server_question *), questions); |
1253 | 0 | if (server_req->base.questions == NULL) |
1254 | 0 | goto err; |
1255 | 0 | |
1256 | 0 | for (i = 0; i < questions; ++i) { |
1257 | 0 | u16 type, class; |
1258 | 0 | struct evdns_server_question *q; |
1259 | 0 | int namelen; |
1260 | 0 | if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0) |
1261 | 0 | goto err; |
1262 | 0 | GET16(type); |
1263 | 0 | GET16(class); |
1264 | 0 | namelen = (int)strlen(tmp_name); |
1265 | 0 | q = mm_malloc(sizeof(struct evdns_server_question) + namelen); |
1266 | 0 | if (!q) |
1267 | 0 | goto err; |
1268 | 0 | q->type = type; |
1269 | 0 | q->dns_question_class = class; |
1270 | 0 | memcpy(q->name, tmp_name, namelen+1); |
1271 | 0 | server_req->base.questions[server_req->base.nquestions++] = q; |
1272 | 0 | } |
1273 | 0 |
|
1274 | 0 | /* Ignore answers, authority, and additional. */ |
1275 | 0 |
|
1276 | 0 | server_req->port = port; |
1277 | 0 | port->refcnt++; |
1278 | 0 |
|
1279 | 0 | /* Only standard queries are supported. */ |
1280 | 0 | if (flags & 0x7800) { |
1281 | 0 | evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL); |
1282 | 0 | return -1; |
1283 | 0 | } |
1284 | 0 |
|
1285 | 0 | port->user_callback(&(server_req->base), port->user_data); |
1286 | 0 |
|
1287 | 0 | return 0; |
1288 | 0 | err: |
1289 | 0 | if (server_req) { |
1290 | 0 | if (server_req->base.questions) { |
1291 | 0 | for (i = 0; i < server_req->base.nquestions; ++i) |
1292 | 0 | mm_free(server_req->base.questions[i]); |
1293 | 0 | mm_free(server_req->base.questions); |
1294 | 0 | } |
1295 | 0 | mm_free(server_req); |
1296 | 0 | } |
1297 | 0 | return -1; |
1298 | 0 |
|
1299 | 0 | #undef SKIP_NAME |
1300 | 0 | #undef GET32 |
1301 | 0 | #undef GET16 |
1302 | 0 | #undef GET8 |
1303 | 0 | } |
1304 | | |
1305 | | |
1306 | | void |
1307 | | evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void)) |
1308 | 0 | { |
1309 | 0 | } |
1310 | | |
1311 | | void |
1312 | | evdns_set_random_bytes_fn(void (*fn)(char *, size_t)) |
1313 | 0 | { |
1314 | 0 | } |
1315 | | |
1316 | | /* Try to choose a strong transaction id which isn't already in flight */ |
1317 | | static u16 |
1318 | 0 | transaction_id_pick(struct evdns_base *base) { |
1319 | 0 | ASSERT_LOCKED(base); |
1320 | 0 | for (;;) { |
1321 | 0 | u16 trans_id; |
1322 | 0 | evutil_secure_rng_get_bytes(&trans_id, sizeof(trans_id)); |
1323 | 0 |
|
1324 | 0 | if (trans_id == 0xffff) continue; |
1325 | 0 | /* now check to see if that id is already inflight */ |
1326 | 0 | if (request_find_from_trans_id(base, trans_id) == NULL) |
1327 | 0 | return trans_id; |
1328 | 0 | } |
1329 | 0 | } |
1330 | | |
1331 | | /* choose a namesever to use. This function will try to ignore */ |
1332 | | /* nameservers which we think are down and load balance across the rest */ |
1333 | | /* by updating the server_head global each time. */ |
1334 | | static struct nameserver * |
1335 | 0 | nameserver_pick(struct evdns_base *base) { |
1336 | 0 | struct nameserver *started_at = base->server_head, *picked; |
1337 | 0 | ASSERT_LOCKED(base); |
1338 | 0 | if (!base->server_head) return NULL; |
1339 | 0 | |
1340 | 0 | /* if we don't have any good nameservers then there's no */ |
1341 | 0 | /* point in trying to find one. */ |
1342 | 0 | if (!base->global_good_nameservers) { |
1343 | 0 | base->server_head = base->server_head->next; |
1344 | 0 | return base->server_head; |
1345 | 0 | } |
1346 | 0 | |
1347 | 0 | /* remember that nameservers are in a circular list */ |
1348 | 0 | for (;;) { |
1349 | 0 | if (base->server_head->state) { |
1350 | 0 | /* we think this server is currently good */ |
1351 | 0 | picked = base->server_head; |
1352 | 0 | base->server_head = base->server_head->next; |
1353 | 0 | return picked; |
1354 | 0 | } |
1355 | 0 | |
1356 | 0 | base->server_head = base->server_head->next; |
1357 | 0 | if (base->server_head == started_at) { |
1358 | 0 | /* all the nameservers seem to be down */ |
1359 | 0 | /* so we just return this one and hope for the */ |
1360 | 0 | /* best */ |
1361 | 0 | EVUTIL_ASSERT(base->global_good_nameservers == 0); |
1362 | 0 | picked = base->server_head; |
1363 | 0 | base->server_head = base->server_head->next; |
1364 | 0 | return picked; |
1365 | 0 | } |
1366 | 0 | } |
1367 | 0 | } |
1368 | | |
1369 | | /* this is called when a namesever socket is ready for reading */ |
1370 | | static void |
1371 | 0 | nameserver_read(struct nameserver *ns) { |
1372 | 0 | struct sockaddr_storage ss; |
1373 | 0 | ev_socklen_t addrlen = sizeof(ss); |
1374 | 0 | u8 packet[1500]; |
1375 | 0 | char addrbuf[128]; |
1376 | 0 | ASSERT_LOCKED(ns->base); |
1377 | 0 |
|
1378 | 0 | for (;;) { |
1379 | 0 | const int r = recvfrom(ns->socket, (void*)packet, |
1380 | 0 | sizeof(packet), 0, |
1381 | 0 | (struct sockaddr*)&ss, &addrlen); |
1382 | 0 | if (r < 0) { |
1383 | 0 | int err = evutil_socket_geterror(ns->socket); |
1384 | 0 | if (EVUTIL_ERR_RW_RETRIABLE(err)) |
1385 | 0 | return; |
1386 | 0 | nameserver_failed(ns, |
1387 | 0 | evutil_socket_error_to_string(err)); |
1388 | 0 | return; |
1389 | 0 | } |
1390 | 0 | if (evutil_sockaddr_cmp((struct sockaddr*)&ss, |
1391 | 0 | (struct sockaddr*)&ns->address, 0)) { |
1392 | 0 | log(EVDNS_LOG_WARN, "Address mismatch on received " |
1393 | 0 | "DNS packet. Apparent source was %s", |
1394 | 0 | evutil_format_sockaddr_port_( |
1395 | 0 | (struct sockaddr *)&ss, |
1396 | 0 | addrbuf, sizeof(addrbuf))); |
1397 | 0 | return; |
1398 | 0 | } |
1399 | 0 |
|
1400 | 0 | ns->timedout = 0; |
1401 | 0 | reply_parse(ns->base, packet, r); |
1402 | 0 | } |
1403 | 0 | } |
1404 | | |
1405 | | /* Read a packet from a DNS client on a server port s, parse it, and */ |
1406 | | /* act accordingly. */ |
1407 | | static void |
1408 | 0 | server_port_read(struct evdns_server_port *s) { |
1409 | 0 | u8 packet[1500]; |
1410 | 0 | struct sockaddr_storage addr; |
1411 | 0 | ev_socklen_t addrlen; |
1412 | 0 | int r; |
1413 | 0 | ASSERT_LOCKED(s); |
1414 | 0 |
|
1415 | 0 | for (;;) { |
1416 | 0 | addrlen = sizeof(struct sockaddr_storage); |
1417 | 0 | r = recvfrom(s->socket, (void*)packet, sizeof(packet), 0, |
1418 | 0 | (struct sockaddr*) &addr, &addrlen); |
1419 | 0 | if (r < 0) { |
1420 | 0 | int err = evutil_socket_geterror(s->socket); |
1421 | 0 | if (EVUTIL_ERR_RW_RETRIABLE(err)) |
1422 | 0 | return; |
1423 | 0 | log(EVDNS_LOG_WARN, |
1424 | 0 | "Error %s (%d) while reading request.", |
1425 | 0 | evutil_socket_error_to_string(err), err); |
1426 | 0 | return; |
1427 | 0 | } |
1428 | 0 | request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen); |
1429 | 0 | } |
1430 | 0 | } |
1431 | | |
1432 | | /* Try to write all pending replies on a given DNS server port. */ |
1433 | | static void |
1434 | | server_port_flush(struct evdns_server_port *port) |
1435 | 0 | { |
1436 | 0 | struct server_request *req = port->pending_replies; |
1437 | 0 | ASSERT_LOCKED(port); |
1438 | 0 | while (req) { |
1439 | 0 | int r = sendto(port->socket, req->response, (int)req->response_len, 0, |
1440 | 0 | (struct sockaddr*) &req->addr, (ev_socklen_t)req->addrlen); |
1441 | 0 | if (r < 0) { |
1442 | 0 | int err = evutil_socket_geterror(port->socket); |
1443 | 0 | if (EVUTIL_ERR_RW_RETRIABLE(err)) |
1444 | 0 | return; |
1445 | 0 | log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", evutil_socket_error_to_string(err), err); |
1446 | 0 | } |
1447 | 0 | if (server_request_free(req)) { |
1448 | 0 | /* we released the last reference to req->port. */ |
1449 | 0 | return; |
1450 | 0 | } else { |
1451 | 0 | EVUTIL_ASSERT(req != port->pending_replies); |
1452 | 0 | req = port->pending_replies; |
1453 | 0 | } |
1454 | 0 | } |
1455 | 0 |
|
1456 | 0 | /* We have no more pending requests; stop listening for 'writeable' events. */ |
1457 | 0 | (void) event_del(&port->event); |
1458 | 0 | event_assign(&port->event, port->event_base, |
1459 | 0 | port->socket, EV_READ | EV_PERSIST, |
1460 | 0 | server_port_ready_callback, port); |
1461 | 0 |
|
1462 | 0 | if (event_add(&port->event, NULL) < 0) { |
1463 | 0 | log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server."); |
1464 | 0 | /* ???? Do more? */ |
1465 | 0 | } |
1466 | 0 | } |
1467 | | |
1468 | | /* set if we are waiting for the ability to write to this server. */ |
1469 | | /* if waiting is true then we ask libevent for EV_WRITE events, otherwise */ |
1470 | | /* we stop these events. */ |
1471 | | static void |
1472 | 0 | nameserver_write_waiting(struct nameserver *ns, char waiting) { |
1473 | 0 | ASSERT_LOCKED(ns->base); |
1474 | 0 | if (ns->write_waiting == waiting) return; |
1475 | 0 | |
1476 | 0 | ns->write_waiting = waiting; |
1477 | 0 | (void) event_del(&ns->event); |
1478 | 0 | event_assign(&ns->event, ns->base->event_base, |
1479 | 0 | ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST, |
1480 | 0 | nameserver_ready_callback, ns); |
1481 | 0 | if (event_add(&ns->event, NULL) < 0) { |
1482 | 0 | char addrbuf[128]; |
1483 | 0 | log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s", |
1484 | 0 | evutil_format_sockaddr_port_( |
1485 | 0 | (struct sockaddr *)&ns->address, |
1486 | 0 | addrbuf, sizeof(addrbuf))); |
1487 | 0 | /* ???? Do more? */ |
1488 | 0 | } |
1489 | 0 | } |
1490 | | |
1491 | | /* a callback function. Called by libevent when the kernel says that */ |
1492 | | /* a nameserver socket is ready for writing or reading */ |
1493 | | static void |
1494 | 0 | nameserver_ready_callback(evutil_socket_t fd, short events, void *arg) { |
1495 | 0 | struct nameserver *ns = (struct nameserver *) arg; |
1496 | 0 | (void)fd; |
1497 | 0 |
|
1498 | 0 | EVDNS_LOCK(ns->base); |
1499 | 0 | if (events & EV_WRITE) { |
1500 | 0 | ns->choked = 0; |
1501 | 0 | if (!evdns_transmit(ns->base)) { |
1502 | 0 | nameserver_write_waiting(ns, 0); |
1503 | 0 | } |
1504 | 0 | } |
1505 | 0 | if (events & EV_READ) { |
1506 | 0 | nameserver_read(ns); |
1507 | 0 | } |
1508 | 0 | EVDNS_UNLOCK(ns->base); |
1509 | 0 | } |
1510 | | |
1511 | | /* a callback function. Called by libevent when the kernel says that */ |
1512 | | /* a server socket is ready for writing or reading. */ |
1513 | | static void |
1514 | 0 | server_port_ready_callback(evutil_socket_t fd, short events, void *arg) { |
1515 | 0 | struct evdns_server_port *port = (struct evdns_server_port *) arg; |
1516 | 0 | (void) fd; |
1517 | 0 |
|
1518 | 0 | EVDNS_LOCK(port); |
1519 | 0 | if (events & EV_WRITE) { |
1520 | 0 | port->choked = 0; |
1521 | 0 | server_port_flush(port); |
1522 | 0 | } |
1523 | 0 | if (events & EV_READ) { |
1524 | 0 | server_port_read(port); |
1525 | 0 | } |
1526 | 0 | EVDNS_UNLOCK(port); |
1527 | 0 | } |
1528 | | |
1529 | | /* This is an inefficient representation; only use it via the dnslabel_table_* |
1530 | | * functions, so that is can be safely replaced with something smarter later. */ |
1531 | 0 | #define MAX_LABELS 128 |
1532 | | /* Structures used to implement name compression */ |
1533 | | struct dnslabel_entry { char *v; off_t pos; }; |
1534 | | struct dnslabel_table { |
1535 | | int n_labels; /* number of current entries */ |
1536 | | /* map from name to position in message */ |
1537 | | struct dnslabel_entry labels[MAX_LABELS]; |
1538 | | }; |
1539 | | |
1540 | | /* Initialize dnslabel_table. */ |
1541 | | static void |
1542 | | dnslabel_table_init(struct dnslabel_table *table) |
1543 | 0 | { |
1544 | 0 | table->n_labels = 0; |
1545 | 0 | } |
1546 | | |
1547 | | /* Free all storage held by table, but not the table itself. */ |
1548 | | static void |
1549 | | dnslabel_clear(struct dnslabel_table *table) |
1550 | 0 | { |
1551 | 0 | int i; |
1552 | 0 | for (i = 0; i < table->n_labels; ++i) |
1553 | 0 | mm_free(table->labels[i].v); |
1554 | 0 | table->n_labels = 0; |
1555 | 0 | } |
1556 | | |
1557 | | /* return the position of the label in the current message, or -1 if the label */ |
1558 | | /* hasn't been used yet. */ |
1559 | | static int |
1560 | | dnslabel_table_get_pos(const struct dnslabel_table *table, const char *label) |
1561 | 0 | { |
1562 | 0 | int i; |
1563 | 0 | for (i = 0; i < table->n_labels; ++i) { |
1564 | 0 | if (!strcmp(label, table->labels[i].v)) |
1565 | 0 | return table->labels[i].pos; |
1566 | 0 | } |
1567 | 0 | return -1; |
1568 | 0 | } |
1569 | | |
1570 | | /* remember that we've used the label at position pos */ |
1571 | | static int |
1572 | | dnslabel_table_add(struct dnslabel_table *table, const char *label, off_t pos) |
1573 | 0 | { |
1574 | 0 | char *v; |
1575 | 0 | int p; |
1576 | 0 | if (table->n_labels == MAX_LABELS) |
1577 | 0 | return (-1); |
1578 | 0 | v = mm_strdup(label); |
1579 | 0 | if (v == NULL) |
1580 | 0 | return (-1); |
1581 | 0 | p = table->n_labels++; |
1582 | 0 | table->labels[p].v = v; |
1583 | 0 | table->labels[p].pos = pos; |
1584 | 0 |
|
1585 | 0 | return (0); |
1586 | 0 | } |
1587 | | |
1588 | | /* Converts a string to a length-prefixed set of DNS labels, starting */ |
1589 | | /* at buf[j]. name and buf must not overlap. name_len should be the length */ |
1590 | | /* of name. table is optional, and is used for compression. */ |
1591 | | /* */ |
1592 | | /* Input: abc.def */ |
1593 | | /* Output: <3>abc<3>def<0> */ |
1594 | | /* */ |
1595 | | /* Returns the first index after the encoded name, or negative on error. */ |
1596 | | /* -1 label was > 63 bytes */ |
1597 | | /* -2 name too long to fit in buffer. */ |
1598 | | /* */ |
1599 | | static off_t |
1600 | | dnsname_to_labels(u8 *const buf, size_t buf_len, off_t j, |
1601 | | const char *name, const size_t name_len, |
1602 | 0 | struct dnslabel_table *table) { |
1603 | 0 | const char *end = name + name_len; |
1604 | 0 | int ref = 0; |
1605 | 0 | u16 t_; |
1606 | 0 |
|
1607 | 0 | #define APPEND16(x) do { \ |
1608 | 0 | if (j + 2 > (off_t)buf_len) \ |
1609 | 0 | goto overflow; \ |
1610 | 0 | t_ = htons(x); \ |
1611 | 0 | memcpy(buf + j, &t_, 2); \ |
1612 | 0 | j += 2; \ |
1613 | 0 | } while (0) |
1614 | 0 | #define APPEND32(x) do { \ |
1615 | 0 | if (j + 4 > (off_t)buf_len) \ |
1616 | 0 | goto overflow; \ |
1617 | 0 | t32_ = htonl(x); \ |
1618 | 0 | memcpy(buf + j, &t32_, 4); \ |
1619 | 0 | j += 4; \ |
1620 | 0 | } while (0) |
1621 | 0 |
|
1622 | 0 | if (name_len > 255) return -2; |
1623 | 0 | |
1624 | 0 | for (;;) { |
1625 | 0 | const char *const start = name; |
1626 | 0 | if (table && (ref = dnslabel_table_get_pos(table, name)) >= 0) { |
1627 | 0 | APPEND16(ref | 0xc000); |
1628 | 0 | return j; |
1629 | 0 | } |
1630 | 0 | name = strchr(name, '.'); |
1631 | 0 | if (!name) { |
1632 | 0 | const size_t label_len = end - start; |
1633 | 0 | if (label_len > 63) return -1; |
1634 | 0 | if ((size_t)(j+label_len+1) > buf_len) return -2; |
1635 | 0 | if (table) dnslabel_table_add(table, start, j); |
1636 | 0 | buf[j++] = (ev_uint8_t)label_len; |
1637 | 0 |
|
1638 | 0 | memcpy(buf + j, start, label_len); |
1639 | 0 | j += (int) label_len; |
1640 | 0 | break; |
1641 | 0 | } else { |
1642 | 0 | /* append length of the label. */ |
1643 | 0 | const size_t label_len = name - start; |
1644 | 0 | if (label_len > 63) return -1; |
1645 | 0 | if ((size_t)(j+label_len+1) > buf_len) return -2; |
1646 | 0 | if (table) dnslabel_table_add(table, start, j); |
1647 | 0 | buf[j++] = (ev_uint8_t)label_len; |
1648 | 0 |
|
1649 | 0 | memcpy(buf + j, start, label_len); |
1650 | 0 | j += (int) label_len; |
1651 | 0 | /* hop over the '.' */ |
1652 | 0 | name++; |
1653 | 0 | } |
1654 | 0 | } |
1655 | 0 |
|
1656 | 0 | /* the labels must be terminated by a 0. */ |
1657 | 0 | /* It's possible that the name ended in a . */ |
1658 | 0 | /* in which case the zero is already there */ |
1659 | 0 | if (!j || buf[j-1]) buf[j++] = 0; |
1660 | 0 | return j; |
1661 | 0 | overflow: |
1662 | 0 | return (-2); |
1663 | 0 | } |
1664 | | |
1665 | | /* Finds the length of a dns request for a DNS name of the given */ |
1666 | | /* length. The actual request may be smaller than the value returned */ |
1667 | | /* here */ |
1668 | | static size_t |
1669 | 0 | evdns_request_len(const size_t name_len) { |
1670 | 0 | return 96 + /* length of the DNS standard header */ |
1671 | 0 | name_len + 2 + |
1672 | 0 | 4; /* space for the resource type */ |
1673 | 0 | } |
1674 | | |
1675 | | /* build a dns request packet into buf. buf should be at least as long */ |
1676 | | /* as evdns_request_len told you it should be. */ |
1677 | | /* */ |
1678 | | /* Returns the amount of space used. Negative on error. */ |
1679 | | static int |
1680 | | evdns_request_data_build(const char *const name, const size_t name_len, |
1681 | | const u16 trans_id, const u16 type, const u16 class, |
1682 | 0 | u8 *const buf, size_t buf_len) { |
1683 | 0 | off_t j = 0; /* current offset into buf */ |
1684 | 0 | u16 t_; /* used by the macros */ |
1685 | 0 |
|
1686 | 0 | APPEND16(trans_id); |
1687 | 0 | APPEND16(0x0100); /* standard query, recusion needed */ |
1688 | 0 | APPEND16(1); /* one question */ |
1689 | 0 | APPEND16(0); /* no answers */ |
1690 | 0 | APPEND16(0); /* no authority */ |
1691 | 0 | APPEND16(0); /* no additional */ |
1692 | 0 |
|
1693 | 0 | j = dnsname_to_labels(buf, buf_len, j, name, name_len, NULL); |
1694 | 0 | if (j < 0) { |
1695 | 0 | return (int)j; |
1696 | 0 | } |
1697 | 0 | |
1698 | 0 | APPEND16(type); |
1699 | 0 | APPEND16(class); |
1700 | 0 |
|
1701 | 0 | return (int)j; |
1702 | 0 | overflow: |
1703 | 0 | return (-1); |
1704 | 0 | } |
1705 | | |
1706 | | /* exported function */ |
1707 | | struct evdns_server_port * |
1708 | | evdns_add_server_port_with_base(struct event_base *base, evutil_socket_t socket, int flags, evdns_request_callback_fn_type cb, void *user_data) |
1709 | 0 | { |
1710 | 0 | struct evdns_server_port *port; |
1711 | 0 | if (flags) |
1712 | 0 | return NULL; /* flags not yet implemented */ |
1713 | 0 | if (!(port = mm_malloc(sizeof(struct evdns_server_port)))) |
1714 | 0 | return NULL; |
1715 | 0 | memset(port, 0, sizeof(struct evdns_server_port)); |
1716 | 0 |
|
1717 | 0 |
|
1718 | 0 | port->socket = socket; |
1719 | 0 | port->refcnt = 1; |
1720 | 0 | port->choked = 0; |
1721 | 0 | port->closing = 0; |
1722 | 0 | port->user_callback = cb; |
1723 | 0 | port->user_data = user_data; |
1724 | 0 | port->pending_replies = NULL; |
1725 | 0 | port->event_base = base; |
1726 | 0 |
|
1727 | 0 | event_assign(&port->event, port->event_base, |
1728 | 0 | port->socket, EV_READ | EV_PERSIST, |
1729 | 0 | server_port_ready_callback, port); |
1730 | 0 | if (event_add(&port->event, NULL) < 0) { |
1731 | 0 | mm_free(port); |
1732 | 0 | return NULL; |
1733 | 0 | } |
1734 | 0 | EVTHREAD_ALLOC_LOCK(port->lock, EVTHREAD_LOCKTYPE_RECURSIVE); |
1735 | 0 | return port; |
1736 | 0 | } |
1737 | | |
1738 | | struct evdns_server_port * |
1739 | | evdns_add_server_port(evutil_socket_t socket, int flags, evdns_request_callback_fn_type cb, void *user_data) |
1740 | 0 | { |
1741 | 0 | return evdns_add_server_port_with_base(NULL, socket, flags, cb, user_data); |
1742 | 0 | } |
1743 | | |
1744 | | /* exported function */ |
1745 | | void |
1746 | | evdns_close_server_port(struct evdns_server_port *port) |
1747 | 0 | { |
1748 | 0 | EVDNS_LOCK(port); |
1749 | 0 | if (--port->refcnt == 0) { |
1750 | 0 | EVDNS_UNLOCK(port); |
1751 | 0 | server_port_free(port); |
1752 | 0 | } else { |
1753 | 0 | port->closing = 1; |
1754 | 0 | } |
1755 | 0 | } |
1756 | | |
1757 | | /* exported function */ |
1758 | | int |
1759 | | evdns_server_request_add_reply(struct evdns_server_request *req_, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data) |
1760 | 0 | { |
1761 | 0 | struct server_request *req = TO_SERVER_REQUEST(req_); |
1762 | 0 | struct server_reply_item **itemp, *item; |
1763 | 0 | int *countp; |
1764 | 0 | int result = -1; |
1765 | 0 |
|
1766 | 0 | EVDNS_LOCK(req->port); |
1767 | 0 | if (req->response) /* have we already answered? */ |
1768 | 0 | goto done; |
1769 | 0 | |
1770 | 0 | switch (section) { |
1771 | 0 | case EVDNS_ANSWER_SECTION: |
1772 | 0 | itemp = &req->answer; |
1773 | 0 | countp = &req->n_answer; |
1774 | 0 | break; |
1775 | 0 | case EVDNS_AUTHORITY_SECTION: |
1776 | 0 | itemp = &req->authority; |
1777 | 0 | countp = &req->n_authority; |
1778 | 0 | break; |
1779 | 0 | case EVDNS_ADDITIONAL_SECTION: |
1780 | 0 | itemp = &req->additional; |
1781 | 0 | countp = &req->n_additional; |
1782 | 0 | break; |
1783 | 0 | default: |
1784 | 0 | goto done; |
1785 | 0 | } |
1786 | 0 | while (*itemp) { |
1787 | 0 | itemp = &((*itemp)->next); |
1788 | 0 | } |
1789 | 0 | item = mm_malloc(sizeof(struct server_reply_item)); |
1790 | 0 | if (!item) |
1791 | 0 | goto done; |
1792 | 0 | item->next = NULL; |
1793 | 0 | if (!(item->name = mm_strdup(name))) { |
1794 | 0 | mm_free(item); |
1795 | 0 | goto done; |
1796 | 0 | } |
1797 | 0 | item->type = type; |
1798 | 0 | item->dns_question_class = class; |
1799 | 0 | item->ttl = ttl; |
1800 | 0 | item->is_name = is_name != 0; |
1801 | 0 | item->datalen = 0; |
1802 | 0 | item->data = NULL; |
1803 | 0 | if (data) { |
1804 | 0 | if (item->is_name) { |
1805 | 0 | if (!(item->data = mm_strdup(data))) { |
1806 | 0 | mm_free(item->name); |
1807 | 0 | mm_free(item); |
1808 | 0 | goto done; |
1809 | 0 | } |
1810 | 0 | item->datalen = (u16)-1; |
1811 | 0 | } else { |
1812 | 0 | if (!(item->data = mm_malloc(datalen))) { |
1813 | 0 | mm_free(item->name); |
1814 | 0 | mm_free(item); |
1815 | 0 | goto done; |
1816 | 0 | } |
1817 | 0 | item->datalen = datalen; |
1818 | 0 | memcpy(item->data, data, datalen); |
1819 | 0 | } |
1820 | 0 | } |
1821 | 0 |
|
1822 | 0 | *itemp = item; |
1823 | 0 | ++(*countp); |
1824 | 0 | result = 0; |
1825 | 0 | done: |
1826 | 0 | EVDNS_UNLOCK(req->port); |
1827 | 0 | return result; |
1828 | 0 | } |
1829 | | |
1830 | | /* exported function */ |
1831 | | int |
1832 | | evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl) |
1833 | 0 | { |
1834 | 0 | return evdns_server_request_add_reply( |
1835 | 0 | req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET, |
1836 | 0 | ttl, n*4, 0, addrs); |
1837 | 0 | } |
1838 | | |
1839 | | /* exported function */ |
1840 | | int |
1841 | | evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl) |
1842 | 0 | { |
1843 | 0 | return evdns_server_request_add_reply( |
1844 | 0 | req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET, |
1845 | 0 | ttl, n*16, 0, addrs); |
1846 | 0 | } |
1847 | | |
1848 | | /* exported function */ |
1849 | | int |
1850 | | evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl) |
1851 | 0 | { |
1852 | 0 | u32 a; |
1853 | 0 | char buf[32]; |
1854 | 0 | if (in && inaddr_name) |
1855 | 0 | return -1; |
1856 | 0 | else if (!in && !inaddr_name) |
1857 | 0 | return -1; |
1858 | 0 | if (in) { |
1859 | 0 | a = ntohl(in->s_addr); |
1860 | 0 | evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa", |
1861 | 0 | (int)(u8)((a )&0xff), |
1862 | 0 | (int)(u8)((a>>8 )&0xff), |
1863 | 0 | (int)(u8)((a>>16)&0xff), |
1864 | 0 | (int)(u8)((a>>24)&0xff)); |
1865 | 0 | inaddr_name = buf; |
1866 | 0 | } |
1867 | 0 | return evdns_server_request_add_reply( |
1868 | 0 | req, EVDNS_ANSWER_SECTION, inaddr_name, TYPE_PTR, CLASS_INET, |
1869 | 0 | ttl, -1, 1, hostname); |
1870 | 0 | } |
1871 | | |
1872 | | /* exported function */ |
1873 | | int |
1874 | | evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl) |
1875 | 0 | { |
1876 | 0 | return evdns_server_request_add_reply( |
1877 | 0 | req, EVDNS_ANSWER_SECTION, name, TYPE_CNAME, CLASS_INET, |
1878 | 0 | ttl, -1, 1, cname); |
1879 | 0 | } |
1880 | | |
1881 | | /* exported function */ |
1882 | | void |
1883 | | evdns_server_request_set_flags(struct evdns_server_request *exreq, int flags) |
1884 | 0 | { |
1885 | 0 | struct server_request *req = TO_SERVER_REQUEST(exreq); |
1886 | 0 | req->base.flags &= ~(EVDNS_FLAGS_AA|EVDNS_FLAGS_RD); |
1887 | 0 | req->base.flags |= flags; |
1888 | 0 | } |
1889 | | |
1890 | | static int |
1891 | | evdns_server_request_format_response(struct server_request *req, int err) |
1892 | 0 | { |
1893 | 0 | unsigned char buf[1500]; |
1894 | 0 | size_t buf_len = sizeof(buf); |
1895 | 0 | off_t j = 0, r; |
1896 | 0 | u16 t_; |
1897 | 0 | u32 t32_; |
1898 | 0 | int i; |
1899 | 0 | u16 flags; |
1900 | 0 | struct dnslabel_table table; |
1901 | 0 |
|
1902 | 0 | if (err < 0 || err > 15) return -1; |
1903 | 0 | |
1904 | 0 | /* Set response bit and error code; copy OPCODE and RD fields from |
1905 | 0 | * question; copy RA and AA if set by caller. */ |
1906 | 0 | flags = req->base.flags; |
1907 | 0 | flags |= (0x8000 | err); |
1908 | 0 |
|
1909 | 0 | dnslabel_table_init(&table); |
1910 | 0 | APPEND16(req->trans_id); |
1911 | 0 | APPEND16(flags); |
1912 | 0 | APPEND16(req->base.nquestions); |
1913 | 0 | APPEND16(req->n_answer); |
1914 | 0 | APPEND16(req->n_authority); |
1915 | 0 | APPEND16(req->n_additional); |
1916 | 0 |
|
1917 | 0 | /* Add questions. */ |
1918 | 0 | for (i=0; i < req->base.nquestions; ++i) { |
1919 | 0 | const char *s = req->base.questions[i]->name; |
1920 | 0 | j = dnsname_to_labels(buf, buf_len, j, s, strlen(s), &table); |
1921 | 0 | if (j < 0) { |
1922 | 0 | dnslabel_clear(&table); |
1923 | 0 | return (int) j; |
1924 | 0 | } |
1925 | 0 | APPEND16(req->base.questions[i]->type); |
1926 | 0 | APPEND16(req->base.questions[i]->dns_question_class); |
1927 | 0 | } |
1928 | 0 |
|
1929 | 0 | /* Add answer, authority, and additional sections. */ |
1930 | 0 | for (i=0; i<3; ++i) { |
1931 | 0 | struct server_reply_item *item; |
1932 | 0 | if (i==0) |
1933 | 0 | item = req->answer; |
1934 | 0 | else if (i==1) |
1935 | 0 | item = req->authority; |
1936 | 0 | else |
1937 | 0 | item = req->additional; |
1938 | 0 | while (item) { |
1939 | 0 | r = dnsname_to_labels(buf, buf_len, j, item->name, strlen(item->name), &table); |
1940 | 0 | if (r < 0) |
1941 | 0 | goto overflow; |
1942 | 0 | j = r; |
1943 | 0 |
|
1944 | 0 | APPEND16(item->type); |
1945 | 0 | APPEND16(item->dns_question_class); |
1946 | 0 | APPEND32(item->ttl); |
1947 | 0 | if (item->is_name) { |
1948 | 0 | off_t len_idx = j, name_start; |
1949 | 0 | j += 2; |
1950 | 0 | name_start = j; |
1951 | 0 | r = dnsname_to_labels(buf, buf_len, j, item->data, strlen(item->data), &table); |
1952 | 0 | if (r < 0) |
1953 | 0 | goto overflow; |
1954 | 0 | j = r; |
1955 | 0 | t_ = htons( (short) (j-name_start) ); |
1956 | 0 | memcpy(buf+len_idx, &t_, 2); |
1957 | 0 | } else { |
1958 | 0 | APPEND16(item->datalen); |
1959 | 0 | if (j+item->datalen > (off_t)buf_len) |
1960 | 0 | goto overflow; |
1961 | 0 | memcpy(buf+j, item->data, item->datalen); |
1962 | 0 | j += item->datalen; |
1963 | 0 | } |
1964 | 0 | item = item->next; |
1965 | 0 | } |
1966 | 0 | } |
1967 | 0 |
|
1968 | 0 | if (j > 512) { |
1969 | 0 | overflow: |
1970 | 0 | j = 512; |
1971 | 0 | buf[2] |= 0x02; /* set the truncated bit. */ |
1972 | 0 | } |
1973 | 0 |
|
1974 | 0 | req->response_len = j; |
1975 | 0 |
|
1976 | 0 | if (!(req->response = mm_malloc(req->response_len))) { |
1977 | 0 | server_request_free_answers(req); |
1978 | 0 | dnslabel_clear(&table); |
1979 | 0 | return (-1); |
1980 | 0 | } |
1981 | 0 | memcpy(req->response, buf, req->response_len); |
1982 | 0 | server_request_free_answers(req); |
1983 | 0 | dnslabel_clear(&table); |
1984 | 0 | return (0); |
1985 | 0 | } |
1986 | | |
1987 | | /* exported function */ |
1988 | | int |
1989 | | evdns_server_request_respond(struct evdns_server_request *req_, int err) |
1990 | 0 | { |
1991 | 0 | struct server_request *req = TO_SERVER_REQUEST(req_); |
1992 | 0 | struct evdns_server_port *port = req->port; |
1993 | 0 | int r = -1; |
1994 | 0 |
|
1995 | 0 | EVDNS_LOCK(port); |
1996 | 0 | if (!req->response) { |
1997 | 0 | if ((r = evdns_server_request_format_response(req, err))<0) |
1998 | 0 | goto done; |
1999 | 0 | } |
2000 | 0 | |
2001 | 0 | r = sendto(port->socket, req->response, (int)req->response_len, 0, |
2002 | 0 | (struct sockaddr*) &req->addr, (ev_socklen_t)req->addrlen); |
2003 | 0 | if (r<0) { |
2004 | 0 | int sock_err = evutil_socket_geterror(port->socket); |
2005 | 0 | if (EVUTIL_ERR_RW_RETRIABLE(sock_err)) |
2006 | 0 | goto done; |
2007 | 0 | |
2008 | 0 | if (port->pending_replies) { |
2009 | 0 | req->prev_pending = port->pending_replies->prev_pending; |
2010 | 0 | req->next_pending = port->pending_replies; |
2011 | 0 | req->prev_pending->next_pending = |
2012 | 0 | req->next_pending->prev_pending = req; |
2013 | 0 | } else { |
2014 | 0 | req->prev_pending = req->next_pending = req; |
2015 | 0 | port->pending_replies = req; |
2016 | 0 | port->choked = 1; |
2017 | 0 |
|
2018 | 0 | (void) event_del(&port->event); |
2019 | 0 | event_assign(&port->event, port->event_base, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port); |
2020 | 0 |
|
2021 | 0 | if (event_add(&port->event, NULL) < 0) { |
2022 | 0 | log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server"); |
2023 | 0 | } |
2024 | 0 |
|
2025 | 0 | } |
2026 | 0 |
|
2027 | 0 | r = 1; |
2028 | 0 | goto done; |
2029 | 0 | } |
2030 | 0 | if (server_request_free(req)) { |
2031 | 0 | r = 0; |
2032 | 0 | goto done; |
2033 | 0 | } |
2034 | 0 | |
2035 | 0 | if (port->pending_replies) |
2036 | 0 | server_port_flush(port); |
2037 | 0 |
|
2038 | 0 | r = 0; |
2039 | 0 | done: |
2040 | 0 | EVDNS_UNLOCK(port); |
2041 | 0 | return r; |
2042 | 0 | } |
2043 | | |
2044 | | /* Free all storage held by RRs in req. */ |
2045 | | static void |
2046 | | server_request_free_answers(struct server_request *req) |
2047 | 0 | { |
2048 | 0 | struct server_reply_item *victim, *next, **list; |
2049 | 0 | int i; |
2050 | 0 | for (i = 0; i < 3; ++i) { |
2051 | 0 | if (i==0) |
2052 | 0 | list = &req->answer; |
2053 | 0 | else if (i==1) |
2054 | 0 | list = &req->authority; |
2055 | 0 | else |
2056 | 0 | list = &req->additional; |
2057 | 0 |
|
2058 | 0 | victim = *list; |
2059 | 0 | while (victim) { |
2060 | 0 | next = victim->next; |
2061 | 0 | mm_free(victim->name); |
2062 | 0 | if (victim->data) |
2063 | 0 | mm_free(victim->data); |
2064 | 0 | mm_free(victim); |
2065 | 0 | victim = next; |
2066 | 0 | } |
2067 | 0 | *list = NULL; |
2068 | 0 | } |
2069 | 0 | } |
2070 | | |
2071 | | /* Free all storage held by req, and remove links to it. */ |
2072 | | /* return true iff we just wound up freeing the server_port. */ |
2073 | | static int |
2074 | | server_request_free(struct server_request *req) |
2075 | 0 | { |
2076 | 0 | int i, rc=1, lock=0; |
2077 | 0 | if (req->base.questions) { |
2078 | 0 | for (i = 0; i < req->base.nquestions; ++i) |
2079 | 0 | mm_free(req->base.questions[i]); |
2080 | 0 | mm_free(req->base.questions); |
2081 | 0 | } |
2082 | 0 |
|
2083 | 0 | if (req->port) { |
2084 | 0 | EVDNS_LOCK(req->port); |
2085 | 0 | lock=1; |
2086 | 0 | if (req->port->pending_replies == req) { |
2087 | 0 | if (req->next_pending && req->next_pending != req) |
2088 | 0 | req->port->pending_replies = req->next_pending; |
2089 | 0 | else |
2090 | 0 | req->port->pending_replies = NULL; |
2091 | 0 | } |
2092 | 0 | rc = --req->port->refcnt; |
2093 | 0 | } |
2094 | 0 |
|
2095 | 0 | if (req->response) { |
2096 | 0 | mm_free(req->response); |
2097 | 0 | } |
2098 | 0 |
|
2099 | 0 | server_request_free_answers(req); |
2100 | 0 |
|
2101 | 0 | if (req->next_pending && req->next_pending != req) { |
2102 | 0 | req->next_pending->prev_pending = req->prev_pending; |
2103 | 0 | req->prev_pending->next_pending = req->next_pending; |
2104 | 0 | } |
2105 | 0 |
|
2106 | 0 | if (rc == 0) { |
2107 | 0 | EVDNS_UNLOCK(req->port); /* ????? nickm */ |
2108 | 0 | server_port_free(req->port); |
2109 | 0 | mm_free(req); |
2110 | 0 | return (1); |
2111 | 0 | } |
2112 | 0 | if (lock) |
2113 | 0 | EVDNS_UNLOCK(req->port); |
2114 | 0 | mm_free(req); |
2115 | 0 | return (0); |
2116 | 0 | } |
2117 | | |
2118 | | /* Free all storage held by an evdns_server_port. Only called when */ |
2119 | | static void |
2120 | | server_port_free(struct evdns_server_port *port) |
2121 | 0 | { |
2122 | 0 | EVUTIL_ASSERT(port); |
2123 | 0 | EVUTIL_ASSERT(!port->refcnt); |
2124 | 0 | EVUTIL_ASSERT(!port->pending_replies); |
2125 | 0 | if (port->socket > 0) { |
2126 | 0 | evutil_closesocket(port->socket); |
2127 | 0 | port->socket = -1; |
2128 | 0 | } |
2129 | 0 | (void) event_del(&port->event); |
2130 | 0 | event_debug_unassign(&port->event); |
2131 | 0 | EVTHREAD_FREE_LOCK(port->lock, EVTHREAD_LOCKTYPE_RECURSIVE); |
2132 | 0 | mm_free(port); |
2133 | 0 | } |
2134 | | |
2135 | | /* exported function */ |
2136 | | int |
2137 | | evdns_server_request_drop(struct evdns_server_request *req_) |
2138 | 0 | { |
2139 | 0 | struct server_request *req = TO_SERVER_REQUEST(req_); |
2140 | 0 | server_request_free(req); |
2141 | 0 | return 0; |
2142 | 0 | } |
2143 | | |
2144 | | /* exported function */ |
2145 | | int |
2146 | | evdns_server_request_get_requesting_addr(struct evdns_server_request *req_, struct sockaddr *sa, int addr_len) |
2147 | 0 | { |
2148 | 0 | struct server_request *req = TO_SERVER_REQUEST(req_); |
2149 | 0 | if (addr_len < (int)req->addrlen) |
2150 | 0 | return -1; |
2151 | 0 | memcpy(sa, &(req->addr), req->addrlen); |
2152 | 0 | return req->addrlen; |
2153 | 0 | } |
2154 | | |
2155 | | #undef APPEND16 |
2156 | | #undef APPEND32 |
2157 | | |
2158 | | /* this is a libevent callback function which is called when a request */ |
2159 | | /* has timed out. */ |
2160 | | static void |
2161 | 0 | evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg) { |
2162 | 0 | struct request *const req = (struct request *) arg; |
2163 | 0 | struct evdns_base *base = req->base; |
2164 | 0 |
|
2165 | 0 | (void) fd; |
2166 | 0 | (void) events; |
2167 | 0 |
|
2168 | 0 | log(EVDNS_LOG_DEBUG, "Request %p timed out", arg); |
2169 | 0 | EVDNS_LOCK(base); |
2170 | 0 |
|
2171 | 0 | if (req->tx_count >= req->base->global_max_retransmits) { |
2172 | 0 | struct nameserver *ns = req->ns; |
2173 | 0 | /* this request has failed */ |
2174 | 0 | log(EVDNS_LOG_DEBUG, "Giving up on request %p; tx_count==%d", |
2175 | 0 | arg, req->tx_count); |
2176 | 0 | reply_schedule_callback(req, 0, DNS_ERR_TIMEOUT, NULL); |
2177 | 0 |
|
2178 | 0 | request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1); |
2179 | 0 | nameserver_failed(ns, "request timed out."); |
2180 | 0 | } else { |
2181 | 0 | /* retransmit it */ |
2182 | 0 | log(EVDNS_LOG_DEBUG, "Retransmitting request %p; tx_count==%d", |
2183 | 0 | arg, req->tx_count); |
2184 | 0 | (void) evtimer_del(&req->timeout_event); |
2185 | 0 | request_swap_ns(req, nameserver_pick(base)); |
2186 | 0 | evdns_request_transmit(req); |
2187 | 0 |
|
2188 | 0 | req->ns->timedout++; |
2189 | 0 | if (req->ns->timedout > req->base->global_max_nameserver_timeout) { |
2190 | 0 | req->ns->timedout = 0; |
2191 | 0 | nameserver_failed(req->ns, "request timed out."); |
2192 | 0 | } |
2193 | 0 | } |
2194 | 0 |
|
2195 | 0 | EVDNS_UNLOCK(base); |
2196 | 0 | } |
2197 | | |
2198 | | /* try to send a request to a given server. */ |
2199 | | /* */ |
2200 | | /* return: */ |
2201 | | /* 0 ok */ |
2202 | | /* 1 temporary failure */ |
2203 | | /* 2 other failure */ |
2204 | | static int |
2205 | 0 | evdns_request_transmit_to(struct request *req, struct nameserver *server) { |
2206 | 0 | int r; |
2207 | 0 | ASSERT_LOCKED(req->base); |
2208 | 0 | ASSERT_VALID_REQUEST(req); |
2209 | 0 |
|
2210 | 0 | if (server->requests_inflight == 1 && |
2211 | 0 | req->base->disable_when_inactive && |
2212 | 0 | event_add(&server->event, NULL) < 0) { |
2213 | 0 | return 1; |
2214 | 0 | } |
2215 | 0 | |
2216 | 0 | r = sendto(server->socket, (void*)req->request, req->request_len, 0, |
2217 | 0 | (struct sockaddr *)&server->address, server->addrlen); |
2218 | 0 | if (r < 0) { |
2219 | 0 | int err = evutil_socket_geterror(server->socket); |
2220 | 0 | if (EVUTIL_ERR_RW_RETRIABLE(err)) |
2221 | 0 | return 1; |
2222 | 0 | nameserver_failed(req->ns, evutil_socket_error_to_string(err)); |
2223 | 0 | return 2; |
2224 | 0 | } else if (r != (int)req->request_len) { |
2225 | 0 | return 1; /* short write */ |
2226 | 0 | } else { |
2227 | 0 | return 0; |
2228 | 0 | } |
2229 | 0 | } |
2230 | | |
2231 | | /* try to send a request, updating the fields of the request */ |
2232 | | /* as needed */ |
2233 | | /* */ |
2234 | | /* return: */ |
2235 | | /* 0 ok */ |
2236 | | /* 1 failed */ |
2237 | | static int |
2238 | 0 | evdns_request_transmit(struct request *req) { |
2239 | 0 | int retcode = 0, r; |
2240 | 0 |
|
2241 | 0 | ASSERT_LOCKED(req->base); |
2242 | 0 | ASSERT_VALID_REQUEST(req); |
2243 | 0 | /* if we fail to send this packet then this flag marks it */ |
2244 | 0 | /* for evdns_transmit */ |
2245 | 0 | req->transmit_me = 1; |
2246 | 0 | EVUTIL_ASSERT(req->trans_id != 0xffff); |
2247 | 0 |
|
2248 | 0 | if (!req->ns) |
2249 | 0 | { |
2250 | 0 | /* unable to transmit request if no nameservers */ |
2251 | 0 | return 1; |
2252 | 0 | } |
2253 | 0 | |
2254 | 0 | if (req->ns->choked) { |
2255 | 0 | /* don't bother trying to write to a socket */ |
2256 | 0 | /* which we have had EAGAIN from */ |
2257 | 0 | return 1; |
2258 | 0 | } |
2259 | 0 | |
2260 | 0 | r = evdns_request_transmit_to(req, req->ns); |
2261 | 0 | switch (r) { |
2262 | 0 | case 1: |
2263 | 0 | /* temp failure */ |
2264 | 0 | req->ns->choked = 1; |
2265 | 0 | nameserver_write_waiting(req->ns, 1); |
2266 | 0 | return 1; |
2267 | 0 | case 2: |
2268 | 0 | /* failed to transmit the request entirely. we can fallthrough since |
2269 | 0 | * we'll set a timeout, which will time out, and make us retransmit the |
2270 | 0 | * request anyway. */ |
2271 | 0 | retcode = 1; |
2272 | 0 | EVUTIL_FALLTHROUGH; |
2273 | 0 | default: |
2274 | 0 | /* all ok */ |
2275 | 0 | log(EVDNS_LOG_DEBUG, |
2276 | 0 | "Setting timeout for request %p, sent to nameserver %p", req, req->ns); |
2277 | 0 | if (evtimer_add(&req->timeout_event, &req->base->global_timeout) < 0) { |
2278 | 0 | log(EVDNS_LOG_WARN, |
2279 | 0 | "Error from libevent when adding timer for request %p", |
2280 | 0 | req); |
2281 | 0 | /* ???? Do more? */ |
2282 | 0 | } |
2283 | 0 | req->tx_count++; |
2284 | 0 | req->transmit_me = 0; |
2285 | 0 | return retcode; |
2286 | 0 | } |
2287 | 0 | } |
2288 | | |
2289 | | static void |
2290 | 0 | nameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) { |
2291 | 0 | struct nameserver *const ns = (struct nameserver *) arg; |
2292 | 0 | (void) type; |
2293 | 0 | (void) count; |
2294 | 0 | (void) ttl; |
2295 | 0 | (void) addresses; |
2296 | 0 |
|
2297 | 0 | if (result == DNS_ERR_CANCEL) { |
2298 | 0 | /* We canceled this request because the nameserver came up |
2299 | 0 | * for some other reason. Do not change our opinion about |
2300 | 0 | * the nameserver. */ |
2301 | 0 | return; |
2302 | 0 | } |
2303 | 0 | |
2304 | 0 | EVDNS_LOCK(ns->base); |
2305 | 0 | ns->probe_request = NULL; |
2306 | 0 | if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) { |
2307 | 0 | /* this is a good reply */ |
2308 | 0 | nameserver_up(ns); |
2309 | 0 | } else { |
2310 | 0 | nameserver_probe_failed(ns); |
2311 | 0 | } |
2312 | 0 | EVDNS_UNLOCK(ns->base); |
2313 | 0 | } |
2314 | | |
2315 | | static void |
2316 | 0 | nameserver_send_probe(struct nameserver *const ns) { |
2317 | 0 | struct evdns_request *handle; |
2318 | 0 | struct request *req; |
2319 | 0 | char addrbuf[128]; |
2320 | 0 | /* here we need to send a probe to a given nameserver */ |
2321 | 0 | /* in the hope that it is up now. */ |
2322 | 0 |
|
2323 | 0 | ASSERT_LOCKED(ns->base); |
2324 | 0 | log(EVDNS_LOG_DEBUG, "Sending probe to %s", |
2325 | 0 | evutil_format_sockaddr_port_( |
2326 | 0 | (struct sockaddr *)&ns->address, |
2327 | 0 | addrbuf, sizeof(addrbuf))); |
2328 | 0 | handle = mm_calloc(1, sizeof(*handle)); |
2329 | 0 | if (!handle) return; |
2330 | 0 | req = request_new(ns->base, handle, TYPE_A, "google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns); |
2331 | 0 | if (!req) { |
2332 | 0 | mm_free(handle); |
2333 | 0 | return; |
2334 | 0 | } |
2335 | 0 | ns->probe_request = handle; |
2336 | 0 | /* we force this into the inflight queue no matter what */ |
2337 | 0 | request_trans_id_set(req, transaction_id_pick(ns->base)); |
2338 | 0 | req->ns = ns; |
2339 | 0 | request_submit(req); |
2340 | 0 | } |
2341 | | |
2342 | | /* returns: */ |
2343 | | /* 0 didn't try to transmit anything */ |
2344 | | /* 1 tried to transmit something */ |
2345 | | static int |
2346 | 0 | evdns_transmit(struct evdns_base *base) { |
2347 | 0 | char did_try_to_transmit = 0; |
2348 | 0 | int i; |
2349 | 0 |
|
2350 | 0 | ASSERT_LOCKED(base); |
2351 | 0 | for (i = 0; i < base->n_req_heads; ++i) { |
2352 | 0 | if (base->req_heads[i]) { |
2353 | 0 | struct request *const started_at = base->req_heads[i], *req = started_at; |
2354 | 0 | /* first transmit all the requests which are currently waiting */ |
2355 | 0 | do { |
2356 | 0 | if (req->transmit_me) { |
2357 | 0 | did_try_to_transmit = 1; |
2358 | 0 | evdns_request_transmit(req); |
2359 | 0 | } |
2360 | 0 |
|
2361 | 0 | req = req->next; |
2362 | 0 | } while (req != started_at); |
2363 | 0 | } |
2364 | 0 | } |
2365 | 0 |
|
2366 | 0 | return did_try_to_transmit; |
2367 | 0 | } |
2368 | | |
2369 | | /* exported function */ |
2370 | | int |
2371 | | evdns_base_count_nameservers(struct evdns_base *base) |
2372 | 0 | { |
2373 | 0 | const struct nameserver *server; |
2374 | 0 | int n = 0; |
2375 | 0 |
|
2376 | 0 | EVDNS_LOCK(base); |
2377 | 0 | server = base->server_head; |
2378 | 0 | if (!server) |
2379 | 0 | goto done; |
2380 | 0 | do { |
2381 | 0 | ++n; |
2382 | 0 | server = server->next; |
2383 | 0 | } while (server != base->server_head); |
2384 | 0 | done: |
2385 | 0 | EVDNS_UNLOCK(base); |
2386 | 0 | return n; |
2387 | 0 | } |
2388 | | |
2389 | | int |
2390 | | evdns_count_nameservers(void) |
2391 | 0 | { |
2392 | 0 | return evdns_base_count_nameservers(current_base); |
2393 | 0 | } |
2394 | | |
2395 | | /* exported function */ |
2396 | | int |
2397 | | evdns_base_clear_nameservers_and_suspend(struct evdns_base *base) |
2398 | 0 | { |
2399 | 0 | struct nameserver *server, *started_at; |
2400 | 0 | int i; |
2401 | 0 |
|
2402 | 0 | EVDNS_LOCK(base); |
2403 | 0 | server = base->server_head; |
2404 | 0 | started_at = base->server_head; |
2405 | 0 | if (!server) { |
2406 | 0 | EVDNS_UNLOCK(base); |
2407 | 0 | return 0; |
2408 | 0 | } |
2409 | 0 | while (1) { |
2410 | 0 | struct nameserver *next = server->next; |
2411 | 0 | (void) event_del(&server->event); |
2412 | 0 | if (evtimer_initialized(&server->timeout_event)) |
2413 | 0 | (void) evtimer_del(&server->timeout_event); |
2414 | 0 | if (server->probe_request) { |
2415 | 0 | evdns_cancel_request(server->base, server->probe_request); |
2416 | 0 | server->probe_request = NULL; |
2417 | 0 | } |
2418 | 0 | if (server->socket >= 0) |
2419 | 0 | evutil_closesocket(server->socket); |
2420 | 0 | mm_free(server); |
2421 | 0 | if (next == started_at) |
2422 | 0 | break; |
2423 | 0 | server = next; |
2424 | 0 | } |
2425 | 0 | base->server_head = NULL; |
2426 | 0 | base->global_good_nameservers = 0; |
2427 | 0 |
|
2428 | 0 | for (i = 0; i < base->n_req_heads; ++i) { |
2429 | 0 | struct request *req, *req_started_at; |
2430 | 0 | req = req_started_at = base->req_heads[i]; |
2431 | 0 | while (req) { |
2432 | 0 | struct request *next = req->next; |
2433 | 0 | req->tx_count = req->reissue_count = 0; |
2434 | 0 | req->ns = NULL; |
2435 | 0 | /* ???? What to do about searches? */ |
2436 | 0 | (void) evtimer_del(&req->timeout_event); |
2437 | 0 | req->trans_id = 0; |
2438 | 0 | req->transmit_me = 0; |
2439 | 0 |
|
2440 | 0 | base->global_requests_waiting++; |
2441 | 0 | evdns_request_insert(req, &base->req_waiting_head); |
2442 | 0 | /* We want to insert these suspended elements at the front of |
2443 | 0 | * the waiting queue, since they were pending before any of |
2444 | 0 | * the waiting entries were added. This is a circular list, |
2445 | 0 | * so we can just shift the start back by one.*/ |
2446 | 0 | base->req_waiting_head = base->req_waiting_head->prev; |
2447 | 0 |
|
2448 | 0 | if (next == req_started_at) |
2449 | 0 | break; |
2450 | 0 | req = next; |
2451 | 0 | } |
2452 | 0 | base->req_heads[i] = NULL; |
2453 | 0 | } |
2454 | 0 |
|
2455 | 0 | base->global_requests_inflight = 0; |
2456 | 0 |
|
2457 | 0 | EVDNS_UNLOCK(base); |
2458 | 0 | return 0; |
2459 | 0 | } |
2460 | | |
2461 | | int |
2462 | | evdns_clear_nameservers_and_suspend(void) |
2463 | 0 | { |
2464 | 0 | return evdns_base_clear_nameservers_and_suspend(current_base); |
2465 | 0 | } |
2466 | | |
2467 | | |
2468 | | /* exported function */ |
2469 | | int |
2470 | | evdns_base_resume(struct evdns_base *base) |
2471 | 0 | { |
2472 | 0 | EVDNS_LOCK(base); |
2473 | 0 | evdns_requests_pump_waiting_queue(base); |
2474 | 0 | EVDNS_UNLOCK(base); |
2475 | 0 |
|
2476 | 0 | return 0; |
2477 | 0 | } |
2478 | | |
2479 | | int |
2480 | | evdns_resume(void) |
2481 | 0 | { |
2482 | 0 | return evdns_base_resume(current_base); |
2483 | 0 | } |
2484 | | |
2485 | | static int |
2486 | 0 | evdns_nameserver_add_impl_(struct evdns_base *base, const struct sockaddr *address, int addrlen) { |
2487 | 0 | /* first check to see if we already have this nameserver */ |
2488 | 0 |
|
2489 | 0 | const struct nameserver *server = base->server_head, *const started_at = base->server_head; |
2490 | 0 | struct nameserver *ns; |
2491 | 0 | int err = 0; |
2492 | 0 | char addrbuf[128]; |
2493 | 0 |
|
2494 | 0 | ASSERT_LOCKED(base); |
2495 | 0 | if (server) { |
2496 | 0 | do { |
2497 | 0 | if (!evutil_sockaddr_cmp((struct sockaddr*)&server->address, address, 1)) return 3; |
2498 | 0 | server = server->next; |
2499 | 0 | } while (server != started_at); |
2500 | 0 | } |
2501 | 0 | if (addrlen > (int)sizeof(ns->address)) { |
2502 | 0 | log(EVDNS_LOG_DEBUG, "Addrlen %d too long.", (int)addrlen); |
2503 | 0 | return 2; |
2504 | 0 | } |
2505 | 0 |
|
2506 | 0 | ns = (struct nameserver *) mm_malloc(sizeof(struct nameserver)); |
2507 | 0 | if (!ns) return -1; |
2508 | 0 | |
2509 | 0 | memset(ns, 0, sizeof(struct nameserver)); |
2510 | 0 | ns->base = base; |
2511 | 0 |
|
2512 | 0 | evtimer_assign(&ns->timeout_event, ns->base->event_base, nameserver_prod_callback, ns); |
2513 | 0 |
|
2514 | 0 | ns->socket = evutil_socket_(address->sa_family, |
2515 | 0 | SOCK_DGRAM|EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC, 0); |
2516 | 0 | if (ns->socket < 0) { err = 1; goto out1; } |
2517 | 0 | |
2518 | 0 | if (base->global_outgoing_addrlen && |
2519 | 0 | !evutil_sockaddr_is_loopback_(address)) { |
2520 | 0 | if (bind(ns->socket, |
2521 | 0 | (struct sockaddr*)&base->global_outgoing_address, |
2522 | 0 | base->global_outgoing_addrlen) < 0) { |
2523 | 0 | log(EVDNS_LOG_WARN,"Couldn't bind to outgoing address"); |
2524 | 0 | err = 2; |
2525 | 0 | goto out2; |
2526 | 0 | } |
2527 | 0 | } |
2528 | 0 |
|
2529 | 0 | memcpy(&ns->address, address, addrlen); |
2530 | 0 | ns->addrlen = addrlen; |
2531 | 0 | ns->state = 1; |
2532 | 0 | event_assign(&ns->event, ns->base->event_base, ns->socket, |
2533 | 0 | EV_READ | EV_PERSIST, nameserver_ready_callback, ns); |
2534 | 0 | if (!base->disable_when_inactive && event_add(&ns->event, NULL) < 0) { |
2535 | 0 | err = 2; |
2536 | 0 | goto out2; |
2537 | 0 | } |
2538 | 0 | |
2539 | 0 | log(EVDNS_LOG_DEBUG, "Added nameserver %s as %p", |
2540 | 0 | evutil_format_sockaddr_port_(address, addrbuf, sizeof(addrbuf)), ns); |
2541 | 0 |
|
2542 | 0 | /* insert this nameserver into the list of them */ |
2543 | 0 | if (!base->server_head) { |
2544 | 0 | ns->next = ns->prev = ns; |
2545 | 0 | base->server_head = ns; |
2546 | 0 | } else { |
2547 | 0 | ns->next = base->server_head->next; |
2548 | 0 | ns->prev = base->server_head; |
2549 | 0 | base->server_head->next = ns; |
2550 | 0 | ns->next->prev = ns; |
2551 | 0 | } |
2552 | 0 |
|
2553 | 0 | base->global_good_nameservers++; |
2554 | 0 |
|
2555 | 0 | return 0; |
2556 | 0 |
|
2557 | 0 | out2: |
2558 | 0 | evutil_closesocket(ns->socket); |
2559 | 0 | out1: |
2560 | 0 | event_debug_unassign(&ns->event); |
2561 | 0 | mm_free(ns); |
2562 | 0 | log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d", |
2563 | 0 | evutil_format_sockaddr_port_(address, addrbuf, sizeof(addrbuf)), err); |
2564 | 0 | return err; |
2565 | 0 | } |
2566 | | |
2567 | | /* exported function */ |
2568 | | int |
2569 | | evdns_base_nameserver_add(struct evdns_base *base, unsigned long int address) |
2570 | 0 | { |
2571 | 0 | struct sockaddr_in sin; |
2572 | 0 | int res; |
2573 | 0 | memset(&sin, 0, sizeof(sin)); |
2574 | 0 | sin.sin_addr.s_addr = address; |
2575 | 0 | sin.sin_port = htons(53); |
2576 | 0 | sin.sin_family = AF_INET; |
2577 | 0 | EVDNS_LOCK(base); |
2578 | 0 | res = evdns_nameserver_add_impl_(base, (struct sockaddr*)&sin, sizeof(sin)); |
2579 | 0 | EVDNS_UNLOCK(base); |
2580 | 0 | return res; |
2581 | 0 | } |
2582 | | |
2583 | | int |
2584 | 0 | evdns_nameserver_add(unsigned long int address) { |
2585 | 0 | if (!current_base) |
2586 | 0 | current_base = evdns_base_new(NULL, 0); |
2587 | 0 | return evdns_base_nameserver_add(current_base, address); |
2588 | 0 | } |
2589 | | |
2590 | | static void |
2591 | | sockaddr_setport(struct sockaddr *sa, ev_uint16_t port) |
2592 | 0 | { |
2593 | 0 | if (sa->sa_family == AF_INET) { |
2594 | 0 | ((struct sockaddr_in *)sa)->sin_port = htons(port); |
2595 | 0 | } else if (sa->sa_family == AF_INET6) { |
2596 | 0 | ((struct sockaddr_in6 *)sa)->sin6_port = htons(port); |
2597 | 0 | } |
2598 | 0 | } |
2599 | | |
2600 | | static ev_uint16_t |
2601 | | sockaddr_getport(struct sockaddr *sa) |
2602 | 0 | { |
2603 | 0 | if (sa->sa_family == AF_INET) { |
2604 | 0 | return ntohs(((struct sockaddr_in *)sa)->sin_port); |
2605 | 0 | } else if (sa->sa_family == AF_INET6) { |
2606 | 0 | return ntohs(((struct sockaddr_in6 *)sa)->sin6_port); |
2607 | 0 | } else { |
2608 | 0 | return 0; |
2609 | 0 | } |
2610 | 0 | } |
2611 | | |
2612 | | /* exported function */ |
2613 | | int |
2614 | 0 | evdns_base_nameserver_ip_add(struct evdns_base *base, const char *ip_as_string) { |
2615 | 0 | struct sockaddr_storage ss; |
2616 | 0 | struct sockaddr *sa; |
2617 | 0 | int len = sizeof(ss); |
2618 | 0 | int res; |
2619 | 0 | if (evutil_parse_sockaddr_port(ip_as_string, (struct sockaddr *)&ss, |
2620 | 0 | &len)) { |
2621 | 0 | log(EVDNS_LOG_WARN, "Unable to parse nameserver address %s", |
2622 | 0 | ip_as_string); |
2623 | 0 | return 4; |
2624 | 0 | } |
2625 | 0 | sa = (struct sockaddr *) &ss; |
2626 | 0 | if (sockaddr_getport(sa) == 0) |
2627 | 0 | sockaddr_setport(sa, 53); |
2628 | 0 |
|
2629 | 0 | EVDNS_LOCK(base); |
2630 | 0 | res = evdns_nameserver_add_impl_(base, sa, len); |
2631 | 0 | EVDNS_UNLOCK(base); |
2632 | 0 | return res; |
2633 | 0 | } |
2634 | | |
2635 | | int |
2636 | 0 | evdns_nameserver_ip_add(const char *ip_as_string) { |
2637 | 0 | if (!current_base) |
2638 | 0 | current_base = evdns_base_new(NULL, 0); |
2639 | 0 | return evdns_base_nameserver_ip_add(current_base, ip_as_string); |
2640 | 0 | } |
2641 | | |
2642 | | int |
2643 | | evdns_base_nameserver_sockaddr_add(struct evdns_base *base, |
2644 | | const struct sockaddr *sa, ev_socklen_t len, unsigned flags) |
2645 | 0 | { |
2646 | 0 | int res; |
2647 | 0 | EVUTIL_ASSERT(base); |
2648 | 0 | EVDNS_LOCK(base); |
2649 | 0 | res = evdns_nameserver_add_impl_(base, sa, len); |
2650 | 0 | EVDNS_UNLOCK(base); |
2651 | 0 | return res; |
2652 | 0 | } |
2653 | | |
2654 | | int |
2655 | | evdns_base_get_nameserver_addr(struct evdns_base *base, int idx, |
2656 | | struct sockaddr *sa, ev_socklen_t len) |
2657 | 0 | { |
2658 | 0 | int result = -1; |
2659 | 0 | int i; |
2660 | 0 | struct nameserver *server; |
2661 | 0 | EVDNS_LOCK(base); |
2662 | 0 | server = base->server_head; |
2663 | 0 | for (i = 0; i < idx && server; ++i, server = server->next) { |
2664 | 0 | if (server->next == base->server_head) |
2665 | 0 | goto done; |
2666 | 0 | } |
2667 | 0 | if (! server) |
2668 | 0 | goto done; |
2669 | 0 | |
2670 | 0 | if (server->addrlen > len) { |
2671 | 0 | result = (int) server->addrlen; |
2672 | 0 | goto done; |
2673 | 0 | } |
2674 | 0 | |
2675 | 0 | memcpy(sa, &server->address, server->addrlen); |
2676 | 0 | result = (int) server->addrlen; |
2677 | 0 | done: |
2678 | 0 | EVDNS_UNLOCK(base); |
2679 | 0 | return result; |
2680 | 0 | } |
2681 | | |
2682 | | /* remove from the queue */ |
2683 | | static void |
2684 | | evdns_request_remove(struct request *req, struct request **head) |
2685 | 0 | { |
2686 | 0 | ASSERT_LOCKED(req->base); |
2687 | 0 | ASSERT_VALID_REQUEST(req); |
2688 | 0 |
|
2689 | | #if 0 |
2690 | | { |
2691 | | struct request *ptr; |
2692 | | int found = 0; |
2693 | | EVUTIL_ASSERT(*head != NULL); |
2694 | | |
2695 | | ptr = *head; |
2696 | | do { |
2697 | | if (ptr == req) { |
2698 | | found = 1; |
2699 | | break; |
2700 | | } |
2701 | | ptr = ptr->next; |
2702 | | } while (ptr != *head); |
2703 | | EVUTIL_ASSERT(found); |
2704 | | |
2705 | | EVUTIL_ASSERT(req->next); |
2706 | | } |
2707 | | #endif |
2708 | |
|
2709 | 0 | if (req->next == req) { |
2710 | 0 | /* only item in the list */ |
2711 | 0 | *head = NULL; |
2712 | 0 | } else { |
2713 | 0 | req->next->prev = req->prev; |
2714 | 0 | req->prev->next = req->next; |
2715 | 0 | if (*head == req) *head = req->next; |
2716 | 0 | } |
2717 | 0 | req->next = req->prev = NULL; |
2718 | 0 | } |
2719 | | |
2720 | | /* insert into the tail of the queue */ |
2721 | | static void |
2722 | 0 | evdns_request_insert(struct request *req, struct request **head) { |
2723 | 0 | ASSERT_LOCKED(req->base); |
2724 | 0 | ASSERT_VALID_REQUEST(req); |
2725 | 0 | if (!*head) { |
2726 | 0 | *head = req; |
2727 | 0 | req->next = req->prev = req; |
2728 | 0 | return; |
2729 | 0 | } |
2730 | 0 | |
2731 | 0 | req->prev = (*head)->prev; |
2732 | 0 | req->prev->next = req; |
2733 | 0 | req->next = *head; |
2734 | 0 | (*head)->prev = req; |
2735 | 0 | } |
2736 | | |
2737 | | static int |
2738 | 0 | string_num_dots(const char *s) { |
2739 | 0 | int count = 0; |
2740 | 0 | while ((s = strchr(s, '.'))) { |
2741 | 0 | s++; |
2742 | 0 | count++; |
2743 | 0 | } |
2744 | 0 | return count; |
2745 | 0 | } |
2746 | | |
2747 | | static struct request * |
2748 | | request_new(struct evdns_base *base, struct evdns_request *handle, int type, |
2749 | | const char *name, int flags, evdns_callback_type callback, |
2750 | 0 | void *user_ptr) { |
2751 | 0 |
|
2752 | 0 | const char issuing_now = |
2753 | 0 | (base->global_requests_inflight < base->global_max_requests_inflight) ? 1 : 0; |
2754 | 0 |
|
2755 | 0 | const size_t name_len = strlen(name); |
2756 | 0 | const size_t request_max_len = evdns_request_len(name_len); |
2757 | 0 | const u16 trans_id = issuing_now ? transaction_id_pick(base) : 0xffff; |
2758 | 0 | /* the request data is alloced in a single block with the header */ |
2759 | 0 | struct request *const req = |
2760 | 0 | mm_malloc(sizeof(struct request) + request_max_len); |
2761 | 0 | int rlen; |
2762 | 0 | char namebuf[256]; |
2763 | 0 | (void) flags; |
2764 | 0 |
|
2765 | 0 | ASSERT_LOCKED(base); |
2766 | 0 |
|
2767 | 0 | if (!req) return NULL; |
2768 | 0 | |
2769 | 0 | if (name_len >= sizeof(namebuf)) { |
2770 | 0 | mm_free(req); |
2771 | 0 | return NULL; |
2772 | 0 | } |
2773 | 0 |
|
2774 | 0 | memset(req, 0, sizeof(struct request)); |
2775 | 0 | req->base = base; |
2776 | 0 |
|
2777 | 0 | evtimer_assign(&req->timeout_event, req->base->event_base, evdns_request_timeout_callback, req); |
2778 | 0 |
|
2779 | 0 | if (base->global_randomize_case) { |
2780 | 0 | unsigned i; |
2781 | 0 | char randbits[(sizeof(namebuf)+7)/8]; |
2782 | 0 | strlcpy(namebuf, name, sizeof(namebuf)); |
2783 | 0 | evutil_secure_rng_get_bytes(randbits, (name_len+7)/8); |
2784 | 0 | for (i = 0; i < name_len; ++i) { |
2785 | 0 | if (EVUTIL_ISALPHA_(namebuf[i])) { |
2786 | 0 | if ((randbits[i >> 3] & (1<<(i & 7)))) |
2787 | 0 | namebuf[i] |= 0x20; |
2788 | 0 | else |
2789 | 0 | namebuf[i] &= ~0x20; |
2790 | 0 | } |
2791 | 0 | } |
2792 | 0 | name = namebuf; |
2793 | 0 | } |
2794 | 0 |
|
2795 | 0 | /* request data lives just after the header */ |
2796 | 0 | req->request = ((u8 *) req) + sizeof(struct request); |
2797 | 0 | /* denotes that the request data shouldn't be free()ed */ |
2798 | 0 | req->request_appended = 1; |
2799 | 0 | rlen = evdns_request_data_build(name, name_len, trans_id, |
2800 | 0 | type, CLASS_INET, req->request, request_max_len); |
2801 | 0 | if (rlen < 0) |
2802 | 0 | goto err1; |
2803 | 0 | |
2804 | 0 | req->request_len = rlen; |
2805 | 0 | req->trans_id = trans_id; |
2806 | 0 | req->tx_count = 0; |
2807 | 0 | req->request_type = type; |
2808 | 0 | req->user_pointer = user_ptr; |
2809 | 0 | req->user_callback = callback; |
2810 | 0 | req->ns = issuing_now ? nameserver_pick(base) : NULL; |
2811 | 0 | req->next = req->prev = NULL; |
2812 | 0 | req->handle = handle; |
2813 | 0 | if (handle) { |
2814 | 0 | handle->current_req = req; |
2815 | 0 | handle->base = base; |
2816 | 0 | } |
2817 | 0 |
|
2818 | 0 | return req; |
2819 | 0 | err1: |
2820 | 0 | mm_free(req); |
2821 | 0 | return NULL; |
2822 | 0 | } |
2823 | | |
2824 | | static void |
2825 | 0 | request_submit(struct request *const req) { |
2826 | 0 | struct evdns_base *base = req->base; |
2827 | 0 | ASSERT_LOCKED(base); |
2828 | 0 | ASSERT_VALID_REQUEST(req); |
2829 | 0 | if (req->ns) { |
2830 | 0 | /* if it has a nameserver assigned then this is going */ |
2831 | 0 | /* straight into the inflight queue */ |
2832 | 0 | evdns_request_insert(req, &REQ_HEAD(base, req->trans_id)); |
2833 | 0 |
|
2834 | 0 | base->global_requests_inflight++; |
2835 | 0 | req->ns->requests_inflight++; |
2836 | 0 |
|
2837 | 0 | evdns_request_transmit(req); |
2838 | 0 | } else { |
2839 | 0 | evdns_request_insert(req, &base->req_waiting_head); |
2840 | 0 | base->global_requests_waiting++; |
2841 | 0 | } |
2842 | 0 | } |
2843 | | |
2844 | | /* exported function */ |
2845 | | void |
2846 | | evdns_cancel_request(struct evdns_base *base, struct evdns_request *handle) |
2847 | 0 | { |
2848 | 0 | struct request *req; |
2849 | 0 |
|
2850 | 0 | if (!handle->current_req) |
2851 | 0 | return; |
2852 | 0 | |
2853 | 0 | if (!base) { |
2854 | 0 | /* This redundancy is silly; can we fix it? (Not for 2.0) XXXX */ |
2855 | 0 | base = handle->base; |
2856 | 0 | if (!base) |
2857 | 0 | base = handle->current_req->base; |
2858 | 0 | } |
2859 | 0 |
|
2860 | 0 | EVDNS_LOCK(base); |
2861 | 0 | if (handle->pending_cb) { |
2862 | 0 | EVDNS_UNLOCK(base); |
2863 | 0 | return; |
2864 | 0 | } |
2865 | 0 |
|
2866 | 0 | req = handle->current_req; |
2867 | 0 | ASSERT_VALID_REQUEST(req); |
2868 | 0 |
|
2869 | 0 | reply_schedule_callback(req, 0, DNS_ERR_CANCEL, NULL); |
2870 | 0 | if (req->ns) { |
2871 | 0 | /* remove from inflight queue */ |
2872 | 0 | request_finished(req, &REQ_HEAD(base, req->trans_id), 1); |
2873 | 0 | } else { |
2874 | 0 | /* remove from global_waiting head */ |
2875 | 0 | request_finished(req, &base->req_waiting_head, 1); |
2876 | 0 | } |
2877 | 0 | EVDNS_UNLOCK(base); |
2878 | 0 | } |
2879 | | |
2880 | | /* exported function */ |
2881 | | struct evdns_request * |
2882 | | evdns_base_resolve_ipv4(struct evdns_base *base, const char *name, int flags, |
2883 | 0 | evdns_callback_type callback, void *ptr) { |
2884 | 0 | struct evdns_request *handle; |
2885 | 0 | struct request *req; |
2886 | 0 | log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name); |
2887 | 0 | handle = mm_calloc(1, sizeof(*handle)); |
2888 | 0 | if (handle == NULL) |
2889 | 0 | return NULL; |
2890 | 0 | EVDNS_LOCK(base); |
2891 | 0 | if (flags & DNS_QUERY_NO_SEARCH) { |
2892 | 0 | req = |
2893 | 0 | request_new(base, handle, TYPE_A, name, flags, |
2894 | 0 | callback, ptr); |
2895 | 0 | if (req) |
2896 | 0 | request_submit(req); |
2897 | 0 | } else { |
2898 | 0 | search_request_new(base, handle, TYPE_A, name, flags, |
2899 | 0 | callback, ptr); |
2900 | 0 | } |
2901 | 0 | if (handle->current_req == NULL) { |
2902 | 0 | mm_free(handle); |
2903 | 0 | handle = NULL; |
2904 | 0 | } |
2905 | 0 | EVDNS_UNLOCK(base); |
2906 | 0 | return handle; |
2907 | 0 | } |
2908 | | |
2909 | | int evdns_resolve_ipv4(const char *name, int flags, |
2910 | | evdns_callback_type callback, void *ptr) |
2911 | 0 | { |
2912 | 0 | return evdns_base_resolve_ipv4(current_base, name, flags, callback, ptr) |
2913 | 0 | ? 0 : -1; |
2914 | 0 | } |
2915 | | |
2916 | | |
2917 | | /* exported function */ |
2918 | | struct evdns_request * |
2919 | | evdns_base_resolve_ipv6(struct evdns_base *base, |
2920 | | const char *name, int flags, |
2921 | | evdns_callback_type callback, void *ptr) |
2922 | 0 | { |
2923 | 0 | struct evdns_request *handle; |
2924 | 0 | struct request *req; |
2925 | 0 | log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name); |
2926 | 0 | handle = mm_calloc(1, sizeof(*handle)); |
2927 | 0 | if (handle == NULL) |
2928 | 0 | return NULL; |
2929 | 0 | EVDNS_LOCK(base); |
2930 | 0 | if (flags & DNS_QUERY_NO_SEARCH) { |
2931 | 0 | req = request_new(base, handle, TYPE_AAAA, name, flags, |
2932 | 0 | callback, ptr); |
2933 | 0 | if (req) |
2934 | 0 | request_submit(req); |
2935 | 0 | } else { |
2936 | 0 | search_request_new(base, handle, TYPE_AAAA, name, flags, |
2937 | 0 | callback, ptr); |
2938 | 0 | } |
2939 | 0 | if (handle->current_req == NULL) { |
2940 | 0 | mm_free(handle); |
2941 | 0 | handle = NULL; |
2942 | 0 | } |
2943 | 0 | EVDNS_UNLOCK(base); |
2944 | 0 | return handle; |
2945 | 0 | } |
2946 | | |
2947 | | int evdns_resolve_ipv6(const char *name, int flags, |
2948 | 0 | evdns_callback_type callback, void *ptr) { |
2949 | 0 | return evdns_base_resolve_ipv6(current_base, name, flags, callback, ptr) |
2950 | 0 | ? 0 : -1; |
2951 | 0 | } |
2952 | | |
2953 | | struct evdns_request * |
2954 | 0 | evdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) { |
2955 | 0 | char buf[32]; |
2956 | 0 | struct evdns_request *handle; |
2957 | 0 | struct request *req; |
2958 | 0 | u32 a; |
2959 | 0 | EVUTIL_ASSERT(in); |
2960 | 0 | a = ntohl(in->s_addr); |
2961 | 0 | evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa", |
2962 | 0 | (int)(u8)((a )&0xff), |
2963 | 0 | (int)(u8)((a>>8 )&0xff), |
2964 | 0 | (int)(u8)((a>>16)&0xff), |
2965 | 0 | (int)(u8)((a>>24)&0xff)); |
2966 | 0 | handle = mm_calloc(1, sizeof(*handle)); |
2967 | 0 | if (handle == NULL) |
2968 | 0 | return NULL; |
2969 | 0 | log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf); |
2970 | 0 | EVDNS_LOCK(base); |
2971 | 0 | req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr); |
2972 | 0 | if (req) |
2973 | 0 | request_submit(req); |
2974 | 0 | if (handle->current_req == NULL) { |
2975 | 0 | mm_free(handle); |
2976 | 0 | handle = NULL; |
2977 | 0 | } |
2978 | 0 | EVDNS_UNLOCK(base); |
2979 | 0 | return (handle); |
2980 | 0 | } |
2981 | | |
2982 | 0 | int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) { |
2983 | 0 | return evdns_base_resolve_reverse(current_base, in, flags, callback, ptr) |
2984 | 0 | ? 0 : -1; |
2985 | 0 | } |
2986 | | |
2987 | | struct evdns_request * |
2988 | 0 | evdns_base_resolve_reverse_ipv6(struct evdns_base *base, const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) { |
2989 | 0 | /* 32 nybbles, 32 periods, "ip6.arpa", NUL. */ |
2990 | 0 | char buf[73]; |
2991 | 0 | char *cp; |
2992 | 0 | struct evdns_request *handle; |
2993 | 0 | struct request *req; |
2994 | 0 | int i; |
2995 | 0 | EVUTIL_ASSERT(in); |
2996 | 0 | cp = buf; |
2997 | 0 | for (i=15; i >= 0; --i) { |
2998 | 0 | u8 byte = in->s6_addr[i]; |
2999 | 0 | *cp++ = "0123456789abcdef"[byte & 0x0f]; |
3000 | 0 | *cp++ = '.'; |
3001 | 0 | *cp++ = "0123456789abcdef"[byte >> 4]; |
3002 | 0 | *cp++ = '.'; |
3003 | 0 | } |
3004 | 0 | EVUTIL_ASSERT(cp + strlen("ip6.arpa") < buf+sizeof(buf)); |
3005 | 0 | memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1); |
3006 | 0 | handle = mm_calloc(1, sizeof(*handle)); |
3007 | 0 | if (handle == NULL) |
3008 | 0 | return NULL; |
3009 | 0 | log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf); |
3010 | 0 | EVDNS_LOCK(base); |
3011 | 0 | req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr); |
3012 | 0 | if (req) |
3013 | 0 | request_submit(req); |
3014 | 0 | if (handle->current_req == NULL) { |
3015 | 0 | mm_free(handle); |
3016 | 0 | handle = NULL; |
3017 | 0 | } |
3018 | 0 | EVDNS_UNLOCK(base); |
3019 | 0 | return (handle); |
3020 | 0 | } |
3021 | | |
3022 | 0 | int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) { |
3023 | 0 | return evdns_base_resolve_reverse_ipv6(current_base, in, flags, callback, ptr) |
3024 | 0 | ? 0 : -1; |
3025 | 0 | } |
3026 | | |
3027 | | /* ================================================================= */ |
3028 | | /* Search support */ |
3029 | | /* */ |
3030 | | /* the libc resolver has support for searching a number of domains */ |
3031 | | /* to find a name. If nothing else then it takes the single domain */ |
3032 | | /* from the gethostname() call. */ |
3033 | | /* */ |
3034 | | /* It can also be configured via the domain and search options in a */ |
3035 | | /* resolv.conf. */ |
3036 | | /* */ |
3037 | | /* The ndots option controls how many dots it takes for the resolver */ |
3038 | | /* to decide that a name is non-local and so try a raw lookup first. */ |
3039 | | |
3040 | | struct search_domain { |
3041 | | int len; |
3042 | | struct search_domain *next; |
3043 | | /* the text string is appended to this structure */ |
3044 | | }; |
3045 | | |
3046 | | struct search_state { |
3047 | | int refcount; |
3048 | | int ndots; |
3049 | | int num_domains; |
3050 | | struct search_domain *head; |
3051 | | }; |
3052 | | |
3053 | | static void |
3054 | 0 | search_state_decref(struct search_state *const state) { |
3055 | 0 | if (!state) return; |
3056 | 0 | state->refcount--; |
3057 | 0 | if (!state->refcount) { |
3058 | 0 | struct search_domain *next, *dom; |
3059 | 0 | for (dom = state->head; dom; dom = next) { |
3060 | 0 | next = dom->next; |
3061 | 0 | mm_free(dom); |
3062 | 0 | } |
3063 | 0 | mm_free(state); |
3064 | 0 | } |
3065 | 0 | } |
3066 | | |
3067 | | static struct search_state * |
3068 | 0 | search_state_new(void) { |
3069 | 0 | struct search_state *state = (struct search_state *) mm_malloc(sizeof(struct search_state)); |
3070 | 0 | if (!state) return NULL; |
3071 | 0 | memset(state, 0, sizeof(struct search_state)); |
3072 | 0 | state->refcount = 1; |
3073 | 0 | state->ndots = 1; |
3074 | 0 |
|
3075 | 0 | return state; |
3076 | 0 | } |
3077 | | |
3078 | | static void |
3079 | 0 | search_postfix_clear(struct evdns_base *base) { |
3080 | 0 | search_state_decref(base->global_search_state); |
3081 | 0 |
|
3082 | 0 | base->global_search_state = search_state_new(); |
3083 | 0 | } |
3084 | | |
3085 | | /* exported function */ |
3086 | | void |
3087 | | evdns_base_search_clear(struct evdns_base *base) |
3088 | 0 | { |
3089 | 0 | EVDNS_LOCK(base); |
3090 | 0 | search_postfix_clear(base); |
3091 | 0 | EVDNS_UNLOCK(base); |
3092 | 0 | } |
3093 | | |
3094 | | void |
3095 | 0 | evdns_search_clear(void) { |
3096 | 0 | evdns_base_search_clear(current_base); |
3097 | 0 | } |
3098 | | |
3099 | | static void |
3100 | 0 | search_postfix_add(struct evdns_base *base, const char *domain) { |
3101 | 0 | size_t domain_len; |
3102 | 0 | struct search_domain *sdomain; |
3103 | 0 | while (domain[0] == '.') domain++; |
3104 | 0 | domain_len = strlen(domain); |
3105 | 0 |
|
3106 | 0 | ASSERT_LOCKED(base); |
3107 | 0 | if (!base->global_search_state) base->global_search_state = search_state_new(); |
3108 | 0 | if (!base->global_search_state) return; |
3109 | 0 | base->global_search_state->num_domains++; |
3110 | 0 |
|
3111 | 0 | sdomain = (struct search_domain *) mm_malloc(sizeof(struct search_domain) + domain_len); |
3112 | 0 | if (!sdomain) return; |
3113 | 0 | memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len); |
3114 | 0 | sdomain->next = base->global_search_state->head; |
3115 | 0 | sdomain->len = (int) domain_len; |
3116 | 0 |
|
3117 | 0 | base->global_search_state->head = sdomain; |
3118 | 0 | } |
3119 | | |
3120 | | /* reverse the order of members in the postfix list. This is needed because, */ |
3121 | | /* when parsing resolv.conf we push elements in the wrong order */ |
3122 | | static void |
3123 | 0 | search_reverse(struct evdns_base *base) { |
3124 | 0 | struct search_domain *cur, *prev = NULL, *next; |
3125 | 0 | ASSERT_LOCKED(base); |
3126 | 0 | cur = base->global_search_state->head; |
3127 | 0 | while (cur) { |
3128 | 0 | next = cur->next; |
3129 | 0 | cur->next = prev; |
3130 | 0 | prev = cur; |
3131 | 0 | cur = next; |
3132 | 0 | } |
3133 | 0 |
|
3134 | 0 | base->global_search_state->head = prev; |
3135 | 0 | } |
3136 | | |
3137 | | /* exported function */ |
3138 | | void |
3139 | 0 | evdns_base_search_add(struct evdns_base *base, const char *domain) { |
3140 | 0 | EVDNS_LOCK(base); |
3141 | 0 | search_postfix_add(base, domain); |
3142 | 0 | EVDNS_UNLOCK(base); |
3143 | 0 | } |
3144 | | void |
3145 | 0 | evdns_search_add(const char *domain) { |
3146 | 0 | evdns_base_search_add(current_base, domain); |
3147 | 0 | } |
3148 | | |
3149 | | /* exported function */ |
3150 | | void |
3151 | 0 | evdns_base_search_ndots_set(struct evdns_base *base, const int ndots) { |
3152 | 0 | EVDNS_LOCK(base); |
3153 | 0 | if (!base->global_search_state) base->global_search_state = search_state_new(); |
3154 | 0 | if (base->global_search_state) |
3155 | 0 | base->global_search_state->ndots = ndots; |
3156 | 0 | EVDNS_UNLOCK(base); |
3157 | 0 | } |
3158 | | void |
3159 | 0 | evdns_search_ndots_set(const int ndots) { |
3160 | 0 | evdns_base_search_ndots_set(current_base, ndots); |
3161 | 0 | } |
3162 | | |
3163 | | static void |
3164 | 0 | search_set_from_hostname(struct evdns_base *base) { |
3165 | 0 | char hostname[HOST_NAME_MAX + 1], *domainname; |
3166 | 0 |
|
3167 | 0 | ASSERT_LOCKED(base); |
3168 | 0 | search_postfix_clear(base); |
3169 | 0 | if (gethostname(hostname, sizeof(hostname))) return; |
3170 | 0 | domainname = strchr(hostname, '.'); |
3171 | 0 | if (!domainname) return; |
3172 | 0 | search_postfix_add(base, domainname); |
3173 | 0 | } |
3174 | | |
3175 | | /* warning: returns malloced string */ |
3176 | | static char * |
3177 | 0 | search_make_new(const struct search_state *const state, int n, const char *const base_name) { |
3178 | 0 | const size_t base_len = strlen(base_name); |
3179 | 0 | char need_to_append_dot; |
3180 | 0 | struct search_domain *dom; |
3181 | 0 |
|
3182 | 0 | if (!base_len) return NULL; |
3183 | 0 | need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1; |
3184 | 0 |
|
3185 | 0 | for (dom = state->head; dom; dom = dom->next) { |
3186 | 0 | if (!n--) { |
3187 | 0 | /* this is the postfix we want */ |
3188 | 0 | /* the actual postfix string is kept at the end of the structure */ |
3189 | 0 | const u8 *const postfix = ((u8 *) dom) + sizeof(struct search_domain); |
3190 | 0 | const int postfix_len = dom->len; |
3191 | 0 | char *const newname = (char *) mm_malloc(base_len + need_to_append_dot + postfix_len + 1); |
3192 | 0 | if (!newname) return NULL; |
3193 | 0 | memcpy(newname, base_name, base_len); |
3194 | 0 | if (need_to_append_dot) newname[base_len] = '.'; |
3195 | 0 | memcpy(newname + base_len + need_to_append_dot, postfix, postfix_len); |
3196 | 0 | newname[base_len + need_to_append_dot + postfix_len] = 0; |
3197 | 0 | return newname; |
3198 | 0 | } |
3199 | 0 | } |
3200 | 0 |
|
3201 | 0 | /* we ran off the end of the list and still didn't find the requested string */ |
3202 | 0 | EVUTIL_ASSERT(0); |
3203 | 0 | return NULL; /* unreachable; stops warnings in some compilers. */ |
3204 | 0 | } |
3205 | | |
3206 | | static struct request * |
3207 | | search_request_new(struct evdns_base *base, struct evdns_request *handle, |
3208 | | int type, const char *const name, int flags, |
3209 | 0 | evdns_callback_type user_callback, void *user_arg) { |
3210 | 0 | ASSERT_LOCKED(base); |
3211 | 0 | EVUTIL_ASSERT(type == TYPE_A || type == TYPE_AAAA); |
3212 | 0 | EVUTIL_ASSERT(handle->current_req == NULL); |
3213 | 0 | if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) && |
3214 | 0 | base->global_search_state && |
3215 | 0 | base->global_search_state->num_domains) { |
3216 | 0 | /* we have some domains to search */ |
3217 | 0 | struct request *req; |
3218 | 0 | if (string_num_dots(name) >= base->global_search_state->ndots) { |
3219 | 0 | req = request_new(base, handle, type, name, flags, user_callback, user_arg); |
3220 | 0 | if (!req) return NULL; |
3221 | 0 | handle->search_index = -1; |
3222 | 0 | } else { |
3223 | 0 | char *const new_name = search_make_new(base->global_search_state, 0, name); |
3224 | 0 | if (!new_name) return NULL; |
3225 | 0 | req = request_new(base, handle, type, new_name, flags, user_callback, user_arg); |
3226 | 0 | mm_free(new_name); |
3227 | 0 | if (!req) return NULL; |
3228 | 0 | handle->search_index = 0; |
3229 | 0 | } |
3230 | 0 | EVUTIL_ASSERT(handle->search_origname == NULL); |
3231 | 0 | handle->search_origname = mm_strdup(name); |
3232 | 0 | if (handle->search_origname == NULL) { |
3233 | 0 | /* XXX Should we dealloc req? If yes, how? */ |
3234 | 0 | if (req) |
3235 | 0 | mm_free(req); |
3236 | 0 | return NULL; |
3237 | 0 | } |
3238 | 0 | handle->search_state = base->global_search_state; |
3239 | 0 | handle->search_flags = flags; |
3240 | 0 | base->global_search_state->refcount++; |
3241 | 0 | request_submit(req); |
3242 | 0 | return req; |
3243 | 0 | } else { |
3244 | 0 | struct request *const req = request_new(base, handle, type, name, flags, user_callback, user_arg); |
3245 | 0 | if (!req) return NULL; |
3246 | 0 | request_submit(req); |
3247 | 0 | return req; |
3248 | 0 | } |
3249 | 0 | } |
3250 | | |
3251 | | /* this is called when a request has failed to find a name. We need to check */ |
3252 | | /* if it is part of a search and, if so, try the next name in the list */ |
3253 | | /* returns: */ |
3254 | | /* 0 another request has been submitted */ |
3255 | | /* 1 no more requests needed */ |
3256 | | static int |
3257 | 0 | search_try_next(struct evdns_request *const handle) { |
3258 | 0 | struct request *req = handle->current_req; |
3259 | 0 | struct evdns_base *base = req->base; |
3260 | 0 | struct request *newreq; |
3261 | 0 | ASSERT_LOCKED(base); |
3262 | 0 | if (handle->search_state) { |
3263 | 0 | /* it is part of a search */ |
3264 | 0 | char *new_name; |
3265 | 0 | handle->search_index++; |
3266 | 0 | if (handle->search_index >= handle->search_state->num_domains) { |
3267 | 0 | /* no more postfixes to try, however we may need to try */ |
3268 | 0 | /* this name without a postfix */ |
3269 | 0 | if (string_num_dots(handle->search_origname) < handle->search_state->ndots) { |
3270 | 0 | /* yep, we need to try it raw */ |
3271 | 0 | newreq = request_new(base, NULL, req->request_type, handle->search_origname, handle->search_flags, req->user_callback, req->user_pointer); |
3272 | 0 | log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", handle->search_origname); |
3273 | 0 | if (newreq) { |
3274 | 0 | search_request_finished(handle); |
3275 | 0 | goto submit_next; |
3276 | 0 | } |
3277 | 0 | } |
3278 | 0 | return 1; |
3279 | 0 | } |
3280 | 0 | |
3281 | 0 | new_name = search_make_new(handle->search_state, handle->search_index, handle->search_origname); |
3282 | 0 | if (!new_name) return 1; |
3283 | 0 | log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, handle->search_index); |
3284 | 0 | newreq = request_new(base, NULL, req->request_type, new_name, handle->search_flags, req->user_callback, req->user_pointer); |
3285 | 0 | mm_free(new_name); |
3286 | 0 | if (!newreq) return 1; |
3287 | 0 | goto submit_next; |
3288 | 0 | } |
3289 | 0 | return 1; |
3290 | 0 | |
3291 | 0 | submit_next: |
3292 | 0 | request_finished(req, &REQ_HEAD(req->base, req->trans_id), 0); |
3293 | 0 | handle->current_req = newreq; |
3294 | 0 | newreq->handle = handle; |
3295 | 0 | request_submit(newreq); |
3296 | 0 | return 0; |
3297 | 0 | } |
3298 | | |
3299 | | static void |
3300 | 0 | search_request_finished(struct evdns_request *const handle) { |
3301 | 0 | ASSERT_LOCKED(handle->current_req->base); |
3302 | 0 | if (handle->search_state) { |
3303 | 0 | search_state_decref(handle->search_state); |
3304 | 0 | handle->search_state = NULL; |
3305 | 0 | } |
3306 | 0 | if (handle->search_origname) { |
3307 | 0 | mm_free(handle->search_origname); |
3308 | 0 | handle->search_origname = NULL; |
3309 | 0 | } |
3310 | 0 | } |
3311 | | |
3312 | | /* ================================================================= */ |
3313 | | /* Parsing resolv.conf files */ |
3314 | | |
3315 | | static void |
3316 | 0 | evdns_resolv_set_defaults(struct evdns_base *base, int flags) { |
3317 | 0 | /* if the file isn't found then we assume a local resolver */ |
3318 | 0 | ASSERT_LOCKED(base); |
3319 | 0 | if (flags & DNS_OPTION_SEARCH) search_set_from_hostname(base); |
3320 | 0 | if (flags & DNS_OPTION_NAMESERVERS) evdns_base_nameserver_ip_add(base,"127.0.0.1"); |
3321 | 0 | } |
3322 | | |
3323 | | #ifndef EVENT__HAVE_STRTOK_R |
3324 | | static char * |
3325 | | strtok_r(char *s, const char *delim, char **state) { |
3326 | | char *cp, *start; |
3327 | | start = cp = s ? s : *state; |
3328 | | if (!cp) |
3329 | | return NULL; |
3330 | | while (*cp && !strchr(delim, *cp)) |
3331 | | ++cp; |
3332 | | if (!*cp) { |
3333 | | if (cp == start) |
3334 | | return NULL; |
3335 | | *state = NULL; |
3336 | | return start; |
3337 | | } else { |
3338 | | *cp++ = '\0'; |
3339 | | *state = cp; |
3340 | | return start; |
3341 | | } |
3342 | | } |
3343 | | #endif |
3344 | | |
3345 | | /* helper version of atoi which returns -1 on error */ |
3346 | | static int |
3347 | | strtoint(const char *const str) |
3348 | 0 | { |
3349 | 0 | char *endptr; |
3350 | 0 | const int r = strtol(str, &endptr, 10); |
3351 | 0 | if (*endptr) return -1; |
3352 | 0 | return r; |
3353 | 0 | } |
3354 | | |
3355 | | /* Parse a number of seconds into a timeval; return -1 on error. */ |
3356 | | static int |
3357 | | evdns_strtotimeval(const char *const str, struct timeval *out) |
3358 | 0 | { |
3359 | 0 | double d; |
3360 | 0 | char *endptr; |
3361 | 0 | d = strtod(str, &endptr); |
3362 | 0 | if (*endptr) return -1; |
3363 | 0 | if (d < 0) return -1; |
3364 | 0 | out->tv_sec = (int) d; |
3365 | 0 | out->tv_usec = (int) ((d - (int) d)*1000000); |
3366 | 0 | if (out->tv_sec == 0 && out->tv_usec < 1000) /* less than 1 msec */ |
3367 | 0 | return -1; |
3368 | 0 | return 0; |
3369 | 0 | } |
3370 | | |
3371 | | /* helper version of atoi that returns -1 on error and clips to bounds. */ |
3372 | | static int |
3373 | | strtoint_clipped(const char *const str, int min, int max) |
3374 | 0 | { |
3375 | 0 | int r = strtoint(str); |
3376 | 0 | if (r == -1) |
3377 | 0 | return r; |
3378 | 0 | else if (r<min) |
3379 | 0 | return min; |
3380 | 0 | else if (r>max) |
3381 | 0 | return max; |
3382 | 0 | else |
3383 | 0 | return r; |
3384 | 0 | } |
3385 | | |
3386 | | static int |
3387 | | evdns_base_set_max_requests_inflight(struct evdns_base *base, int maxinflight) |
3388 | 0 | { |
3389 | 0 | int old_n_heads = base->n_req_heads, n_heads; |
3390 | 0 | struct request **old_heads = base->req_heads, **new_heads, *req; |
3391 | 0 | int i; |
3392 | 0 |
|
3393 | 0 | ASSERT_LOCKED(base); |
3394 | 0 | if (maxinflight < 1) |
3395 | 0 | maxinflight = 1; |
3396 | 0 | n_heads = (maxinflight+4) / 5; |
3397 | 0 | EVUTIL_ASSERT(n_heads > 0); |
3398 | 0 | new_heads = mm_calloc(n_heads, sizeof(struct request*)); |
3399 | 0 | if (!new_heads) |
3400 | 0 | return (-1); |
3401 | 0 | if (old_heads) { |
3402 | 0 | for (i = 0; i < old_n_heads; ++i) { |
3403 | 0 | while (old_heads[i]) { |
3404 | 0 | req = old_heads[i]; |
3405 | 0 | evdns_request_remove(req, &old_heads[i]); |
3406 | 0 | evdns_request_insert(req, &new_heads[req->trans_id % n_heads]); |
3407 | 0 | } |
3408 | 0 | } |
3409 | 0 | mm_free(old_heads); |
3410 | 0 | } |
3411 | 0 | base->req_heads = new_heads; |
3412 | 0 | base->n_req_heads = n_heads; |
3413 | 0 | base->global_max_requests_inflight = maxinflight; |
3414 | 0 | return (0); |
3415 | 0 | } |
3416 | | |
3417 | | /* exported function */ |
3418 | | int |
3419 | | evdns_base_set_option(struct evdns_base *base, |
3420 | | const char *option, const char *val) |
3421 | 0 | { |
3422 | 0 | int res; |
3423 | 0 | EVDNS_LOCK(base); |
3424 | 0 | res = evdns_base_set_option_impl(base, option, val, DNS_OPTIONS_ALL); |
3425 | 0 | EVDNS_UNLOCK(base); |
3426 | 0 | return res; |
3427 | 0 | } |
3428 | | |
3429 | | static inline int |
3430 | | str_matches_option(const char *s1, const char *optionname) |
3431 | | { |
3432 | | /* Option names are given as "option:" We accept either 'option' in |
3433 | | * s1, or 'option:randomjunk'. The latter form is to implement the |
3434 | | * resolv.conf parser. */ |
3435 | | size_t optlen = strlen(optionname); |
3436 | | size_t slen = strlen(s1); |
3437 | | if (slen == optlen || slen == optlen - 1) |
3438 | | return !strncmp(s1, optionname, slen); |
3439 | | else if (slen > optlen) |
3440 | | return !strncmp(s1, optionname, optlen); |
3441 | | else |
3442 | | return 0; |
3443 | | } |
3444 | | |
3445 | | static int |
3446 | | evdns_base_set_option_impl(struct evdns_base *base, |
3447 | | const char *option, const char *val, int flags) |
3448 | 0 | { |
3449 | 0 | ASSERT_LOCKED(base); |
3450 | 0 | if (str_matches_option(option, "ndots:")) { |
3451 | 0 | const int ndots = strtoint(val); |
3452 | 0 | if (ndots == -1) return -1; |
3453 | 0 | if (!(flags & DNS_OPTION_SEARCH)) return 0; |
3454 | 0 | log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots); |
3455 | 0 | if (!base->global_search_state) base->global_search_state = search_state_new(); |
3456 | 0 | if (!base->global_search_state) return -1; |
3457 | 0 | base->global_search_state->ndots = ndots; |
3458 | 0 | } else if (str_matches_option(option, "timeout:")) { |
3459 | 0 | struct timeval tv; |
3460 | 0 | if (evdns_strtotimeval(val, &tv) == -1) return -1; |
3461 | 0 | if (!(flags & DNS_OPTION_MISC)) return 0; |
3462 | 0 | log(EVDNS_LOG_DEBUG, "Setting timeout to %s", val); |
3463 | 0 | memcpy(&base->global_timeout, &tv, sizeof(struct timeval)); |
3464 | 0 | } else if (str_matches_option(option, "getaddrinfo-allow-skew:")) { |
3465 | 0 | struct timeval tv; |
3466 | 0 | if (evdns_strtotimeval(val, &tv) == -1) return -1; |
3467 | 0 | if (!(flags & DNS_OPTION_MISC)) return 0; |
3468 | 0 | log(EVDNS_LOG_DEBUG, "Setting getaddrinfo-allow-skew to %s", |
3469 | 0 | val); |
3470 | 0 | memcpy(&base->global_getaddrinfo_allow_skew, &tv, |
3471 | 0 | sizeof(struct timeval)); |
3472 | 0 | } else if (str_matches_option(option, "max-timeouts:")) { |
3473 | 0 | const int maxtimeout = strtoint_clipped(val, 1, 255); |
3474 | 0 | if (maxtimeout == -1) return -1; |
3475 | 0 | if (!(flags & DNS_OPTION_MISC)) return 0; |
3476 | 0 | log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d", |
3477 | 0 | maxtimeout); |
3478 | 0 | base->global_max_nameserver_timeout = maxtimeout; |
3479 | 0 | } else if (str_matches_option(option, "max-inflight:")) { |
3480 | 0 | const int maxinflight = strtoint_clipped(val, 1, 65000); |
3481 | 0 | if (maxinflight == -1) return -1; |
3482 | 0 | if (!(flags & DNS_OPTION_MISC)) return 0; |
3483 | 0 | log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d", |
3484 | 0 | maxinflight); |
3485 | 0 | evdns_base_set_max_requests_inflight(base, maxinflight); |
3486 | 0 | } else if (str_matches_option(option, "attempts:")) { |
3487 | 0 | int retries = strtoint(val); |
3488 | 0 | if (retries == -1) return -1; |
3489 | 0 | if (retries > 255) retries = 255; |
3490 | 0 | if (!(flags & DNS_OPTION_MISC)) return 0; |
3491 | 0 | log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries); |
3492 | 0 | base->global_max_retransmits = retries; |
3493 | 0 | } else if (str_matches_option(option, "randomize-case:")) { |
3494 | 0 | int randcase = strtoint(val); |
3495 | 0 | if (!(flags & DNS_OPTION_MISC)) return 0; |
3496 | 0 | base->global_randomize_case = randcase; |
3497 | 0 | } else if (str_matches_option(option, "bind-to:")) { |
3498 | 0 | /* XXX This only applies to successive nameservers, not |
3499 | 0 | * to already-configured ones. We might want to fix that. */ |
3500 | 0 | int len = sizeof(base->global_outgoing_address); |
3501 | 0 | if (!(flags & DNS_OPTION_NAMESERVERS)) return 0; |
3502 | 0 | if (evutil_parse_sockaddr_port(val, |
3503 | 0 | (struct sockaddr*)&base->global_outgoing_address, &len)) |
3504 | 0 | return -1; |
3505 | 0 | base->global_outgoing_addrlen = len; |
3506 | 0 | } else if (str_matches_option(option, "initial-probe-timeout:")) { |
3507 | 0 | struct timeval tv; |
3508 | 0 | if (evdns_strtotimeval(val, &tv) == -1) return -1; |
3509 | 0 | if (tv.tv_sec > 3600) |
3510 | 0 | tv.tv_sec = 3600; |
3511 | 0 | if (!(flags & DNS_OPTION_MISC)) return 0; |
3512 | 0 | log(EVDNS_LOG_DEBUG, "Setting initial probe timeout to %s", |
3513 | 0 | val); |
3514 | 0 | memcpy(&base->global_nameserver_probe_initial_timeout, &tv, |
3515 | 0 | sizeof(tv)); |
3516 | 0 | } |
3517 | 0 | return 0; |
3518 | 0 | } |
3519 | | |
3520 | | int |
3521 | | evdns_set_option(const char *option, const char *val, int flags) |
3522 | 0 | { |
3523 | 0 | if (!current_base) |
3524 | 0 | current_base = evdns_base_new(NULL, 0); |
3525 | 0 | return evdns_base_set_option(current_base, option, val); |
3526 | 0 | } |
3527 | | |
3528 | | static void |
3529 | | resolv_conf_parse_line(struct evdns_base *base, char *const start, int flags) { |
3530 | | char *strtok_state; |
3531 | | static const char *const delims = " \t"; |
3532 | | #define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state) |
3533 | | |
3534 | | |
3535 | | char *const first_token = strtok_r(start, delims, &strtok_state); |
3536 | | ASSERT_LOCKED(base); |
3537 | | if (!first_token) return; |
3538 | | |
3539 | | if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) { |
3540 | | const char *const nameserver = NEXT_TOKEN; |
3541 | | |
3542 | | if (nameserver) |
3543 | | evdns_base_nameserver_ip_add(base, nameserver); |
3544 | | } else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) { |
3545 | | const char *const domain = NEXT_TOKEN; |
3546 | | if (domain) { |
3547 | | search_postfix_clear(base); |
3548 | | search_postfix_add(base, domain); |
3549 | | } |
3550 | | } else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) { |
3551 | | const char *domain; |
3552 | | search_postfix_clear(base); |
3553 | | |
3554 | | while ((domain = NEXT_TOKEN)) { |
3555 | | search_postfix_add(base, domain); |
3556 | | } |
3557 | | search_reverse(base); |
3558 | | } else if (!strcmp(first_token, "options")) { |
3559 | | const char *option; |
3560 | | while ((option = NEXT_TOKEN)) { |
3561 | | const char *val = strchr(option, ':'); |
3562 | | evdns_base_set_option_impl(base, option, val ? val+1 : "", flags); |
3563 | | } |
3564 | | } |
3565 | | #undef NEXT_TOKEN |
3566 | | } |
3567 | | |
3568 | | /* exported function */ |
3569 | | /* returns: */ |
3570 | | /* 0 no errors */ |
3571 | | /* 1 failed to open file */ |
3572 | | /* 2 failed to stat file */ |
3573 | | /* 3 file too large */ |
3574 | | /* 4 out of memory */ |
3575 | | /* 5 short read from file */ |
3576 | | int |
3577 | 0 | evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename) { |
3578 | 0 | int res; |
3579 | 0 | EVDNS_LOCK(base); |
3580 | 0 | res = evdns_base_resolv_conf_parse_impl(base, flags, filename); |
3581 | 0 | EVDNS_UNLOCK(base); |
3582 | 0 | return res; |
3583 | 0 | } |
3584 | | |
3585 | | static char * |
3586 | | evdns_get_default_hosts_filename(void) |
3587 | 0 | { |
3588 | | #ifdef _WIN32 |
3589 | | /* Windows is a little coy about where it puts its configuration |
3590 | | * files. Sure, they're _usually_ in C:\windows\system32, but |
3591 | | * there's no reason in principle they couldn't be in |
3592 | | * W:\hoboken chicken emergency\ |
3593 | | */ |
3594 | | char path[MAX_PATH+1]; |
3595 | | static const char hostfile[] = "\\drivers\\etc\\hosts"; |
3596 | | char *path_out; |
3597 | | size_t len_out; |
3598 | | |
3599 | | if (! SHGetSpecialFolderPathA(NULL, path, CSIDL_SYSTEM, 0)) |
3600 | | return NULL; |
3601 | | len_out = strlen(path)+strlen(hostfile)+1; |
3602 | | path_out = mm_malloc(len_out); |
3603 | | evutil_snprintf(path_out, len_out, "%s%s", path, hostfile); |
3604 | | return path_out; |
3605 | | #else |
3606 | 0 | return mm_strdup("/etc/hosts"); |
3607 | 0 | #endif |
3608 | 0 | } |
3609 | | |
3610 | | static int |
3611 | 0 | evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename) { |
3612 | 0 | size_t n; |
3613 | 0 | char *resolv; |
3614 | 0 | char *start; |
3615 | 0 | int err = 0; |
3616 | 0 |
|
3617 | 0 | log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename); |
3618 | 0 |
|
3619 | 0 | if (flags & DNS_OPTION_HOSTSFILE) { |
3620 | 0 | char *fname = evdns_get_default_hosts_filename(); |
3621 | 0 | evdns_base_load_hosts(base, fname); |
3622 | 0 | if (fname) |
3623 | 0 | mm_free(fname); |
3624 | 0 | } |
3625 | 0 |
|
3626 | 0 | if ((err = evutil_read_file_(filename, &resolv, &n, 0)) < 0) { |
3627 | 0 | if (err == -1) { |
3628 | 0 | /* No file. */ |
3629 | 0 | evdns_resolv_set_defaults(base, flags); |
3630 | 0 | return 1; |
3631 | 0 | } else { |
3632 | 0 | return 2; |
3633 | 0 | } |
3634 | 0 | } |
3635 | 0 | |
3636 | 0 | start = resolv; |
3637 | 0 | for (;;) { |
3638 | 0 | char *const newline = strchr(start, '\n'); |
3639 | 0 | if (!newline) { |
3640 | 0 | resolv_conf_parse_line(base, start, flags); |
3641 | 0 | break; |
3642 | 0 | } else { |
3643 | 0 | *newline = 0; |
3644 | 0 | resolv_conf_parse_line(base, start, flags); |
3645 | 0 | start = newline + 1; |
3646 | 0 | } |
3647 | 0 | } |
3648 | 0 |
|
3649 | 0 | if (!base->server_head && (flags & DNS_OPTION_NAMESERVERS)) { |
3650 | 0 | /* no nameservers were configured. */ |
3651 | 0 | evdns_base_nameserver_ip_add(base, "127.0.0.1"); |
3652 | 0 | err = 6; |
3653 | 0 | } |
3654 | 0 | if (flags & DNS_OPTION_SEARCH && (!base->global_search_state || base->global_search_state->num_domains == 0)) { |
3655 | 0 | search_set_from_hostname(base); |
3656 | 0 | } |
3657 | 0 |
|
3658 | 0 | mm_free(resolv); |
3659 | 0 | return err; |
3660 | 0 | } |
3661 | | |
3662 | | int |
3663 | 0 | evdns_resolv_conf_parse(int flags, const char *const filename) { |
3664 | 0 | if (!current_base) |
3665 | 0 | current_base = evdns_base_new(NULL, 0); |
3666 | 0 | return evdns_base_resolv_conf_parse(current_base, flags, filename); |
3667 | 0 | } |
3668 | | |
3669 | | |
3670 | | #ifdef _WIN32 |
3671 | | /* Add multiple nameservers from a space-or-comma-separated list. */ |
3672 | | static int |
3673 | | evdns_nameserver_ip_add_line(struct evdns_base *base, const char *ips) { |
3674 | | const char *addr; |
3675 | | char *buf; |
3676 | | int r; |
3677 | | ASSERT_LOCKED(base); |
3678 | | while (*ips) { |
3679 | | while (isspace(*ips) || *ips == ',' || *ips == '\t') |
3680 | | ++ips; |
3681 | | addr = ips; |
3682 | | while (isdigit(*ips) || *ips == '.' || *ips == ':' || |
3683 | | *ips=='[' || *ips==']') |
3684 | | ++ips; |
3685 | | buf = mm_malloc(ips-addr+1); |
3686 | | if (!buf) return 4; |
3687 | | memcpy(buf, addr, ips-addr); |
3688 | | buf[ips-addr] = '\0'; |
3689 | | r = evdns_base_nameserver_ip_add(base, buf); |
3690 | | mm_free(buf); |
3691 | | if (r) return r; |
3692 | | } |
3693 | | return 0; |
3694 | | } |
3695 | | |
3696 | | typedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*); |
3697 | | |
3698 | | /* Use the windows GetNetworkParams interface in iphlpapi.dll to */ |
3699 | | /* figure out what our nameservers are. */ |
3700 | | static int |
3701 | | load_nameservers_with_getnetworkparams(struct evdns_base *base) |
3702 | | { |
3703 | | /* Based on MSDN examples and inspection of c-ares code. */ |
3704 | | FIXED_INFO *fixed; |
3705 | | HMODULE handle = 0; |
3706 | | ULONG size = sizeof(FIXED_INFO); |
3707 | | void *buf = NULL; |
3708 | | int status = 0, r, added_any; |
3709 | | IP_ADDR_STRING *ns; |
3710 | | GetNetworkParams_fn_t fn; |
3711 | | |
3712 | | ASSERT_LOCKED(base); |
3713 | | if (!(handle = evutil_load_windows_system_library_( |
3714 | | TEXT("iphlpapi.dll")))) { |
3715 | | log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll"); |
3716 | | status = -1; |
3717 | | goto done; |
3718 | | } |
3719 | | if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, "GetNetworkParams"))) { |
3720 | | log(EVDNS_LOG_WARN, "Could not get address of function."); |
3721 | | status = -1; |
3722 | | goto done; |
3723 | | } |
3724 | | |
3725 | | buf = mm_malloc(size); |
3726 | | if (!buf) { status = 4; goto done; } |
3727 | | fixed = buf; |
3728 | | r = fn(fixed, &size); |
3729 | | if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) { |
3730 | | status = -1; |
3731 | | goto done; |
3732 | | } |
3733 | | if (r != ERROR_SUCCESS) { |
3734 | | mm_free(buf); |
3735 | | buf = mm_malloc(size); |
3736 | | if (!buf) { status = 4; goto done; } |
3737 | | fixed = buf; |
3738 | | r = fn(fixed, &size); |
3739 | | if (r != ERROR_SUCCESS) { |
3740 | | log(EVDNS_LOG_DEBUG, "fn() failed."); |
3741 | | status = -1; |
3742 | | goto done; |
3743 | | } |
3744 | | } |
3745 | | |
3746 | | EVUTIL_ASSERT(fixed); |
3747 | | added_any = 0; |
3748 | | ns = &(fixed->DnsServerList); |
3749 | | while (ns) { |
3750 | | r = evdns_nameserver_ip_add_line(base, ns->IpAddress.String); |
3751 | | if (r) { |
3752 | | log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list,error: %d", |
3753 | | (ns->IpAddress.String),(int)GetLastError()); |
3754 | | status = r; |
3755 | | } else { |
3756 | | ++added_any; |
3757 | | log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String); |
3758 | | } |
3759 | | |
3760 | | ns = ns->Next; |
3761 | | } |
3762 | | |
3763 | | if (!added_any) { |
3764 | | log(EVDNS_LOG_DEBUG, "No nameservers added."); |
3765 | | if (status == 0) |
3766 | | status = -1; |
3767 | | } else { |
3768 | | status = 0; |
3769 | | } |
3770 | | |
3771 | | done: |
3772 | | if (buf) |
3773 | | mm_free(buf); |
3774 | | if (handle) |
3775 | | FreeLibrary(handle); |
3776 | | return status; |
3777 | | } |
3778 | | |
3779 | | static int |
3780 | | config_nameserver_from_reg_key(struct evdns_base *base, HKEY key, const TCHAR *subkey) |
3781 | | { |
3782 | | char *buf; |
3783 | | DWORD bufsz = 0, type = 0; |
3784 | | int status = 0; |
3785 | | |
3786 | | ASSERT_LOCKED(base); |
3787 | | if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz) |
3788 | | != ERROR_MORE_DATA) |
3789 | | return -1; |
3790 | | if (!(buf = mm_malloc(bufsz))) |
3791 | | return -1; |
3792 | | |
3793 | | if (RegQueryValueEx(key, subkey, 0, &type, (LPBYTE)buf, &bufsz) |
3794 | | == ERROR_SUCCESS && bufsz > 1) { |
3795 | | status = evdns_nameserver_ip_add_line(base,buf); |
3796 | | } |
3797 | | |
3798 | | mm_free(buf); |
3799 | | return status; |
3800 | | } |
3801 | | |
3802 | | #define SERVICES_KEY TEXT("System\\CurrentControlSet\\Services\\") |
3803 | | #define WIN_NS_9X_KEY SERVICES_KEY TEXT("VxD\\MSTCP") |
3804 | | #define WIN_NS_NT_KEY SERVICES_KEY TEXT("Tcpip\\Parameters") |
3805 | | |
3806 | | static int |
3807 | | load_nameservers_from_registry(struct evdns_base *base) |
3808 | | { |
3809 | | int found = 0; |
3810 | | int r; |
3811 | | #define TRY(k, name) \ |
3812 | | if (!found && config_nameserver_from_reg_key(base,k,TEXT(name)) == 0) { \ |
3813 | | log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \ |
3814 | | found = 1; \ |
3815 | | } else if (!found) { \ |
3816 | | log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \ |
3817 | | #k,#name); \ |
3818 | | } |
3819 | | |
3820 | | ASSERT_LOCKED(base); |
3821 | | |
3822 | | if (((int)GetVersion()) > 0) { /* NT */ |
3823 | | HKEY nt_key = 0, interfaces_key = 0; |
3824 | | |
3825 | | if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, |
3826 | | KEY_READ, &nt_key) != ERROR_SUCCESS) { |
3827 | | log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError()); |
3828 | | return -1; |
3829 | | } |
3830 | | r = RegOpenKeyEx(nt_key, TEXT("Interfaces"), 0, |
3831 | | KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, |
3832 | | &interfaces_key); |
3833 | | if (r != ERROR_SUCCESS) { |
3834 | | log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError()); |
3835 | | return -1; |
3836 | | } |
3837 | | TRY(nt_key, "NameServer"); |
3838 | | TRY(nt_key, "DhcpNameServer"); |
3839 | | TRY(interfaces_key, "NameServer"); |
3840 | | TRY(interfaces_key, "DhcpNameServer"); |
3841 | | RegCloseKey(interfaces_key); |
3842 | | RegCloseKey(nt_key); |
3843 | | } else { |
3844 | | HKEY win_key = 0; |
3845 | | if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0, |
3846 | | KEY_READ, &win_key) != ERROR_SUCCESS) { |
3847 | | log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError()); |
3848 | | return -1; |
3849 | | } |
3850 | | TRY(win_key, "NameServer"); |
3851 | | RegCloseKey(win_key); |
3852 | | } |
3853 | | |
3854 | | if (found == 0) { |
3855 | | log(EVDNS_LOG_WARN,"Didn't find any nameservers."); |
3856 | | } |
3857 | | |
3858 | | return found ? 0 : -1; |
3859 | | #undef TRY |
3860 | | } |
3861 | | |
3862 | | int |
3863 | | evdns_base_config_windows_nameservers(struct evdns_base *base) |
3864 | | { |
3865 | | int r; |
3866 | | char *fname; |
3867 | | if (base == NULL) |
3868 | | base = current_base; |
3869 | | if (base == NULL) |
3870 | | return -1; |
3871 | | EVDNS_LOCK(base); |
3872 | | fname = evdns_get_default_hosts_filename(); |
3873 | | log(EVDNS_LOG_DEBUG, "Loading hosts entries from %s", fname); |
3874 | | evdns_base_load_hosts(base, fname); |
3875 | | if (fname) |
3876 | | mm_free(fname); |
3877 | | |
3878 | | if (load_nameservers_with_getnetworkparams(base) == 0) { |
3879 | | EVDNS_UNLOCK(base); |
3880 | | return 0; |
3881 | | } |
3882 | | r = load_nameservers_from_registry(base); |
3883 | | |
3884 | | EVDNS_UNLOCK(base); |
3885 | | return r; |
3886 | | } |
3887 | | |
3888 | | int |
3889 | | evdns_config_windows_nameservers(void) |
3890 | | { |
3891 | | if (!current_base) { |
3892 | | current_base = evdns_base_new(NULL, 1); |
3893 | | return current_base == NULL ? -1 : 0; |
3894 | | } else { |
3895 | | return evdns_base_config_windows_nameservers(current_base); |
3896 | | } |
3897 | | } |
3898 | | #endif |
3899 | | |
3900 | | struct evdns_base * |
3901 | | evdns_base_new(struct event_base *event_base, int flags) |
3902 | 0 | { |
3903 | 0 | struct evdns_base *base; |
3904 | 0 |
|
3905 | 0 | if (evutil_secure_rng_init() < 0) { |
3906 | 0 | log(EVDNS_LOG_WARN, "Unable to seed random number generator; " |
3907 | 0 | "DNS can't run."); |
3908 | 0 | return NULL; |
3909 | 0 | } |
3910 | 0 |
|
3911 | 0 | /* Give the evutil library a hook into its evdns-enabled |
3912 | 0 | * functionality. We can't just call evdns_getaddrinfo directly or |
3913 | 0 | * else libevent-core will depend on libevent-extras. */ |
3914 | 0 | evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo); |
3915 | 0 | evutil_set_evdns_getaddrinfo_cancel_fn_(evdns_getaddrinfo_cancel); |
3916 | 0 |
|
3917 | 0 | base = mm_malloc(sizeof(struct evdns_base)); |
3918 | 0 | if (base == NULL) |
3919 | 0 | return (NULL); |
3920 | 0 | memset(base, 0, sizeof(struct evdns_base)); |
3921 | 0 | base->req_waiting_head = NULL; |
3922 | 0 |
|
3923 | 0 | EVTHREAD_ALLOC_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE); |
3924 | 0 | EVDNS_LOCK(base); |
3925 | 0 |
|
3926 | 0 | /* Set max requests inflight and allocate req_heads. */ |
3927 | 0 | base->req_heads = NULL; |
3928 | 0 |
|
3929 | 0 | evdns_base_set_max_requests_inflight(base, 64); |
3930 | 0 |
|
3931 | 0 | base->server_head = NULL; |
3932 | 0 | base->event_base = event_base; |
3933 | 0 | base->global_good_nameservers = base->global_requests_inflight = |
3934 | 0 | base->global_requests_waiting = 0; |
3935 | 0 |
|
3936 | 0 | base->global_timeout.tv_sec = 5; |
3937 | 0 | base->global_timeout.tv_usec = 0; |
3938 | 0 | base->global_max_reissues = 1; |
3939 | 0 | base->global_max_retransmits = 3; |
3940 | 0 | base->global_max_nameserver_timeout = 3; |
3941 | 0 | base->global_search_state = NULL; |
3942 | 0 | base->global_randomize_case = 1; |
3943 | 0 | base->global_getaddrinfo_allow_skew.tv_sec = 3; |
3944 | 0 | base->global_getaddrinfo_allow_skew.tv_usec = 0; |
3945 | 0 | base->global_nameserver_probe_initial_timeout.tv_sec = 10; |
3946 | 0 | base->global_nameserver_probe_initial_timeout.tv_usec = 0; |
3947 | 0 |
|
3948 | 0 | TAILQ_INIT(&base->hostsdb); |
3949 | 0 |
|
3950 | 0 | #define EVDNS_BASE_ALL_FLAGS (0x8001) |
3951 | 0 | if (flags & ~EVDNS_BASE_ALL_FLAGS) { |
3952 | 0 | flags = EVDNS_BASE_INITIALIZE_NAMESERVERS; |
3953 | 0 | log(EVDNS_LOG_WARN, |
3954 | 0 | "Unrecognized flag passed to evdns_base_new(). Assuming " |
3955 | 0 | "you meant EVDNS_BASE_INITIALIZE_NAMESERVERS."); |
3956 | 0 | } |
3957 | 0 | #undef EVDNS_BASE_ALL_FLAGS |
3958 | 0 |
|
3959 | 0 | if (flags & EVDNS_BASE_INITIALIZE_NAMESERVERS) { |
3960 | 0 | int r; |
3961 | | #ifdef _WIN32 |
3962 | | r = evdns_base_config_windows_nameservers(base); |
3963 | | #else |
3964 | 0 | r = evdns_base_resolv_conf_parse(base, DNS_OPTIONS_ALL, "/etc/resolv.conf"); |
3965 | 0 | #endif |
3966 | 0 | if (r == -1) { |
3967 | 0 | evdns_base_free_and_unlock(base, 0); |
3968 | 0 | return NULL; |
3969 | 0 | } |
3970 | 0 | } |
3971 | 0 | if (flags & EVDNS_BASE_DISABLE_WHEN_INACTIVE) { |
3972 | 0 | base->disable_when_inactive = 1; |
3973 | 0 | } |
3974 | 0 |
|
3975 | 0 | EVDNS_UNLOCK(base); |
3976 | 0 | return base; |
3977 | 0 | } |
3978 | | |
3979 | | int |
3980 | | evdns_init(void) |
3981 | 0 | { |
3982 | 0 | struct evdns_base *base = evdns_base_new(NULL, 1); |
3983 | 0 | if (base) { |
3984 | 0 | current_base = base; |
3985 | 0 | return 0; |
3986 | 0 | } else { |
3987 | 0 | return -1; |
3988 | 0 | } |
3989 | 0 | } |
3990 | | |
3991 | | const char * |
3992 | | evdns_err_to_string(int err) |
3993 | 0 | { |
3994 | 0 | switch (err) { |
3995 | 0 | case DNS_ERR_NONE: return "no error"; |
3996 | 0 | case DNS_ERR_FORMAT: return "misformatted query"; |
3997 | 0 | case DNS_ERR_SERVERFAILED: return "server failed"; |
3998 | 0 | case DNS_ERR_NOTEXIST: return "name does not exist"; |
3999 | 0 | case DNS_ERR_NOTIMPL: return "query not implemented"; |
4000 | 0 | case DNS_ERR_REFUSED: return "refused"; |
4001 | 0 |
|
4002 | 0 | case DNS_ERR_TRUNCATED: return "reply truncated or ill-formed"; |
4003 | 0 | case DNS_ERR_UNKNOWN: return "unknown"; |
4004 | 0 | case DNS_ERR_TIMEOUT: return "request timed out"; |
4005 | 0 | case DNS_ERR_SHUTDOWN: return "dns subsystem shut down"; |
4006 | 0 | case DNS_ERR_CANCEL: return "dns request canceled"; |
4007 | 0 | case DNS_ERR_NODATA: return "no records in the reply"; |
4008 | 0 | default: return "[Unknown error code]"; |
4009 | 0 | } |
4010 | 0 | } |
4011 | | |
4012 | | static void |
4013 | | evdns_nameserver_free(struct nameserver *server) |
4014 | 0 | { |
4015 | 0 | if (server->socket >= 0) |
4016 | 0 | evutil_closesocket(server->socket); |
4017 | 0 | (void) event_del(&server->event); |
4018 | 0 | event_debug_unassign(&server->event); |
4019 | 0 | if (server->state == 0) |
4020 | 0 | (void) event_del(&server->timeout_event); |
4021 | 0 | if (server->probe_request) { |
4022 | 0 | evdns_cancel_request(server->base, server->probe_request); |
4023 | 0 | server->probe_request = NULL; |
4024 | 0 | } |
4025 | 0 | event_debug_unassign(&server->timeout_event); |
4026 | 0 | mm_free(server); |
4027 | 0 | } |
4028 | | |
4029 | | static void |
4030 | | evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests) |
4031 | 0 | { |
4032 | 0 | struct nameserver *server, *server_next; |
4033 | 0 | struct search_domain *dom, *dom_next; |
4034 | 0 | int i; |
4035 | 0 |
|
4036 | 0 | /* Requires that we hold the lock. */ |
4037 | 0 |
|
4038 | 0 | /* TODO(nickm) we might need to refcount here. */ |
4039 | 0 |
|
4040 | 0 | for (i = 0; i < base->n_req_heads; ++i) { |
4041 | 0 | while (base->req_heads[i]) { |
4042 | 0 | if (fail_requests) |
4043 | 0 | reply_schedule_callback(base->req_heads[i], 0, DNS_ERR_SHUTDOWN, NULL); |
4044 | 0 | request_finished(base->req_heads[i], &REQ_HEAD(base, base->req_heads[i]->trans_id), 1); |
4045 | 0 | } |
4046 | 0 | } |
4047 | 0 | while (base->req_waiting_head) { |
4048 | 0 | if (fail_requests) |
4049 | 0 | reply_schedule_callback(base->req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL); |
4050 | 0 | request_finished(base->req_waiting_head, &base->req_waiting_head, 1); |
4051 | 0 | } |
4052 | 0 | base->global_requests_inflight = base->global_requests_waiting = 0; |
4053 | 0 |
|
4054 | 0 | for (server = base->server_head; server; server = server_next) { |
4055 | 0 | server_next = server->next; |
4056 | 0 | /** already done something before */ |
4057 | 0 | server->probe_request = NULL; |
4058 | 0 | evdns_nameserver_free(server); |
4059 | 0 | if (server_next == base->server_head) |
4060 | 0 | break; |
4061 | 0 | } |
4062 | 0 | base->server_head = NULL; |
4063 | 0 | base->global_good_nameservers = 0; |
4064 | 0 |
|
4065 | 0 | if (base->global_search_state) { |
4066 | 0 | for (dom = base->global_search_state->head; dom; dom = dom_next) { |
4067 | 0 | dom_next = dom->next; |
4068 | 0 | mm_free(dom); |
4069 | 0 | } |
4070 | 0 | mm_free(base->global_search_state); |
4071 | 0 | base->global_search_state = NULL; |
4072 | 0 | } |
4073 | 0 |
|
4074 | 0 | { |
4075 | 0 | struct hosts_entry *victim; |
4076 | 0 | while ((victim = TAILQ_FIRST(&base->hostsdb))) { |
4077 | 0 | TAILQ_REMOVE(&base->hostsdb, victim, next); |
4078 | 0 | mm_free(victim); |
4079 | 0 | } |
4080 | 0 | } |
4081 | 0 |
|
4082 | 0 | mm_free(base->req_heads); |
4083 | 0 |
|
4084 | 0 | EVDNS_UNLOCK(base); |
4085 | 0 | EVTHREAD_FREE_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE); |
4086 | 0 |
|
4087 | 0 | mm_free(base); |
4088 | 0 | } |
4089 | | |
4090 | | void |
4091 | | evdns_base_free(struct evdns_base *base, int fail_requests) |
4092 | 0 | { |
4093 | 0 | EVDNS_LOCK(base); |
4094 | 0 | evdns_base_free_and_unlock(base, fail_requests); |
4095 | 0 | } |
4096 | | |
4097 | | void |
4098 | | evdns_base_clear_host_addresses(struct evdns_base *base) |
4099 | 0 | { |
4100 | 0 | struct hosts_entry *victim; |
4101 | 0 | EVDNS_LOCK(base); |
4102 | 0 | while ((victim = TAILQ_FIRST(&base->hostsdb))) { |
4103 | 0 | TAILQ_REMOVE(&base->hostsdb, victim, next); |
4104 | 0 | mm_free(victim); |
4105 | 0 | } |
4106 | 0 | EVDNS_UNLOCK(base); |
4107 | 0 | } |
4108 | | |
4109 | | void |
4110 | | evdns_shutdown(int fail_requests) |
4111 | 0 | { |
4112 | 0 | if (current_base) { |
4113 | 0 | struct evdns_base *b = current_base; |
4114 | 0 | current_base = NULL; |
4115 | 0 | evdns_base_free(b, fail_requests); |
4116 | 0 | } |
4117 | 0 | evdns_log_fn = NULL; |
4118 | 0 | } |
4119 | | |
4120 | | static int |
4121 | | evdns_base_parse_hosts_line(struct evdns_base *base, char *line) |
4122 | 0 | { |
4123 | 0 | char *strtok_state; |
4124 | 0 | static const char *const delims = " \t"; |
4125 | 0 | char *const addr = strtok_r(line, delims, &strtok_state); |
4126 | 0 | char *hostname, *hash; |
4127 | 0 | struct sockaddr_storage ss; |
4128 | 0 | int socklen = sizeof(ss); |
4129 | 0 | ASSERT_LOCKED(base); |
4130 | 0 |
|
4131 | 0 | #define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state) |
4132 | 0 |
|
4133 | 0 | if (!addr || *addr == '#') |
4134 | 0 | return 0; |
4135 | 0 | |
4136 | 0 | memset(&ss, 0, sizeof(ss)); |
4137 | 0 | if (evutil_parse_sockaddr_port(addr, (struct sockaddr*)&ss, &socklen)<0) |
4138 | 0 | return -1; |
4139 | 0 | if (socklen > (int)sizeof(struct sockaddr_in6)) |
4140 | 0 | return -1; |
4141 | 0 | |
4142 | 0 | if (sockaddr_getport((struct sockaddr*)&ss)) |
4143 | 0 | return -1; |
4144 | 0 | |
4145 | 0 | while ((hostname = NEXT_TOKEN)) { |
4146 | 0 | struct hosts_entry *he; |
4147 | 0 | size_t namelen; |
4148 | 0 | if ((hash = strchr(hostname, '#'))) { |
4149 | 0 | if (hash == hostname) |
4150 | 0 | return 0; |
4151 | 0 | *hash = '\0'; |
4152 | 0 | } |
4153 | 0 |
|
4154 | 0 | namelen = strlen(hostname); |
4155 | 0 |
|
4156 | 0 | he = mm_calloc(1, sizeof(struct hosts_entry)+namelen); |
4157 | 0 | if (!he) |
4158 | 0 | return -1; |
4159 | 0 | EVUTIL_ASSERT(socklen <= (int)sizeof(he->addr)); |
4160 | 0 | memcpy(&he->addr, &ss, socklen); |
4161 | 0 | memcpy(he->hostname, hostname, namelen+1); |
4162 | 0 | he->addrlen = socklen; |
4163 | 0 |
|
4164 | 0 | TAILQ_INSERT_TAIL(&base->hostsdb, he, next); |
4165 | 0 |
|
4166 | 0 | if (hash) |
4167 | 0 | return 0; |
4168 | 0 | } |
4169 | 0 |
|
4170 | 0 | return 0; |
4171 | 0 | #undef NEXT_TOKEN |
4172 | 0 | } |
4173 | | |
4174 | | static int |
4175 | | evdns_base_load_hosts_impl(struct evdns_base *base, const char *hosts_fname) |
4176 | 0 | { |
4177 | 0 | char *str=NULL, *cp, *eol; |
4178 | 0 | size_t len; |
4179 | 0 | int err=0; |
4180 | 0 |
|
4181 | 0 | ASSERT_LOCKED(base); |
4182 | 0 |
|
4183 | 0 | if (hosts_fname == NULL || |
4184 | 0 | (err = evutil_read_file_(hosts_fname, &str, &len, 0)) < 0) { |
4185 | 0 | char tmp[64]; |
4186 | 0 | strlcpy(tmp, "127.0.0.1 localhost", sizeof(tmp)); |
4187 | 0 | evdns_base_parse_hosts_line(base, tmp); |
4188 | 0 | strlcpy(tmp, "::1 localhost", sizeof(tmp)); |
4189 | 0 | evdns_base_parse_hosts_line(base, tmp); |
4190 | 0 | return err ? -1 : 0; |
4191 | 0 | } |
4192 | 0 |
|
4193 | 0 | /* This will break early if there is a NUL in the hosts file. |
4194 | 0 | * Probably not a problem.*/ |
4195 | 0 | cp = str; |
4196 | 0 | for (;;) { |
4197 | 0 | eol = strchr(cp, '\n'); |
4198 | 0 |
|
4199 | 0 | if (eol) { |
4200 | 0 | *eol = '\0'; |
4201 | 0 | evdns_base_parse_hosts_line(base, cp); |
4202 | 0 | cp = eol+1; |
4203 | 0 | } else { |
4204 | 0 | evdns_base_parse_hosts_line(base, cp); |
4205 | 0 | break; |
4206 | 0 | } |
4207 | 0 | } |
4208 | 0 |
|
4209 | 0 | mm_free(str); |
4210 | 0 | return 0; |
4211 | 0 | } |
4212 | | |
4213 | | int |
4214 | | evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname) |
4215 | 0 | { |
4216 | 0 | int res; |
4217 | 0 | if (!base) |
4218 | 0 | base = current_base; |
4219 | 0 | EVDNS_LOCK(base); |
4220 | 0 | res = evdns_base_load_hosts_impl(base, hosts_fname); |
4221 | 0 | EVDNS_UNLOCK(base); |
4222 | 0 | return res; |
4223 | 0 | } |
4224 | | |
4225 | | /* A single request for a getaddrinfo, either v4 or v6. */ |
4226 | | struct getaddrinfo_subrequest { |
4227 | | struct evdns_request *r; |
4228 | | ev_uint32_t type; |
4229 | | }; |
4230 | | |
4231 | | /* State data used to implement an in-progress getaddrinfo. */ |
4232 | | struct evdns_getaddrinfo_request { |
4233 | | struct evdns_base *evdns_base; |
4234 | | /* Copy of the modified 'hints' data that we'll use to build |
4235 | | * answers. */ |
4236 | | struct evutil_addrinfo hints; |
4237 | | /* The callback to invoke when we're done */ |
4238 | | evdns_getaddrinfo_cb user_cb; |
4239 | | /* User-supplied data to give to the callback. */ |
4240 | | void *user_data; |
4241 | | /* The port to use when building sockaddrs. */ |
4242 | | ev_uint16_t port; |
4243 | | /* The sub_request for an A record (if any) */ |
4244 | | struct getaddrinfo_subrequest ipv4_request; |
4245 | | /* The sub_request for an AAAA record (if any) */ |
4246 | | struct getaddrinfo_subrequest ipv6_request; |
4247 | | |
4248 | | /* The cname result that we were told (if any) */ |
4249 | | char *cname_result; |
4250 | | |
4251 | | /* If we have one request answered and one request still inflight, |
4252 | | * then this field holds the answer from the first request... */ |
4253 | | struct evutil_addrinfo *pending_result; |
4254 | | /* And this event is a timeout that will tell us to cancel the second |
4255 | | * request if it's taking a long time. */ |
4256 | | struct event timeout; |
4257 | | |
4258 | | /* And this field holds the error code from the first request... */ |
4259 | | int pending_error; |
4260 | | /* If this is set, the user canceled this request. */ |
4261 | | unsigned user_canceled : 1; |
4262 | | /* If this is set, the user can no longer cancel this request; we're |
4263 | | * just waiting for the free. */ |
4264 | | unsigned request_done : 1; |
4265 | | }; |
4266 | | |
4267 | | /* Convert an evdns errors to the equivalent getaddrinfo error. */ |
4268 | | static int |
4269 | | evdns_err_to_getaddrinfo_err(int e1) |
4270 | 0 | { |
4271 | 0 | /* XXX Do this better! */ |
4272 | 0 | if (e1 == DNS_ERR_NONE) |
4273 | 0 | return 0; |
4274 | 0 | else if (e1 == DNS_ERR_NOTEXIST) |
4275 | 0 | return EVUTIL_EAI_NONAME; |
4276 | 0 | else |
4277 | 0 | return EVUTIL_EAI_FAIL; |
4278 | 0 | } |
4279 | | |
4280 | | /* Return the more informative of two getaddrinfo errors. */ |
4281 | | static int |
4282 | | getaddrinfo_merge_err(int e1, int e2) |
4283 | 0 | { |
4284 | 0 | /* XXXX be cleverer here. */ |
4285 | 0 | if (e1 == 0) |
4286 | 0 | return e2; |
4287 | 0 | else |
4288 | 0 | return e1; |
4289 | 0 | } |
4290 | | |
4291 | | static void |
4292 | | free_getaddrinfo_request(struct evdns_getaddrinfo_request *data) |
4293 | 0 | { |
4294 | 0 | /* DO NOT CALL this if either of the requests is pending. Only once |
4295 | 0 | * both callbacks have been invoked is it safe to free the request */ |
4296 | 0 | if (data->pending_result) |
4297 | 0 | evutil_freeaddrinfo(data->pending_result); |
4298 | 0 | if (data->cname_result) |
4299 | 0 | mm_free(data->cname_result); |
4300 | 0 | event_del(&data->timeout); |
4301 | 0 | mm_free(data); |
4302 | 0 | return; |
4303 | 0 | } |
4304 | | |
4305 | | static void |
4306 | | add_cname_to_reply(struct evdns_getaddrinfo_request *data, |
4307 | | struct evutil_addrinfo *ai) |
4308 | 0 | { |
4309 | 0 | if (data->cname_result && ai) { |
4310 | 0 | ai->ai_canonname = data->cname_result; |
4311 | 0 | data->cname_result = NULL; |
4312 | 0 | } |
4313 | 0 | } |
4314 | | |
4315 | | /* Callback: invoked when one request in a mixed-format A/AAAA getaddrinfo |
4316 | | * request has finished, but the other one took too long to answer. Pass |
4317 | | * along the answer we got, and cancel the other request. |
4318 | | */ |
4319 | | static void |
4320 | | evdns_getaddrinfo_timeout_cb(evutil_socket_t fd, short what, void *ptr) |
4321 | 0 | { |
4322 | 0 | int v4_timedout = 0, v6_timedout = 0; |
4323 | 0 | struct evdns_getaddrinfo_request *data = ptr; |
4324 | 0 |
|
4325 | 0 | /* Cancel any pending requests, and note which one */ |
4326 | 0 | if (data->ipv4_request.r) { |
4327 | 0 | /* XXXX This does nothing if the request's callback is already |
4328 | 0 | * running (pending_cb is set). */ |
4329 | 0 | evdns_cancel_request(NULL, data->ipv4_request.r); |
4330 | 0 | v4_timedout = 1; |
4331 | 0 | EVDNS_LOCK(data->evdns_base); |
4332 | 0 | ++data->evdns_base->getaddrinfo_ipv4_timeouts; |
4333 | 0 | EVDNS_UNLOCK(data->evdns_base); |
4334 | 0 | } |
4335 | 0 | if (data->ipv6_request.r) { |
4336 | 0 | /* XXXX This does nothing if the request's callback is already |
4337 | 0 | * running (pending_cb is set). */ |
4338 | 0 | evdns_cancel_request(NULL, data->ipv6_request.r); |
4339 | 0 | v6_timedout = 1; |
4340 | 0 | EVDNS_LOCK(data->evdns_base); |
4341 | 0 | ++data->evdns_base->getaddrinfo_ipv6_timeouts; |
4342 | 0 | EVDNS_UNLOCK(data->evdns_base); |
4343 | 0 | } |
4344 | 0 |
|
4345 | 0 | /* We only use this timeout callback when we have an answer for |
4346 | 0 | * one address. */ |
4347 | 0 | EVUTIL_ASSERT(!v4_timedout || !v6_timedout); |
4348 | 0 |
|
4349 | 0 | /* Report the outcome of the other request that didn't time out. */ |
4350 | 0 | if (data->pending_result) { |
4351 | 0 | add_cname_to_reply(data, data->pending_result); |
4352 | 0 | data->user_cb(0, data->pending_result, data->user_data); |
4353 | 0 | data->pending_result = NULL; |
4354 | 0 | } else { |
4355 | 0 | int e = data->pending_error; |
4356 | 0 | if (!e) |
4357 | 0 | e = EVUTIL_EAI_AGAIN; |
4358 | 0 | data->user_cb(e, NULL, data->user_data); |
4359 | 0 | } |
4360 | 0 |
|
4361 | 0 | data->user_cb = NULL; /* prevent double-call if evdns callbacks are |
4362 | 0 | * in-progress. XXXX It would be better if this |
4363 | 0 | * weren't necessary. */ |
4364 | 0 |
|
4365 | 0 | if (!v4_timedout && !v6_timedout) { |
4366 | 0 | /* should be impossible? XXXX */ |
4367 | 0 | free_getaddrinfo_request(data); |
4368 | 0 | } |
4369 | 0 | } |
4370 | | |
4371 | | static int |
4372 | | evdns_getaddrinfo_set_timeout(struct evdns_base *evdns_base, |
4373 | | struct evdns_getaddrinfo_request *data) |
4374 | 0 | { |
4375 | 0 | return event_add(&data->timeout, &evdns_base->global_getaddrinfo_allow_skew); |
4376 | 0 | } |
4377 | | |
4378 | | static inline int |
4379 | | evdns_result_is_answer(int result) |
4380 | 0 | { |
4381 | 0 | return (result != DNS_ERR_NOTIMPL && result != DNS_ERR_REFUSED && |
4382 | 0 | result != DNS_ERR_SERVERFAILED && result != DNS_ERR_CANCEL); |
4383 | 0 | } |
4384 | | |
4385 | | static void |
4386 | | evdns_getaddrinfo_gotresolve(int result, char type, int count, |
4387 | | int ttl, void *addresses, void *arg) |
4388 | 0 | { |
4389 | 0 | int i; |
4390 | 0 | struct getaddrinfo_subrequest *req = arg; |
4391 | 0 | struct getaddrinfo_subrequest *other_req; |
4392 | 0 | struct evdns_getaddrinfo_request *data; |
4393 | 0 |
|
4394 | 0 | struct evutil_addrinfo *res; |
4395 | 0 |
|
4396 | 0 | struct sockaddr_in sin; |
4397 | 0 | struct sockaddr_in6 sin6; |
4398 | 0 | struct sockaddr *sa; |
4399 | 0 | int socklen, addrlen; |
4400 | 0 | void *addrp; |
4401 | 0 | int err; |
4402 | 0 | int user_canceled; |
4403 | 0 |
|
4404 | 0 | EVUTIL_ASSERT(req->type == DNS_IPv4_A || req->type == DNS_IPv6_AAAA); |
4405 | 0 | if (req->type == DNS_IPv4_A) { |
4406 | 0 | data = EVUTIL_UPCAST(req, struct evdns_getaddrinfo_request, ipv4_request); |
4407 | 0 | other_req = &data->ipv6_request; |
4408 | 0 | } else { |
4409 | 0 | data = EVUTIL_UPCAST(req, struct evdns_getaddrinfo_request, ipv6_request); |
4410 | 0 | other_req = &data->ipv4_request; |
4411 | 0 | } |
4412 | 0 |
|
4413 | 0 | /** Called from evdns_base_free() with @fail_requests == 1 */ |
4414 | 0 | if (result != DNS_ERR_SHUTDOWN) { |
4415 | 0 | EVDNS_LOCK(data->evdns_base); |
4416 | 0 | if (evdns_result_is_answer(result)) { |
4417 | 0 | if (req->type == DNS_IPv4_A) |
4418 | 0 | ++data->evdns_base->getaddrinfo_ipv4_answered; |
4419 | 0 | else |
4420 | 0 | ++data->evdns_base->getaddrinfo_ipv6_answered; |
4421 | 0 | } |
4422 | 0 | user_canceled = data->user_canceled; |
4423 | 0 | if (other_req->r == NULL) |
4424 | 0 | data->request_done = 1; |
4425 | 0 | EVDNS_UNLOCK(data->evdns_base); |
4426 | 0 | } else { |
4427 | 0 | data->evdns_base = NULL; |
4428 | 0 | user_canceled = data->user_canceled; |
4429 | 0 | } |
4430 | 0 |
|
4431 | 0 | req->r = NULL; |
4432 | 0 |
|
4433 | 0 | if (result == DNS_ERR_CANCEL && ! user_canceled) { |
4434 | 0 | /* Internal cancel request from timeout or internal error. |
4435 | 0 | * we already answered the user. */ |
4436 | 0 | if (other_req->r == NULL) |
4437 | 0 | free_getaddrinfo_request(data); |
4438 | 0 | return; |
4439 | 0 | } |
4440 | 0 |
|
4441 | 0 | if (data->user_cb == NULL) { |
4442 | 0 | /* We already answered. XXXX This shouldn't be needed; see |
4443 | 0 | * comments in evdns_getaddrinfo_timeout_cb */ |
4444 | 0 | free_getaddrinfo_request(data); |
4445 | 0 | return; |
4446 | 0 | } |
4447 | 0 | |
4448 | 0 | if (result == DNS_ERR_NONE) { |
4449 | 0 | if (count == 0) |
4450 | 0 | err = EVUTIL_EAI_NODATA; |
4451 | 0 | else |
4452 | 0 | err = 0; |
4453 | 0 | } else { |
4454 | 0 | err = evdns_err_to_getaddrinfo_err(result); |
4455 | 0 | } |
4456 | 0 |
|
4457 | 0 | if (err) { |
4458 | 0 | /* Looks like we got an error. */ |
4459 | 0 | if (other_req->r) { |
4460 | 0 | /* The other request is still working; maybe it will |
4461 | 0 | * succeed. */ |
4462 | 0 | /* XXXX handle failure from set_timeout */ |
4463 | 0 | if (result != DNS_ERR_SHUTDOWN) { |
4464 | 0 | evdns_getaddrinfo_set_timeout(data->evdns_base, data); |
4465 | 0 | } |
4466 | 0 | data->pending_error = err; |
4467 | 0 | return; |
4468 | 0 | } |
4469 | 0 |
|
4470 | 0 | if (user_canceled) { |
4471 | 0 | data->user_cb(EVUTIL_EAI_CANCEL, NULL, data->user_data); |
4472 | 0 | } else if (data->pending_result) { |
4473 | 0 | /* If we have an answer waiting, and we weren't |
4474 | 0 | * canceled, ignore this error. */ |
4475 | 0 | add_cname_to_reply(data, data->pending_result); |
4476 | 0 | data->user_cb(0, data->pending_result, data->user_data); |
4477 | 0 | data->pending_result = NULL; |
4478 | 0 | } else { |
4479 | 0 | if (data->pending_error) |
4480 | 0 | err = getaddrinfo_merge_err(err, |
4481 | 0 | data->pending_error); |
4482 | 0 | data->user_cb(err, NULL, data->user_data); |
4483 | 0 | } |
4484 | 0 | free_getaddrinfo_request(data); |
4485 | 0 | return; |
4486 | 0 | } else if (user_canceled) { |
4487 | 0 | if (other_req->r) { |
4488 | 0 | /* The other request is still working; let it hit this |
4489 | 0 | * callback with EVUTIL_EAI_CANCEL callback and report |
4490 | 0 | * the failure. */ |
4491 | 0 | return; |
4492 | 0 | } |
4493 | 0 | data->user_cb(EVUTIL_EAI_CANCEL, NULL, data->user_data); |
4494 | 0 | free_getaddrinfo_request(data); |
4495 | 0 | return; |
4496 | 0 | } |
4497 | 0 |
|
4498 | 0 | /* Looks like we got some answers. We should turn them into addrinfos |
4499 | 0 | * and then either queue those or return them all. */ |
4500 | 0 | EVUTIL_ASSERT(type == DNS_IPv4_A || type == DNS_IPv6_AAAA); |
4501 | 0 |
|
4502 | 0 | if (type == DNS_IPv4_A) { |
4503 | 0 | memset(&sin, 0, sizeof(sin)); |
4504 | 0 | sin.sin_family = AF_INET; |
4505 | 0 | sin.sin_port = htons(data->port); |
4506 | 0 |
|
4507 | 0 | sa = (struct sockaddr *)&sin; |
4508 | 0 | socklen = sizeof(sin); |
4509 | 0 | addrlen = 4; |
4510 | 0 | addrp = &sin.sin_addr.s_addr; |
4511 | 0 | } else { |
4512 | 0 | memset(&sin6, 0, sizeof(sin6)); |
4513 | 0 | sin6.sin6_family = AF_INET6; |
4514 | 0 | sin6.sin6_port = htons(data->port); |
4515 | 0 |
|
4516 | 0 | sa = (struct sockaddr *)&sin6; |
4517 | 0 | socklen = sizeof(sin6); |
4518 | 0 | addrlen = 16; |
4519 | 0 | addrp = &sin6.sin6_addr.s6_addr; |
4520 | 0 | } |
4521 | 0 |
|
4522 | 0 | res = NULL; |
4523 | 0 | for (i=0; i < count; ++i) { |
4524 | 0 | struct evutil_addrinfo *ai; |
4525 | 0 | memcpy(addrp, ((char*)addresses)+i*addrlen, addrlen); |
4526 | 0 | ai = evutil_new_addrinfo_(sa, socklen, &data->hints); |
4527 | 0 | if (!ai) { |
4528 | 0 | if (other_req->r) { |
4529 | 0 | evdns_cancel_request(NULL, other_req->r); |
4530 | 0 | } |
4531 | 0 | data->user_cb(EVUTIL_EAI_MEMORY, NULL, data->user_data); |
4532 | 0 | if (res) |
4533 | 0 | evutil_freeaddrinfo(res); |
4534 | 0 |
|
4535 | 0 | if (other_req->r == NULL) |
4536 | 0 | free_getaddrinfo_request(data); |
4537 | 0 | return; |
4538 | 0 | } |
4539 | 0 | res = evutil_addrinfo_append_(res, ai); |
4540 | 0 | } |
4541 | 0 |
|
4542 | 0 | if (other_req->r) { |
4543 | 0 | /* The other request is still in progress; wait for it */ |
4544 | 0 | /* XXXX handle failure from set_timeout */ |
4545 | 0 | evdns_getaddrinfo_set_timeout(data->evdns_base, data); |
4546 | 0 | data->pending_result = res; |
4547 | 0 | return; |
4548 | 0 | } else { |
4549 | 0 | /* The other request is done or never started; append its |
4550 | 0 | * results (if any) and return them. */ |
4551 | 0 | if (data->pending_result) { |
4552 | 0 | if (req->type == DNS_IPv4_A) |
4553 | 0 | res = evutil_addrinfo_append_(res, |
4554 | 0 | data->pending_result); |
4555 | 0 | else |
4556 | 0 | res = evutil_addrinfo_append_( |
4557 | 0 | data->pending_result, res); |
4558 | 0 | data->pending_result = NULL; |
4559 | 0 | } |
4560 | 0 |
|
4561 | 0 | /* Call the user callback. */ |
4562 | 0 | add_cname_to_reply(data, res); |
4563 | 0 | data->user_cb(0, res, data->user_data); |
4564 | 0 |
|
4565 | 0 | /* Free data. */ |
4566 | 0 | free_getaddrinfo_request(data); |
4567 | 0 | } |
4568 | 0 | } |
4569 | | |
4570 | | static struct hosts_entry * |
4571 | | find_hosts_entry(struct evdns_base *base, const char *hostname, |
4572 | | struct hosts_entry *find_after) |
4573 | 0 | { |
4574 | 0 | struct hosts_entry *e; |
4575 | 0 |
|
4576 | 0 | if (find_after) |
4577 | 0 | e = TAILQ_NEXT(find_after, next); |
4578 | 0 | else |
4579 | 0 | e = TAILQ_FIRST(&base->hostsdb); |
4580 | 0 |
|
4581 | 0 | for (; e; e = TAILQ_NEXT(e, next)) { |
4582 | 0 | if (!evutil_ascii_strcasecmp(e->hostname, hostname)) |
4583 | 0 | return e; |
4584 | 0 | } |
4585 | 0 | return NULL; |
4586 | 0 | } |
4587 | | |
4588 | | static int |
4589 | | evdns_getaddrinfo_fromhosts(struct evdns_base *base, |
4590 | | const char *nodename, struct evutil_addrinfo *hints, ev_uint16_t port, |
4591 | | struct evutil_addrinfo **res) |
4592 | 0 | { |
4593 | 0 | int n_found = 0; |
4594 | 0 | struct hosts_entry *e; |
4595 | 0 | struct evutil_addrinfo *ai=NULL; |
4596 | 0 | int f = hints->ai_family; |
4597 | 0 |
|
4598 | 0 | EVDNS_LOCK(base); |
4599 | 0 | for (e = find_hosts_entry(base, nodename, NULL); e; |
4600 | 0 | e = find_hosts_entry(base, nodename, e)) { |
4601 | 0 | struct evutil_addrinfo *ai_new; |
4602 | 0 | ++n_found; |
4603 | 0 | if ((e->addr.sa.sa_family == AF_INET && f == PF_INET6) || |
4604 | 0 | (e->addr.sa.sa_family == AF_INET6 && f == PF_INET)) |
4605 | 0 | continue; |
4606 | 0 | ai_new = evutil_new_addrinfo_(&e->addr.sa, e->addrlen, hints); |
4607 | 0 | if (!ai_new) { |
4608 | 0 | n_found = 0; |
4609 | 0 | goto out; |
4610 | 0 | } |
4611 | 0 | sockaddr_setport(ai_new->ai_addr, port); |
4612 | 0 | ai = evutil_addrinfo_append_(ai, ai_new); |
4613 | 0 | } |
4614 | 0 | EVDNS_UNLOCK(base); |
4615 | 0 | out: |
4616 | 0 | if (n_found) { |
4617 | 0 | /* Note that we return an empty answer if we found entries for |
4618 | 0 | * this hostname but none were of the right address type. */ |
4619 | 0 | *res = ai; |
4620 | 0 | return 0; |
4621 | 0 | } else { |
4622 | 0 | if (ai) |
4623 | 0 | evutil_freeaddrinfo(ai); |
4624 | 0 | return -1; |
4625 | 0 | } |
4626 | 0 | } |
4627 | | |
4628 | | struct evdns_getaddrinfo_request * |
4629 | | evdns_getaddrinfo(struct evdns_base *dns_base, |
4630 | | const char *nodename, const char *servname, |
4631 | | const struct evutil_addrinfo *hints_in, |
4632 | | evdns_getaddrinfo_cb cb, void *arg) |
4633 | 0 | { |
4634 | 0 | struct evdns_getaddrinfo_request *data; |
4635 | 0 | struct evutil_addrinfo hints; |
4636 | 0 | struct evutil_addrinfo *res = NULL; |
4637 | 0 | int err; |
4638 | 0 | int port = 0; |
4639 | 0 | int want_cname = 0; |
4640 | 0 | int started = 0; |
4641 | 0 |
|
4642 | 0 | if (!dns_base) { |
4643 | 0 | dns_base = current_base; |
4644 | 0 | if (!dns_base) { |
4645 | 0 | log(EVDNS_LOG_WARN, |
4646 | 0 | "Call to getaddrinfo_async with no " |
4647 | 0 | "evdns_base configured."); |
4648 | 0 | cb(EVUTIL_EAI_FAIL, NULL, arg); /* ??? better error? */ |
4649 | 0 | return NULL; |
4650 | 0 | } |
4651 | 0 | } |
4652 | 0 |
|
4653 | 0 | /* If we _must_ answer this immediately, do so. */ |
4654 | 0 | if ((hints_in && (hints_in->ai_flags & EVUTIL_AI_NUMERICHOST))) { |
4655 | 0 | res = NULL; |
4656 | 0 | err = evutil_getaddrinfo(nodename, servname, hints_in, &res); |
4657 | 0 | cb(err, res, arg); |
4658 | 0 | return NULL; |
4659 | 0 | } |
4660 | 0 | |
4661 | 0 | if (hints_in) { |
4662 | 0 | memcpy(&hints, hints_in, sizeof(hints)); |
4663 | 0 | } else { |
4664 | 0 | memset(&hints, 0, sizeof(hints)); |
4665 | 0 | hints.ai_family = PF_UNSPEC; |
4666 | 0 | } |
4667 | 0 |
|
4668 | 0 | evutil_adjust_hints_for_addrconfig_(&hints); |
4669 | 0 |
|
4670 | 0 | /* Now try to see if we _can_ answer immediately. */ |
4671 | 0 | /* (It would be nice to do this by calling getaddrinfo directly, with |
4672 | 0 | * AI_NUMERICHOST, on plaforms that have it, but we can't: there isn't |
4673 | 0 | * a reliable way to distinguish the "that wasn't a numeric host!" case |
4674 | 0 | * from any other EAI_NONAME cases.) */ |
4675 | 0 | err = evutil_getaddrinfo_common_(nodename, servname, &hints, &res, &port); |
4676 | 0 | if (err != EVUTIL_EAI_NEED_RESOLVE) { |
4677 | 0 | cb(err, res, arg); |
4678 | 0 | return NULL; |
4679 | 0 | } |
4680 | 0 | |
4681 | 0 | /* If there is an entry in the hosts file, we should give it now. */ |
4682 | 0 | if (!evdns_getaddrinfo_fromhosts(dns_base, nodename, &hints, port, &res)) { |
4683 | 0 | cb(0, res, arg); |
4684 | 0 | return NULL; |
4685 | 0 | } |
4686 | 0 | |
4687 | 0 | /* Okay, things are serious now. We're going to need to actually |
4688 | 0 | * launch a request. |
4689 | 0 | */ |
4690 | 0 | data = mm_calloc(1,sizeof(struct evdns_getaddrinfo_request)); |
4691 | 0 | if (!data) { |
4692 | 0 | cb(EVUTIL_EAI_MEMORY, NULL, arg); |
4693 | 0 | return NULL; |
4694 | 0 | } |
4695 | 0 |
|
4696 | 0 | memcpy(&data->hints, &hints, sizeof(data->hints)); |
4697 | 0 | data->port = (ev_uint16_t)port; |
4698 | 0 | data->ipv4_request.type = DNS_IPv4_A; |
4699 | 0 | data->ipv6_request.type = DNS_IPv6_AAAA; |
4700 | 0 | data->user_cb = cb; |
4701 | 0 | data->user_data = arg; |
4702 | 0 | data->evdns_base = dns_base; |
4703 | 0 |
|
4704 | 0 | want_cname = (hints.ai_flags & EVUTIL_AI_CANONNAME); |
4705 | 0 |
|
4706 | 0 | /* If we are asked for a PF_UNSPEC address, we launch two requests in |
4707 | 0 | * parallel: one for an A address and one for an AAAA address. We |
4708 | 0 | * can't send just one request, since many servers only answer one |
4709 | 0 | * question per DNS request. |
4710 | 0 | * |
4711 | 0 | * Once we have the answer to one request, we allow for a short |
4712 | 0 | * timeout before we report it, to see if the other one arrives. If |
4713 | 0 | * they both show up in time, then we report both the answers. |
4714 | 0 | * |
4715 | 0 | * If too many addresses of one type time out or fail, we should stop |
4716 | 0 | * launching those requests. (XXX we don't do that yet.) |
4717 | 0 | */ |
4718 | 0 |
|
4719 | 0 | EVDNS_LOCK(dns_base); |
4720 | 0 |
|
4721 | 0 | if (hints.ai_family != PF_INET6) { |
4722 | 0 | log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv4 as %p", |
4723 | 0 | nodename, &data->ipv4_request); |
4724 | 0 |
|
4725 | 0 | data->ipv4_request.r = evdns_base_resolve_ipv4(dns_base, |
4726 | 0 | nodename, 0, evdns_getaddrinfo_gotresolve, |
4727 | 0 | &data->ipv4_request); |
4728 | 0 | if (want_cname && data->ipv4_request.r) |
4729 | 0 | data->ipv4_request.r->current_req->put_cname_in_ptr = |
4730 | 0 | &data->cname_result; |
4731 | 0 | } |
4732 | 0 | if (hints.ai_family != PF_INET) { |
4733 | 0 | log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv6 as %p", |
4734 | 0 | nodename, &data->ipv6_request); |
4735 | 0 |
|
4736 | 0 | data->ipv6_request.r = evdns_base_resolve_ipv6(dns_base, |
4737 | 0 | nodename, 0, evdns_getaddrinfo_gotresolve, |
4738 | 0 | &data->ipv6_request); |
4739 | 0 | if (want_cname && data->ipv6_request.r) |
4740 | 0 | data->ipv6_request.r->current_req->put_cname_in_ptr = |
4741 | 0 | &data->cname_result; |
4742 | 0 | } |
4743 | 0 |
|
4744 | 0 | evtimer_assign(&data->timeout, dns_base->event_base, |
4745 | 0 | evdns_getaddrinfo_timeout_cb, data); |
4746 | 0 |
|
4747 | 0 | started = (data->ipv4_request.r || data->ipv6_request.r); |
4748 | 0 |
|
4749 | 0 | EVDNS_UNLOCK(dns_base); |
4750 | 0 |
|
4751 | 0 | if (started) { |
4752 | 0 | return data; |
4753 | 0 | } else { |
4754 | 0 | mm_free(data); |
4755 | 0 | cb(EVUTIL_EAI_FAIL, NULL, arg); |
4756 | 0 | return NULL; |
4757 | 0 | } |
4758 | 0 | } |
4759 | | |
4760 | | void |
4761 | | evdns_getaddrinfo_cancel(struct evdns_getaddrinfo_request *data) |
4762 | 0 | { |
4763 | 0 | EVDNS_LOCK(data->evdns_base); |
4764 | 0 | if (data->request_done) { |
4765 | 0 | EVDNS_UNLOCK(data->evdns_base); |
4766 | 0 | return; |
4767 | 0 | } |
4768 | 0 | event_del(&data->timeout); |
4769 | 0 | data->user_canceled = 1; |
4770 | 0 | if (data->ipv4_request.r) |
4771 | 0 | evdns_cancel_request(data->evdns_base, data->ipv4_request.r); |
4772 | 0 | if (data->ipv6_request.r) |
4773 | 0 | evdns_cancel_request(data->evdns_base, data->ipv6_request.r); |
4774 | 0 | EVDNS_UNLOCK(data->evdns_base); |
4775 | 0 | } |