1 | #define DNS_USE_GETTIMEOFDAY_FOR_ID 1 |
|
|
2 | #define HAVE_STRUCT_IN6_ADDR 1 |
|
|
3 | |
|
|
4 | /* The original version of this module was written by Adam Langley; for |
|
|
5 | * a history of modifications, check out the subversion logs. |
|
|
6 | * |
|
|
7 | * When editing this module, try to keep it re-mergeable by Adam. Don't |
|
|
8 | * reformat the whitespace, add Tor dependencies, or so on. |
|
|
9 | * |
|
|
10 | * TODO: |
|
|
11 | * - Support IPv6 and PTR records. |
|
|
12 | * - Replace all externally visible magic numbers with #defined constants. |
|
|
13 | * - Write doccumentation for APIs of all external functions. |
|
|
14 | */ |
|
|
15 | |
|
|
16 | /* Async DNS Library |
|
|
17 | * Adam Langley <agl@imperialviolet.org> |
|
|
18 | * http://www.imperialviolet.org/eventdns.html |
|
|
19 | * Public Domain code |
|
|
20 | * |
|
|
21 | * This software is Public Domain. To view a copy of the public domain dedication, |
|
|
22 | * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to |
|
|
23 | * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. |
|
|
24 | * |
|
|
25 | * I ask and expect, but do not require, that all derivative works contain an |
|
|
26 | * attribution similar to: |
|
|
27 | * Parts developed by Adam Langley <agl@imperialviolet.org> |
|
|
28 | * |
|
|
29 | * You may wish to replace the word "Parts" with something else depending on |
|
|
30 | * the amount of original code. |
|
|
31 | * |
|
|
32 | * (Derivative works does not include programs which link against, run or include |
|
|
33 | * the source verbatim in their source distributions) |
|
|
34 | * |
|
|
35 | * Version: 0.1b |
|
|
36 | */ |
|
|
37 | |
|
|
38 | #include <sys/types.h> |
|
|
39 | #ifdef HAVE_CONFIG_H |
|
|
40 | #include "config.h" |
|
|
41 | #endif |
|
|
42 | |
|
|
43 | #ifdef WIN32 |
|
|
44 | #include "misc.h" |
|
|
45 | #endif |
|
|
46 | |
|
|
47 | /* #define NDEBUG */ |
|
|
48 | |
|
|
49 | #ifndef DNS_USE_CPU_CLOCK_FOR_ID |
|
|
50 | #ifndef DNS_USE_GETTIMEOFDAY_FOR_ID |
|
|
51 | #ifndef DNS_USE_OPENSSL_FOR_ID |
|
|
52 | #error Must configure at least one id generation method. |
|
|
53 | #error Please see the documentation. |
|
|
54 | #endif |
|
|
55 | #endif |
|
|
56 | #endif |
|
|
57 | |
|
|
58 | /* #define _POSIX_C_SOURCE 200507 */ |
|
|
59 | #define _GNU_SOURCE |
|
|
60 | |
|
|
61 | #ifdef DNS_USE_CPU_CLOCK_FOR_ID |
|
|
62 | #ifdef DNS_USE_OPENSSL_FOR_ID |
|
|
63 | #error Multiple id options selected |
|
|
64 | #endif |
|
|
65 | #ifdef DNS_USE_GETTIMEOFDAY_FOR_ID |
|
|
66 | #error Multiple id options selected |
|
|
67 | #endif |
|
|
68 | #include <time.h> |
|
|
69 | #endif |
|
|
70 | |
|
|
71 | #ifdef DNS_USE_OPENSSL_FOR_ID |
|
|
72 | #ifdef DNS_USE_GETTIMEOFDAY_FOR_ID |
|
|
73 | #error Multiple id options selected |
|
|
74 | #endif |
|
|
75 | #include <openssl/rand.h> |
|
|
76 | #endif |
|
|
77 | |
|
|
78 | #define _FORTIFY_SOURCE 3 |
|
|
79 | |
|
|
80 | #include <string.h> |
|
|
81 | #include <fcntl.h> |
|
|
82 | #include <sys/time.h> |
|
|
83 | #ifdef HAVE_STDINT_H |
|
|
84 | #include <stdint.h> |
|
|
85 | #endif |
|
|
86 | #include <stdlib.h> |
|
|
87 | #include <string.h> |
|
|
88 | #include <errno.h> |
|
|
89 | #include <assert.h> |
|
|
90 | #include <unistd.h> |
|
|
91 | #include <limits.h> |
|
|
92 | #include <sys/stat.h> |
|
|
93 | #include <ctype.h> |
|
|
94 | #include <stdio.h> |
|
|
95 | #include <stdarg.h> |
|
|
96 | |
|
|
97 | #include "evdns.h" |
|
|
98 | #ifdef WIN32 |
|
|
99 | #include <windows.h> |
|
|
100 | #include <winsock2.h> |
|
|
101 | #include <iphlpapi.h> |
|
|
102 | #else |
|
|
103 | #include <sys/socket.h> |
|
|
104 | #include <netinet/in.h> |
|
|
105 | #include <arpa/inet.h> |
|
|
106 | #endif |
|
|
107 | |
|
|
108 | #ifdef HAVE_NETINET_IN6_H |
|
|
109 | #include <netinet/in6.h> |
|
|
110 | #endif |
|
|
111 | |
|
|
112 | #ifdef WIN32 |
|
|
113 | typedef int socklen_t; |
|
|
114 | #endif |
|
|
115 | |
|
|
116 | #define EVDNS_LOG_DEBUG 0 |
|
|
117 | #define EVDNS_LOG_WARN 1 |
|
|
118 | |
|
|
119 | #ifndef HOST_NAME_MAX |
|
|
120 | #define HOST_NAME_MAX 255 |
|
|
121 | #endif |
|
|
122 | |
|
|
123 | #ifndef NDEBUG |
|
|
124 | #include <stdio.h> |
|
|
125 | #endif |
|
|
126 | |
|
|
127 | #undef MIN |
|
|
128 | #define MIN(a,b) ((a)<(b)?(a):(b)) |
|
|
129 | |
|
|
130 | #ifdef __USE_ISOC99B |
|
|
131 | /* libevent doesn't work without this */ |
|
|
132 | typedef uint8_t u_char; |
|
|
133 | typedef unsigned int uint; |
|
|
134 | #endif |
|
|
135 | #include <event.h> |
|
|
136 | |
|
|
137 | #define u64 uint64_t |
|
|
138 | #define u32 uint32_t |
|
|
139 | #define u16 uint16_t |
|
|
140 | #define u8 uint8_t |
|
|
141 | |
|
|
142 | #define MAX_ADDRS 4 /* maximum number of addresses from a single packet */ |
|
|
143 | /* which we bother recording */ |
|
|
144 | |
|
|
145 | #define TYPE_A EVDNS_TYPE_A |
|
|
146 | #define TYPE_CNAME 5 |
|
|
147 | #define TYPE_PTR EVDNS_TYPE_PTR |
|
|
148 | #define TYPE_AAAA EVDNS_TYPE_AAAA |
|
|
149 | |
|
|
150 | #define CLASS_INET EVDNS_CLASS_INET |
|
|
151 | |
|
|
152 | struct request { |
|
|
153 | u8 *request; /* the dns packet data */ |
|
|
154 | unsigned int request_len; |
|
|
155 | int reissue_count; |
|
|
156 | int tx_count; /* the number of times that this packet has been sent */ |
|
|
157 | unsigned int request_type; /* TYPE_PTR or TYPE_A */ |
|
|
158 | void *user_pointer; /* the pointer given to us for this request */ |
|
|
159 | evdns_callback_type user_callback; |
|
|
160 | struct nameserver *ns; /* the server which we last sent it */ |
|
|
161 | |
|
|
162 | /* elements used by the searching code */ |
|
|
163 | int search_index; |
|
|
164 | struct search_state *search_state; |
|
|
165 | char *search_origname; /* needs to be free()ed */ |
|
|
166 | int search_flags; |
|
|
167 | |
|
|
168 | /* these objects are kept in a circular list */ |
|
|
169 | struct request *next, *prev; |
|
|
170 | |
|
|
171 | struct event timeout_event; |
|
|
172 | |
|
|
173 | u16 trans_id; /* the transaction id */ |
|
|
174 | char request_appended; /* true if the request pointer is data which follows this struct */ |
|
|
175 | char transmit_me; /* needs to be transmitted */ |
|
|
176 | }; |
|
|
177 | |
|
|
178 | #ifndef HAVE_STRUCT_IN6_ADDR |
|
|
179 | struct in6_addr { |
|
|
180 | u8 s6_addr[16]; |
|
|
181 | }; |
|
|
182 | #endif |
|
|
183 | |
|
|
184 | struct reply { |
|
|
185 | unsigned int type; |
|
|
186 | unsigned int have_answer; |
|
|
187 | union { |
|
|
188 | struct { |
|
|
189 | u32 addrcount; |
|
|
190 | u32 addresses[MAX_ADDRS]; |
|
|
191 | } a; |
|
|
192 | struct { |
|
|
193 | u32 addrcount; |
|
|
194 | struct in6_addr addresses[MAX_ADDRS]; |
|
|
195 | } aaaa; |
|
|
196 | struct { |
|
|
197 | char name[HOST_NAME_MAX]; |
|
|
198 | } ptr; |
|
|
199 | } data; |
|
|
200 | }; |
|
|
201 | |
|
|
202 | struct nameserver { |
|
|
203 | int socket; /* a connected UDP socket */ |
|
|
204 | u32 address; |
|
|
205 | int failed_times; /* number of times which we have given this server a chance */ |
|
|
206 | int timedout; /* number of times in a row a request has timed out */ |
|
|
207 | struct event event; |
|
|
208 | /* these objects are kept in a circular list */ |
|
|
209 | struct nameserver *next, *prev; |
|
|
210 | struct event timeout_event; /* used to keep the timeout for */ |
|
|
211 | /* when we next probe this server. */ |
|
|
212 | /* Valid if state == 0 */ |
|
|
213 | char state; /* zero if we think that this server is down */ |
|
|
214 | char choked; /* true if we have an EAGAIN from this server's socket */ |
|
|
215 | char write_waiting; /* true if we are waiting for EV_WRITE events */ |
|
|
216 | }; |
|
|
217 | |
|
|
218 | static struct request *req_head = NULL, *req_waiting_head = NULL; |
|
|
219 | static struct nameserver *server_head = NULL; |
|
|
220 | |
|
|
221 | /* Represents a local port where we're listening for DNS requests. Right now, */ |
|
|
222 | /* only UDP is supported. */ |
|
|
223 | struct evdns_server_port { |
|
|
224 | int socket; /* socket we use to read queries and write replies. */ |
|
|
225 | int refcnt; /* reference count. */ |
|
|
226 | char choked; /* Are we currently blocked from writing? */ |
|
|
227 | char closing; /* Are we trying to close this port, pending writes? */ |
|
|
228 | evdns_request_callback_fn_type user_callback; /* Fn to handle requests */ |
|
|
229 | void *user_data; /* Opaque pointer passed to user_callback */ |
|
|
230 | struct event event; /* Read/write event */ |
|
|
231 | /* circular list of replies that we want to write. */ |
|
|
232 | struct server_request *pending_replies; |
|
|
233 | }; |
|
|
234 | |
|
|
235 | /* Represents part of a reply being built. (That is, a single RR.) */ |
|
|
236 | struct server_reply_item { |
|
|
237 | struct server_reply_item *next; /* next item in sequence. */ |
|
|
238 | char *name; /* name part of the RR */ |
|
|
239 | u16 type : 16; /* The RR type */ |
|
|
240 | u16 class : 16; /* The RR class (usually CLASS_INET) */ |
|
|
241 | u32 ttl; /* The RR TTL */ |
|
|
242 | char is_name; /* True iff data is a label */ |
|
|
243 | u16 datalen; /* Length of data; -1 if data is a label */ |
|
|
244 | void *data; /* The contents of the RR */ |
|
|
245 | }; |
|
|
246 | |
|
|
247 | /* Represents a request that we've received as a DNS server, and holds */ |
|
|
248 | /* the components of the reply as we're constructing it. */ |
|
|
249 | struct server_request { |
|
|
250 | /* Pointers to the next and previous entries on the list of replies */ |
|
|
251 | /* that we're waiting to write. Only set if we have tried to respond */ |
|
|
252 | /* and gotten EAGAIN. */ |
|
|
253 | struct server_request *next_pending; |
|
|
254 | struct server_request *prev_pending; |
|
|
255 | |
|
|
256 | u16 trans_id; /* Transaction id. */ |
|
|
257 | struct evdns_server_port *port; /* Which port received this request on? */ |
|
|
258 | struct sockaddr_storage addr; /* Where to send the response */ |
|
|
259 | socklen_t addrlen; /* length of addr */ |
|
|
260 | |
|
|
261 | int n_answer; /* how many answer RRs have been set? */ |
|
|
262 | int n_authority; /* how many authority RRs have been set? */ |
|
|
263 | int n_additional; /* how many additional RRs have been set? */ |
|
|
264 | |
|
|
265 | struct server_reply_item *answer; /* linked list of answer RRs */ |
|
|
266 | struct server_reply_item *authority; /* linked list of authority RRs */ |
|
|
267 | struct server_reply_item *additional; /* linked list of additional RRs */ |
|
|
268 | |
|
|
269 | /* Constructed response. Only set once we're ready to send a reply. */ |
|
|
270 | /* Once this is set, the RR fields are cleared, and no more should be set. */ |
|
|
271 | char *response; |
|
|
272 | size_t response_len; |
|
|
273 | |
|
|
274 | /* Caller-visible fields: flags, questions. */ |
|
|
275 | struct evdns_server_request base; |
|
|
276 | }; |
|
|
277 | |
|
|
278 | /* helper macro */ |
|
|
279 | #define OFFSET_OF(st, member) ((off_t) (((char*)&((st*)0)->member)-(char*)0)) |
|
|
280 | |
|
|
281 | /* Given a pointer to an evdns_server_request, get the corresponding */ |
|
|
282 | /* server_request. */ |
|
|
283 | #define TO_SERVER_REQUEST(base_ptr) \ |
|
|
284 | ((struct server_request*) \ |
|
|
285 | (((char*)(base_ptr) - OFFSET_OF(struct server_request, base)))) |
|
|
286 | |
|
|
287 | /* The number of good nameservers that we have */ |
|
|
288 | static int global_good_nameservers = 0; |
|
|
289 | |
|
|
290 | /* inflight requests are contained in the req_head list */ |
|
|
291 | /* and are actually going out across the network */ |
|
|
292 | static int global_requests_inflight = 0; |
|
|
293 | /* requests which aren't inflight are in the waiting list */ |
|
|
294 | /* and are counted here */ |
|
|
295 | static int global_requests_waiting = 0; |
|
|
296 | |
|
|
297 | static int global_max_requests_inflight = 64; |
|
|
298 | |
|
|
299 | static struct timeval global_timeout = {5, 0}; /* 5 seconds */ |
|
|
300 | static int global_max_reissues = 1; /* a reissue occurs when we get some errors from the server */ |
|
|
301 | static int global_max_retransmits = 3; /* number of times we'll retransmit a request which timed out */ |
|
|
302 | /* number of timeouts in a row before we consider this server to be down */ |
|
|
303 | static int global_max_nameserver_timeout = 3; |
|
|
304 | |
|
|
305 | /* These are the timeout values for nameservers. If we find a nameserver is down */ |
|
|
306 | /* we try to probe it at intervals as given below. Values are in seconds. */ |
|
|
307 | static const struct timeval global_nameserver_timeouts[] = {{10, 0}, {60, 0}, {300, 0}, {900, 0}, {3600, 0}}; |
|
|
308 | static const int global_nameserver_timeouts_length = sizeof(global_nameserver_timeouts)/sizeof(struct timeval); |
|
|
309 | |
|
|
310 | static struct nameserver *nameserver_pick(void); |
|
|
311 | static void evdns_request_insert(struct request *req, struct request **head); |
|
|
312 | static void nameserver_ready_callback(int fd, short events, void *arg); |
|
|
313 | static int evdns_transmit(void); |
|
|
314 | static int evdns_request_transmit(struct request *req); |
|
|
315 | static void nameserver_send_probe(struct nameserver *const ns); |
|
|
316 | static void search_request_finished(struct request *const); |
|
|
317 | static int search_try_next(struct request *const req); |
|
|
318 | static int search_request_new(int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg); |
|
|
319 | static void evdns_requests_pump_waiting_queue(void); |
|
|
320 | static u16 transaction_id_pick(void); |
|
|
321 | static struct request *request_new(int type, const char *name, int flags, evdns_callback_type callback, void *ptr); |
|
|
322 | static void request_submit(struct request *req); |
|
|
323 | |
|
|
324 | static int server_request_free(struct server_request *req); |
|
|
325 | static void server_request_free_answers(struct server_request *req); |
|
|
326 | static void server_port_free(struct evdns_server_port *port); |
|
|
327 | static void server_port_ready_callback(int fd, short events, void *arg); |
|
|
328 | |
|
|
329 | static int strtoint(const char *const str); |
|
|
330 | |
|
|
331 | #ifdef WIN32 |
|
|
332 | static int |
|
|
333 | last_error(int sock) |
|
|
334 | { |
|
|
335 | int optval, optvallen=sizeof(optval); |
|
|
336 | int err = WSAGetLastError(); |
|
|
337 | if (err == WSAEWOULDBLOCK && sock >= 0) { |
|
|
338 | if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval, |
|
|
339 | &optvallen)) |
|
|
340 | return err; |
|
|
341 | if (optval) |
|
|
342 | return optval; |
|
|
343 | } |
|
|
344 | return err; |
|
|
345 | |
|
|
346 | } |
|
|
347 | static int |
|
|
348 | error_is_eagain(int err) |
|
|
349 | { |
|
|
350 | return err == EAGAIN || err == WSAEWOULDBLOCK; |
|
|
351 | } |
|
|
352 | static int |
|
|
353 | inet_aton(const char *c, struct in_addr *addr) |
|
|
354 | { |
|
|
355 | uint32_t r; |
|
|
356 | if (strcmp(c, "255.255.255.255") == 0) { |
|
|
357 | addr->s_addr = 0xffffffffu; |
|
|
358 | } else { |
|
|
359 | r = inet_addr(c); |
|
|
360 | if (r == INADDR_NONE) |
|
|
361 | return 0; |
|
|
362 | addr->s_addr = r; |
|
|
363 | } |
|
|
364 | return 1; |
|
|
365 | } |
|
|
366 | #define CLOSE_SOCKET(x) closesocket(x) |
|
|
367 | #else |
|
|
368 | #define last_error(sock) (errno) |
|
|
369 | #define error_is_eagain(err) ((err) == EAGAIN) |
|
|
370 | #define CLOSE_SOCKET(x) close(x) |
|
|
371 | #endif |
|
|
372 | |
|
|
373 | #define ISSPACE(c) isspace((int)(unsigned char)(c)) |
|
|
374 | #define ISDIGIT(c) isdigit((int)(unsigned char)(c)) |
|
|
375 | |
|
|
376 | #ifndef NDEBUG |
|
|
377 | static const char * |
|
|
378 | debug_ntoa(u32 address) |
|
|
379 | { |
|
|
380 | static char buf[32]; |
|
|
381 | u32 a = ntohl(address); |
|
|
382 | snprintf(buf, sizeof(buf), "%d.%d.%d.%d", |
|
|
383 | (int)(u8)((a>>24)&0xff), |
|
|
384 | (int)(u8)((a>>16)&0xff), |
|
|
385 | (int)(u8)((a>>8 )&0xff), |
|
|
386 | (int)(u8)((a )&0xff)); |
|
|
387 | return buf; |
|
|
388 | } |
|
|
389 | #endif |
|
|
390 | |
|
|
391 | static evdns_debug_log_fn_type evdns_log_fn = NULL; |
|
|
392 | |
|
|
393 | void |
|
|
394 | evdns_set_log_fn(evdns_debug_log_fn_type fn) |
|
|
395 | { |
|
|
396 | evdns_log_fn = fn; |
|
|
397 | } |
|
|
398 | |
|
|
399 | #ifdef __GNUC__ |
|
|
400 | #define EVDNS_LOG_CHECK __attribute__ ((format(printf, 2, 3))) |
|
|
401 | #else |
|
|
402 | #define EVDNS_LOG_CHECK |
|
|
403 | #endif |
|
|
404 | |
|
|
405 | static void _evdns_log(int warn, const char *fmt, ...) EVDNS_LOG_CHECK; |
|
|
406 | static void |
|
|
407 | _evdns_log(int warn, const char *fmt, ...) |
|
|
408 | { |
|
|
409 | va_list args; |
|
|
410 | static char buf[512]; |
|
|
411 | if (!evdns_log_fn) |
|
|
412 | return; |
|
|
413 | va_start(args,fmt); |
|
|
414 | #ifdef WIN32 |
|
|
415 | _vsnprintf(buf, sizeof(buf), fmt, args); |
|
|
416 | #else |
|
|
417 | vsnprintf(buf, sizeof(buf), fmt, args); |
|
|
418 | #endif |
|
|
419 | buf[sizeof(buf)-1] = '\0'; |
|
|
420 | evdns_log_fn(warn, buf); |
|
|
421 | va_end(args); |
|
|
422 | } |
|
|
423 | |
|
|
424 | #define log _evdns_log |
|
|
425 | |
|
|
426 | /* This walks the list of inflight requests to find the */ |
|
|
427 | /* one with a matching transaction id. Returns NULL on */ |
|
|
428 | /* failure */ |
|
|
429 | static struct request * |
|
|
430 | request_find_from_trans_id(u16 trans_id) { |
|
|
431 | struct request *req = req_head, *const started_at = req_head; |
|
|
432 | |
|
|
433 | if (req) { |
|
|
434 | do { |
|
|
435 | if (req->trans_id == trans_id) return req; |
|
|
436 | req = req->next; |
|
|
437 | } while (req != started_at); |
|
|
438 | } |
|
|
439 | |
|
|
440 | return NULL; |
|
|
441 | } |
|
|
442 | |
|
|
443 | /* a libevent callback function which is called when a nameserver */ |
|
|
444 | /* has gone down and we want to test if it has came back to life yet */ |
|
|
445 | static void |
|
|
446 | nameserver_prod_callback(int fd, short events, void *arg) { |
|
|
447 | struct nameserver *const ns = (struct nameserver *) arg; |
|
|
448 | (void)fd; |
|
|
449 | (void)events; |
|
|
450 | |
|
|
451 | nameserver_send_probe(ns); |
|
|
452 | } |
|
|
453 | |
|
|
454 | /* a libevent callback which is called when a nameserver probe (to see if */ |
|
|
455 | /* it has come back to life) times out. We increment the count of failed_times */ |
|
|
456 | /* and wait longer to send the next probe packet. */ |
|
|
457 | static void |
|
|
458 | nameserver_probe_failed(struct nameserver *const ns) { |
|
|
459 | const struct timeval * timeout; |
|
|
460 | (void) evtimer_del(&ns->timeout_event); |
|
|
461 | if (ns->state == 1) { |
|
|
462 | /* This can happen if the nameserver acts in a way which makes us mark */ |
|
|
463 | /* it as bad and then starts sending good replies. */ |
|
|
464 | return; |
|
|
465 | } |
|
|
466 | |
|
|
467 | timeout = |
|
|
468 | &global_nameserver_timeouts[MIN(ns->failed_times, |
|
|
469 | global_nameserver_timeouts_length - 1)]; |
|
|
470 | ns->failed_times++; |
|
|
471 | |
|
|
472 | evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns); |
|
|
473 | if (evtimer_add(&ns->timeout_event, (struct timeval *) timeout) < 0) { |
|
|
474 | log(EVDNS_LOG_WARN, |
|
|
475 | "Error from libevent when adding timer event for %s", |
|
|
476 | debug_ntoa(ns->address)); |
|
|
477 | /* ???? Do more? */ |
|
|
478 | } |
|
|
479 | } |
|
|
480 | |
|
|
481 | /* called when a nameserver has been deemed to have failed. For example, too */ |
|
|
482 | /* many packets have timed out etc */ |
|
|
483 | static void |
|
|
484 | nameserver_failed(struct nameserver *const ns, const char *msg) { |
|
|
485 | struct request *req, *started_at; |
|
|
486 | /* if this nameserver has already been marked as failed */ |
|
|
487 | /* then don't do anything */ |
|
|
488 | if (!ns->state) return; |
|
|
489 | |
|
|
490 | log(EVDNS_LOG_WARN, "Nameserver %s has failed: %s", |
|
|
491 | debug_ntoa(ns->address), msg); |
|
|
492 | global_good_nameservers--; |
|
|
493 | assert(global_good_nameservers >= 0); |
|
|
494 | if (global_good_nameservers == 0) { |
|
|
495 | log(EVDNS_LOG_WARN, "All nameservers have failed"); |
|
|
496 | } |
|
|
497 | |
|
|
498 | ns->state = 0; |
|
|
499 | ns->failed_times = 1; |
|
|
500 | |
|
|
501 | evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns); |
|
|
502 | if (evtimer_add(&ns->timeout_event, (struct timeval *) &global_nameserver_timeouts[0]) < 0) { |
|
|
503 | log(EVDNS_LOG_WARN, |
|
|
504 | "Error from libevent when adding timer event for %s", |
|
|
505 | debug_ntoa(ns->address)); |
|
|
506 | /* ???? Do more? */ |
|
|
507 | } |
|
|
508 | |
|
|
509 | /* walk the list of inflight requests to see if any can be reassigned to */ |
|
|
510 | /* a different server. Requests in the waiting queue don't have a */ |
|
|
511 | /* nameserver assigned yet */ |
|
|
512 | |
|
|
513 | /* if we don't have *any* good nameservers then there's no point */ |
|
|
514 | /* trying to reassign requests to one */ |
|
|
515 | if (!global_good_nameservers) return; |
|
|
516 | |
|
|
517 | req = req_head; |
|
|
518 | started_at = req_head; |
|
|
519 | if (req) { |
|
|
520 | do { |
|
|
521 | if (req->tx_count == 0 && req->ns == ns) { |
|
|
522 | /* still waiting to go out, can be moved */ |
|
|
523 | /* to another server */ |
|
|
524 | req->ns = nameserver_pick(); |
|
|
525 | } |
|
|
526 | req = req->next; |
|
|
527 | } while (req != started_at); |
|
|
528 | } |
|
|
529 | } |
|
|
530 | |
|
|
531 | static void |
|
|
532 | nameserver_up(struct nameserver *const ns) { |
|
|
533 | if (ns->state) return; |
|
|
534 | log(EVDNS_LOG_WARN, "Nameserver %s is back up", |
|
|
535 | debug_ntoa(ns->address)); |
|
|
536 | evtimer_del(&ns->timeout_event); |
|
|
537 | ns->state = 1; |
|
|
538 | ns->failed_times = 0; |
|
|
539 | ns->timedout = 0; |
|
|
540 | global_good_nameservers++; |
|
|
541 | } |
|
|
542 | |
|
|
543 | static void |
|
|
544 | request_trans_id_set(struct request *const req, const u16 trans_id) { |
|
|
545 | req->trans_id = trans_id; |
|
|
546 | *((u16 *) req->request) = htons(trans_id); |
|
|
547 | } |
|
|
548 | |
|
|
549 | /* Called to remove a request from a list and dealloc it. */ |
|
|
550 | /* head is a pointer to the head of the list it should be */ |
|
|
551 | /* removed from or NULL if the request isn't in a list. */ |
|
|
552 | static void |
|
|
553 | request_finished(struct request *const req, struct request **head) { |
|
|
554 | if (head) { |
|
|
555 | if (req->next == req) { |
|
|
556 | /* only item in the list */ |
|
|
557 | *head = NULL; |
|
|
558 | } else { |
|
|
559 | req->next->prev = req->prev; |
|
|
560 | req->prev->next = req->next; |
|
|
561 | if (*head == req) *head = req->next; |
|
|
562 | } |
|
|
563 | } |
|
|
564 | |
|
|
565 | log(EVDNS_LOG_DEBUG, "Removing timeout for request %lx", |
|
|
566 | (unsigned long) req); |
|
|
567 | evtimer_del(&req->timeout_event); |
|
|
568 | |
|
|
569 | search_request_finished(req); |
|
|
570 | global_requests_inflight--; |
|
|
571 | |
|
|
572 | if (!req->request_appended) { |
|
|
573 | /* need to free the request data on it's own */ |
|
|
574 | free(req->request); |
|
|
575 | } else { |
|
|
576 | /* the request data is appended onto the header */ |
|
|
577 | /* so everything gets free()ed when we: */ |
|
|
578 | } |
|
|
579 | |
|
|
580 | free(req); |
|
|
581 | |
|
|
582 | evdns_requests_pump_waiting_queue(); |
|
|
583 | } |
|
|
584 | |
|
|
585 | /* This is called when a server returns a funny error code. */ |
|
|
586 | /* We try the request again with another server. */ |
|
|
587 | /* */ |
|
|
588 | /* return: */ |
|
|
589 | /* 0 ok */ |
|
|
590 | /* 1 failed/reissue is pointless */ |
|
|
591 | static int |
|
|
592 | request_reissue(struct request *req) { |
|
|
593 | const struct nameserver *const last_ns = req->ns; |
|
|
594 | /* the last nameserver should have been marked as failing */ |
|
|
595 | /* by the caller of this function, therefore pick will try */ |
|
|
596 | /* not to return it */ |
|
|
597 | req->ns = nameserver_pick(); |
|
|
598 | if (req->ns == last_ns) { |
|
|
599 | /* ... but pick did return it */ |
|
|
600 | /* not a lot of point in trying again with the */ |
|
|
601 | /* same server */ |
|
|
602 | return 1; |
|
|
603 | } |
|
|
604 | |
|
|
605 | req->reissue_count++; |
|
|
606 | req->tx_count = 0; |
|
|
607 | req->transmit_me = 1; |
|
|
608 | |
|
|
609 | return 0; |
|
|
610 | } |
|
|
611 | |
|
|
612 | /* this function looks for space on the inflight queue and promotes */ |
|
|
613 | /* requests from the waiting queue if it can. */ |
|
|
614 | static void |
|
|
615 | evdns_requests_pump_waiting_queue(void) { |
|
|
616 | while (global_requests_inflight < global_max_requests_inflight && |
|
|
617 | global_requests_waiting) { |
|
|
618 | struct request *req; |
|
|
619 | /* move a request from the waiting queue to the inflight queue */ |
|
|
620 | assert(req_waiting_head); |
|
|
621 | if (req_waiting_head->next == req_waiting_head) { |
|
|
622 | /* only one item in the queue */ |
|
|
623 | req = req_waiting_head; |
|
|
624 | req_waiting_head = NULL; |
|
|
625 | } else { |
|
|
626 | req = req_waiting_head; |
|
|
627 | req->next->prev = req->prev; |
|
|
628 | req->prev->next = req->next; |
|
|
629 | req_waiting_head = req->next; |
|
|
630 | } |
|
|
631 | |
|
|
632 | global_requests_waiting--; |
|
|
633 | global_requests_inflight++; |
|
|
634 | |
|
|
635 | req->ns = nameserver_pick(); |
|
|
636 | request_trans_id_set(req, transaction_id_pick()); |
|
|
637 | |
|
|
638 | evdns_request_insert(req, &req_head); |
|
|
639 | evdns_request_transmit(req); |
|
|
640 | evdns_transmit(); |
|
|
641 | } |
|
|
642 | } |
|
|
643 | |
|
|
644 | static void |
|
|
645 | reply_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply) { |
|
|
646 | switch (req->request_type) { |
|
|
647 | case TYPE_A: |
|
|
648 | if (reply) |
|
|
649 | req->user_callback(DNS_ERR_NONE, DNS_IPv4_A, |
|
|
650 | reply->data.a.addrcount, ttl, |
|
|
651 | reply->data.a.addresses, |
|
|
652 | req->user_pointer); |
|
|
653 | else |
|
|
654 | req->user_callback(err, 0, 0, 0, NULL, req->user_pointer); |
|
|
655 | return; |
|
|
656 | case TYPE_PTR: |
|
|
657 | if (reply) { |
|
|
658 | char *name = reply->data.ptr.name; |
|
|
659 | req->user_callback(DNS_ERR_NONE, DNS_PTR, 1, ttl, |
|
|
660 | &name, req->user_pointer); |
|
|
661 | } else { |
|
|
662 | req->user_callback(err, 0, 0, 0, NULL, |
|
|
663 | req->user_pointer); |
|
|
664 | } |
|
|
665 | return; |
|
|
666 | case TYPE_AAAA: |
|
|
667 | if (reply) |
|
|
668 | req->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA, |
|
|
669 | reply->data.aaaa.addrcount, ttl, |
|
|
670 | reply->data.aaaa.addresses, |
|
|
671 | req->user_pointer); |
|
|
672 | else |
|
|
673 | req->user_callback(err, 0, 0, 0, NULL, req->user_pointer); |
|
|
674 | return; |
|
|
675 | } |
|
|
676 | assert(0); |
|
|
677 | } |
|
|
678 | |
|
|
679 | /* this processes a parsed reply packet */ |
|
|
680 | static void |
|
|
681 | reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) { |
|
|
682 | int error; |
|
|
683 | static const int error_codes[] = {DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST, DNS_ERR_NOTIMPL, DNS_ERR_REFUSED}; |
|
|
684 | |
|
|
685 | if (flags & 0x020f || !reply || !reply->have_answer) { |
|
|
686 | /* there was an error */ |
|
|
687 | if (flags & 0x0200) { |
|
|
688 | error = DNS_ERR_TRUNCATED; |
|
|
689 | } else { |
|
|
690 | u16 error_code = (flags & 0x000f) - 1; |
|
|
691 | if (error_code > 4) { |
|
|
692 | error = DNS_ERR_UNKNOWN; |
|
|
693 | } else { |
|
|
694 | error = error_codes[error_code]; |
|
|
695 | } |
|
|
696 | } |
|
|
697 | |
|
|
698 | switch(error) { |
|
|
699 | case DNS_ERR_NOTIMPL: |
|
|
700 | case DNS_ERR_REFUSED: |
|
|
701 | /* we regard these errors as marking a bad nameserver */ |
|
|
702 | if (req->reissue_count < global_max_reissues) { |
|
|
703 | char msg[64]; |
|
|
704 | snprintf(msg, sizeof(msg), "Bad response %d (%s)", |
|
|
705 | error, evdns_err_to_string(error)); |
|
|
706 | nameserver_failed(req->ns, msg); |
|
|
707 | if (!request_reissue(req)) return; |
|
|
708 | } |
|
|
709 | break; |
|
|
710 | case DNS_ERR_SERVERFAILED: |
|
|
711 | /* rcode 2 (servfailed) sometimes means "we are broken" and |
|
|
712 | * sometimes (with some binds) means "that request was very |
|
|
713 | * confusing." Treat this as a timeout, not a failure. |
|
|
714 | */ |
|
|
715 | log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver %s; " |
|
|
716 | "will allow the request to time out.", |
|
|
717 | debug_ntoa(req->ns->address)); |
|
|
718 | break; |
|
|
719 | default: |
|
|
720 | /* we got a good reply from the nameserver */ |
|
|
721 | nameserver_up(req->ns); |
|
|
722 | } |
|
|
723 | |
|
|
724 | if (req->search_state && req->request_type != TYPE_PTR) { |
|
|
725 | /* if we have a list of domains to search in, try the next one */ |
|
|
726 | if (!search_try_next(req)) { |
|
|
727 | /* a new request was issued so this request is finished and */ |
|
|
728 | /* the user callback will be made when that request (or a */ |
|
|
729 | /* child of it) finishes. */ |
|
|
730 | request_finished(req, &req_head); |
|
|
731 | return; |
|
|
732 | } |
|
|
733 | } |
|
|
734 | |
|
|
735 | /* all else failed. Pass the failure up */ |
|
|
736 | reply_callback(req, 0, error, NULL); |
|
|
737 | request_finished(req, &req_head); |
|
|
738 | } else { |
|
|
739 | /* all ok, tell the user */ |
|
|
740 | reply_callback(req, ttl, 0, reply); |
|
|
741 | nameserver_up(req->ns); |
|
|
742 | request_finished(req, &req_head); |
|
|
743 | } |
|
|
744 | } |
|
|
745 | |
|
|
746 | static int |
|
|
747 | name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) { |
|
|
748 | int name_end = -1; |
|
|
749 | int j = *idx; |
|
|
750 | int ptr_count = 0; |
|
|
751 | #define GET32(x) do { if (j + 4 > length) goto err; memcpy(&_t32, packet + j, 4); j += 4; x = ntohl(_t32); } while(0) |
|
|
752 | #define GET16(x) do { if (j + 2 > length) goto err; memcpy(&_t, packet + j, 2); j += 2; x = ntohs(_t); } while(0) |
|
|
753 | #define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while(0) |
|
|
754 | |
|
|
755 | char *cp = name_out; |
|
|
756 | const char *const end = name_out + name_out_len; |
|
|
757 | |
|
|
758 | /* Normally, names are a series of length prefixed strings terminated */ |
|
|
759 | /* with a length of 0 (the lengths are u8's < 63). */ |
|
|
760 | /* However, the length can start with a pair of 1 bits and that */ |
|
|
761 | /* means that the next 14 bits are a pointer within the current */ |
|
|
762 | /* packet. */ |
|
|
763 | |
|
|
764 | for(;;) { |
|
|
765 | u8 label_len; |
|
|
766 | if (j >= length) return -1; |
|
|
767 | GET8(label_len); |
|
|
768 | if (!label_len) break; |
|
|
769 | if (label_len & 0xc0) { |
|
|
770 | u8 ptr_low; |
|
|
771 | GET8(ptr_low); |
|
|
772 | if (name_end < 0) name_end = j; |
|
|
773 | j = (((int)label_len & 0x3f) << 8) + ptr_low; |
|
|
774 | /* Make sure that the target offset is in-bounds. */ |
|
|
775 | if (j < 0 || j >= length) return -1; |
|
|
776 | /* If we've jumped more times than there are characters in the |
|
|
777 | * message, we must have a loop. */ |
|
|
778 | if (++ptr_count > length) return -1; |
|
|
779 | continue; |
|
|
780 | } |
|
|
781 | if (label_len > 63) return -1; |
|
|
782 | if (cp != name_out) { |
|
|
783 | if (cp + 1 >= end) return -1; |
|
|
784 | *cp++ = '.'; |
|
|
785 | } |
|
|
786 | if (cp + label_len >= end) return -1; |
|
|
787 | memcpy(cp, packet + j, label_len); |
|
|
788 | cp += label_len; |
|
|
789 | j += label_len; |
|
|
790 | } |
|
|
791 | if (cp >= end) return -1; |
|
|
792 | *cp = '\0'; |
|
|
793 | if (name_end < 0) |
|
|
794 | *idx = j; |
|
|
795 | else |
|
|
796 | *idx = name_end; |
|
|
797 | return 0; |
|
|
798 | err: |
|
|
799 | return -1; |
|
|
800 | } |
|
|
801 | |
|
|
802 | /* parses a raw request from a nameserver */ |
|
|
803 | static int |
|
|
804 | reply_parse(u8 *packet, int length) { |
|
|
805 | int j = 0; /* index into packet */ |
|
|
806 | u16 _t; /* used by the macros */ |
|
|
807 | u32 _t32; /* used by the macros */ |
|
|
808 | char tmp_name[256]; /* used by the macros */ |
|
|
809 | |
|
|
810 | u16 trans_id, questions, answers, authority, additional, datalength; |
|
|
811 | u16 flags = 0; |
|
|
812 | u32 ttl, ttl_r = 0xffffffff; |
|
|
813 | struct reply reply; |
|
|
814 | struct request *req = NULL; |
|
|
815 | unsigned int i; |
|
|
816 | |
|
|
817 | GET16(trans_id); |
|
|
818 | GET16(flags); |
|
|
819 | GET16(questions); |
|
|
820 | GET16(answers); |
|
|
821 | GET16(authority); |
|
|
822 | GET16(additional); |
|
|
823 | (void) authority; /* suppress "unused variable" warnings. */ |
|
|
824 | (void) additional; /* suppress "unused variable" warnings. */ |
|
|
825 | |
|
|
826 | req = request_find_from_trans_id(trans_id); |
|
|
827 | if (!req) return -1; |
|
|
828 | |
|
|
829 | memset(&reply, 0, sizeof(reply)); |
|
|
830 | |
|
|
831 | /* If it's not an answer, it doesn't correspond to any request. */ |
|
|
832 | if (!(flags & 0x8000)) return -1; /* must be an answer */ |
|
|
833 | if (flags & 0x020f) { |
|
|
834 | /* there was an error */ |
|
|
835 | goto err; |
|
|
836 | } |
|
|
837 | /* if (!answers) return; */ /* must have an answer of some form */ |
|
|
838 | |
|
|
839 | /* This macro skips a name in the DNS reply. */ |
|
|
840 | #define SKIP_NAME \ |
|
|
841 | do { tmp_name[0] = '\0'; \ |
|
|
842 | if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0) \ |
|
|
843 | goto err; \ |
|
|
844 | } while(0); |
|
|
845 | |
|
|
846 | reply.type = req->request_type; |
|
|
847 | |
|
|
848 | /* skip over each question in the reply */ |
|
|
849 | for (i = 0; i < questions; ++i) { |
|
|
850 | /* the question looks like |
|
|
851 | * <label:name><u16:type><u16:class> |
|
|
852 | */ |
|
|
853 | SKIP_NAME; |
|
|
854 | j += 4; |
|
|
855 | if (j >= length) goto err; |
|
|
856 | } |
|
|
857 | |
|
|
858 | /* now we have the answer section which looks like |
|
|
859 | * <label:name><u16:type><u16:class><u32:ttl><u16:len><data...> |
|
|
860 | */ |
|
|
861 | |
|
|
862 | for (i = 0; i < answers; ++i) { |
|
|
863 | u16 type, class; |
|
|
864 | |
|
|
865 | SKIP_NAME; |
|
|
866 | GET16(type); |
|
|
867 | GET16(class); |
|
|
868 | GET32(ttl); |
|
|
869 | GET16(datalength); |
|
|
870 | |
|
|
871 | if (type == TYPE_A && class == CLASS_INET) { |
|
|
872 | int addrcount, addrtocopy; |
|
|
873 | if (req->request_type != TYPE_A) { |
|
|
874 | j += datalength; continue; |
|
|
875 | } |
|
|
876 | if ((datalength & 3) != 0) /* not an even number of As. */ |
|
|
877 | goto err; |
|
|
878 | addrcount = datalength >> 2; |
|
|
879 | addrtocopy = MIN(MAX_ADDRS - reply.data.a.addrcount, (unsigned)addrcount); |
|
|
880 | |
|
|
881 | ttl_r = MIN(ttl_r, ttl); |
|
|
882 | /* we only bother with the first four addresses. */ |
|
|
883 | if (j + 4*addrtocopy > length) goto err; |
|
|
884 | memcpy(&reply.data.a.addresses[reply.data.a.addrcount], |
|
|
885 | packet + j, 4*addrtocopy); |
|
|
886 | j += 4*addrtocopy; |
|
|
887 | reply.data.a.addrcount += addrtocopy; |
|
|
888 | reply.have_answer = 1; |
|
|
889 | if (reply.data.a.addrcount == MAX_ADDRS) break; |
|
|
890 | } else if (type == TYPE_PTR && class == CLASS_INET) { |
|
|
891 | if (req->request_type != TYPE_PTR) { |
|
|
892 | j += datalength; continue; |
|
|
893 | } |
|
|
894 | if (name_parse(packet, length, &j, reply.data.ptr.name, |
|
|
895 | sizeof(reply.data.ptr.name))<0) |
|
|
896 | goto err; |
|
|
897 | ttl_r = MIN(ttl_r, ttl); |
|
|
898 | reply.have_answer = 1; |
|
|
899 | break; |
|
|
900 | } else if (type == TYPE_AAAA && class == CLASS_INET) { |
|
|
901 | int addrcount, addrtocopy; |
|
|
902 | if (req->request_type != TYPE_AAAA) { |
|
|
903 | j += datalength; continue; |
|
|
904 | } |
|
|
905 | if ((datalength & 15) != 0) /* not an even number of AAAAs. */ |
|
|
906 | goto err; |
|
|
907 | addrcount = datalength >> 4; /* each address is 16 bytes long */ |
|
|
908 | addrtocopy = MIN(MAX_ADDRS - reply.data.aaaa.addrcount, (unsigned)addrcount); |
|
|
909 | ttl_r = MIN(ttl_r, ttl); |
|
|
910 | |
|
|
911 | /* we only bother with the first four addresses. */ |
|
|
912 | if (j + 16*addrtocopy > length) goto err; |
|
|
913 | memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount], |
|
|
914 | packet + j, 16*addrtocopy); |
|
|
915 | reply.data.aaaa.addrcount += addrtocopy; |
|
|
916 | j += 16*addrtocopy; |
|
|
917 | reply.have_answer = 1; |
|
|
918 | if (reply.data.aaaa.addrcount == MAX_ADDRS) break; |
|
|
919 | } else { |
|
|
920 | /* skip over any other type of resource */ |
|
|
921 | j += datalength; |
|
|
922 | } |
|
|
923 | } |
|
|
924 | |
|
|
925 | reply_handle(req, flags, ttl_r, &reply); |
|
|
926 | return 0; |
|
|
927 | err: |
|
|
928 | if (req) |
|
|
929 | reply_handle(req, flags, 0, NULL); |
|
|
930 | return -1; |
|
|
931 | } |
|
|
932 | |
|
|
933 | /* Parse a raw request (packet,length) sent to a nameserver port (port) from */ |
|
|
934 | /* a DNS client (addr,addrlen), and if it's well-formed, call the corresponding */ |
|
|
935 | /* callback. */ |
|
|
936 | static int |
|
|
937 | request_parse(u8 *packet, int length, struct evdns_server_port *port, struct sockaddr *addr, socklen_t addrlen) |
|
|
938 | { |
|
|
939 | int j = 0; /* index into packet */ |
|
|
940 | u16 _t; /* used by the macros */ |
|
|
941 | char tmp_name[256]; /* used by the macros */ |
|
|
942 | |
|
|
943 | int i; |
|
|
944 | u16 trans_id, flags, questions, answers, authority, additional; |
|
|
945 | struct server_request *server_req = NULL; |
|
|
946 | |
|
|
947 | /* Get the header fields */ |
|
|
948 | GET16(trans_id); |
|
|
949 | GET16(flags); |
|
|
950 | GET16(questions); |
|
|
951 | GET16(answers); |
|
|
952 | GET16(authority); |
|
|
953 | GET16(additional); |
|
|
954 | |
|
|
955 | if (flags & 0x8000) return -1; /* Must not be an answer. */ |
|
|
956 | if (flags & 0x7800) return -1; /* only standard queries are supported */ |
|
|
957 | flags &= 0x0300; /* Only TC and RD get preserved. */ |
|
|
958 | |
|
|
959 | server_req = malloc(sizeof(struct server_request)); |
|
|
960 | if (server_req == NULL) return -1; |
|
|
961 | memset(server_req, 0, sizeof(struct server_request)); |
|
|
962 | |
|
|
963 | server_req->trans_id = trans_id; |
|
|
964 | memcpy(&server_req->addr, addr, addrlen); |
|
|
965 | server_req->addrlen = addrlen; |
|
|
966 | |
|
|
967 | server_req->base.flags = flags; |
|
|
968 | server_req->base.nquestions = 0; |
|
|
969 | server_req->base.questions = malloc(sizeof(struct evdns_server_question *) * questions); |
|
|
970 | if (server_req->base.questions == NULL) |
|
|
971 | goto err; |
|
|
972 | |
|
|
973 | for (i = 0; i < questions; ++i) { |
|
|
974 | u16 type, class; |
|
|
975 | struct evdns_server_question *q; |
|
|
976 | int namelen; |
|
|
977 | if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0) |
|
|
978 | goto err; |
|
|
979 | GET16(type); |
|
|
980 | GET16(class); |
|
|
981 | namelen = strlen(tmp_name); |
|
|
982 | q = malloc(sizeof(struct evdns_server_question) + namelen); |
|
|
983 | if (!q) |
|
|
984 | goto err; |
|
|
985 | q->type = type; |
|
|
986 | q->class = class; |
|
|
987 | memcpy(q->name, tmp_name, namelen+1); |
|
|
988 | server_req->base.questions[server_req->base.nquestions++] = q; |
|
|
989 | } |
|
|
990 | |
|
|
991 | /* Ignore answers, authority, and additional. */ |
|
|
992 | |
|
|
993 | server_req->port = port; |
|
|
994 | port->refcnt++; |
|
|
995 | port->user_callback(&(server_req->base), port->user_data); |
|
|
996 | |
|
|
997 | return 0; |
|
|
998 | err: |
|
|
999 | if (server_req) { |
|
|
1000 | if (server_req->base.questions) { |
|
|
1001 | for (i = 0; i < server_req->base.nquestions; ++i) |
|
|
1002 | free(server_req->base.questions[i]); |
|
|
1003 | free(server_req->base.questions); |
|
|
1004 | } |
|
|
1005 | free(server_req); |
|
|
1006 | } |
|
|
1007 | return -1; |
|
|
1008 | |
|
|
1009 | #undef SKIP_NAME |
|
|
1010 | #undef GET32 |
|
|
1011 | #undef GET16 |
|
|
1012 | #undef GET8 |
|
|
1013 | } |
|
|
1014 | |
|
|
1015 | /* Try to choose a strong transaction id which isn't already in flight */ |
|
|
1016 | static u16 |
|
|
1017 | transaction_id_pick(void) { |
|
|
1018 | for (;;) { |
|
|
1019 | const struct request *req = req_head, *started_at; |
|
|
1020 | #ifdef DNS_USE_CPU_CLOCK_FOR_ID |
|
|
1021 | struct timespec ts; |
|
|
1022 | u16 trans_id; |
|
|
1023 | #ifdef CLOCK_MONOTONIC |
|
|
1024 | if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) |
|
|
1025 | #else |
|
|
1026 | if (clock_gettime(CLOCK_REALTIME, &ts) == -1) |
|
|
1027 | #endif |
|
|
1028 | event_err(1, "clock_gettime"); |
|
|
1029 | trans_id = ts.tv_nsec & 0xffff; |
|
|
1030 | #endif |
|
|
1031 | |
|
|
1032 | #ifdef DNS_USE_GETTIMEOFDAY_FOR_ID |
|
|
1033 | struct timeval tv; |
|
|
1034 | u16 trans_id; |
|
|
1035 | gettimeofday(&tv, NULL); |
|
|
1036 | trans_id = tv.tv_usec & 0xffff; |
|
|
1037 | #endif |
|
|
1038 | |
|
|
1039 | #ifdef DNS_USE_OPENSSL_FOR_ID |
|
|
1040 | u16 trans_id; |
|
|
1041 | if (RAND_pseudo_bytes((u8 *) &trans_id, 2) == -1) { |
|
|
1042 | /* in the case that the RAND call fails we back */ |
|
|
1043 | /* down to using gettimeofday. */ |
|
|
1044 | struct timeval tv; |
|
|
1045 | gettimeofday(&tv, NULL); |
|
|
1046 | trans_id = tv.tv_usec & 0xffff; */ |
|
|
1047 | abort(); |
|
|
1048 | } |
|
|
1049 | #endif |
|
|
1050 | |
|
|
1051 | if (trans_id == 0xffff) continue; |
|
|
1052 | /* now check to see if that id is already inflight */ |
|
|
1053 | req = started_at = req_head; |
|
|
1054 | if (req) { |
|
|
1055 | do { |
|
|
1056 | if (req->trans_id == trans_id) break; |
|
|
1057 | req = req->next; |
|
|
1058 | } while (req != started_at); |
|
|
1059 | } |
|
|
1060 | /* we didn't find it, so this is a good id */ |
|
|
1061 | if (req == started_at) return trans_id; |
|
|
1062 | } |
|
|
1063 | } |
|
|
1064 | |
|
|
1065 | /* choose a namesever to use. This function will try to ignore */ |
|
|
1066 | /* nameservers which we think are down and load balance across the rest */ |
|
|
1067 | /* by updating the server_head global each time. */ |
|
|
1068 | static struct nameserver * |
|
|
1069 | nameserver_pick(void) { |
|
|
1070 | struct nameserver *started_at = server_head, *picked; |
|
|
1071 | if (!server_head) return NULL; |
|
|
1072 | |
|
|
1073 | /* if we don't have any good nameservers then there's no */ |
|
|
1074 | /* point in trying to find one. */ |
|
|
1075 | if (!global_good_nameservers) { |
|
|
1076 | server_head = server_head->next; |
|
|
1077 | return server_head; |
|
|
1078 | } |
|
|
1079 | |
|
|
1080 | /* remember that nameservers are in a circular list */ |
|
|
1081 | for (;;) { |
|
|
1082 | if (server_head->state) { |
|
|
1083 | /* we think this server is currently good */ |
|
|
1084 | picked = server_head; |
|
|
1085 | server_head = server_head->next; |
|
|
1086 | return picked; |
|
|
1087 | } |
|
|
1088 | |
|
|
1089 | server_head = server_head->next; |
|
|
1090 | if (server_head == started_at) { |
|
|
1091 | /* all the nameservers seem to be down */ |
|
|
1092 | /* so we just return this one and hope for the */ |
|
|
1093 | /* best */ |
|
|
1094 | assert(global_good_nameservers == 0); |
|
|
1095 | picked = server_head; |
|
|
1096 | server_head = server_head->next; |
|
|
1097 | return picked; |
|
|
1098 | } |
|
|
1099 | } |
|
|
1100 | } |
|
|
1101 | |
|
|
1102 | /* this is called when a namesever socket is ready for reading */ |
|
|
1103 | static void |
|
|
1104 | nameserver_read(struct nameserver *ns) { |
|
|
1105 | u8 packet[1500]; |
|
|
1106 | |
|
|
1107 | for (;;) { |
|
|
1108 | const int r = recv(ns->socket, packet, sizeof(packet), 0); |
|
|
1109 | if (r < 0) { |
|
|
1110 | int err = last_error(ns->socket); |
|
|
1111 | if (error_is_eagain(err)) return; |
|
|
1112 | nameserver_failed(ns, strerror(err)); |
|
|
1113 | return; |
|
|
1114 | } |
|
|
1115 | ns->timedout = 0; |
|
|
1116 | reply_parse(packet, r); |
|
|
1117 | } |
|
|
1118 | } |
|
|
1119 | |
|
|
1120 | /* Read a packet from a DNS client on a server port s, parse it, and */ |
|
|
1121 | /* act accordingly. */ |
|
|
1122 | static void |
|
|
1123 | server_port_read(struct evdns_server_port *s) { |
|
|
1124 | u8 packet[1500]; |
|
|
1125 | struct sockaddr_storage addr; |
|
|
1126 | socklen_t addrlen; |
|
|
1127 | int r; |
|
|
1128 | |
|
|
1129 | for (;;) { |
|
|
1130 | addrlen = sizeof(struct sockaddr_storage); |
|
|
1131 | r = recvfrom(s->socket, packet, sizeof(packet), 0, |
|
|
1132 | (struct sockaddr*) &addr, &addrlen); |
|
|
1133 | if (r < 0) { |
|
|
1134 | int err = last_error(s->socket); |
|
|
1135 | if (error_is_eagain(err)) return; |
|
|
1136 | log(EVDNS_LOG_WARN, "Error %s (%d) while reading request.", |
|
|
1137 | strerror(err), err); |
|
|
1138 | return; |
|
|
1139 | } |
|
|
1140 | request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen); |
|
|
1141 | } |
|
|
1142 | } |
|
|
1143 | |
|
|
1144 | /* Try to write all pending replies on a given DNS server port. */ |
|
|
1145 | static void |
|
|
1146 | server_port_flush(struct evdns_server_port *port) |
|
|
1147 | { |
|
|
1148 | while (port->pending_replies) { |
|
|
1149 | struct server_request *req = port->pending_replies; |
|
|
1150 | int r = sendto(port->socket, req->response, req->response_len, 0, |
|
|
1151 | (struct sockaddr*) &req->addr, req->addrlen); |
|
|
1152 | if (r < 0) { |
|
|
1153 | int err = last_error(port->socket); |
|
|
1154 | if (error_is_eagain(err)) |
|
|
1155 | return; |
|
|
1156 | log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", strerror(err), err); |
|
|
1157 | } |
|
|
1158 | if (server_request_free(req)) { |
|
|
1159 | /* we released the last reference to req->port. */ |
|
|
1160 | return; |
|
|
1161 | } |
|
|
1162 | } |
|
|
1163 | |
|
|
1164 | /* We have no more pending requests; stop listening for 'writeable' events. */ |
|
|
1165 | (void) event_del(&port->event); |
|
|
1166 | event_set(&port->event, port->socket, EV_READ | EV_PERSIST, |
|
|
1167 | server_port_ready_callback, port); |
|
|
1168 | if (event_add(&port->event, NULL) < 0) { |
|
|
1169 | log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server."); |
|
|
1170 | /* ???? Do more? */ |
|
|
1171 | } |
|
|
1172 | } |
|
|
1173 | |
|
|
1174 | /* set if we are waiting for the ability to write to this server. */ |
|
|
1175 | /* if waiting is true then we ask libevent for EV_WRITE events, otherwise */ |
|
|
1176 | /* we stop these events. */ |
|
|
1177 | static void |
|
|
1178 | nameserver_write_waiting(struct nameserver *ns, char waiting) { |
|
|
1179 | if (ns->write_waiting == waiting) return; |
|
|
1180 | |
|
|
1181 | ns->write_waiting = waiting; |
|
|
1182 | (void) event_del(&ns->event); |
|
|
1183 | event_set(&ns->event, ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST, |
|
|
1184 | nameserver_ready_callback, ns); |
|
|
1185 | if (event_add(&ns->event, NULL) < 0) { |
|
|
1186 | log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s", |
|
|
1187 | debug_ntoa(ns->address)); |
|
|
1188 | /* ???? Do more? */ |
|
|
1189 | } |
|
|
1190 | } |
|
|
1191 | |
|
|
1192 | /* a callback function. Called by libevent when the kernel says that */ |
|
|
1193 | /* a nameserver socket is ready for writing or reading */ |
|
|
1194 | static void |
|
|
1195 | nameserver_ready_callback(int fd, short events, void *arg) { |
|
|
1196 | struct nameserver *ns = (struct nameserver *) arg; |
|
|
1197 | (void)fd; |
|
|
1198 | |
|
|
1199 | if (events & EV_WRITE) { |
|
|
1200 | ns->choked = 0; |
|
|
1201 | if (!evdns_transmit()) { |
|
|
1202 | nameserver_write_waiting(ns, 0); |
|
|
1203 | } |
|
|
1204 | } |
|
|
1205 | if (events & EV_READ) { |
|
|
1206 | nameserver_read(ns); |
|
|
1207 | } |
|
|
1208 | } |
|
|
1209 | |
|
|
1210 | /* a callback function. Called by libevent when the kernel says that */ |
|
|
1211 | /* a server socket is ready for writing or reading. */ |
|
|
1212 | static void |
|
|
1213 | server_port_ready_callback(int fd, short events, void *arg) { |
|
|
1214 | struct evdns_server_port *port = (struct evdns_server_port *) arg; |
|
|
1215 | (void) fd; |
|
|
1216 | |
|
|
1217 | if (events & EV_WRITE) { |
|
|
1218 | port->choked = 0; |
|
|
1219 | server_port_flush(port); |
|
|
1220 | } |
|
|
1221 | if (events & EV_READ) { |
|
|
1222 | server_port_read(port); |
|
|
1223 | } |
|
|
1224 | } |
|
|
1225 | |
|
|
1226 | /* This is an inefficient representation; only use it via the dnslabel_table_* |
|
|
1227 | * functions, so that is can be safely replaced with something smarter later. */ |
|
|
1228 | #define MAX_LABELS 128 |
|
|
1229 | /* Structures used to implement name compression */ |
|
|
1230 | struct dnslabel_entry { char *v; off_t pos; }; |
|
|
1231 | struct dnslabel_table { |
|
|
1232 | int n_labels; /* number of current entries */ |
|
|
1233 | /* map from name to position in message */ |
|
|
1234 | struct dnslabel_entry labels[MAX_LABELS]; |
|
|
1235 | }; |
|
|
1236 | |
|
|
1237 | /* Initialize dnslabel_table. */ |
|
|
1238 | static void |
|
|
1239 | dnslabel_table_init(struct dnslabel_table *table) |
|
|
1240 | { |
|
|
1241 | table->n_labels = 0; |
|
|
1242 | } |
|
|
1243 | |
|
|
1244 | /* Free all storage held by table, but not the table itself. */ |
|
|
1245 | static void |
|
|
1246 | dnslabel_clear(struct dnslabel_table *table) |
|
|
1247 | { |
|
|
1248 | int i; |
|
|
1249 | for (i = 0; i < table->n_labels; ++i) |
|
|
1250 | free(table->labels[i].v); |
|
|
1251 | table->n_labels = 0; |
|
|
1252 | } |
|
|
1253 | |
|
|
1254 | /* return the position of the label in the current message, or -1 if the label */ |
|
|
1255 | /* hasn't been used yet. */ |
|
|
1256 | static int |
|
|
1257 | dnslabel_table_get_pos(const struct dnslabel_table *table, const char *label) |
|
|
1258 | { |
|
|
1259 | int i; |
|
|
1260 | for (i = 0; i < table->n_labels; ++i) { |
|
|
1261 | if (!strcmp(label, table->labels[i].v)) |
|
|
1262 | return table->labels[i].pos; |
|
|
1263 | } |
|
|
1264 | return -1; |
|
|
1265 | } |
|
|
1266 | |
|
|
1267 | /* remember that we've used the label at position pos */ |
|
|
1268 | static int |
|
|
1269 | dnslabel_table_add(struct dnslabel_table *table, const char *label, off_t pos) |
|
|
1270 | { |
|
|
1271 | char *v; |
|
|
1272 | int p; |
|
|
1273 | if (table->n_labels == MAX_LABELS) |
|
|
1274 | return (-1); |
|
|
1275 | v = strdup(label); |
|
|
1276 | if (v == NULL) |
|
|
1277 | return (-1); |
|
|
1278 | p = table->n_labels++; |
|
|
1279 | table->labels[p].v = v; |
|
|
1280 | table->labels[p].pos = pos; |
|
|
1281 | |
|
|
1282 | return (0); |
|
|
1283 | } |
|
|
1284 | |
|
|
1285 | /* Converts a string to a length-prefixed set of DNS labels, starting */ |
|
|
1286 | /* at buf[j]. name and buf must not overlap. name_len should be the length */ |
|
|
1287 | /* of name. table is optional, and is used for compression. */ |
|
|
1288 | /* */ |
|
|
1289 | /* Input: abc.def */ |
|
|
1290 | /* Output: <3>abc<3>def<0> */ |
|
|
1291 | /* */ |
|
|
1292 | /* Returns the first index after the encoded name, or negative on error. */ |
|
|
1293 | /* -1 label was > 63 bytes */ |
|
|
1294 | /* -2 name too long to fit in buffer. */ |
|
|
1295 | /* */ |
|
|
1296 | static off_t |
|
|
1297 | dnsname_to_labels(u8 *const buf, size_t buf_len, off_t j, |
|
|
1298 | const char *name, const int name_len, |
|
|
1299 | struct dnslabel_table *table) { |
|
|
1300 | const char *end = name + name_len; |
|
|
1301 | int ref = 0; |
|
|
1302 | u16 _t; |
|
|
1303 | |
|
|
1304 | #define APPEND16(x) do { \ |
|
|
1305 | if (j + 2 > (off_t)buf_len) \ |
|
|
1306 | goto overflow; \ |
|
|
1307 | _t = htons(x); \ |
|
|
1308 | memcpy(buf + j, &_t, 2); \ |
|
|
1309 | j += 2; \ |
|
|
1310 | } while (0) |
|
|
1311 | #define APPEND32(x) do { \ |
|
|
1312 | if (j + 4 > (off_t)buf_len) \ |
|
|
1313 | goto overflow; \ |
|
|
1314 | _t32 = htonl(x); \ |
|
|
1315 | memcpy(buf + j, &_t32, 4); \ |
|
|
1316 | j += 4; \ |
|
|
1317 | } while (0) |
|
|
1318 | |
|
|
1319 | if (name_len > 255) return -2; |
|
|
1320 | |
|
|
1321 | for (;;) { |
|
|
1322 | const char *const start = name; |
|
|
1323 | if (table && (ref = dnslabel_table_get_pos(table, name)) >= 0) { |
|
|
1324 | APPEND16(ref | 0xc000); |
|
|
1325 | return j; |
|
|
1326 | } |
|
|
1327 | name = strchr(name, '.'); |
|
|
1328 | if (!name) { |
|
|
1329 | const unsigned int label_len = end - start; |
|
|
1330 | if (label_len > 63) return -1; |
|
|
1331 | if ((size_t)(j+label_len+1) > buf_len) return -2; |
|
|
1332 | if (table) dnslabel_table_add(table, start, j); |
|
|
1333 | buf[j++] = label_len; |
|
|
1334 | |
|
|
1335 | memcpy(buf + j, start, end - start); |
|
|
1336 | j += end - start; |
|
|
1337 | break; |
|
|
1338 | } else { |
|
|
1339 | /* append length of the label. */ |
|
|
1340 | const unsigned int label_len = name - start; |
|
|
1341 | if (label_len > 63) return -1; |
|
|
1342 | if ((size_t)(j+label_len+1) > buf_len) return -2; |
|
|
1343 | if (table) dnslabel_table_add(table, start, j); |
|
|
1344 | buf[j++] = label_len; |
|
|
1345 | |
|
|
1346 | memcpy(buf + j, start, name - start); |
|
|
1347 | j += name - start; |
|
|
1348 | /* hop over the '.' */ |
|
|
1349 | name++; |
|
|
1350 | } |
|
|
1351 | } |
|
|
1352 | |
|
|
1353 | /* the labels must be terminated by a 0. */ |
|
|
1354 | /* It's possible that the name ended in a . */ |
|
|
1355 | /* in which case the zero is already there */ |
|
|
1356 | if (!j || buf[j-1]) buf[j++] = 0; |
|
|
1357 | return j; |
|
|
1358 | overflow: |
|
|
1359 | return (-2); |
|
|
1360 | } |
|
|
1361 | |
|
|
1362 | /* Finds the length of a dns request for a DNS name of the given */ |
|
|
1363 | /* length. The actual request may be smaller than the value returned */ |
|
|
1364 | /* here */ |
|
|
1365 | static int |
|
|
1366 | evdns_request_len(const int name_len) { |
|
|
1367 | return 96 + /* length of the DNS standard header */ |
|
|
1368 | name_len + 2 + |
|
|
1369 | 4; /* space for the resource type */ |
|
|
1370 | } |
|
|
1371 | |
|
|
1372 | /* build a dns request packet into buf. buf should be at least as long */ |
|
|
1373 | /* as evdns_request_len told you it should be. */ |
|
|
1374 | /* */ |
|
|
1375 | /* Returns the amount of space used. Negative on error. */ |
|
|
1376 | static int |
|
|
1377 | evdns_request_data_build(const char *const name, const int name_len, |
|
|
1378 | const u16 trans_id, const u16 type, const u16 class, |
|
|
1379 | u8 *const buf, size_t buf_len) { |
|
|
1380 | off_t j = 0; /* current offset into buf */ |
|
|
1381 | u16 _t; /* used by the macros */ |
|
|
1382 | |
|
|
1383 | APPEND16(trans_id); |
|
|
1384 | APPEND16(0x0100); /* standard query, recusion needed */ |
|
|
1385 | APPEND16(1); /* one question */ |
|
|
1386 | APPEND16(0); /* no answers */ |
|
|
1387 | APPEND16(0); /* no authority */ |
|
|
1388 | APPEND16(0); /* no additional */ |
|
|
1389 | |
|
|
1390 | j = dnsname_to_labels(buf, buf_len, j, name, name_len, NULL); |
|
|
1391 | if (j < 0) { |
|
|
1392 | return (int)j; |
|
|
1393 | } |
|
|
1394 | |
|
|
1395 | APPEND16(type); |
|
|
1396 | APPEND16(class); |
|
|
1397 | |
|
|
1398 | return (int)j; |
|
|
1399 | overflow: |
|
|
1400 | return (-1); |
|
|
1401 | } |
|
|
1402 | |
|
|
1403 | /* exported function */ |
|
|
1404 | struct evdns_server_port * |
|
|
1405 | evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type cb, void *user_data) |
|
|
1406 | { |
|
|
1407 | struct evdns_server_port *port; |
|
|
1408 | if (!(port = malloc(sizeof(struct evdns_server_port)))) |
|
|
1409 | return NULL; |
|
|
1410 | memset(port, 0, sizeof(struct evdns_server_port)); |
|
|
1411 | |
|
|
1412 | assert(!is_tcp); /* TCP sockets not yet implemented */ |
|
|
1413 | port->socket = socket; |
|
|
1414 | port->refcnt = 1; |
|
|
1415 | port->choked = 0; |
|
|
1416 | port->closing = 0; |
|
|
1417 | port->user_callback = cb; |
|
|
1418 | port->user_data = user_data; |
|
|
1419 | port->pending_replies = NULL; |
|
|
1420 | |
|
|
1421 | event_set(&port->event, port->socket, EV_READ | EV_PERSIST, |
|
|
1422 | server_port_ready_callback, port); |
|
|
1423 | event_add(&port->event, NULL); /* check return. */ |
|
|
1424 | return port; |
|
|
1425 | } |
|
|
1426 | |
|
|
1427 | /* exported function */ |
|
|
1428 | void |
|
|
1429 | evdns_close_server_port(struct evdns_server_port *port) |
|
|
1430 | { |
|
|
1431 | if (--port->refcnt == 0) |
|
|
1432 | server_port_free(port); |
|
|
1433 | port->closing = 1; |
|
|
1434 | } |
|
|
1435 | |
|
|
1436 | /* exported function */ |
|
|
1437 | int |
|
|
1438 | 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) |
|
|
1439 | { |
|
|
1440 | struct server_request *req = TO_SERVER_REQUEST(_req); |
|
|
1441 | struct server_reply_item **itemp, *item; |
|
|
1442 | int *countp; |
|
|
1443 | |
|
|
1444 | if (req->response) /* have we already answered? */ |
|
|
1445 | return (-1); |
|
|
1446 | |
|
|
1447 | switch (section) { |
|
|
1448 | case EVDNS_ANSWER_SECTION: |
|
|
1449 | itemp = &req->answer; |
|
|
1450 | countp = &req->n_answer; |
|
|
1451 | break; |
|
|
1452 | case EVDNS_AUTHORITY_SECTION: |
|
|
1453 | itemp = &req->authority; |
|
|
1454 | countp = &req->n_authority; |
|
|
1455 | break; |
|
|
1456 | case EVDNS_ADDITIONAL_SECTION: |
|
|
1457 | itemp = &req->additional; |
|
|
1458 | countp = &req->n_additional; |
|
|
1459 | break; |
|
|
1460 | default: |
|
|
1461 | return (-1); |
|
|
1462 | } |
|
|
1463 | while (*itemp) { |
|
|
1464 | itemp = &((*itemp)->next); |
|
|
1465 | } |
|
|
1466 | item = malloc(sizeof(struct server_reply_item)); |
|
|
1467 | if (!item) |
|
|
1468 | return -1; |
|
|
1469 | item->next = NULL; |
|
|
1470 | if (!(item->name = strdup(name))) { |
|
|
1471 | free(item); |
|
|
1472 | return -1; |
|
|
1473 | } |
|
|
1474 | item->type = type; |
|
|
1475 | item->class = class; |
|
|
1476 | item->ttl = ttl; |
|
|
1477 | item->is_name = is_name != 0; |
|
|
1478 | item->datalen = 0; |
|
|
1479 | item->data = NULL; |
|
|
1480 | if (data) { |
|
|
1481 | if (item->is_name) { |
|
|
1482 | if (!(item->data = strdup(data))) { |
|
|
1483 | free(item->name); |
|
|
1484 | free(item); |
|
|
1485 | return -1; |
|
|
1486 | } |
|
|
1487 | item->datalen = (u16)-1; |
|
|
1488 | } else { |
|
|
1489 | if (!(item->data = malloc(datalen))) { |
|
|
1490 | free(item->name); |
|
|
1491 | free(item); |
|
|
1492 | return -1; |
|
|
1493 | } |
|
|
1494 | item->datalen = datalen; |
|
|
1495 | memcpy(item->data, data, datalen); |
|
|
1496 | } |
|
|
1497 | } |
|
|
1498 | |
|
|
1499 | *itemp = item; |
|
|
1500 | ++(*countp); |
|
|
1501 | return 0; |
|
|
1502 | } |
|
|
1503 | |
|
|
1504 | /* exported function */ |
|
|
1505 | int |
|
|
1506 | evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl) |
|
|
1507 | { |
|
|
1508 | return evdns_server_request_add_reply( |
|
|
1509 | req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET, |
|
|
1510 | ttl, n*4, 0, addrs); |
|
|
1511 | } |
|
|
1512 | |
|
|
1513 | /* exported function */ |
|
|
1514 | int |
|
|
1515 | evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl) |
|
|
1516 | { |
|
|
1517 | return evdns_server_request_add_reply( |
|
|
1518 | req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET, |
|
|
1519 | ttl, n*16, 0, addrs); |
|
|
1520 | } |
|
|
1521 | |
|
|
1522 | /* exported function */ |
|
|
1523 | int |
|
|
1524 | evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl) |
|
|
1525 | { |
|
|
1526 | u32 a; |
|
|
1527 | char buf[32]; |
|
|
1528 | assert(in || inaddr_name); |
|
|
1529 | assert(!(in && inaddr_name)); |
|
|
1530 | if (in) { |
|
|
1531 | a = ntohl(in->s_addr); |
|
|
1532 | snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa", |
|
|
1533 | (int)(u8)((a )&0xff), |
|
|
1534 | (int)(u8)((a>>8 )&0xff), |
|
|
1535 | (int)(u8)((a>>16)&0xff), |
|
|
1536 | (int)(u8)((a>>24)&0xff)); |
|
|
1537 | inaddr_name = buf; |
|
|
1538 | } |
|
|
1539 | return evdns_server_request_add_reply( |
|
|
1540 | req, EVDNS_ANSWER_SECTION, inaddr_name, TYPE_PTR, CLASS_INET, |
|
|
1541 | ttl, -1, 1, hostname); |
|
|
1542 | } |
|
|
1543 | |
|
|
1544 | /* exported function */ |
|
|
1545 | int |
|
|
1546 | evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl) |
|
|
1547 | { |
|
|
1548 | return evdns_server_request_add_reply( |
|
|
1549 | req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET, |
|
|
1550 | ttl, -1, 1, cname); |
|
|
1551 | } |
|
|
1552 | |
|
|
1553 | |
|
|
1554 | static int |
|
|
1555 | evdns_server_request_format_response(struct server_request *req, int err) |
|
|
1556 | { |
|
|
1557 | unsigned char buf[1500]; |
|
|
1558 | size_t buf_len = sizeof(buf); |
|
|
1559 | off_t j = 0, r; |
|
|
1560 | u16 _t; |
|
|
1561 | u32 _t32; |
|
|
1562 | int i; |
|
|
1563 | u16 flags; |
|
|
1564 | struct dnslabel_table table; |
|
|
1565 | |
|
|
1566 | if (err < 0 || err > 15) return -1; |
|
|
1567 | |
|
|
1568 | /* Set response bit and error code; copy OPCODE and RD fields from |
|
|
1569 | * question; copy RA and AA if set by caller. */ |
|
|
1570 | flags = req->base.flags; |
|
|
1571 | flags |= (0x8000 | err); |
|
|
1572 | |
|
|
1573 | dnslabel_table_init(&table); |
|
|
1574 | APPEND16(req->trans_id); |
|
|
1575 | APPEND16(flags); |
|
|
1576 | APPEND16(req->base.nquestions); |
|
|
1577 | APPEND16(req->n_answer); |
|
|
1578 | APPEND16(req->n_authority); |
|
|
1579 | APPEND16(req->n_additional); |
|
|
1580 | |
|
|
1581 | /* Add questions. */ |
|
|
1582 | for (i=0; i < req->base.nquestions; ++i) { |
|
|
1583 | const char *s = req->base.questions[i]->name; |
|
|
1584 | j = dnsname_to_labels(buf, buf_len, j, s, strlen(s), &table); |
|
|
1585 | if (j < 0) { |
|
|
1586 | dnslabel_clear(&table); |
|
|
1587 | return (int) j; |
|
|
1588 | } |
|
|
1589 | APPEND16(req->base.questions[i]->type); |
|
|
1590 | APPEND16(req->base.questions[i]->class); |
|
|
1591 | } |
|
|
1592 | |
|
|
1593 | /* Add answer, authority, and additional sections. */ |
|
|
1594 | for (i=0; i<3; ++i) { |
|
|
1595 | struct server_reply_item *item; |
|
|
1596 | if (i==0) |
|
|
1597 | item = req->answer; |
|
|
1598 | else if (i==1) |
|
|
1599 | item = req->authority; |
|
|
1600 | else |
|
|
1601 | item = req->additional; |
|
|
1602 | while (item) { |
|
|
1603 | r = dnsname_to_labels(buf, buf_len, j, item->name, strlen(item->name), &table); |
|
|
1604 | if (r < 0) |
|
|
1605 | goto overflow; |
|
|
1606 | j = r; |
|
|
1607 | |
|
|
1608 | APPEND16(item->type); |
|
|
1609 | APPEND16(item->class); |
|
|
1610 | APPEND32(item->ttl); |
|
|
1611 | if (item->is_name) { |
|
|
1612 | off_t len_idx = j, name_start; |
|
|
1613 | j += 2; |
|
|
1614 | name_start = j; |
|
|
1615 | r = dnsname_to_labels(buf, buf_len, j, item->data, strlen(item->data), &table); |
|
|
1616 | if (r < 0) |
|
|
1617 | goto overflow; |
|
|
1618 | j = r; |
|
|
1619 | _t = htons( (j-name_start) ); |
|
|
1620 | memcpy(buf+len_idx, &_t, 2); |
|
|
1621 | } else { |
|
|
1622 | APPEND16(item->datalen); |
|
|
1623 | if (j+item->datalen > (off_t)buf_len) |
|
|
1624 | goto overflow; |
|
|
1625 | memcpy(buf+j, item->data, item->datalen); |
|
|
1626 | j += item->datalen; |
|
|
1627 | } |
|
|
1628 | item = item->next; |
|
|
1629 | } |
|
|
1630 | } |
|
|
1631 | |
|
|
1632 | if (j > 512) { |
|
|
1633 | overflow: |
|
|
1634 | j = 512; |
|
|
1635 | buf[3] |= 0x02; /* set the truncated bit. */ |
|
|
1636 | } |
|
|
1637 | |
|
|
1638 | req->response_len = j; |
|
|
1639 | |
|
|
1640 | if (!(req->response = malloc(req->response_len))) { |
|
|
1641 | server_request_free_answers(req); |
|
|
1642 | dnslabel_clear(&table); |
|
|
1643 | return (-1); |
|
|
1644 | } |
|
|
1645 | memcpy(req->response, buf, req->response_len); |
|
|
1646 | server_request_free_answers(req); |
|
|
1647 | dnslabel_clear(&table); |
|
|
1648 | return (0); |
|
|
1649 | } |
|
|
1650 | |
|
|
1651 | /* exported function */ |
|
|
1652 | int |
|
|
1653 | evdns_server_request_respond(struct evdns_server_request *_req, int err) |
|
|
1654 | { |
|
|
1655 | struct server_request *req = TO_SERVER_REQUEST(_req); |
|
|
1656 | struct evdns_server_port *port = req->port; |
|
|
1657 | int r; |
|
|
1658 | if (!req->response) { |
|
|
1659 | if ((r = evdns_server_request_format_response(req, err))<0) |
|
|
1660 | return r; |
|
|
1661 | } |
|
|
1662 | |
|
|
1663 | r = sendto(port->socket, req->response, req->response_len, 0, |
|
|
1664 | (struct sockaddr*) &req->addr, req->addrlen); |
|
|
1665 | if (r<0) { |
|
|
1666 | int err = last_error(port->socket); |
|
|
1667 | if (! error_is_eagain(err)) |
|
|
1668 | return -1; |
|
|
1669 | |
|
|
1670 | if (port->pending_replies) { |
|
|
1671 | req->prev_pending = port->pending_replies->prev_pending; |
|
|
1672 | req->next_pending = port->pending_replies; |
|
|
1673 | req->prev_pending->next_pending = |
|
|
1674 | req->next_pending->prev_pending = req; |
|
|
1675 | } else { |
|
|
1676 | req->prev_pending = req->next_pending = req; |
|
|
1677 | port->pending_replies = req; |
|
|
1678 | port->choked = 1; |
|
|
1679 | |
|
|
1680 | (void) event_del(&port->event); |
|
|
1681 | event_set(&port->event, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port); |
|
|
1682 | |
|
|
1683 | if (event_add(&port->event, NULL) < 0) { |
|
|
1684 | log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server"); |
|
|
1685 | } |
|
|
1686 | |
|
|
1687 | } |
|
|
1688 | |
|
|
1689 | return 1; |
|
|
1690 | } |
|
|
1691 | if (server_request_free(req)) |
|
|
1692 | return 0; |
|
|
1693 | |
|
|
1694 | if (port->pending_replies) |
|
|
1695 | server_port_flush(port); |
|
|
1696 | |
|
|
1697 | return 0; |
|
|
1698 | } |
|
|
1699 | |
|
|
1700 | /* Free all storage held by RRs in req. */ |
|
|
1701 | static void |
|
|
1702 | server_request_free_answers(struct server_request *req) |
|
|
1703 | { |
|
|
1704 | struct server_reply_item *victim, *next, **list; |
|
|
1705 | int i; |
|
|
1706 | for (i = 0; i < 3; ++i) { |
|
|
1707 | if (i==0) |
|
|
1708 | list = &req->answer; |
|
|
1709 | else if (i==1) |
|
|
1710 | list = &req->authority; |
|
|
1711 | else |
|
|
1712 | list = &req->additional; |
|
|
1713 | |
|
|
1714 | victim = *list; |
|
|
1715 | while (victim) { |
|
|
1716 | next = victim->next; |
|
|
1717 | free(victim->name); |
|
|
1718 | if (victim->data) |
|
|
1719 | free(victim->data); |
|
|
1720 | free(victim); |
|
|
1721 | victim = next; |
|
|
1722 | } |
|
|
1723 | *list = NULL; |
|
|
1724 | } |
|
|
1725 | } |
|
|
1726 | |
|
|
1727 | /* Free all storage held by req, and remove links to it. */ |
|
|
1728 | /* return true iff we just wound up freeing the server_port. */ |
|
|
1729 | static int |
|
|
1730 | server_request_free(struct server_request *req) |
|
|
1731 | { |
|
|
1732 | int i, rc=1; |
|
|
1733 | if (req->base.questions) { |
|
|
1734 | for (i = 0; i < req->base.nquestions; ++i) |
|
|
1735 | free(req->base.questions[i]); |
|
|
1736 | free(req->base.questions); |
|
|
1737 | } |
|
|
1738 | |
|
|
1739 | if (req->port) { |
|
|
1740 | if (req->port->pending_replies == req) { |
|
|
1741 | if (req->next_pending) |
|
|
1742 | req->port->pending_replies = req->next_pending; |
|
|
1743 | else |
|
|
1744 | req->port->pending_replies = NULL; |
|
|
1745 | } |
|
|
1746 | rc = --req->port->refcnt; |
|
|
1747 | } |
|
|
1748 | |
|
|
1749 | if (req->response) { |
|
|
1750 | free(req->response); |
|
|
1751 | } |
|
|
1752 | |
|
|
1753 | server_request_free_answers(req); |
|
|
1754 | |
|
|
1755 | if (req->next_pending && req->next_pending != req) { |
|
|
1756 | req->next_pending->prev_pending = req->prev_pending; |
|
|
1757 | req->prev_pending->next_pending = req->next_pending; |
|
|
1758 | } |
|
|
1759 | |
|
|
1760 | if (rc == 0) { |
|
|
1761 | server_port_free(req->port); |
|
|
1762 | free(req); |
|
|
1763 | return (1); |
|
|
1764 | } |
|
|
1765 | free(req); |
|
|
1766 | return (0); |
|
|
1767 | } |
|
|
1768 | |
|
|
1769 | /* Free all storage held by an evdns_server_port. Only called when */ |
|
|
1770 | static void |
|
|
1771 | server_port_free(struct evdns_server_port *port) |
|
|
1772 | { |
|
|
1773 | assert(port); |
|
|
1774 | assert(!port->refcnt); |
|
|
1775 | assert(!port->pending_replies); |
|
|
1776 | if (port->socket > 0) { |
|
|
1777 | CLOSE_SOCKET(port->socket); |
|
|
1778 | port->socket = -1; |
|
|
1779 | } |
|
|
1780 | (void) event_del(&port->event); |
|
|
1781 | /* XXXX actually free the port? -NM */ |
|
|
1782 | } |
|
|
1783 | |
|
|
1784 | /* exported function */ |
|
|
1785 | int |
|
|
1786 | evdns_server_request_drop(struct evdns_server_request *_req) |
|
|
1787 | { |
|
|
1788 | struct server_request *req = TO_SERVER_REQUEST(_req); |
|
|
1789 | server_request_free(req); |
|
|
1790 | return 0; |
|
|
1791 | } |
|
|
1792 | |
|
|
1793 | /* exported function */ |
|
|
1794 | int |
|
|
1795 | evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len) |
|
|
1796 | { |
|
|
1797 | struct server_request *req = TO_SERVER_REQUEST(_req); |
|
|
1798 | if (addr_len < (int)req->addrlen) |
|
|
1799 | return -1; |
|
|
1800 | memcpy(sa, &(req->addr), req->addrlen); |
|
|
1801 | return req->addrlen; |
|
|
1802 | } |
|
|
1803 | |
|
|
1804 | #undef APPEND16 |
|
|
1805 | #undef APPEND32 |
|
|
1806 | |
|
|
1807 | /* this is a libevent callback function which is called when a request */ |
|
|
1808 | /* has timed out. */ |
|
|
1809 | static void |
|
|
1810 | evdns_request_timeout_callback(int fd, short events, void *arg) { |
|
|
1811 | struct request *const req = (struct request *) arg; |
|
|
1812 | (void) fd; |
|
|
1813 | (void) events; |
|
|
1814 | |
|
|
1815 | log(EVDNS_LOG_DEBUG, "Request %lx timed out", (unsigned long) arg); |
|
|
1816 | |
|
|
1817 | req->ns->timedout++; |
|
|
1818 | if (req->ns->timedout > global_max_nameserver_timeout) { |
|
|
1819 | req->ns->timedout = 0; |
|
|
1820 | nameserver_failed(req->ns, "request timed out."); |
|
|
1821 | } |
|
|
1822 | |
|
|
1823 | (void) evtimer_del(&req->timeout_event); |
|
|
1824 | if (req->tx_count >= global_max_retransmits) { |
|
|
1825 | /* this request has failed */ |
|
|
1826 | reply_callback(req, 0, DNS_ERR_TIMEOUT, NULL); |
|
|
1827 | request_finished(req, &req_head); |
|
|
1828 | } else { |
|
|
1829 | /* retransmit it */ |
|
|
1830 | evdns_request_transmit(req); |
|
|
1831 | } |
|
|
1832 | } |
|
|
1833 | |
|
|
1834 | /* try to send a request to a given server. */ |
|
|
1835 | /* */ |
|
|
1836 | /* return: */ |
|
|
1837 | /* 0 ok */ |
|
|
1838 | /* 1 temporary failure */ |
|
|
1839 | /* 2 other failure */ |
|
|
1840 | static int |
|
|
1841 | evdns_request_transmit_to(struct request *req, struct nameserver *server) { |
|
|
1842 | const int r = send(server->socket, req->request, req->request_len, 0); |
|
|
1843 | if (r < 0) { |
|
|
1844 | int err = last_error(server->socket); |
|
|
1845 | if (error_is_eagain(err)) return 1; |
|
|
1846 | nameserver_failed(req->ns, strerror(err)); |
|
|
1847 | return 2; |
|
|
1848 | } else if (r != (int)req->request_len) { |
|
|
1849 | return 1; /* short write */ |
|
|
1850 | } else { |
|
|
1851 | return 0; |
|
|
1852 | } |
|
|
1853 | } |
|
|
1854 | |
|
|
1855 | /* try to send a request, updating the fields of the request */ |
|
|
1856 | /* as needed */ |
|
|
1857 | /* */ |
|
|
1858 | /* return: */ |
|
|
1859 | /* 0 ok */ |
|
|
1860 | /* 1 failed */ |
|
|
1861 | static int |
|
|
1862 | evdns_request_transmit(struct request *req) { |
|
|
1863 | int retcode = 0, r; |
|
|
1864 | |
|
|
1865 | /* if we fail to send this packet then this flag marks it */ |
|
|
1866 | /* for evdns_transmit */ |
|
|
1867 | req->transmit_me = 1; |
|
|
1868 | if (req->trans_id == 0xffff) abort(); |
|
|
1869 | |
|
|
1870 | if (req->ns->choked) { |
|
|
1871 | /* don't bother trying to write to a socket */ |
|
|
1872 | /* which we have had EAGAIN from */ |
|
|
1873 | return 1; |
|
|
1874 | } |
|
|
1875 | |
|
|
1876 | r = evdns_request_transmit_to(req, req->ns); |
|
|
1877 | switch (r) { |
|
|
1878 | case 1: |
|
|
1879 | /* temp failure */ |
|
|
1880 | req->ns->choked = 1; |
|
|
1881 | nameserver_write_waiting(req->ns, 1); |
|
|
1882 | return 1; |
|
|
1883 | case 2: |
|
|
1884 | /* failed in some other way */ |
|
|
1885 | retcode = 1; |
|
|
1886 | /* fall through */ |
|
|
1887 | default: |
|
|
1888 | /* all ok */ |
|
|
1889 | log(EVDNS_LOG_DEBUG, |
|
|
1890 | "Setting timeout for request %lx", (unsigned long) req); |
|
|
1891 | evtimer_set(&req->timeout_event, evdns_request_timeout_callback, req); |
|
|
1892 | if (evtimer_add(&req->timeout_event, &global_timeout) < 0) { |
|
|
1893 | log(EVDNS_LOG_WARN, |
|
|
1894 | "Error from libevent when adding timer for request %lx", |
|
|
1895 | (unsigned long) req); |
|
|
1896 | /* ???? Do more? */ |
|
|
1897 | } |
|
|
1898 | req->tx_count++; |
|
|
1899 | req->transmit_me = 0; |
|
|
1900 | return retcode; |
|
|
1901 | } |
|
|
1902 | } |
|
|
1903 | |
|
|
1904 | static void |
|
|
1905 | nameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) { |
|
|
1906 | struct nameserver *const ns = (struct nameserver *) arg; |
|
|
1907 | (void) type; |
|
|
1908 | (void) count; |
|
|
1909 | (void) ttl; |
|
|
1910 | (void) addresses; |
|
|
1911 | |
|
|
1912 | if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) { |
|
|
1913 | /* this is a good reply */ |
|
|
1914 | nameserver_up(ns); |
|
|
1915 | } else nameserver_probe_failed(ns); |
|
|
1916 | } |
|
|
1917 | |
|
|
1918 | static void |
|
|
1919 | nameserver_send_probe(struct nameserver *const ns) { |
|
|
1920 | struct request *req; |
|
|
1921 | /* here we need to send a probe to a given nameserver */ |
|
|
1922 | /* in the hope that it is up now. */ |
|
|
1923 | |
|
|
1924 | log(EVDNS_LOG_DEBUG, "Sending probe to %s", debug_ntoa(ns->address)); |
|
|
1925 | |
|
|
1926 | req = request_new(TYPE_A, "www.google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns); |
|
|
1927 | if (!req) return; |
|
|
1928 | /* we force this into the inflight queue no matter what */ |
|
|
1929 | request_trans_id_set(req, transaction_id_pick()); |
|
|
1930 | req->ns = ns; |
|
|
1931 | request_submit(req); |
|
|
1932 | } |
|
|
1933 | |
|
|
1934 | /* returns: */ |
|
|
1935 | /* 0 didn't try to transmit anything */ |
|
|
1936 | /* 1 tried to transmit something */ |
|
|
1937 | static int |
|
|
1938 | evdns_transmit(void) { |
|
|
1939 | char did_try_to_transmit = 0; |
|
|
1940 | |
|
|
1941 | if (req_head) { |
|
|
1942 | struct request *const started_at = req_head, *req = req_head; |
|
|
1943 | /* first transmit all the requests which are currently waiting */ |
|
|
1944 | do { |
|
|
1945 | if (req->transmit_me) { |
|
|
1946 | did_try_to_transmit = 1; |
|
|
1947 | evdns_request_transmit(req); |
|
|
1948 | } |
|
|
1949 | |
|
|
1950 | req = req->next; |
|
|
1951 | } while (req != started_at); |
|
|
1952 | } |
|
|
1953 | |
|
|
1954 | return did_try_to_transmit; |
|
|
1955 | } |
|
|
1956 | |
|
|
1957 | /* exported function */ |
|
|
1958 | int |
|
|
1959 | evdns_count_nameservers(void) |
|
|
1960 | { |
|
|
1961 | const struct nameserver *server = server_head; |
|
|
1962 | int n = 0; |
|
|
1963 | if (!server) |
|
|
1964 | return 0; |
|
|
1965 | do { |
|
|
1966 | ++n; |
|
|
1967 | server = server->next; |
|
|
1968 | } while (server != server_head); |
|
|
1969 | return n; |
|
|
1970 | } |
|
|
1971 | |
|
|
1972 | /* exported function */ |
|
|
1973 | int |
|
|
1974 | evdns_clear_nameservers_and_suspend(void) |
|
|
1975 | { |
|
|
1976 | struct nameserver *server = server_head, *started_at = server_head; |
|
|
1977 | struct request *req = req_head, *req_started_at = req_head; |
|
|
1978 | |
|
|
1979 | if (!server) |
|
|
1980 | return 0; |
|
|
1981 | while (1) { |
|
|
1982 | struct nameserver *next = server->next; |
|
|
1983 | (void) event_del(&server->event); |
|
|
1984 | (void) evtimer_del(&server->timeout_event); |
|
|
1985 | if (server->socket >= 0) |
|
|
1986 | CLOSE_SOCKET(server->socket); |
|
|
1987 | free(server); |
|
|
1988 | if (next == started_at) |
|
|
1989 | break; |
|
|
1990 | server = next; |
|
|
1991 | } |
|
|
1992 | server_head = NULL; |
|
|
1993 | global_good_nameservers = 0; |
|
|
1994 | |
|
|
1995 | while (req) { |
|
|
1996 | struct request *next = req->next; |
|
|
1997 | req->tx_count = req->reissue_count = 0; |
|
|
1998 | req->ns = NULL; |
|
|
1999 | /* ???? What to do about searches? */ |
|
|
2000 | (void) evtimer_del(&req->timeout_event); |
|
|
2001 | req->trans_id = 0; |
|
|
2002 | req->transmit_me = 0; |
|
|
2003 | |
|
|
2004 | global_requests_waiting++; |
|
|
2005 | evdns_request_insert(req, &req_waiting_head); |
|
|
2006 | /* We want to insert these suspended elements at the front of |
|
|
2007 | * the waiting queue, since they were pending before any of |
|
|
2008 | * the waiting entries were added. This is a circular list, |
|
|
2009 | * so we can just shift the start back by one.*/ |
|
|
2010 | req_waiting_head = req_waiting_head->prev; |
|
|
2011 | |
|
|
2012 | if (next == req_started_at) |
|
|
2013 | break; |
|
|
2014 | req = next; |
|
|
2015 | } |
|
|
2016 | req_head = NULL; |
|
|
2017 | global_requests_inflight = 0; |
|
|
2018 | |
|
|
2019 | return 0; |
|
|
2020 | } |
|
|
2021 | |
|
|
2022 | |
|
|
2023 | /* exported function */ |
|
|
2024 | int |
|
|
2025 | evdns_resume(void) |
|
|
2026 | { |
|
|
2027 | evdns_requests_pump_waiting_queue(); |
|
|
2028 | return 0; |
|
|
2029 | } |
|
|
2030 | |
|
|
2031 | static int |
|
|
2032 | _evdns_nameserver_add_impl(unsigned long int address, int port) { |
|
|
2033 | /* first check to see if we already have this nameserver */ |
|
|
2034 | |
|
|
2035 | const struct nameserver *server = server_head, *const started_at = server_head; |
|
|
2036 | struct nameserver *ns; |
|
|
2037 | struct sockaddr_in sin; |
|
|
2038 | int err = 0; |
|
|
2039 | if (server) { |
|
|
2040 | do { |
|
|
2041 | if (server->address == address) return 3; |
|
|
2042 | server = server->next; |
|
|
2043 | } while (server != started_at); |
|
|
2044 | } |
|
|
2045 | |
|
|
2046 | ns = (struct nameserver *) malloc(sizeof(struct nameserver)); |
|
|
2047 | if (!ns) return -1; |
|
|
2048 | |
|
|
2049 | memset(ns, 0, sizeof(struct nameserver)); |
|
|
2050 | |
|
|
2051 | ns->socket = socket(PF_INET, SOCK_DGRAM, 0); |
|
|
2052 | if (ns->socket < 0) { err = 1; goto out1; } |
|
|
2053 | #ifdef WIN32 |
|
|
2054 | { |
|
|
2055 | u_long nonblocking = 1; |
|
|
2056 | ioctlsocket(ns->socket, FIONBIO, &nonblocking); |
|
|
2057 | } |
|
|
2058 | #else |
|
|
2059 | fcntl(ns->socket, F_SETFL, O_NONBLOCK); |
|
|
2060 | #endif |
|
|
2061 | sin.sin_addr.s_addr = address; |
|
|
2062 | sin.sin_port = htons(port); |
|
|
2063 | sin.sin_family = AF_INET; |
|
|
2064 | if (connect(ns->socket, (struct sockaddr *) &sin, sizeof(sin)) != 0) { |
|
|
2065 | err = 2; |
|
|
2066 | goto out2; |
|
|
2067 | } |
|
|
2068 | |
|
|
2069 | ns->address = address; |
|
|
2070 | ns->state = 1; |
|
|
2071 | event_set(&ns->event, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns); |
|
|
2072 | if (event_add(&ns->event, NULL) < 0) { |
|
|
2073 | err = 2; |
|
|
2074 | goto out2; |
|
|
2075 | } |
|
|
2076 | |
|
|
2077 | log(EVDNS_LOG_DEBUG, "Added nameserver %s", debug_ntoa(address)); |
|
|
2078 | |
|
|
2079 | /* insert this nameserver into the list of them */ |
|
|
2080 | if (!server_head) { |
|
|
2081 | ns->next = ns->prev = ns; |
|
|
2082 | server_head = ns; |
|
|
2083 | } else { |
|
|
2084 | ns->next = server_head->next; |
|
|
2085 | ns->prev = server_head; |
|
|
2086 | server_head->next = ns; |
|
|
2087 | if (server_head->prev == server_head) { |
|
|
2088 | server_head->prev = ns; |
|
|
2089 | } |
|
|
2090 | } |
|
|
2091 | |
|
|
2092 | global_good_nameservers++; |
|
|
2093 | |
|
|
2094 | return 0; |
|
|
2095 | |
|
|
2096 | out2: |
|
|
2097 | CLOSE_SOCKET(ns->socket); |
|
|
2098 | out1: |
|
|
2099 | free(ns); |
|
|
2100 | log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d", debug_ntoa(address), err); |
|
|
2101 | return err; |
|
|
2102 | } |
|
|
2103 | |
|
|
2104 | /* exported function */ |
|
|
2105 | int |
|
|
2106 | evdns_nameserver_add(unsigned long int address) { |
|
|
2107 | return _evdns_nameserver_add_impl(address, 53); |
|
|
2108 | } |
|
|
2109 | |
|
|
2110 | /* exported function */ |
|
|
2111 | int |
|
|
2112 | evdns_nameserver_ip_add(const char *ip_as_string) { |
|
|
2113 | struct in_addr ina; |
|
|
2114 | int port; |
|
|
2115 | char buf[20]; |
|
|
2116 | const char *cp; |
|
|
2117 | cp = strchr(ip_as_string, ':'); |
|
|
2118 | if (! cp) { |
|
|
2119 | cp = ip_as_string; |
|
|
2120 | port = 53; |
|
|
2121 | } else { |
|
|
2122 | port = strtoint(cp+1); |
|
|
2123 | if (port < 0 || port > 65535) { |
|
|
2124 | return 4; |
|
|
2125 | } |
|
|
2126 | if ((cp-ip_as_string) >= (int)sizeof(buf)) { |
|
|
2127 | return 4; |
|
|
2128 | } |
|
|
2129 | memcpy(buf, ip_as_string, cp-ip_as_string); |
|
|
2130 | buf[cp-ip_as_string] = '\0'; |
|
|
2131 | cp = buf; |
|
|
2132 | } |
|
|
2133 | if (!inet_aton(cp, &ina)) { |
|
|
2134 | return 4; |
|
|
2135 | } |
|
|
2136 | return _evdns_nameserver_add_impl(ina.s_addr, port); |
|
|
2137 | } |
|
|
2138 | |
|
|
2139 | /* insert into the tail of the queue */ |
|
|
2140 | static void |
|
|
2141 | evdns_request_insert(struct request *req, struct request **head) { |
|
|
2142 | if (!*head) { |
|
|
2143 | *head = req; |
|
|
2144 | req->next = req->prev = req; |
|
|
2145 | return; |
|
|
2146 | } |
|
|
2147 | |
|
|
2148 | req->prev = (*head)->prev; |
|
|
2149 | req->prev->next = req; |
|
|
2150 | req->next = *head; |
|
|
2151 | (*head)->prev = req; |
|
|
2152 | } |
|
|
2153 | |
|
|
2154 | static int |
|
|
2155 | string_num_dots(const char *s) { |
|
|
2156 | int count = 0; |
|
|
2157 | while ((s = strchr(s, '.'))) { |
|
|
2158 | s++; |
|
|
2159 | count++; |
|
|
2160 | } |
|
|
2161 | return count; |
|
|
2162 | } |
|
|
2163 | |
|
|
2164 | static struct request * |
|
|
2165 | request_new(int type, const char *name, int flags, |
|
|
2166 | evdns_callback_type callback, void *user_ptr) { |
|
|
2167 | const char issuing_now = |
|
|
2168 | (global_requests_inflight < global_max_requests_inflight) ? 1 : 0; |
|
|
2169 | |
|
|
2170 | const int name_len = strlen(name); |
|
|
2171 | const int request_max_len = evdns_request_len(name_len); |
|
|
2172 | const u16 trans_id = issuing_now ? transaction_id_pick() : 0xffff; |
|
|
2173 | /* the request data is alloced in a single block with the header */ |
|
|
2174 | struct request *const req = |
|
|
2175 | (struct request *) malloc(sizeof(struct request) + request_max_len); |
|
|
2176 | int rlen; |
|
|
2177 | (void) flags; |
|
|
2178 | |
|
|
2179 | if (!req) return NULL; |
|
|
2180 | memset(req, 0, sizeof(struct request)); |
|
|
2181 | |
|
|
2182 | /* request data lives just after the header */ |
|
|
2183 | req->request = ((u8 *) req) + sizeof(struct request); |
|
|
2184 | /* denotes that the request data shouldn't be free()ed */ |
|
|
2185 | req->request_appended = 1; |
|
|
2186 | rlen = evdns_request_data_build(name, name_len, trans_id, |
|
|
2187 | type, CLASS_INET, req->request, request_max_len); |
|
|
2188 | if (rlen < 0) |
|
|
2189 | goto err1; |
|
|
2190 | req->request_len = rlen; |
|
|
2191 | req->trans_id = trans_id; |
|
|
2192 | req->tx_count = 0; |
|
|
2193 | req->request_type = type; |
|
|
2194 | req->user_pointer = user_ptr; |
|
|
2195 | req->user_callback = callback; |
|
|
2196 | req->ns = issuing_now ? nameserver_pick() : NULL; |
|
|
2197 | req->next = req->prev = NULL; |
|
|
2198 | |
|
|
2199 | return req; |
|
|
2200 | err1: |
|
|
2201 | free(req); |
|
|
2202 | return NULL; |
|
|
2203 | } |
|
|
2204 | |
|
|
2205 | static void |
|
|
2206 | request_submit(struct request *const req) { |
|
|
2207 | if (req->ns) { |
|
|
2208 | /* if it has a nameserver assigned then this is going */ |
|
|
2209 | /* straight into the inflight queue */ |
|
|
2210 | evdns_request_insert(req, &req_head); |
|
|
2211 | global_requests_inflight++; |
|
|
2212 | evdns_request_transmit(req); |
|
|
2213 | } else { |
|
|
2214 | evdns_request_insert(req, &req_waiting_head); |
|
|
2215 | global_requests_waiting++; |
|
|
2216 | } |
|
|
2217 | } |
|
|
2218 | |
|
|
2219 | /* exported function */ |
|
|
2220 | int evdns_resolve_ipv4(const char *name, int flags, |
|
|
2221 | evdns_callback_type callback, void *ptr) { |
|
|
2222 | log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name); |
|
|
2223 | if (flags & DNS_QUERY_NO_SEARCH) { |
|
|
2224 | struct request *const req = |
|
|
2225 | request_new(TYPE_A, name, flags, callback, ptr); |
|
|
2226 | if (req == NULL) |
|
|
2227 | return (1); |
|
|
2228 | request_submit(req); |
|
|
2229 | return (0); |
|
|
2230 | } else { |
|
|
2231 | return (search_request_new(TYPE_A, name, flags, callback, ptr)); |
|
|
2232 | } |
|
|
2233 | } |
|
|
2234 | |
|
|
2235 | /* exported function */ |
|
|
2236 | int evdns_resolve_ipv6(const char *name, int flags, |
|
|
2237 | evdns_callback_type callback, void *ptr) { |
|
|
2238 | log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name); |
|
|
2239 | if (flags & DNS_QUERY_NO_SEARCH) { |
|
|
2240 | struct request *const req = |
|
|
2241 | request_new(TYPE_AAAA, name, flags, callback, ptr); |
|
|
2242 | if (req == NULL) |
|
|
2243 | return (1); |
|
|
2244 | request_submit(req); |
|
|
2245 | return (0); |
|
|
2246 | } else { |
|
|
2247 | return (search_request_new(TYPE_AAAA, name, flags, callback, ptr)); |
|
|
2248 | } |
|
|
2249 | } |
|
|
2250 | |
|
|
2251 | int evdns_resolve_reverse(struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) { |
|
|
2252 | char buf[32]; |
|
|
2253 | struct request *req; |
|
|
2254 | u32 a; |
|
|
2255 | assert(in); |
|
|
2256 | a = ntohl(in->s_addr); |
|
|
2257 | snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa", |
|
|
2258 | (int)(u8)((a )&0xff), |
|
|
2259 | (int)(u8)((a>>8 )&0xff), |
|
|
2260 | (int)(u8)((a>>16)&0xff), |
|
|
2261 | (int)(u8)((a>>24)&0xff)); |
|
|
2262 | log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf); |
|
|
2263 | req = request_new(TYPE_PTR, buf, flags, callback, ptr); |
|
|
2264 | if (!req) return 1; |
|
|
2265 | request_submit(req); |
|
|
2266 | return 0; |
|
|
2267 | } |
|
|
2268 | |
|
|
2269 | int evdns_resolve_reverse_ipv6(struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) { |
|
|
2270 | char buf[96]; |
|
|
2271 | char *cp; |
|
|
2272 | struct request *req; |
|
|
2273 | int i; |
|
|
2274 | assert(in); |
|
|
2275 | cp = buf; |
|
|
2276 | for (i=15; i >= 0; --i) { |
|
|
2277 | u8 byte = in->s6_addr[i]; |
|
|
2278 | *cp++ = "0123456789abcdef"[byte & 0x0f]; |
|
|
2279 | *cp++ = '.'; |
|
|
2280 | *cp++ = "0123456789abcdef"[byte >> 4]; |
|
|
2281 | *cp++ = '.'; |
|
|
2282 | } |
|
|
2283 | assert(cp + strlen(".ip6.arpa") < buf+sizeof(buf)); |
|
|
2284 | memcpy(cp, ".ip6.arpa", strlen(".ip6.arpa")+1); |
|
|
2285 | log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf); |
|
|
2286 | req = request_new(TYPE_PTR, buf, flags, callback, ptr); |
|
|
2287 | if (!req) return 1; |
|
|
2288 | request_submit(req); |
|
|
2289 | return 0; |
|
|
2290 | } |
|
|
2291 | |
|
|
2292 | /*/////////////////////////////////////////////////////////////////// */ |
|
|
2293 | /* Search support */ |
|
|
2294 | /* */ |
|
|
2295 | /* the libc resolver has support for searching a number of domains */ |
|
|
2296 | /* to find a name. If nothing else then it takes the single domain */ |
|
|
2297 | /* from the gethostname() call. */ |
|
|
2298 | /* */ |
|
|
2299 | /* It can also be configured via the domain and search options in a */ |
|
|
2300 | /* resolv.conf. */ |
|
|
2301 | /* */ |
|
|
2302 | /* The ndots option controls how many dots it takes for the resolver */ |
|
|
2303 | /* to decide that a name is non-local and so try a raw lookup first. */ |
|
|
2304 | |
|
|
2305 | struct search_domain { |
|
|
2306 | int len; |
|
|
2307 | struct search_domain *next; |
|
|
2308 | /* the text string is appended to this structure */ |
|
|
2309 | }; |
|
|
2310 | |
|
|
2311 | struct search_state { |
|
|
2312 | int refcount; |
|
|
2313 | int ndots; |
|
|
2314 | int num_domains; |
|
|
2315 | struct search_domain *head; |
|
|
2316 | }; |
|
|
2317 | |
|
|
2318 | static struct search_state *global_search_state = NULL; |
|
|
2319 | |
|
|
2320 | static void |
|
|
2321 | search_state_decref(struct search_state *const state) { |
|
|
2322 | if (!state) return; |
|
|
2323 | state->refcount--; |
|
|
2324 | if (!state->refcount) { |
|
|
2325 | struct search_domain *next, *dom; |
|
|
2326 | for (dom = state->head; dom; dom = next) { |
|
|
2327 | next = dom->next; |
|
|
2328 | free(dom); |
|
|
2329 | } |
|
|
2330 | free(state); |
|
|
2331 | } |
|
|
2332 | } |
|
|
2333 | |
|
|
2334 | static struct search_state * |
|
|
2335 | search_state_new(void) { |
|
|
2336 | struct search_state *state = (struct search_state *) malloc(sizeof(struct search_state)); |
|
|
2337 | if (!state) return NULL; |
|
|
2338 | memset(state, 0, sizeof(struct search_state)); |
|
|
2339 | state->refcount = 1; |
|
|
2340 | state->ndots = 1; |
|
|
2341 | |
|
|
2342 | return state; |
|
|
2343 | } |
|
|
2344 | |
|
|
2345 | static void |
|
|
2346 | search_postfix_clear(void) { |
|
|
2347 | search_state_decref(global_search_state); |
|
|
2348 | |
|
|
2349 | global_search_state = search_state_new(); |
|
|
2350 | } |
|
|
2351 | |
|
|
2352 | /* exported function */ |
|
|
2353 | void |
|
|
2354 | evdns_search_clear(void) { |
|
|
2355 | search_postfix_clear(); |
|
|
2356 | } |
|
|
2357 | |
|
|
2358 | static void |
|
|
2359 | search_postfix_add(const char *domain) { |
|
|
2360 | int domain_len; |
|
|
2361 | struct search_domain *sdomain; |
|
|
2362 | while (domain[0] == '.') domain++; |
|
|
2363 | domain_len = strlen(domain); |
|
|
2364 | |
|
|
2365 | if (!global_search_state) global_search_state = search_state_new(); |
|
|
2366 | if (!global_search_state) return; |
|
|
2367 | global_search_state->num_domains++; |
|
|
2368 | |
|
|
2369 | sdomain = (struct search_domain *) malloc(sizeof(struct search_domain) + domain_len); |
|
|
2370 | if (!sdomain) return; |
|
|
2371 | memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len); |
|
|
2372 | sdomain->next = global_search_state->head; |
|
|
2373 | sdomain->len = domain_len; |
|
|
2374 | |
|
|
2375 | global_search_state->head = sdomain; |
|
|
2376 | } |
|
|
2377 | |
|
|
2378 | /* reverse the order of members in the postfix list. This is needed because, */ |
|
|
2379 | /* when parsing resolv.conf we push elements in the wrong order */ |
|
|
2380 | static void |
|
|
2381 | search_reverse(void) { |
|
|
2382 | struct search_domain *cur, *prev = NULL, *next; |
|
|
2383 | cur = global_search_state->head; |
|
|
2384 | while (cur) { |
|
|
2385 | next = cur->next; |
|
|
2386 | cur->next = prev; |
|
|
2387 | prev = cur; |
|
|
2388 | cur = next; |
|
|
2389 | } |
|
|
2390 | |
|
|
2391 | global_search_state->head = prev; |
|
|
2392 | } |
|
|
2393 | |
|
|
2394 | /* exported function */ |
|
|
2395 | void |
|
|
2396 | evdns_search_add(const char *domain) { |
|
|
2397 | search_postfix_add(domain); |
|
|
2398 | } |
|
|
2399 | |
|
|
2400 | /* exported function */ |
|
|
2401 | void |
|
|
2402 | evdns_search_ndots_set(const int ndots) { |
|
|
2403 | if (!global_search_state) global_search_state = search_state_new(); |
|
|
2404 | if (!global_search_state) return; |
|
|
2405 | global_search_state->ndots = ndots; |
|
|
2406 | } |
|
|
2407 | |
|
|
2408 | static void |
|
|
2409 | search_set_from_hostname(void) { |
|
|
2410 | char hostname[HOST_NAME_MAX + 1], *domainname; |
|
|
2411 | |
|
|
2412 | search_postfix_clear(); |
|
|
2413 | if (gethostname(hostname, sizeof(hostname))) return; |
|
|
2414 | domainname = strchr(hostname, '.'); |
|
|
2415 | if (!domainname) return; |
|
|
2416 | search_postfix_add(domainname); |
|
|
2417 | } |
|
|
2418 | |
|
|
2419 | /* warning: returns malloced string */ |
|
|
2420 | static char * |
|
|
2421 | search_make_new(const struct search_state *const state, int n, const char *const base_name) { |
|
|
2422 | const int base_len = strlen(base_name); |
|
|
2423 | const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1; |
|
|
2424 | struct search_domain *dom; |
|
|
2425 | |
|
|
2426 | for (dom = state->head; dom; dom = dom->next) { |
|
|
2427 | if (!n--) { |
|
|
2428 | /* this is the postfix we want */ |
|
|
2429 | /* the actual postfix string is kept at the end of the structure */ |
|
|
2430 | const u8 *const postfix = ((u8 *) dom) + sizeof(struct search_domain); |
|
|
2431 | const int postfix_len = dom->len; |
|
|
2432 | char *const newname = (char *) malloc(base_len + need_to_append_dot + postfix_len + 1); |
|
|
2433 | if (!newname) return NULL; |
|
|
2434 | memcpy(newname, base_name, base_len); |
|
|
2435 | if (need_to_append_dot) newname[base_len] = '.'; |
|
|
2436 | memcpy(newname + base_len + need_to_append_dot, postfix, postfix_len); |
|
|
2437 | newname[base_len + need_to_append_dot + postfix_len] = 0; |
|
|
2438 | return newname; |
|
|
2439 | } |
|
|
2440 | } |
|
|
2441 | |
|
|
2442 | /* we ran off the end of the list and still didn't find the requested string */ |
|
|
2443 | abort(); |
|
|
2444 | return NULL; /* unreachable; stops warnings in some compilers. */ |
|
|
2445 | } |
|
|
2446 | |
|
|
2447 | static int |
|
|
2448 | search_request_new(int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg) { |
|
|
2449 | assert(type == TYPE_A || type == TYPE_AAAA); |
|
|
2450 | if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) && |
|
|
2451 | global_search_state && |
|
|
2452 | global_search_state->num_domains) { |
|
|
2453 | /* we have some domains to search */ |
|
|
2454 | struct request *req; |
|
|
2455 | if (string_num_dots(name) >= global_search_state->ndots) { |
|
|
2456 | req = request_new(type, name, flags, user_callback, user_arg); |
|
|
2457 | if (!req) return 1; |
|
|
2458 | req->search_index = -1; |
|
|
2459 | } else { |
|
|
2460 | char *const new_name = search_make_new(global_search_state, 0, name); |
|
|
2461 | if (!new_name) return 1; |
|
|
2462 | req = request_new(type, new_name, flags, user_callback, user_arg); |
|
|
2463 | free(new_name); |
|
|
2464 | if (!req) return 1; |
|
|
2465 | req->search_index = 0; |
|
|
2466 | } |
|
|
2467 | req->search_origname = strdup(name); |
|
|
2468 | req->search_state = global_search_state; |
|
|
2469 | req->search_flags = flags; |
|
|
2470 | global_search_state->refcount++; |
|
|
2471 | request_submit(req); |
|
|
2472 | return 0; |
|
|
2473 | } else { |
|
|
2474 | struct request *const req = request_new(type, name, flags, user_callback, user_arg); |
|
|
2475 | if (!req) return 1; |
|
|
2476 | request_submit(req); |
|
|
2477 | return 0; |
|
|
2478 | } |
|
|
2479 | } |
|
|
2480 | |
|
|
2481 | /* this is called when a request has failed to find a name. We need to check */ |
|
|
2482 | /* if it is part of a search and, if so, try the next name in the list */ |
|
|
2483 | /* returns: */ |
|
|
2484 | /* 0 another request has been submitted */ |
|
|
2485 | /* 1 no more requests needed */ |
|
|
2486 | static int |
|
|
2487 | search_try_next(struct request *const req) { |
|
|
2488 | if (req->search_state) { |
|
|
2489 | /* it is part of a search */ |
|
|
2490 | char *new_name; |
|
|
2491 | struct request *newreq; |
|
|
2492 | req->search_index++; |
|
|
2493 | if (req->search_index >= req->search_state->num_domains) { |
|
|
2494 | /* no more postfixes to try, however we may need to try */ |
|
|
2495 | /* this name without a postfix */ |
|
|
2496 | if (string_num_dots(req->search_origname) < req->search_state->ndots) { |
|
|
2497 | /* yep, we need to try it raw */ |
|
|
2498 | struct request *const newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer); |
|
|
2499 | log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname); |
|
|
2500 | if (newreq) { |
|
|
2501 | request_submit(newreq); |
|
|
2502 | return 0; |
|
|
2503 | } |
|
|
2504 | } |
|
|
2505 | return 1; |
|
|
2506 | } |
|
|
2507 | |
|
|
2508 | new_name = search_make_new(req->search_state, req->search_index, req->search_origname); |
|
|
2509 | if (!new_name) return 1; |
|
|
2510 | log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, req->search_index); |
|
|
2511 | newreq = request_new(req->request_type, new_name, req->search_flags, req->user_callback, req->user_pointer); |
|
|
2512 | free(new_name); |
|
|
2513 | if (!newreq) return 1; |
|
|
2514 | newreq->search_origname = req->search_origname; |
|
|
2515 | req->search_origname = NULL; |
|
|
2516 | newreq->search_state = req->search_state; |
|
|
2517 | newreq->search_flags = req->search_flags; |
|
|
2518 | newreq->search_index = req->search_index; |
|
|
2519 | newreq->search_state->refcount++; |
|
|
2520 | request_submit(newreq); |
|
|
2521 | return 0; |
|
|
2522 | } |
|
|
2523 | return 1; |
|
|
2524 | } |
|
|
2525 | |
|
|
2526 | static void |
|
|
2527 | search_request_finished(struct request *const req) { |
|
|
2528 | if (req->search_state) { |
|
|
2529 | search_state_decref(req->search_state); |
|
|
2530 | req->search_state = NULL; |
|
|
2531 | } |
|
|
2532 | if (req->search_origname) { |
|
|
2533 | free(req->search_origname); |
|
|
2534 | req->search_origname = NULL; |
|
|
2535 | } |
|
|
2536 | } |
|
|
2537 | |
|
|
2538 | /*/////////////////////////////////////////////////////////////////// */ |
|
|
2539 | /* Parsing resolv.conf files */ |
|
|
2540 | |
|
|
2541 | static void |
|
|
2542 | evdns_resolv_set_defaults(int flags) { |
|
|
2543 | /* if the file isn't found then we assume a local resolver */ |
|
|
2544 | if (flags & DNS_OPTION_SEARCH) search_set_from_hostname(); |
|
|
2545 | if (flags & DNS_OPTION_NAMESERVERS) evdns_nameserver_ip_add("127.0.0.1"); |
|
|
2546 | } |
|
|
2547 | |
|
|
2548 | #ifndef HAVE_STRTOK_R |
|
|
2549 | static char * |
|
|
2550 | fake_strtok_r(char *s, const char *delim, char **state) { |
|
|
2551 | return strtok(s, delim); |
|
|
2552 | } |
|
|
2553 | #endif |
|
|
2554 | |
|
|
2555 | /* helper version of atoi which returns -1 on error */ |
|
|
2556 | static int |
|
|
2557 | strtoint(const char *const str) { |
|
|
2558 | char *endptr; |
|
|
2559 | const int r = strtol(str, &endptr, 10); |
|
|
2560 | if (*endptr) return -1; |
|
|
2561 | return r; |
|
|
2562 | } |
|
|
2563 | |
|
|
2564 | /* helper version of atoi that returns -1 on error and clips to bounds. */ |
|
|
2565 | static int |
|
|
2566 | strtoint_clipped(const char *const str, int min, int max) |
|
|
2567 | { |
|
|
2568 | int r = strtoint(str); |
|
|
2569 | if (r == -1) |
|
|
2570 | return r; |
|
|
2571 | else if (r<min) |
|
|
2572 | return min; |
|
|
2573 | else if (r>max) |
|
|
2574 | return max; |
|
|
2575 | else |
|
|
2576 | return r; |
|
|
2577 | } |
|
|
2578 | |
|
|
2579 | /* exported function */ |
|
|
2580 | int |
|
|
2581 | evdns_set_option(const char *option, const char *val, int flags) |
|
|
2582 | { |
|
|
2583 | if (!strncmp(option, "ndots:", 6)) { |
|
|
2584 | const int ndots = strtoint(val); |
|
|
2585 | if (ndots == -1) return -1; |
|
|
2586 | if (!(flags & DNS_OPTION_SEARCH)) return 0; |
|
|
2587 | log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots); |
|
|
2588 | if (!global_search_state) global_search_state = search_state_new(); |
|
|
2589 | if (!global_search_state) return -1; |
|
|
2590 | global_search_state->ndots = ndots; |
|
|
2591 | } else if (!strncmp(option, "timeout:", 8)) { |
|
|
2592 | const int timeout = strtoint(val); |
|
|
2593 | if (timeout == -1) return -1; |
|
|
2594 | if (!(flags & DNS_OPTION_MISC)) return 0; |
|
|
2595 | log(EVDNS_LOG_DEBUG, "Setting timeout to %d", timeout); |
|
|
2596 | global_timeout.tv_sec = timeout; |
|
|
2597 | } else if (!strncmp(option, "max-timeouts:", 12)) { |
|
|
2598 | const int maxtimeout = strtoint_clipped(val, 1, 255); |
|
|
2599 | if (maxtimeout == -1) return -1; |
|
|
2600 | if (!(flags & DNS_OPTION_MISC)) return 0; |
|
|
2601 | log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d", |
|
|
2602 | maxtimeout); |
|
|
2603 | global_max_nameserver_timeout = maxtimeout; |
|
|
2604 | } else if (!strncmp(option, "max-inflight:", 13)) { |
|
|
2605 | const int maxinflight = strtoint_clipped(val, 1, 65000); |
|
|
2606 | if (maxinflight == -1) return -1; |
|
|
2607 | if (!(flags & DNS_OPTION_MISC)) return 0; |
|
|
2608 | log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d", |
|
|
2609 | maxinflight); |
|
|
2610 | global_max_requests_inflight = maxinflight; |
|
|
2611 | } else if (!strncmp(option, "attempts:", 9)) { |
|
|
2612 | int retries = strtoint(val); |
|
|
2613 | if (retries == -1) return -1; |
|
|
2614 | if (retries > 255) retries = 255; |
|
|
2615 | if (!(flags & DNS_OPTION_MISC)) return 0; |
|
|
2616 | log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries); |
|
|
2617 | global_max_retransmits = retries; |
|
|
2618 | } |
|
|
2619 | return 0; |
|
|
2620 | } |
|
|
2621 | |
|
|
2622 | static void |
|
|
2623 | resolv_conf_parse_line(char *const start, int flags) { |
|
|
2624 | char *strtok_state; |
|
|
2625 | static const char *const delims = " \t"; |
|
|
2626 | #define NEXT_TOKEN fake_strtok_r(NULL, delims, &strtok_state) |
|
|
2627 | |
|
|
2628 | char *const first_token = fake_strtok_r(start, delims, &strtok_state); |
|
|
2629 | if (!first_token) return; |
|
|
2630 | |
|
|
2631 | if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) { |
|
|
2632 | const char *const nameserver = NEXT_TOKEN; |
|
|
2633 | struct in_addr ina; |
|
|
2634 | |
|
|
2635 | if (inet_aton(nameserver, &ina)) { |
|
|
2636 | /* address is valid */ |
|
|
2637 | evdns_nameserver_add(ina.s_addr); |
|
|
2638 | } |
|
|
2639 | } else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) { |
|
|
2640 | const char *const domain = NEXT_TOKEN; |
|
|
2641 | if (domain) { |
|
|
2642 | search_postfix_clear(); |
|
|
2643 | search_postfix_add(domain); |
|
|
2644 | } |
|
|
2645 | } else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) { |
|
|
2646 | const char *domain; |
|
|
2647 | search_postfix_clear(); |
|
|
2648 | |
|
|
2649 | while ((domain = NEXT_TOKEN)) { |
|
|
2650 | search_postfix_add(domain); |
|
|
2651 | } |
|
|
2652 | search_reverse(); |
|
|
2653 | } else if (!strcmp(first_token, "options")) { |
|
|
2654 | const char *option; |
|
|
2655 | while ((option = NEXT_TOKEN)) { |
|
|
2656 | const char *val = strchr(option, ':'); |
|
|
2657 | evdns_set_option(option, val ? val+1 : "", flags); |
|
|
2658 | } |
|
|
2659 | } |
|
|
2660 | #undef NEXT_TOKEN |
|
|
2661 | } |
|
|
2662 | |
|
|
2663 | /* exported function */ |
|
|
2664 | /* returns: */ |
|
|
2665 | /* 0 no errors */ |
|
|
2666 | /* 1 failed to open file */ |
|
|
2667 | /* 2 failed to stat file */ |
|
|
2668 | /* 3 file too large */ |
|
|
2669 | /* 4 out of memory */ |
|
|
2670 | /* 5 short read from file */ |
|
|
2671 | int |
|
|
2672 | evdns_resolv_conf_parse(int flags, const char *const filename) { |
|
|
2673 | struct stat st; |
|
|
2674 | int fd, n, r; |
|
|
2675 | u8 *resolv; |
|
|
2676 | char *start; |
|
|
2677 | int err = 0; |
|
|
2678 | |
|
|
2679 | log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename); |
|
|
2680 | |
|
|
2681 | fd = open(filename, O_RDONLY); |
|
|
2682 | if (fd < 0) { |
|
|
2683 | evdns_resolv_set_defaults(flags); |
|
|
2684 | return 1; |
|
|
2685 | } |
|
|
2686 | |
|
|
2687 | if (fstat(fd, &st)) { err = 2; goto out1; } |
|
|
2688 | if (!st.st_size) { |
|
|
2689 | evdns_resolv_set_defaults(flags); |
|
|
2690 | err = (flags & DNS_OPTION_NAMESERVERS) ? 6 : 0; |
|
|
2691 | goto out1; |
|
|
2692 | } |
|
|
2693 | if (st.st_size > 65535) { err = 3; goto out1; } /* no resolv.conf should be any bigger */ |
|
|
2694 | |
|
|
2695 | resolv = (u8 *) malloc((size_t)st.st_size + 1); |
|
|
2696 | if (!resolv) { err = 4; goto out1; } |
|
|
2697 | |
|
|
2698 | n = 0; |
|
|
2699 | while ((r = read(fd, resolv+n, (size_t)st.st_size-n)) > 0) { |
|
|
2700 | n += r; |
|
|
2701 | if (n == st.st_size) |
|
|
2702 | break; |
|
|
2703 | assert(n < st.st_size); |
|
|
2704 | } |
|
|
2705 | if (r < 0) { err = 5; goto out2; } |
|
|
2706 | resolv[n] = 0; /* we malloced an extra byte; this should be fine. */ |
|
|
2707 | |
|
|
2708 | start = (char *) resolv; |
|
|
2709 | for (;;) { |
|
|
2710 | char *const newline = strchr(start, '\n'); |
|
|
2711 | if (!newline) { |
|
|
2712 | resolv_conf_parse_line(start, flags); |
|
|
2713 | break; |
|
|
2714 | } else { |
|
|
2715 | *newline = 0; |
|
|
2716 | resolv_conf_parse_line(start, flags); |
|
|
2717 | start = newline + 1; |
|
|
2718 | } |
|
|
2719 | } |
|
|
2720 | |
|
|
2721 | if (!server_head && (flags & DNS_OPTION_NAMESERVERS)) { |
|
|
2722 | /* no nameservers were configured. */ |
|
|
2723 | evdns_nameserver_ip_add("127.0.0.1"); |
|
|
2724 | err = 6; |
|
|
2725 | } |
|
|
2726 | if (flags & DNS_OPTION_SEARCH && (!global_search_state || global_search_state->num_domains == 0)) { |
|
|
2727 | search_set_from_hostname(); |
|
|
2728 | } |
|
|
2729 | |
|
|
2730 | out2: |
|
|
2731 | free(resolv); |
|
|
2732 | out1: |
|
|
2733 | close(fd); |
|
|
2734 | return err; |
|
|
2735 | } |
|
|
2736 | |
|
|
2737 | #ifdef WIN32 |
|
|
2738 | /* Add multiple nameservers from a space-or-comma-separated list. */ |
|
|
2739 | static int |
|
|
2740 | evdns_nameserver_ip_add_line(const char *ips) { |
|
|
2741 | const char *addr; |
|
|
2742 | char *buf; |
|
|
2743 | int r; |
|
|
2744 | while (*ips) { |
|
|
2745 | while (ISSPACE(*ips) || *ips == ',' || *ips == '\t') |
|
|
2746 | ++ips; |
|
|
2747 | addr = ips; |
|
|
2748 | while (ISDIGIT(*ips) || *ips == '.' || *ips == ':') |
|
|
2749 | ++ips; |
|
|
2750 | buf = malloc(ips-addr+1); |
|
|
2751 | if (!buf) return 4; |
|
|
2752 | memcpy(buf, addr, ips-addr); |
|
|
2753 | buf[ips-addr] = '\0'; |
|
|
2754 | r = evdns_nameserver_ip_add(buf); |
|
|
2755 | free(buf); |
|
|
2756 | if (r) return r; |
|
|
2757 | } |
|
|
2758 | return 0; |
|
|
2759 | } |
|
|
2760 | |
|
|
2761 | typedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*); |
|
|
2762 | |
|
|
2763 | /* Use the windows GetNetworkParams interface in iphlpapi.dll to */ |
|
|
2764 | /* figure out what our nameservers are. */ |
|
|
2765 | static int |
|
|
2766 | load_nameservers_with_getnetworkparams(void) |
|
|
2767 | { |
|
|
2768 | /* Based on MSDN examples and inspection of c-ares code. */ |
|
|
2769 | FIXED_INFO *fixed; |
|
|
2770 | HMODULE handle = 0; |
|
|
2771 | ULONG size = sizeof(FIXED_INFO); |
|
|
2772 | void *buf = NULL; |
|
|
2773 | int status = 0, r, added_any; |
|
|
2774 | IP_ADDR_STRING *ns; |
|
|
2775 | GetNetworkParams_fn_t fn; |
|
|
2776 | |
|
|
2777 | if (!(handle = LoadLibrary("iphlpapi.dll"))) { |
|
|
2778 | log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll"); |
|
|
2779 | status = -1; |
|
|
2780 | goto done; |
|
|
2781 | } |
|
|
2782 | if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, "GetNetworkParams"))) { |
|
|
2783 | log(EVDNS_LOG_WARN, "Could not get address of function."); |
|
|
2784 | status = -1; |
|
|
2785 | goto done; |
|
|
2786 | } |
|
|
2787 | |
|
|
2788 | buf = malloc(size); |
|
|
2789 | if (!buf) { status = 4; goto done; } |
|
|
2790 | fixed = buf; |
|
|
2791 | r = fn(fixed, &size); |
|
|
2792 | if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) { |
|
|
2793 | status = -1; |
|
|
2794 | goto done; |
|
|
2795 | } |
|
|
2796 | if (r != ERROR_SUCCESS) { |
|
|
2797 | free(buf); |
|
|
2798 | buf = malloc(size); |
|
|
2799 | if (!buf) { status = 4; goto done; } |
|
|
2800 | fixed = buf; |
|
|
2801 | r = fn(fixed, &size); |
|
|
2802 | if (r != ERROR_SUCCESS) { |
|
|
2803 | log(EVDNS_LOG_DEBUG, "fn() failed."); |
|
|
2804 | status = -1; |
|
|
2805 | goto done; |
|
|
2806 | } |
|
|
2807 | } |
|
|
2808 | |
|
|
2809 | assert(fixed); |
|
|
2810 | added_any = 0; |
|
|
2811 | ns = &(fixed->DnsServerList); |
|
|
2812 | while (ns) { |
|
|
2813 | r = evdns_nameserver_ip_add_line(ns->IpAddress.String); |
|
|
2814 | if (r) { |
|
|
2815 | log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list,error: %d", |
|
|
2816 | (ns->IpAddress.String),(int)GetLastError()); |
|
|
2817 | status = r; |
|
|
2818 | goto done; |
|
|
2819 | } else { |
|
|
2820 | log(EVDNS_LOG_DEBUG,"Succesfully added %s as nameserver",ns->IpAddress.String); |
|
|
2821 | } |
|
|
2822 | |
|
|
2823 | added_any++; |
|
|
2824 | ns = ns->Next; |
|
|
2825 | } |
|
|
2826 | |
|
|
2827 | if (!added_any) { |
|
|
2828 | log(EVDNS_LOG_DEBUG, "No nameservers added."); |
|
|
2829 | status = -1; |
|
|
2830 | } |
|
|
2831 | |
|
|
2832 | done: |
|
|
2833 | if (buf) |
|
|
2834 | free(buf); |
|
|
2835 | if (handle) |
|
|
2836 | FreeLibrary(handle); |
|
|
2837 | return status; |
|
|
2838 | } |
|
|
2839 | |
|
|
2840 | static int |
|
|
2841 | config_nameserver_from_reg_key(HKEY key, const char *subkey) |
|
|
2842 | { |
|
|
2843 | char *buf; |
|
|
2844 | DWORD bufsz = 0, type = 0; |
|
|
2845 | int status = 0; |
|
|
2846 | |
|
|
2847 | if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz) |
|
|
2848 | != ERROR_MORE_DATA) |
|
|
2849 | return -1; |
|
|
2850 | if (!(buf = malloc(bufsz))) |
|
|
2851 | return -1; |
|
|
2852 | |
|
|
2853 | if (RegQueryValueEx(key, subkey, 0, &type, (LPBYTE)buf, &bufsz) |
|
|
2854 | == ERROR_SUCCESS && bufsz > 1) { |
|
|
2855 | status = evdns_nameserver_ip_add_line(buf); |
|
|
2856 | } |
|
|
2857 | |
|
|
2858 | free(buf); |
|
|
2859 | return status; |
|
|
2860 | } |
|
|
2861 | |
|
|
2862 | #define SERVICES_KEY "System\\CurrentControlSet\\Services\\" |
|
|
2863 | #define WIN_NS_9X_KEY SERVICES_KEY "VxD\\MSTCP" |
|
|
2864 | #define WIN_NS_NT_KEY SERVICES_KEY "Tcpip\\Parameters" |
|
|
2865 | |
|
|
2866 | static int |
|
|
2867 | load_nameservers_from_registry(void) |
|
|
2868 | { |
|
|
2869 | int found = 0; |
|
|
2870 | int r; |
|
|
2871 | #define TRY(k, name) \ |
|
|
2872 | if (!found && config_nameserver_from_reg_key(k,name) == 0) { \ |
|
|
2873 | log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \ |
|
|
2874 | found = 1; \ |
|
|
2875 | } else if (!found) { \ |
|
|
2876 | log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \ |
|
|
2877 | #k,#name); \ |
|
|
2878 | } |
|
|
2879 | |
|
|
2880 | if (((int)GetVersion()) > 0) { /* NT */ |
|
|
2881 | HKEY nt_key = 0, interfaces_key = 0; |
|
|
2882 | |
|
|
2883 | if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, |
|
|
2884 | KEY_READ, &nt_key) != ERROR_SUCCESS) { |
|
|
2885 | log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError()); |
|
|
2886 | return -1; |
|
|
2887 | } |
|
|
2888 | r = RegOpenKeyEx(nt_key, "Interfaces", 0, |
|
|
2889 | KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, |
|
|
2890 | &interfaces_key); |
|
|
2891 | if (r != ERROR_SUCCESS) { |
|
|
2892 | log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError()); |
|
|
2893 | return -1; |
|
|
2894 | } |
|
|
2895 | TRY(nt_key, "NameServer"); |
|
|
2896 | TRY(nt_key, "DhcpNameServer"); |
|
|
2897 | TRY(interfaces_key, "NameServer"); |
|
|
2898 | TRY(interfaces_key, "DhcpNameServer"); |
|
|
2899 | RegCloseKey(interfaces_key); |
|
|
2900 | RegCloseKey(nt_key); |
|
|
2901 | } else { |
|
|
2902 | HKEY win_key = 0; |
|
|
2903 | if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0, |
|
|
2904 | KEY_READ, &win_key) != ERROR_SUCCESS) { |
|
|
2905 | log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError()); |
|
|
2906 | return -1; |
|
|
2907 | } |
|
|
2908 | TRY(win_key, "NameServer"); |
|
|
2909 | RegCloseKey(win_key); |
|
|
2910 | } |
|
|
2911 | |
|
|
2912 | if (found == 0) { |
|
|
2913 | log(EVDNS_LOG_WARN,"Didn't find any nameservers."); |
|
|
2914 | } |
|
|
2915 | |
|
|
2916 | return found ? 0 : -1; |
|
|
2917 | #undef TRY |
|
|
2918 | } |
|
|
2919 | |
|
|
2920 | int |
|
|
2921 | evdns_config_windows_nameservers(void) |
|
|
2922 | { |
|
|
2923 | if (load_nameservers_with_getnetworkparams() == 0) |
|
|
2924 | return 0; |
|
|
2925 | return load_nameservers_from_registry(); |
|
|
2926 | } |
|
|
2927 | #endif |
|
|
2928 | |
|
|
2929 | int |
|
|
2930 | evdns_init(void) |
|
|
2931 | { |
|
|
2932 | int res = 0; |
|
|
2933 | #ifdef WIN32 |
|
|
2934 | evdns_config_windows_nameservers(); |
|
|
2935 | #else |
|
|
2936 | res = evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf"); |
|
|
2937 | #endif |
|
|
2938 | |
|
|
2939 | return (res); |
|
|
2940 | } |
|
|
2941 | |
|
|
2942 | const char * |
|
|
2943 | evdns_err_to_string(int err) |
|
|
2944 | { |
|
|
2945 | switch (err) { |
|
|
2946 | case DNS_ERR_NONE: return "no error"; |
|
|
2947 | case DNS_ERR_FORMAT: return "misformatted query"; |
|
|
2948 | case DNS_ERR_SERVERFAILED: return "server failed"; |
|
|
2949 | case DNS_ERR_NOTEXIST: return "name does not exist"; |
|
|
2950 | case DNS_ERR_NOTIMPL: return "query not implemented"; |
|
|
2951 | case DNS_ERR_REFUSED: return "refused"; |
|
|
2952 | |
|
|
2953 | case DNS_ERR_TRUNCATED: return "reply truncated or ill-formed"; |
|
|
2954 | case DNS_ERR_UNKNOWN: return "unknown"; |
|
|
2955 | case DNS_ERR_TIMEOUT: return "request timed out"; |
|
|
2956 | case DNS_ERR_SHUTDOWN: return "dns subsystem shut down"; |
|
|
2957 | default: return "[Unknown error code]"; |
|
|
2958 | } |
|
|
2959 | } |
|
|
2960 | |
|
|
2961 | void |
|
|
2962 | evdns_shutdown(int fail_requests) |
|
|
2963 | { |
|
|
2964 | struct nameserver *server, *server_next; |
|
|
2965 | struct search_domain *dom, *dom_next; |
|
|
2966 | |
|
|
2967 | while (req_head) { |
|
|
2968 | if (fail_requests) |
|
|
2969 | reply_callback(req_head, 0, DNS_ERR_SHUTDOWN, NULL); |
|
|
2970 | request_finished(req_head, &req_head); |
|
|
2971 | } |
|
|
2972 | while (req_waiting_head) { |
|
|
2973 | if (fail_requests) |
|
|
2974 | reply_callback(req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL); |
|
|
2975 | request_finished(req_waiting_head, &req_waiting_head); |
|
|
2976 | } |
|
|
2977 | global_requests_inflight = global_requests_waiting = 0; |
|
|
2978 | |
|
|
2979 | for (server = server_head; server; server = server_next) { |
|
|
2980 | server_next = server->next; |
|
|
2981 | if (server->socket >= 0) |
|
|
2982 | CLOSE_SOCKET(server->socket); |
|
|
2983 | (void) event_del(&server->event); |
|
|
2984 | if (server->state == 0) |
|
|
2985 | (void) event_del(&server->timeout_event); |
|
|
2986 | free(server); |
|
|
2987 | if (server_next == server_head) |
|
|
2988 | break; |
|
|
2989 | } |
|
|
2990 | server_head = NULL; |
|
|
2991 | global_good_nameservers = 0; |
|
|
2992 | |
|
|
2993 | if (global_search_state) { |
|
|
2994 | for (dom = global_search_state->head; dom; dom = dom_next) { |
|
|
2995 | dom_next = dom->next; |
|
|
2996 | free(dom); |
|
|
2997 | } |
|
|
2998 | free(global_search_state); |
|
|
2999 | global_search_state = NULL; |
|
|
3000 | } |
|
|
3001 | evdns_log_fn = NULL; |
|
|
3002 | } |
|
|
3003 | |
|
|
3004 | #ifdef EVDNS_MAIN |
|
|
3005 | void |
|
|
3006 | main_callback(int result, char type, int count, int ttl, |
|
|
3007 | void *addrs, void *orig) { |
|
|
3008 | char *n = (char*)orig; |
|
|
3009 | int i; |
|
|
3010 | for (i = 0; i < count; ++i) { |
|
|
3011 | if (type == DNS_IPv4_A) { |
|
|
3012 | printf("%s: %s\n", n, debug_ntoa(((u32*)addrs)[i])); |
|
|
3013 | } else if (type == DNS_PTR) { |
|
|
3014 | printf("%s: %s\n", n, ((char**)addrs)[i]); |
|
|
3015 | } |
|
|
3016 | } |
|
|
3017 | if (!count) { |
|
|
3018 | printf("%s: No answer (%d)\n", n, result); |
|
|
3019 | } |
|
|
3020 | fflush(stdout); |
|
|
3021 | } |
|
|
3022 | void |
|
|
3023 | evdns_server_callback(struct evdns_server_request *req, void *data) |
|
|
3024 | { |
|
|
3025 | int i, r; |
|
|
3026 | (void)data; |
|
|
3027 | /* dummy; give 192.168.11.11 as an answer for all A questions, |
|
|
3028 | * give foo.bar.example.com as an answer for all PTR questions. */ |
|
|
3029 | for (i = 0; i < req->nquestions; ++i) { |
|
|
3030 | u32 ans = htonl(0xc0a80b0bUL); |
|
|
3031 | if (req->questions[i]->type == EVDNS_TYPE_A && |
|
|
3032 | req->questions[i]->class == EVDNS_CLASS_INET) { |
|
|
3033 | printf(" -- replying for %s (A)\n", req->questions[i]->name); |
|
|
3034 | r = evdns_server_request_add_a_reply(req, req->questions[i]->name, |
|
|
3035 | 1, &ans, 10); |
|
|
3036 | if (r<0) |
|
|
3037 | printf("eeep, didn't work.\n"); |
|
|
3038 | } else if (req->questions[i]->type == EVDNS_TYPE_PTR && |
|
|
3039 | req->questions[i]->class == EVDNS_CLASS_INET) { |
|
|
3040 | printf(" -- replying for %s (PTR)\n", req->questions[i]->name); |
|
|
3041 | r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name, |
|
|
3042 | "foo.bar.example.com", 10); |
|
|
3043 | } else { |
|
|
3044 | printf(" -- skipping %s [%d %d]\n", req->questions[i]->name, |
|
|
3045 | req->questions[i]->type, req->questions[i]->class); |
|
|
3046 | } |
|
|
3047 | } |
|
|
3048 | |
|
|
3049 | r = evdns_request_respond(req, 0); |
|
|
3050 | if (r<0) |
|
|
3051 | printf("eeek, couldn't send reply.\n"); |
|
|
3052 | } |
|
|
3053 | |
|
|
3054 | void |
|
|
3055 | logfn(int is_warn, const char *msg) { |
|
|
3056 | (void) is_warn; |
|
|
3057 | fprintf(stderr, "%s\n", msg); |
|
|
3058 | } |
|
|
3059 | int |
|
|
3060 | main(int c, char **v) { |
|
|
3061 | int idx; |
|
|
3062 | int reverse = 0, verbose = 1, servertest = 0; |
|
|
3063 | if (c<2) { |
|
|
3064 | fprintf(stderr, "syntax: %s [-x] [-v] hostname\n", v[0]); |
|
|
3065 | fprintf(stderr, "syntax: %s [-servertest]\n", v[0]); |
|
|
3066 | return 1; |
|
|
3067 | } |
|
|
3068 | idx = 1; |
|
|
3069 | while (idx < c && v[idx][0] == '-') { |
|
|
3070 | if (!strcmp(v[idx], "-x")) |
|
|
3071 | reverse = 1; |
|
|
3072 | else if (!strcmp(v[idx], "-v")) |
|
|
3073 | verbose = 1; |
|
|
3074 | else if (!strcmp(v[idx], "-servertest")) |
|
|
3075 | servertest = 1; |
|
|
3076 | else |
|
|
3077 | fprintf(stderr, "Unknown option %s\n", v[idx]); |
|
|
3078 | ++idx; |
|
|
3079 | } |
|
|
3080 | event_init(); |
|
|
3081 | if (verbose) |
|
|
3082 | evdns_set_log_fn(logfn); |
|
|
3083 | evdns_resolv_conf_parse(DNS_OPTION_NAMESERVERS, "/etc/resolv.conf"); |
|
|
3084 | if (servertest) { |
|
|
3085 | int sock; |
|
|
3086 | struct sockaddr_in my_addr; |
|
|
3087 | sock = socket(PF_INET, SOCK_DGRAM, 0); |
|
|
3088 | fcntl(sock, F_SETFL, O_NONBLOCK); |
|
|
3089 | my_addr.sin_family = AF_INET; |
|
|
3090 | my_addr.sin_port = htons(10053); |
|
|
3091 | my_addr.sin_addr.s_addr = INADDR_ANY; |
|
|
3092 | if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr))<0) { |
|
|
3093 | perror("bind"); |
|
|
3094 | exit(1); |
|
|
3095 | } |
|
|
3096 | evdns_add_server_port(sock, 0, evdns_server_callback, NULL); |
|
|
3097 | } |
|
|
3098 | for (; idx < c; ++idx) { |
|
|
3099 | if (reverse) { |
|
|
3100 | struct in_addr addr; |
|
|
3101 | if (!inet_aton(v[idx], &addr)) { |
|
|
3102 | fprintf(stderr, "Skipping non-IP %s\n", v[idx]); |
|
|
3103 | continue; |
|
|
3104 | } |
|
|
3105 | fprintf(stderr, "resolving %s...\n",v[idx]); |
|
|
3106 | evdns_resolve_reverse(&addr, 0, main_callback, v[idx]); |
|
|
3107 | } else { |
|
|
3108 | fprintf(stderr, "resolving (fwd) %s...\n",v[idx]); |
|
|
3109 | evdns_resolve_ipv4(v[idx], 0, main_callback, v[idx]); |
|
|
3110 | } |
|
|
3111 | } |
|
|
3112 | fflush(stdout); |
|
|
3113 | event_dispatch(); |
|
|
3114 | return 0; |
|
|
3115 | } |
|
|
3116 | #endif |
|
|