|
1 /* |
|
2 * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu> |
|
3 * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson |
|
4 * |
|
5 * Redistribution and use in source and binary forms, with or without |
|
6 * modification, are permitted provided that the following conditions |
|
7 * are met: |
|
8 * 1. Redistributions of source code must retain the above copyright |
|
9 * notice, this list of conditions and the following disclaimer. |
|
10 * 2. Redistributions in binary form must reproduce the above copyright |
|
11 * notice, this list of conditions and the following disclaimer in the |
|
12 * documentation and/or other materials provided with the distribution. |
|
13 * 3. The name of the author may not be used to endorse or promote products |
|
14 * derived from this software without specific prior written permission. |
|
15 * |
|
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
|
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
|
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
|
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
26 */ |
|
27 |
|
28 #ifdef WIN32 |
|
29 #include <winsock2.h> |
|
30 #include <windows.h> |
|
31 #include <ws2tcpip.h> |
|
32 #endif |
|
33 |
|
34 #include "event2/event-config.h" |
|
35 |
|
36 #include <sys/types.h> |
|
37 #include <sys/stat.h> |
|
38 #ifdef _EVENT_HAVE_SYS_TIME_H |
|
39 #include <sys/time.h> |
|
40 #endif |
|
41 #include <sys/queue.h> |
|
42 #ifndef WIN32 |
|
43 #include <sys/socket.h> |
|
44 #include <signal.h> |
|
45 #include <netinet/in.h> |
|
46 #include <arpa/inet.h> |
|
47 #include <unistd.h> |
|
48 #endif |
|
49 #ifdef _EVENT_HAVE_NETINET_IN6_H |
|
50 #include <netinet/in6.h> |
|
51 #endif |
|
52 #ifdef HAVE_NETDB_H |
|
53 #include <netdb.h> |
|
54 #endif |
|
55 #include <fcntl.h> |
|
56 #include <stdlib.h> |
|
57 #include <stdio.h> |
|
58 #include <string.h> |
|
59 #include <errno.h> |
|
60 |
|
61 #include "event2/dns.h" |
|
62 #include "event2/dns_compat.h" |
|
63 #include "event2/dns_struct.h" |
|
64 #include "event2/event.h" |
|
65 #include "event2/event_compat.h" |
|
66 #include "event2/event_struct.h" |
|
67 #include "event2/util.h" |
|
68 #include "event2/listener.h" |
|
69 #include "event2/bufferevent.h" |
|
70 #include "log-internal.h" |
|
71 #include "regress.h" |
|
72 #include "regress_testutils.h" |
|
73 |
|
74 #include "../util-internal.h" |
|
75 |
|
76 static int dns_ok = 0; |
|
77 static int dns_got_cancel = 0; |
|
78 static int dns_err = 0; |
|
79 |
|
80 |
|
81 static void |
|
82 dns_gethostbyname_cb(int result, char type, int count, int ttl, |
|
83 void *addresses, void *arg) |
|
84 { |
|
85 dns_ok = dns_err = 0; |
|
86 |
|
87 if (result == DNS_ERR_TIMEOUT) { |
|
88 printf("[Timed out] "); |
|
89 dns_err = result; |
|
90 goto out; |
|
91 } |
|
92 |
|
93 if (result != DNS_ERR_NONE) { |
|
94 printf("[Error code %d] ", result); |
|
95 goto out; |
|
96 } |
|
97 |
|
98 TT_BLATHER(("type: %d, count: %d, ttl: %d: ", type, count, ttl)); |
|
99 |
|
100 switch (type) { |
|
101 case DNS_IPv6_AAAA: { |
|
102 #if defined(_EVENT_HAVE_STRUCT_IN6_ADDR) && defined(_EVENT_HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN) |
|
103 struct in6_addr *in6_addrs = addresses; |
|
104 char buf[INET6_ADDRSTRLEN+1]; |
|
105 int i; |
|
106 /* a resolution that's not valid does not help */ |
|
107 if (ttl < 0) |
|
108 goto out; |
|
109 for (i = 0; i < count; ++i) { |
|
110 const char *b = evutil_inet_ntop(AF_INET6, &in6_addrs[i], buf,sizeof(buf)); |
|
111 if (b) |
|
112 TT_BLATHER(("%s ", b)); |
|
113 else |
|
114 TT_BLATHER(("%s ", strerror(errno))); |
|
115 } |
|
116 #endif |
|
117 break; |
|
118 } |
|
119 case DNS_IPv4_A: { |
|
120 struct in_addr *in_addrs = addresses; |
|
121 int i; |
|
122 /* a resolution that's not valid does not help */ |
|
123 if (ttl < 0) |
|
124 goto out; |
|
125 for (i = 0; i < count; ++i) |
|
126 TT_BLATHER(("%s ", inet_ntoa(in_addrs[i]))); |
|
127 break; |
|
128 } |
|
129 case DNS_PTR: |
|
130 /* may get at most one PTR */ |
|
131 if (count != 1) |
|
132 goto out; |
|
133 |
|
134 TT_BLATHER(("%s ", *(char **)addresses)); |
|
135 break; |
|
136 default: |
|
137 goto out; |
|
138 } |
|
139 |
|
140 dns_ok = type; |
|
141 |
|
142 out: |
|
143 if (arg == NULL) |
|
144 event_loopexit(NULL); |
|
145 else |
|
146 event_base_loopexit((struct event_base *)arg, NULL); |
|
147 } |
|
148 |
|
149 static void |
|
150 dns_gethostbyname(void) |
|
151 { |
|
152 dns_ok = 0; |
|
153 evdns_resolve_ipv4("www.monkey.org", 0, dns_gethostbyname_cb, NULL); |
|
154 event_dispatch(); |
|
155 |
|
156 tt_int_op(dns_ok, ==, DNS_IPv4_A); |
|
157 test_ok = dns_ok; |
|
158 end: |
|
159 ; |
|
160 } |
|
161 |
|
162 static void |
|
163 dns_gethostbyname6(void) |
|
164 { |
|
165 dns_ok = 0; |
|
166 evdns_resolve_ipv6("www.ietf.org", 0, dns_gethostbyname_cb, NULL); |
|
167 event_dispatch(); |
|
168 |
|
169 if (!dns_ok && dns_err == DNS_ERR_TIMEOUT) { |
|
170 tt_skip(); |
|
171 } |
|
172 |
|
173 tt_int_op(dns_ok, ==, DNS_IPv6_AAAA); |
|
174 test_ok = 1; |
|
175 end: |
|
176 ; |
|
177 } |
|
178 |
|
179 static void |
|
180 dns_gethostbyaddr(void) |
|
181 { |
|
182 struct in_addr in; |
|
183 in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */ |
|
184 dns_ok = 0; |
|
185 evdns_resolve_reverse(&in, 0, dns_gethostbyname_cb, NULL); |
|
186 event_dispatch(); |
|
187 |
|
188 tt_int_op(dns_ok, ==, DNS_PTR); |
|
189 test_ok = dns_ok; |
|
190 end: |
|
191 ; |
|
192 } |
|
193 |
|
194 static void |
|
195 dns_resolve_reverse(void *ptr) |
|
196 { |
|
197 struct in_addr in; |
|
198 struct event_base *base = event_base_new(); |
|
199 struct evdns_base *dns = evdns_base_new(base, 1/* init name servers */); |
|
200 struct evdns_request *req = NULL; |
|
201 |
|
202 tt_assert(base); |
|
203 tt_assert(dns); |
|
204 in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */ |
|
205 dns_ok = 0; |
|
206 |
|
207 req = evdns_base_resolve_reverse( |
|
208 dns, &in, 0, dns_gethostbyname_cb, base); |
|
209 tt_assert(req); |
|
210 |
|
211 event_base_dispatch(base); |
|
212 |
|
213 tt_int_op(dns_ok, ==, DNS_PTR); |
|
214 |
|
215 end: |
|
216 if (dns) |
|
217 evdns_base_free(dns, 0); |
|
218 if (base) |
|
219 event_base_free(base); |
|
220 } |
|
221 |
|
222 static int n_server_responses = 0; |
|
223 |
|
224 static void |
|
225 dns_server_request_cb(struct evdns_server_request *req, void *data) |
|
226 { |
|
227 int i, r; |
|
228 const char TEST_ARPA[] = "11.11.168.192.in-addr.arpa"; |
|
229 const char TEST_IN6[] = |
|
230 "f.e.f.e." "0.0.0.0." "0.0.0.0." "1.1.1.1." |
|
231 "a.a.a.a." "0.0.0.0." "0.0.0.0." "0.f.f.f.ip6.arpa"; |
|
232 |
|
233 for (i = 0; i < req->nquestions; ++i) { |
|
234 const int qtype = req->questions[i]->type; |
|
235 const int qclass = req->questions[i]->dns_question_class; |
|
236 const char *qname = req->questions[i]->name; |
|
237 |
|
238 struct in_addr ans; |
|
239 ans.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */ |
|
240 if (qtype == EVDNS_TYPE_A && |
|
241 qclass == EVDNS_CLASS_INET && |
|
242 !evutil_ascii_strcasecmp(qname, "zz.example.com")) { |
|
243 r = evdns_server_request_add_a_reply(req, qname, |
|
244 1, &ans.s_addr, 12345); |
|
245 if (r<0) |
|
246 dns_ok = 0; |
|
247 } else if (qtype == EVDNS_TYPE_AAAA && |
|
248 qclass == EVDNS_CLASS_INET && |
|
249 !evutil_ascii_strcasecmp(qname, "zz.example.com")) { |
|
250 char addr6[17] = "abcdefghijklmnop"; |
|
251 r = evdns_server_request_add_aaaa_reply(req, |
|
252 qname, 1, addr6, 123); |
|
253 if (r<0) |
|
254 dns_ok = 0; |
|
255 } else if (qtype == EVDNS_TYPE_PTR && |
|
256 qclass == EVDNS_CLASS_INET && |
|
257 !evutil_ascii_strcasecmp(qname, TEST_ARPA)) { |
|
258 r = evdns_server_request_add_ptr_reply(req, NULL, |
|
259 qname, "ZZ.EXAMPLE.COM", 54321); |
|
260 if (r<0) |
|
261 dns_ok = 0; |
|
262 } else if (qtype == EVDNS_TYPE_PTR && |
|
263 qclass == EVDNS_CLASS_INET && |
|
264 !evutil_ascii_strcasecmp(qname, TEST_IN6)){ |
|
265 r = evdns_server_request_add_ptr_reply(req, NULL, |
|
266 qname, |
|
267 "ZZ-INET6.EXAMPLE.COM", 54322); |
|
268 if (r<0) |
|
269 dns_ok = 0; |
|
270 } else if (qtype == EVDNS_TYPE_A && |
|
271 qclass == EVDNS_CLASS_INET && |
|
272 !evutil_ascii_strcasecmp(qname, "drop.example.com")) { |
|
273 if (evdns_server_request_drop(req)<0) |
|
274 dns_ok = 0; |
|
275 return; |
|
276 } else { |
|
277 printf("Unexpected question %d %d \"%s\" ", |
|
278 qtype, qclass, qname); |
|
279 dns_ok = 0; |
|
280 } |
|
281 } |
|
282 r = evdns_server_request_respond(req, 0); |
|
283 if (r<0) { |
|
284 printf("Couldn't send reply. "); |
|
285 dns_ok = 0; |
|
286 } |
|
287 } |
|
288 |
|
289 static void |
|
290 dns_server_gethostbyname_cb(int result, char type, int count, int ttl, |
|
291 void *addresses, void *arg) |
|
292 { |
|
293 if (result == DNS_ERR_CANCEL) { |
|
294 if (arg != (void*)(char*)90909) { |
|
295 printf("Unexpected cancelation"); |
|
296 dns_ok = 0; |
|
297 } |
|
298 dns_got_cancel = 1; |
|
299 goto out; |
|
300 } |
|
301 if (result != DNS_ERR_NONE) { |
|
302 printf("Unexpected result %d. ", result); |
|
303 dns_ok = 0; |
|
304 goto out; |
|
305 } |
|
306 if (count != 1) { |
|
307 printf("Unexpected answer count %d. ", count); |
|
308 dns_ok = 0; |
|
309 goto out; |
|
310 } |
|
311 switch (type) { |
|
312 case DNS_IPv4_A: { |
|
313 struct in_addr *in_addrs = addresses; |
|
314 if (in_addrs[0].s_addr != htonl(0xc0a80b0bUL) || ttl != 12345) { |
|
315 printf("Bad IPv4 response \"%s\" %d. ", |
|
316 inet_ntoa(in_addrs[0]), ttl); |
|
317 dns_ok = 0; |
|
318 goto out; |
|
319 } |
|
320 break; |
|
321 } |
|
322 case DNS_IPv6_AAAA: { |
|
323 #if defined (_EVENT_HAVE_STRUCT_IN6_ADDR) && defined(_EVENT_HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN) |
|
324 struct in6_addr *in6_addrs = addresses; |
|
325 char buf[INET6_ADDRSTRLEN+1]; |
|
326 if (memcmp(&in6_addrs[0].s6_addr, "abcdefghijklmnop", 16) |
|
327 || ttl != 123) { |
|
328 const char *b = evutil_inet_ntop(AF_INET6, &in6_addrs[0],buf,sizeof(buf)); |
|
329 printf("Bad IPv6 response \"%s\" %d. ", b, ttl); |
|
330 dns_ok = 0; |
|
331 goto out; |
|
332 } |
|
333 #endif |
|
334 break; |
|
335 } |
|
336 case DNS_PTR: { |
|
337 char **addrs = addresses; |
|
338 if (arg != (void*)6) { |
|
339 if (strcmp(addrs[0], "ZZ.EXAMPLE.COM") || |
|
340 ttl != 54321) { |
|
341 printf("Bad PTR response \"%s\" %d. ", |
|
342 addrs[0], ttl); |
|
343 dns_ok = 0; |
|
344 goto out; |
|
345 } |
|
346 } else { |
|
347 if (strcmp(addrs[0], "ZZ-INET6.EXAMPLE.COM") || |
|
348 ttl != 54322) { |
|
349 printf("Bad ipv6 PTR response \"%s\" %d. ", |
|
350 addrs[0], ttl); |
|
351 dns_ok = 0; |
|
352 goto out; |
|
353 } |
|
354 } |
|
355 break; |
|
356 } |
|
357 default: |
|
358 printf("Bad response type %d. ", type); |
|
359 dns_ok = 0; |
|
360 } |
|
361 out: |
|
362 if (++n_server_responses == 3) { |
|
363 event_loopexit(NULL); |
|
364 } |
|
365 } |
|
366 |
|
367 static void |
|
368 dns_server(void) |
|
369 { |
|
370 evutil_socket_t sock=-1; |
|
371 struct sockaddr_in my_addr; |
|
372 struct sockaddr_storage ss; |
|
373 ev_socklen_t slen; |
|
374 struct evdns_server_port *port=NULL; |
|
375 struct in_addr resolve_addr; |
|
376 struct in6_addr resolve_addr6; |
|
377 struct evdns_base *base=NULL; |
|
378 struct evdns_request *req=NULL; |
|
379 |
|
380 dns_ok = 1; |
|
381 |
|
382 base = evdns_base_new(NULL, 0); |
|
383 |
|
384 /* Now configure a nameserver port. */ |
|
385 sock = socket(AF_INET, SOCK_DGRAM, 0); |
|
386 if (sock<0) { |
|
387 tt_abort_perror("socket"); |
|
388 } |
|
389 |
|
390 evutil_make_socket_nonblocking(sock); |
|
391 |
|
392 memset(&my_addr, 0, sizeof(my_addr)); |
|
393 my_addr.sin_family = AF_INET; |
|
394 my_addr.sin_port = 0; /* kernel picks */ |
|
395 my_addr.sin_addr.s_addr = htonl(0x7f000001UL); |
|
396 if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) { |
|
397 tt_abort_perror("bind"); |
|
398 } |
|
399 slen = sizeof(ss); |
|
400 if (getsockname(sock, (struct sockaddr*)&ss, &slen) < 0) { |
|
401 tt_abort_perror("getsockname"); |
|
402 } |
|
403 |
|
404 port = evdns_add_server_port(sock, 0, dns_server_request_cb, NULL); |
|
405 |
|
406 /* Add ourself as the only nameserver, and make sure we really are |
|
407 * the only nameserver. */ |
|
408 evdns_base_nameserver_sockaddr_add(base, (struct sockaddr*)&ss, slen, 0); |
|
409 tt_int_op(evdns_base_count_nameservers(base), ==, 1); |
|
410 |
|
411 /* Send some queries. */ |
|
412 evdns_base_resolve_ipv4(base, "zz.example.com", DNS_QUERY_NO_SEARCH, |
|
413 dns_server_gethostbyname_cb, NULL); |
|
414 evdns_base_resolve_ipv6(base, "zz.example.com", DNS_QUERY_NO_SEARCH, |
|
415 dns_server_gethostbyname_cb, NULL); |
|
416 resolve_addr.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */ |
|
417 evdns_base_resolve_reverse(base, &resolve_addr, 0, |
|
418 dns_server_gethostbyname_cb, NULL); |
|
419 memcpy(resolve_addr6.s6_addr, |
|
420 "\xff\xf0\x00\x00\x00\x00\xaa\xaa" |
|
421 "\x11\x11\x00\x00\x00\x00\xef\xef", 16); |
|
422 evdns_base_resolve_reverse_ipv6(base, &resolve_addr6, 0, |
|
423 dns_server_gethostbyname_cb, (void*)6); |
|
424 |
|
425 req = evdns_base_resolve_ipv4(base, |
|
426 "drop.example.com", DNS_QUERY_NO_SEARCH, |
|
427 dns_server_gethostbyname_cb, (void*)(char*)90909); |
|
428 |
|
429 evdns_cancel_request(base, req); |
|
430 |
|
431 event_dispatch(); |
|
432 |
|
433 tt_assert(dns_got_cancel); |
|
434 test_ok = dns_ok; |
|
435 |
|
436 end: |
|
437 if (port) |
|
438 evdns_close_server_port(port); |
|
439 if (sock >= 0) |
|
440 evutil_closesocket(sock); |
|
441 if (base) |
|
442 evdns_base_free(base, 0); |
|
443 } |
|
444 |
|
445 static int n_replies_left; |
|
446 static struct event_base *exit_base; |
|
447 |
|
448 struct generic_dns_callback_result { |
|
449 int result; |
|
450 char type; |
|
451 int count; |
|
452 int ttl; |
|
453 size_t addrs_len; |
|
454 void *addrs; |
|
455 char addrs_buf[256]; |
|
456 }; |
|
457 |
|
458 static void |
|
459 generic_dns_callback(int result, char type, int count, int ttl, void *addresses, |
|
460 void *arg) |
|
461 { |
|
462 size_t len; |
|
463 struct generic_dns_callback_result *res = arg; |
|
464 res->result = result; |
|
465 res->type = type; |
|
466 res->count = count; |
|
467 res->ttl = ttl; |
|
468 |
|
469 if (type == DNS_IPv4_A) |
|
470 len = count * 4; |
|
471 else if (type == DNS_IPv6_AAAA) |
|
472 len = count * 16; |
|
473 else if (type == DNS_PTR) |
|
474 len = strlen(addresses)+1; |
|
475 else { |
|
476 res->addrs_len = len = 0; |
|
477 res->addrs = NULL; |
|
478 } |
|
479 if (len) { |
|
480 res->addrs_len = len; |
|
481 if (len > 256) |
|
482 len = 256; |
|
483 memcpy(res->addrs_buf, addresses, len); |
|
484 res->addrs = res->addrs_buf; |
|
485 } |
|
486 |
|
487 if (--n_replies_left == 0) |
|
488 event_base_loopexit(exit_base, NULL); |
|
489 } |
|
490 |
|
491 static struct regress_dns_server_table search_table[] = { |
|
492 { "host.a.example.com", "err", "3", 0 }, |
|
493 { "host.b.example.com", "err", "3", 0 }, |
|
494 { "host.c.example.com", "A", "11.22.33.44", 0 }, |
|
495 { "host2.a.example.com", "err", "3", 0 }, |
|
496 { "host2.b.example.com", "A", "200.100.0.100", 0 }, |
|
497 { "host2.c.example.com", "err", "3", 0 }, |
|
498 { "hostn.a.example.com", "errsoa", "0", 0 }, |
|
499 { "hostn.b.example.com", "errsoa", "3", 0 }, |
|
500 { "hostn.c.example.com", "err", "0", 0 }, |
|
501 |
|
502 { "host", "err", "3", 0 }, |
|
503 { "host2", "err", "3", 0 }, |
|
504 { "*", "err", "3", 0 }, |
|
505 { NULL, NULL, NULL, 0 } |
|
506 }; |
|
507 |
|
508 static void |
|
509 dns_search_test(void *arg) |
|
510 { |
|
511 struct basic_test_data *data = arg; |
|
512 struct event_base *base = data->base; |
|
513 struct evdns_base *dns = NULL; |
|
514 ev_uint16_t portnum = 0; |
|
515 char buf[64]; |
|
516 |
|
517 struct generic_dns_callback_result r[8]; |
|
518 |
|
519 tt_assert(regress_dnsserver(base, &portnum, search_table)); |
|
520 evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); |
|
521 |
|
522 dns = evdns_base_new(base, 0); |
|
523 tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); |
|
524 |
|
525 evdns_base_search_add(dns, "a.example.com"); |
|
526 evdns_base_search_add(dns, "b.example.com"); |
|
527 evdns_base_search_add(dns, "c.example.com"); |
|
528 |
|
529 n_replies_left = sizeof(r)/sizeof(r[0]); |
|
530 exit_base = base; |
|
531 |
|
532 evdns_base_resolve_ipv4(dns, "host", 0, generic_dns_callback, &r[0]); |
|
533 evdns_base_resolve_ipv4(dns, "host2", 0, generic_dns_callback, &r[1]); |
|
534 evdns_base_resolve_ipv4(dns, "host", DNS_NO_SEARCH, generic_dns_callback, &r[2]); |
|
535 evdns_base_resolve_ipv4(dns, "host2", DNS_NO_SEARCH, generic_dns_callback, &r[3]); |
|
536 evdns_base_resolve_ipv4(dns, "host3", 0, generic_dns_callback, &r[4]); |
|
537 evdns_base_resolve_ipv4(dns, "hostn.a.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[5]); |
|
538 evdns_base_resolve_ipv4(dns, "hostn.b.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[6]); |
|
539 evdns_base_resolve_ipv4(dns, "hostn.c.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[7]); |
|
540 |
|
541 event_base_dispatch(base); |
|
542 |
|
543 tt_int_op(r[0].type, ==, DNS_IPv4_A); |
|
544 tt_int_op(r[0].count, ==, 1); |
|
545 tt_int_op(((ev_uint32_t*)r[0].addrs)[0], ==, htonl(0x0b16212c)); |
|
546 tt_int_op(r[1].type, ==, DNS_IPv4_A); |
|
547 tt_int_op(r[1].count, ==, 1); |
|
548 tt_int_op(((ev_uint32_t*)r[1].addrs)[0], ==, htonl(0xc8640064)); |
|
549 tt_int_op(r[2].result, ==, DNS_ERR_NOTEXIST); |
|
550 tt_int_op(r[3].result, ==, DNS_ERR_NOTEXIST); |
|
551 tt_int_op(r[4].result, ==, DNS_ERR_NOTEXIST); |
|
552 tt_int_op(r[5].result, ==, DNS_ERR_NODATA); |
|
553 tt_int_op(r[5].ttl, ==, 42); |
|
554 tt_int_op(r[6].result, ==, DNS_ERR_NOTEXIST); |
|
555 tt_int_op(r[6].ttl, ==, 42); |
|
556 tt_int_op(r[7].result, ==, DNS_ERR_NODATA); |
|
557 tt_int_op(r[7].ttl, ==, 0); |
|
558 |
|
559 end: |
|
560 if (dns) |
|
561 evdns_base_free(dns, 0); |
|
562 |
|
563 regress_clean_dnsserver(); |
|
564 } |
|
565 |
|
566 static int request_count = 0; |
|
567 static struct evdns_request *current_req = NULL; |
|
568 |
|
569 static void |
|
570 search_cancel_server_cb(struct evdns_server_request *req, void *data) |
|
571 { |
|
572 const char *question; |
|
573 |
|
574 if (req->nquestions != 1) |
|
575 TT_DIE(("Only handling one question at a time; got %d", |
|
576 req->nquestions)); |
|
577 |
|
578 question = req->questions[0]->name; |
|
579 |
|
580 TT_BLATHER(("got question, %s", question)); |
|
581 |
|
582 tt_assert(request_count > 0); |
|
583 tt_assert(!evdns_server_request_respond(req, 3)); |
|
584 |
|
585 if (!--request_count) |
|
586 evdns_cancel_request(NULL, current_req); |
|
587 |
|
588 end: |
|
589 ; |
|
590 } |
|
591 |
|
592 static void |
|
593 dns_search_cancel_test(void *arg) |
|
594 { |
|
595 struct basic_test_data *data = arg; |
|
596 struct event_base *base = data->base; |
|
597 struct evdns_base *dns = NULL; |
|
598 struct evdns_server_port *port = NULL; |
|
599 ev_uint16_t portnum = 0; |
|
600 struct generic_dns_callback_result r1; |
|
601 char buf[64]; |
|
602 |
|
603 port = regress_get_dnsserver(base, &portnum, NULL, |
|
604 search_cancel_server_cb, NULL); |
|
605 tt_assert(port); |
|
606 evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); |
|
607 |
|
608 dns = evdns_base_new(base, 0); |
|
609 tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); |
|
610 |
|
611 evdns_base_search_add(dns, "a.example.com"); |
|
612 evdns_base_search_add(dns, "b.example.com"); |
|
613 evdns_base_search_add(dns, "c.example.com"); |
|
614 evdns_base_search_add(dns, "d.example.com"); |
|
615 |
|
616 exit_base = base; |
|
617 request_count = 3; |
|
618 n_replies_left = 1; |
|
619 |
|
620 current_req = evdns_base_resolve_ipv4(dns, "host", 0, |
|
621 generic_dns_callback, &r1); |
|
622 event_base_dispatch(base); |
|
623 |
|
624 tt_int_op(r1.result, ==, DNS_ERR_CANCEL); |
|
625 |
|
626 end: |
|
627 if (port) |
|
628 evdns_close_server_port(port); |
|
629 if (dns) |
|
630 evdns_base_free(dns, 0); |
|
631 } |
|
632 |
|
633 static void |
|
634 fail_server_cb(struct evdns_server_request *req, void *data) |
|
635 { |
|
636 const char *question; |
|
637 int *count = data; |
|
638 struct in_addr in; |
|
639 |
|
640 /* Drop the first N requests that we get. */ |
|
641 if (*count > 0) { |
|
642 --*count; |
|
643 tt_want(! evdns_server_request_drop(req)); |
|
644 return; |
|
645 } |
|
646 |
|
647 if (req->nquestions != 1) |
|
648 TT_DIE(("Only handling one question at a time; got %d", |
|
649 req->nquestions)); |
|
650 |
|
651 question = req->questions[0]->name; |
|
652 |
|
653 if (!evutil_ascii_strcasecmp(question, "google.com")) { |
|
654 /* Detect a probe, and get out of the loop. */ |
|
655 event_base_loopexit(exit_base, NULL); |
|
656 } |
|
657 |
|
658 evutil_inet_pton(AF_INET, "16.32.64.128", &in); |
|
659 evdns_server_request_add_a_reply(req, question, 1, &in.s_addr, |
|
660 100); |
|
661 tt_assert(! evdns_server_request_respond(req, 0)) |
|
662 return; |
|
663 end: |
|
664 tt_want(! evdns_server_request_drop(req)); |
|
665 } |
|
666 |
|
667 static void |
|
668 dns_retry_test(void *arg) |
|
669 { |
|
670 struct basic_test_data *data = arg; |
|
671 struct event_base *base = data->base; |
|
672 struct evdns_server_port *port = NULL; |
|
673 struct evdns_base *dns = NULL; |
|
674 int drop_count = 2; |
|
675 ev_uint16_t portnum = 0; |
|
676 char buf[64]; |
|
677 |
|
678 struct generic_dns_callback_result r1; |
|
679 |
|
680 port = regress_get_dnsserver(base, &portnum, NULL, |
|
681 fail_server_cb, &drop_count); |
|
682 tt_assert(port); |
|
683 evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); |
|
684 |
|
685 dns = evdns_base_new(base, 0); |
|
686 tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); |
|
687 tt_assert(! evdns_base_set_option(dns, "timeout", "0.3")); |
|
688 tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "10")); |
|
689 tt_assert(! evdns_base_set_option(dns, "initial-probe-timeout", "0.5")); |
|
690 |
|
691 evdns_base_resolve_ipv4(dns, "host.example.com", 0, |
|
692 generic_dns_callback, &r1); |
|
693 |
|
694 n_replies_left = 1; |
|
695 exit_base = base; |
|
696 |
|
697 event_base_dispatch(base); |
|
698 |
|
699 tt_int_op(drop_count, ==, 0); |
|
700 |
|
701 tt_int_op(r1.type, ==, DNS_IPv4_A); |
|
702 tt_int_op(r1.count, ==, 1); |
|
703 tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x10204080)); |
|
704 |
|
705 /* Now try again, but this time have the server get treated as |
|
706 * failed, so we can send it a test probe. */ |
|
707 drop_count = 4; |
|
708 tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "3")); |
|
709 tt_assert(! evdns_base_set_option(dns, "attempts:", "4")); |
|
710 memset(&r1, 0, sizeof(r1)); |
|
711 |
|
712 evdns_base_resolve_ipv4(dns, "host.example.com", 0, |
|
713 generic_dns_callback, &r1); |
|
714 |
|
715 n_replies_left = 2; |
|
716 |
|
717 /* This will run until it answers the "google.com" probe request. */ |
|
718 event_base_dispatch(base); |
|
719 |
|
720 /* We'll treat the server as failed here. */ |
|
721 tt_int_op(r1.result, ==, DNS_ERR_TIMEOUT); |
|
722 |
|
723 /* It should work this time. */ |
|
724 tt_int_op(drop_count, ==, 0); |
|
725 evdns_base_resolve_ipv4(dns, "host.example.com", 0, |
|
726 generic_dns_callback, &r1); |
|
727 |
|
728 event_base_dispatch(base); |
|
729 tt_int_op(r1.result, ==, DNS_ERR_NONE); |
|
730 tt_int_op(r1.type, ==, DNS_IPv4_A); |
|
731 tt_int_op(r1.count, ==, 1); |
|
732 tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x10204080)); |
|
733 |
|
734 end: |
|
735 if (dns) |
|
736 evdns_base_free(dns, 0); |
|
737 if (port) |
|
738 evdns_close_server_port(port); |
|
739 } |
|
740 |
|
741 static struct regress_dns_server_table internal_error_table[] = { |
|
742 /* Error 4 (NOTIMPL) makes us reissue the request to another server |
|
743 if we can. |
|
744 |
|
745 XXXX we should reissue under a much wider set of circumstances! |
|
746 */ |
|
747 { "foof.example.com", "err", "4", 0 }, |
|
748 { NULL, NULL, NULL, 0 } |
|
749 }; |
|
750 |
|
751 static struct regress_dns_server_table reissue_table[] = { |
|
752 { "foof.example.com", "A", "240.15.240.15", 0 }, |
|
753 { NULL, NULL, NULL, 0 } |
|
754 }; |
|
755 |
|
756 static void |
|
757 dns_reissue_test(void *arg) |
|
758 { |
|
759 struct basic_test_data *data = arg; |
|
760 struct event_base *base = data->base; |
|
761 struct evdns_server_port *port1 = NULL, *port2 = NULL; |
|
762 struct evdns_base *dns = NULL; |
|
763 struct generic_dns_callback_result r1; |
|
764 ev_uint16_t portnum1 = 0, portnum2=0; |
|
765 char buf1[64], buf2[64]; |
|
766 |
|
767 port1 = regress_get_dnsserver(base, &portnum1, NULL, |
|
768 regress_dns_server_cb, internal_error_table); |
|
769 tt_assert(port1); |
|
770 port2 = regress_get_dnsserver(base, &portnum2, NULL, |
|
771 regress_dns_server_cb, reissue_table); |
|
772 tt_assert(port2); |
|
773 evutil_snprintf(buf1, sizeof(buf1), "127.0.0.1:%d", (int)portnum1); |
|
774 evutil_snprintf(buf2, sizeof(buf2), "127.0.0.1:%d", (int)portnum2); |
|
775 |
|
776 dns = evdns_base_new(base, 0); |
|
777 tt_assert(!evdns_base_nameserver_ip_add(dns, buf1)); |
|
778 tt_assert(! evdns_base_set_option(dns, "timeout:", "0.3")); |
|
779 tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "2")); |
|
780 tt_assert(! evdns_base_set_option(dns, "attempts:", "5")); |
|
781 |
|
782 memset(&r1, 0, sizeof(r1)); |
|
783 evdns_base_resolve_ipv4(dns, "foof.example.com", 0, |
|
784 generic_dns_callback, &r1); |
|
785 |
|
786 /* Add this after, so that we are sure to get a reissue. */ |
|
787 tt_assert(!evdns_base_nameserver_ip_add(dns, buf2)); |
|
788 |
|
789 n_replies_left = 1; |
|
790 exit_base = base; |
|
791 |
|
792 event_base_dispatch(base); |
|
793 tt_int_op(r1.result, ==, DNS_ERR_NONE); |
|
794 tt_int_op(r1.type, ==, DNS_IPv4_A); |
|
795 tt_int_op(r1.count, ==, 1); |
|
796 tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0xf00ff00f)); |
|
797 |
|
798 /* Make sure we dropped at least once. */ |
|
799 tt_int_op(internal_error_table[0].seen, >, 0); |
|
800 |
|
801 end: |
|
802 if (dns) |
|
803 evdns_base_free(dns, 0); |
|
804 if (port1) |
|
805 evdns_close_server_port(port1); |
|
806 if (port2) |
|
807 evdns_close_server_port(port2); |
|
808 } |
|
809 |
|
810 #if 0 |
|
811 static void |
|
812 dumb_bytes_fn(char *p, size_t n) |
|
813 { |
|
814 unsigned i; |
|
815 /* This gets us 6 bits of entropy per transaction ID, which means we |
|
816 * will have probably have collisions and need to pick again. */ |
|
817 for (i=0;i<n;++i) |
|
818 p[i] = (char)(rand() & 7); |
|
819 } |
|
820 #endif |
|
821 |
|
822 static void |
|
823 dns_inflight_test(void *arg) |
|
824 { |
|
825 struct basic_test_data *data = arg; |
|
826 struct event_base *base = data->base; |
|
827 struct evdns_base *dns = NULL; |
|
828 ev_uint16_t portnum = 0; |
|
829 char buf[64]; |
|
830 |
|
831 struct generic_dns_callback_result r[20]; |
|
832 int i; |
|
833 |
|
834 tt_assert(regress_dnsserver(base, &portnum, reissue_table)); |
|
835 evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum); |
|
836 |
|
837 dns = evdns_base_new(base, 0); |
|
838 tt_assert(!evdns_base_nameserver_ip_add(dns, buf)); |
|
839 tt_assert(! evdns_base_set_option(dns, "max-inflight:", "3")); |
|
840 tt_assert(! evdns_base_set_option(dns, "randomize-case:", "0")); |
|
841 |
|
842 for (i=0;i<20;++i) |
|
843 evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r[i]); |
|
844 |
|
845 n_replies_left = 20; |
|
846 exit_base = base; |
|
847 |
|
848 event_base_dispatch(base); |
|
849 |
|
850 for (i=0;i<20;++i) { |
|
851 tt_int_op(r[i].type, ==, DNS_IPv4_A); |
|
852 tt_int_op(r[i].count, ==, 1); |
|
853 tt_int_op(((ev_uint32_t*)r[i].addrs)[0], ==, htonl(0xf00ff00f)); |
|
854 } |
|
855 |
|
856 end: |
|
857 if (dns) |
|
858 evdns_base_free(dns, 0); |
|
859 regress_clean_dnsserver(); |
|
860 } |
|
861 |
|
862 /* === Test for bufferevent_socket_connect_hostname */ |
|
863 |
|
864 static int total_connected_or_failed = 0; |
|
865 static int total_n_accepted = 0; |
|
866 static struct event_base *be_connect_hostname_base = NULL; |
|
867 |
|
868 /* Implements a DNS server for the connect_hostname test and the |
|
869 * getaddrinfo_async test */ |
|
870 static void |
|
871 be_getaddrinfo_server_cb(struct evdns_server_request *req, void *data) |
|
872 { |
|
873 int i; |
|
874 int *n_got_p=data; |
|
875 int added_any=0; |
|
876 ++*n_got_p; |
|
877 |
|
878 for (i=0;i<req->nquestions;++i) { |
|
879 const int qtype = req->questions[i]->type; |
|
880 const int qclass = req->questions[i]->dns_question_class; |
|
881 const char *qname = req->questions[i]->name; |
|
882 struct in_addr ans; |
|
883 struct in6_addr ans6; |
|
884 memset(&ans6, 0, sizeof(ans6)); |
|
885 |
|
886 if (qtype == EVDNS_TYPE_A && |
|
887 qclass == EVDNS_CLASS_INET && |
|
888 !evutil_ascii_strcasecmp(qname, "nobodaddy.example.com")) { |
|
889 ans.s_addr = htonl(0x7f000001); |
|
890 evdns_server_request_add_a_reply(req, qname, |
|
891 1, &ans.s_addr, 2000); |
|
892 added_any = 1; |
|
893 } else if (!evutil_ascii_strcasecmp(qname, |
|
894 "nosuchplace.example.com")) { |
|
895 /* ok, just say notfound. */ |
|
896 } else if (!evutil_ascii_strcasecmp(qname, |
|
897 "both.example.com")) { |
|
898 if (qtype == EVDNS_TYPE_A) { |
|
899 ans.s_addr = htonl(0x50502020); |
|
900 evdns_server_request_add_a_reply(req, qname, |
|
901 1, &ans.s_addr, 2000); |
|
902 added_any = 1; |
|
903 } else if (qtype == EVDNS_TYPE_AAAA) { |
|
904 ans6.s6_addr[0] = 0x80; |
|
905 ans6.s6_addr[1] = 0xff; |
|
906 ans6.s6_addr[14] = 0xbb; |
|
907 ans6.s6_addr[15] = 0xbb; |
|
908 evdns_server_request_add_aaaa_reply(req, qname, |
|
909 1, &ans6.s6_addr, 2000); |
|
910 added_any = 1; |
|
911 } |
|
912 evdns_server_request_add_cname_reply(req, qname, |
|
913 "both-canonical.example.com", 1000); |
|
914 } else if (!evutil_ascii_strcasecmp(qname, |
|
915 "v4only.example.com") || |
|
916 !evutil_ascii_strcasecmp(qname, "v4assert.example.com")) { |
|
917 if (qtype == EVDNS_TYPE_A) { |
|
918 ans.s_addr = htonl(0x12345678); |
|
919 evdns_server_request_add_a_reply(req, qname, |
|
920 1, &ans.s_addr, 2000); |
|
921 added_any = 1; |
|
922 } else if (!evutil_ascii_strcasecmp(qname, |
|
923 "v4assert.example.com")) { |
|
924 TT_FAIL(("Got an AAAA request for v4assert")); |
|
925 } |
|
926 } else if (!evutil_ascii_strcasecmp(qname, |
|
927 "v6only.example.com") || |
|
928 !evutil_ascii_strcasecmp(qname, "v6assert.example.com")) { |
|
929 if (qtype == EVDNS_TYPE_AAAA) { |
|
930 ans6.s6_addr[0] = 0x0b; |
|
931 ans6.s6_addr[1] = 0x0b; |
|
932 ans6.s6_addr[14] = 0xf0; |
|
933 ans6.s6_addr[15] = 0x0d; |
|
934 evdns_server_request_add_aaaa_reply(req, qname, |
|
935 1, &ans6.s6_addr, 2000); |
|
936 added_any = 1; |
|
937 } else if (!evutil_ascii_strcasecmp(qname, |
|
938 "v6assert.example.com")) { |
|
939 TT_FAIL(("Got a A request for v6assert")); |
|
940 } |
|
941 } else if (!evutil_ascii_strcasecmp(qname, |
|
942 "v6timeout.example.com")) { |
|
943 if (qtype == EVDNS_TYPE_A) { |
|
944 ans.s_addr = htonl(0xabcdef01); |
|
945 evdns_server_request_add_a_reply(req, qname, |
|
946 1, &ans.s_addr, 2000); |
|
947 added_any = 1; |
|
948 } else if (qtype == EVDNS_TYPE_AAAA) { |
|
949 /* Let the v6 request time out.*/ |
|
950 evdns_server_request_drop(req); |
|
951 return; |
|
952 } |
|
953 } else if (!evutil_ascii_strcasecmp(qname, |
|
954 "v4timeout.example.com")) { |
|
955 if (qtype == EVDNS_TYPE_AAAA) { |
|
956 ans6.s6_addr[0] = 0x0a; |
|
957 ans6.s6_addr[1] = 0x0a; |
|
958 ans6.s6_addr[14] = 0xff; |
|
959 ans6.s6_addr[15] = 0x01; |
|
960 evdns_server_request_add_aaaa_reply(req, qname, |
|
961 1, &ans6.s6_addr, 2000); |
|
962 added_any = 1; |
|
963 } else if (qtype == EVDNS_TYPE_A) { |
|
964 /* Let the v4 request time out.*/ |
|
965 evdns_server_request_drop(req); |
|
966 return; |
|
967 } |
|
968 } else if (!evutil_ascii_strcasecmp(qname, |
|
969 "v6timeout-nonexist.example.com")) { |
|
970 if (qtype == EVDNS_TYPE_A) { |
|
971 /* Fall through, give an nexist. */ |
|
972 } else if (qtype == EVDNS_TYPE_AAAA) { |
|
973 /* Let the v6 request time out.*/ |
|
974 evdns_server_request_drop(req); |
|
975 return; |
|
976 } |
|
977 } else if (!evutil_ascii_strcasecmp(qname, |
|
978 "all-timeout.example.com")) { |
|
979 /* drop all requests */ |
|
980 evdns_server_request_drop(req); |
|
981 return; |
|
982 } else { |
|
983 TT_GRIPE(("Got weird request for %s",qname)); |
|
984 } |
|
985 } |
|
986 if (added_any) |
|
987 evdns_server_request_respond(req, 0); |
|
988 else |
|
989 evdns_server_request_respond(req, 3); |
|
990 } |
|
991 |
|
992 /* Implements a listener for connect_hostname test. */ |
|
993 static void |
|
994 nil_accept_cb(struct evconnlistener *l, evutil_socket_t fd, struct sockaddr *s, |
|
995 int socklen, void *arg) |
|
996 { |
|
997 int *p = arg; |
|
998 (*p)++; |
|
999 ++total_n_accepted; |
|
1000 /* don't do anything with the socket; let it close when we exit() */ |
|
1001 if (total_n_accepted >= 3 && total_connected_or_failed >= 5) |
|
1002 event_base_loopexit(be_connect_hostname_base, |
|
1003 NULL); |
|
1004 } |
|
1005 |
|
1006 struct be_conn_hostname_result { |
|
1007 int dnserr; |
|
1008 int what; |
|
1009 }; |
|
1010 |
|
1011 /* Bufferevent event callback for the connect_hostname test: remembers what |
|
1012 * event we got. */ |
|
1013 static void |
|
1014 be_connect_hostname_event_cb(struct bufferevent *bev, short what, void *ctx) |
|
1015 { |
|
1016 struct be_conn_hostname_result *got = ctx; |
|
1017 if (!got->what) { |
|
1018 TT_BLATHER(("Got a bufferevent event %d", what)); |
|
1019 got->what = what; |
|
1020 |
|
1021 if ((what & BEV_EVENT_CONNECTED) || (what & BEV_EVENT_ERROR)) { |
|
1022 int r; |
|
1023 if ((r = bufferevent_socket_get_dns_error(bev))) { |
|
1024 got->dnserr = r; |
|
1025 TT_BLATHER(("DNS error %d: %s", r, |
|
1026 evutil_gai_strerror(r))); |
|
1027 } ++total_connected_or_failed; |
|
1028 TT_BLATHER(("Got %d connections or errors.", total_connected_or_failed)); |
|
1029 |
|
1030 if (total_n_accepted >= 3 && total_connected_or_failed >= 5) |
|
1031 event_base_loopexit(be_connect_hostname_base, |
|
1032 NULL); |
|
1033 } |
|
1034 } else { |
|
1035 TT_FAIL(("Two events on one bufferevent. %d,%d", |
|
1036 got->what, (int)what)); |
|
1037 } |
|
1038 } |
|
1039 |
|
1040 static void |
|
1041 test_bufferevent_connect_hostname(void *arg) |
|
1042 { |
|
1043 struct basic_test_data *data = arg; |
|
1044 struct evconnlistener *listener = NULL; |
|
1045 struct bufferevent *be1=NULL, *be2=NULL, *be3=NULL, *be4=NULL, *be5=NULL; |
|
1046 struct be_conn_hostname_result be1_outcome={0,0}, be2_outcome={0,0}, |
|
1047 be3_outcome={0,0}, be4_outcome={0,0}, be5_outcome={0,0}; |
|
1048 int expect_err5; |
|
1049 struct evdns_base *dns=NULL; |
|
1050 struct evdns_server_port *port=NULL; |
|
1051 struct sockaddr_in sin; |
|
1052 int listener_port=-1; |
|
1053 ev_uint16_t dns_port=0; |
|
1054 int n_accept=0, n_dns=0; |
|
1055 char buf[128]; |
|
1056 |
|
1057 be_connect_hostname_base = data->base; |
|
1058 |
|
1059 /* Bind an address and figure out what port it's on. */ |
|
1060 memset(&sin, 0, sizeof(sin)); |
|
1061 sin.sin_family = AF_INET; |
|
1062 sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ |
|
1063 sin.sin_port = 0; |
|
1064 listener = evconnlistener_new_bind(data->base, nil_accept_cb, |
|
1065 &n_accept, |
|
1066 LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC, |
|
1067 -1, (struct sockaddr *)&sin, sizeof(sin)); |
|
1068 tt_assert(listener); |
|
1069 listener_port = regress_get_socket_port( |
|
1070 evconnlistener_get_fd(listener)); |
|
1071 |
|
1072 port = regress_get_dnsserver(data->base, &dns_port, NULL, |
|
1073 be_getaddrinfo_server_cb, &n_dns); |
|
1074 tt_assert(port); |
|
1075 tt_int_op(dns_port, >=, 0); |
|
1076 |
|
1077 /* Start an evdns_base that uses the server as its resolver. */ |
|
1078 dns = evdns_base_new(data->base, 0); |
|
1079 evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)dns_port); |
|
1080 evdns_base_nameserver_ip_add(dns, buf); |
|
1081 |
|
1082 /* Now, finally, at long last, launch the bufferevents. One should do |
|
1083 * a failing lookup IP, one should do a successful lookup by IP, |
|
1084 * and one should do a successful lookup by hostname. */ |
|
1085 be1 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); |
|
1086 be2 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); |
|
1087 be3 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); |
|
1088 be4 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); |
|
1089 be5 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE); |
|
1090 |
|
1091 bufferevent_setcb(be1, NULL, NULL, be_connect_hostname_event_cb, |
|
1092 &be1_outcome); |
|
1093 bufferevent_setcb(be2, NULL, NULL, be_connect_hostname_event_cb, |
|
1094 &be2_outcome); |
|
1095 bufferevent_setcb(be3, NULL, NULL, be_connect_hostname_event_cb, |
|
1096 &be3_outcome); |
|
1097 bufferevent_setcb(be4, NULL, NULL, be_connect_hostname_event_cb, |
|
1098 &be4_outcome); |
|
1099 bufferevent_setcb(be5, NULL, NULL, be_connect_hostname_event_cb, |
|
1100 &be5_outcome); |
|
1101 |
|
1102 /* Launch an async resolve that will fail. */ |
|
1103 tt_assert(!bufferevent_socket_connect_hostname(be1, dns, AF_INET, |
|
1104 "nosuchplace.example.com", listener_port)); |
|
1105 /* Connect to the IP without resolving. */ |
|
1106 tt_assert(!bufferevent_socket_connect_hostname(be2, dns, AF_INET, |
|
1107 "127.0.0.1", listener_port)); |
|
1108 /* Launch an async resolve that will succeed. */ |
|
1109 tt_assert(!bufferevent_socket_connect_hostname(be3, dns, AF_INET, |
|
1110 "nobodaddy.example.com", listener_port)); |
|
1111 /* Use the blocking resolver. This one will fail if your resolver |
|
1112 * can't resolve localhost to 127.0.0.1 */ |
|
1113 tt_assert(!bufferevent_socket_connect_hostname(be4, NULL, AF_INET, |
|
1114 "localhost", listener_port)); |
|
1115 /* Use the blocking resolver with a nonexistent hostname. */ |
|
1116 tt_assert(!bufferevent_socket_connect_hostname(be5, NULL, AF_INET, |
|
1117 "nonesuch.nowhere.example.com", 80)); |
|
1118 { |
|
1119 /* The blocking resolver will use the system nameserver, which |
|
1120 * might tell us anything. (Yes, some twits even pretend that |
|
1121 * example.com is real.) Let's see what answer to expect. */ |
|
1122 struct evutil_addrinfo hints, *ai = NULL; |
|
1123 memset(&hints, 0, sizeof(hints)); |
|
1124 hints.ai_family = AF_INET; |
|
1125 hints.ai_socktype = SOCK_STREAM; |
|
1126 hints.ai_protocol = IPPROTO_TCP; |
|
1127 expect_err5 = evutil_getaddrinfo( |
|
1128 "nonesuch.nowhere.example.com", "80", &hints, &ai); |
|
1129 } |
|
1130 |
|
1131 event_base_dispatch(data->base); |
|
1132 |
|
1133 tt_int_op(be1_outcome.what, ==, BEV_EVENT_ERROR); |
|
1134 tt_int_op(be1_outcome.dnserr, ==, EVUTIL_EAI_NONAME); |
|
1135 tt_int_op(be2_outcome.what, ==, BEV_EVENT_CONNECTED); |
|
1136 tt_int_op(be2_outcome.dnserr, ==, 0); |
|
1137 tt_int_op(be3_outcome.what, ==, BEV_EVENT_CONNECTED); |
|
1138 tt_int_op(be3_outcome.dnserr, ==, 0); |
|
1139 tt_int_op(be4_outcome.what, ==, BEV_EVENT_CONNECTED); |
|
1140 tt_int_op(be4_outcome.dnserr, ==, 0); |
|
1141 if (expect_err5) { |
|
1142 tt_int_op(be5_outcome.what, ==, BEV_EVENT_ERROR); |
|
1143 tt_int_op(be5_outcome.dnserr, ==, expect_err5); |
|
1144 } |
|
1145 |
|
1146 tt_int_op(n_accept, ==, 3); |
|
1147 tt_int_op(n_dns, ==, 2); |
|
1148 |
|
1149 end: |
|
1150 if (listener) |
|
1151 evconnlistener_free(listener); |
|
1152 if (port) |
|
1153 evdns_close_server_port(port); |
|
1154 if (dns) |
|
1155 evdns_base_free(dns, 0); |
|
1156 if (be1) |
|
1157 bufferevent_free(be1); |
|
1158 if (be2) |
|
1159 bufferevent_free(be2); |
|
1160 if (be3) |
|
1161 bufferevent_free(be3); |
|
1162 if (be4) |
|
1163 bufferevent_free(be4); |
|
1164 if (be5) |
|
1165 bufferevent_free(be5); |
|
1166 } |
|
1167 |
|
1168 |
|
1169 struct gai_outcome { |
|
1170 int err; |
|
1171 struct evutil_addrinfo *ai; |
|
1172 }; |
|
1173 |
|
1174 static int n_gai_results_pending = 0; |
|
1175 static struct event_base *exit_base_on_no_pending_results = NULL; |
|
1176 |
|
1177 static void |
|
1178 gai_cb(int err, struct evutil_addrinfo *res, void *ptr) |
|
1179 { |
|
1180 struct gai_outcome *go = ptr; |
|
1181 go->err = err; |
|
1182 go->ai = res; |
|
1183 if (--n_gai_results_pending <= 0 && exit_base_on_no_pending_results) |
|
1184 event_base_loopexit(exit_base_on_no_pending_results, NULL); |
|
1185 if (n_gai_results_pending < 900) |
|
1186 TT_BLATHER(("Got an answer; expecting %d more.", |
|
1187 n_gai_results_pending)); |
|
1188 } |
|
1189 |
|
1190 static void |
|
1191 cancel_gai_cb(evutil_socket_t fd, short what, void *ptr) |
|
1192 { |
|
1193 struct evdns_getaddrinfo_request *r = ptr; |
|
1194 evdns_getaddrinfo_cancel(r); |
|
1195 } |
|
1196 |
|
1197 static void |
|
1198 test_getaddrinfo_async(void *arg) |
|
1199 { |
|
1200 struct basic_test_data *data = arg; |
|
1201 struct evutil_addrinfo hints, *a; |
|
1202 struct gai_outcome local_outcome; |
|
1203 struct gai_outcome a_out[12]; |
|
1204 int i; |
|
1205 struct evdns_getaddrinfo_request *r; |
|
1206 char buf[128]; |
|
1207 struct evdns_server_port *port = NULL; |
|
1208 ev_uint16_t dns_port = 0; |
|
1209 int n_dns_questions = 0; |
|
1210 |
|
1211 struct evdns_base *dns_base = evdns_base_new(data->base, 0); |
|
1212 tt_assert(dns_base); |
|
1213 |
|
1214 /* for localhost */ |
|
1215 evdns_base_load_hosts(dns_base, NULL); |
|
1216 |
|
1217 memset(a_out, 0, sizeof(a_out)); |
|
1218 memset(&local_outcome, 0, sizeof(local_outcome)); |
|
1219 |
|
1220 n_gai_results_pending = 10000; /* don't think about exiting yet. */ |
|
1221 |
|
1222 /* 1. Try some cases that will never hit the asynchronous resolver. */ |
|
1223 /* 1a. Simple case with a symbolic service name */ |
|
1224 memset(&hints, 0, sizeof(hints)); |
|
1225 hints.ai_family = PF_UNSPEC; |
|
1226 hints.ai_socktype = SOCK_STREAM; |
|
1227 memset(&local_outcome, 0, sizeof(local_outcome)); |
|
1228 r = evdns_getaddrinfo(dns_base, "1.2.3.4", "http", |
|
1229 &hints, gai_cb, &local_outcome); |
|
1230 tt_assert(! r); |
|
1231 if (!local_outcome.err) { |
|
1232 tt_ptr_op(local_outcome.ai,!=,NULL); |
|
1233 test_ai_eq(local_outcome.ai, "1.2.3.4:80", SOCK_STREAM, IPPROTO_TCP); |
|
1234 evutil_freeaddrinfo(local_outcome.ai); |
|
1235 local_outcome.ai = NULL; |
|
1236 } else { |
|
1237 TT_BLATHER(("Apparently we have no getservbyname.")); |
|
1238 } |
|
1239 |
|
1240 /* 1b. EVUTIL_AI_NUMERICHOST is set */ |
|
1241 memset(&hints, 0, sizeof(hints)); |
|
1242 hints.ai_family = PF_UNSPEC; |
|
1243 hints.ai_flags = EVUTIL_AI_NUMERICHOST; |
|
1244 memset(&local_outcome, 0, sizeof(local_outcome)); |
|
1245 r = evdns_getaddrinfo(dns_base, "www.google.com", "80", |
|
1246 &hints, gai_cb, &local_outcome); |
|
1247 tt_ptr_op(r,==,NULL); |
|
1248 tt_int_op(local_outcome.err,==,EVUTIL_EAI_NONAME); |
|
1249 tt_ptr_op(local_outcome.ai,==,NULL); |
|
1250 |
|
1251 /* 1c. We give a numeric address (ipv6) */ |
|
1252 memset(&hints, 0, sizeof(hints)); |
|
1253 memset(&local_outcome, 0, sizeof(local_outcome)); |
|
1254 hints.ai_family = PF_UNSPEC; |
|
1255 hints.ai_protocol = IPPROTO_TCP; |
|
1256 r = evdns_getaddrinfo(dns_base, "f::f", "8008", |
|
1257 &hints, gai_cb, &local_outcome); |
|
1258 tt_assert(!r); |
|
1259 tt_int_op(local_outcome.err,==,0); |
|
1260 tt_assert(local_outcome.ai); |
|
1261 tt_ptr_op(local_outcome.ai->ai_next,==,NULL); |
|
1262 test_ai_eq(local_outcome.ai, "[f::f]:8008", SOCK_STREAM, IPPROTO_TCP); |
|
1263 evutil_freeaddrinfo(local_outcome.ai); |
|
1264 local_outcome.ai = NULL; |
|
1265 |
|
1266 /* 1d. We give a numeric address (ipv4) */ |
|
1267 memset(&hints, 0, sizeof(hints)); |
|
1268 memset(&local_outcome, 0, sizeof(local_outcome)); |
|
1269 hints.ai_family = PF_UNSPEC; |
|
1270 r = evdns_getaddrinfo(dns_base, "5.6.7.8", NULL, |
|
1271 &hints, gai_cb, &local_outcome); |
|
1272 tt_assert(!r); |
|
1273 tt_int_op(local_outcome.err,==,0); |
|
1274 tt_assert(local_outcome.ai); |
|
1275 a = ai_find_by_protocol(local_outcome.ai, IPPROTO_TCP); |
|
1276 tt_assert(a); |
|
1277 test_ai_eq(a, "5.6.7.8", SOCK_STREAM, IPPROTO_TCP); |
|
1278 a = ai_find_by_protocol(local_outcome.ai, IPPROTO_UDP); |
|
1279 tt_assert(a); |
|
1280 test_ai_eq(a, "5.6.7.8", SOCK_DGRAM, IPPROTO_UDP); |
|
1281 evutil_freeaddrinfo(local_outcome.ai); |
|
1282 local_outcome.ai = NULL; |
|
1283 |
|
1284 /* 1e. nodename is NULL (bind) */ |
|
1285 memset(&hints, 0, sizeof(hints)); |
|
1286 memset(&local_outcome, 0, sizeof(local_outcome)); |
|
1287 hints.ai_family = PF_UNSPEC; |
|
1288 hints.ai_socktype = SOCK_DGRAM; |
|
1289 hints.ai_flags = EVUTIL_AI_PASSIVE; |
|
1290 r = evdns_getaddrinfo(dns_base, NULL, "9090", |
|
1291 &hints, gai_cb, &local_outcome); |
|
1292 tt_assert(!r); |
|
1293 tt_int_op(local_outcome.err,==,0); |
|
1294 tt_assert(local_outcome.ai); |
|
1295 /* we should get a v4 address of 0.0.0.0... */ |
|
1296 a = ai_find_by_family(local_outcome.ai, PF_INET); |
|
1297 tt_assert(a); |
|
1298 test_ai_eq(a, "0.0.0.0:9090", SOCK_DGRAM, IPPROTO_UDP); |
|
1299 /* ... and a v6 address of ::0 */ |
|
1300 a = ai_find_by_family(local_outcome.ai, PF_INET6); |
|
1301 tt_assert(a); |
|
1302 test_ai_eq(a, "[::]:9090", SOCK_DGRAM, IPPROTO_UDP); |
|
1303 evutil_freeaddrinfo(local_outcome.ai); |
|
1304 local_outcome.ai = NULL; |
|
1305 |
|
1306 /* 1f. nodename is NULL (connect) */ |
|
1307 memset(&hints, 0, sizeof(hints)); |
|
1308 memset(&local_outcome, 0, sizeof(local_outcome)); |
|
1309 hints.ai_family = PF_UNSPEC; |
|
1310 hints.ai_socktype = SOCK_STREAM; |
|
1311 r = evdns_getaddrinfo(dns_base, NULL, "2", |
|
1312 &hints, gai_cb, &local_outcome); |
|
1313 tt_assert(!r); |
|
1314 tt_int_op(local_outcome.err,==,0); |
|
1315 tt_assert(local_outcome.ai); |
|
1316 /* we should get a v4 address of 127.0.0.1 .... */ |
|
1317 a = ai_find_by_family(local_outcome.ai, PF_INET); |
|
1318 tt_assert(a); |
|
1319 test_ai_eq(a, "127.0.0.1:2", SOCK_STREAM, IPPROTO_TCP); |
|
1320 /* ... and a v6 address of ::1 */ |
|
1321 a = ai_find_by_family(local_outcome.ai, PF_INET6); |
|
1322 tt_assert(a); |
|
1323 test_ai_eq(a, "[::1]:2", SOCK_STREAM, IPPROTO_TCP); |
|
1324 evutil_freeaddrinfo(local_outcome.ai); |
|
1325 local_outcome.ai = NULL; |
|
1326 |
|
1327 /* 1g. We find localhost immediately. (pf_unspec) */ |
|
1328 memset(&hints, 0, sizeof(hints)); |
|
1329 memset(&local_outcome, 0, sizeof(local_outcome)); |
|
1330 hints.ai_family = PF_UNSPEC; |
|
1331 hints.ai_socktype = SOCK_STREAM; |
|
1332 r = evdns_getaddrinfo(dns_base, "LOCALHOST", "80", |
|
1333 &hints, gai_cb, &local_outcome); |
|
1334 tt_assert(!r); |
|
1335 tt_int_op(local_outcome.err,==,0); |
|
1336 tt_assert(local_outcome.ai); |
|
1337 /* we should get a v4 address of 127.0.0.1 .... */ |
|
1338 a = ai_find_by_family(local_outcome.ai, PF_INET); |
|
1339 tt_assert(a); |
|
1340 test_ai_eq(a, "127.0.0.1:80", SOCK_STREAM, IPPROTO_TCP); |
|
1341 /* ... and a v6 address of ::1 */ |
|
1342 a = ai_find_by_family(local_outcome.ai, PF_INET6); |
|
1343 tt_assert(a); |
|
1344 test_ai_eq(a, "[::1]:80", SOCK_STREAM, IPPROTO_TCP); |
|
1345 evutil_freeaddrinfo(local_outcome.ai); |
|
1346 local_outcome.ai = NULL; |
|
1347 |
|
1348 /* 1g. We find localhost immediately. (pf_inet6) */ |
|
1349 memset(&hints, 0, sizeof(hints)); |
|
1350 memset(&local_outcome, 0, sizeof(local_outcome)); |
|
1351 hints.ai_family = PF_INET6; |
|
1352 hints.ai_socktype = SOCK_STREAM; |
|
1353 r = evdns_getaddrinfo(dns_base, "LOCALHOST", "9999", |
|
1354 &hints, gai_cb, &local_outcome); |
|
1355 tt_assert(! r); |
|
1356 tt_int_op(local_outcome.err,==,0); |
|
1357 tt_assert(local_outcome.ai); |
|
1358 a = local_outcome.ai; |
|
1359 test_ai_eq(a, "[::1]:9999", SOCK_STREAM, IPPROTO_TCP); |
|
1360 tt_ptr_op(a->ai_next, ==, NULL); |
|
1361 evutil_freeaddrinfo(local_outcome.ai); |
|
1362 local_outcome.ai = NULL; |
|
1363 |
|
1364 /* 2. Okay, now we can actually test the asynchronous resolver. */ |
|
1365 /* Start a dummy local dns server... */ |
|
1366 port = regress_get_dnsserver(data->base, &dns_port, NULL, |
|
1367 be_getaddrinfo_server_cb, &n_dns_questions); |
|
1368 tt_assert(port); |
|
1369 tt_int_op(dns_port, >=, 0); |
|
1370 /* ... and tell the evdns_base about it. */ |
|
1371 evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", dns_port); |
|
1372 evdns_base_nameserver_ip_add(dns_base, buf); |
|
1373 |
|
1374 memset(&hints, 0, sizeof(hints)); |
|
1375 hints.ai_family = PF_UNSPEC; |
|
1376 hints.ai_socktype = SOCK_STREAM; |
|
1377 hints.ai_flags = EVUTIL_AI_CANONNAME; |
|
1378 /* 0: Request for both.example.com should return both addresses. */ |
|
1379 r = evdns_getaddrinfo(dns_base, "both.example.com", "8000", |
|
1380 &hints, gai_cb, &a_out[0]); |
|
1381 tt_assert(r); |
|
1382 |
|
1383 /* 1: Request for v4only.example.com should return one address. */ |
|
1384 r = evdns_getaddrinfo(dns_base, "v4only.example.com", "8001", |
|
1385 &hints, gai_cb, &a_out[1]); |
|
1386 tt_assert(r); |
|
1387 |
|
1388 /* 2: Request for v6only.example.com should return one address. */ |
|
1389 hints.ai_flags = 0; |
|
1390 r = evdns_getaddrinfo(dns_base, "v6only.example.com", "8002", |
|
1391 &hints, gai_cb, &a_out[2]); |
|
1392 tt_assert(r); |
|
1393 |
|
1394 /* 3: PF_INET request for v4assert.example.com should not generate a |
|
1395 * v6 request. The server will fail the test if it does. */ |
|
1396 hints.ai_family = PF_INET; |
|
1397 r = evdns_getaddrinfo(dns_base, "v4assert.example.com", "8003", |
|
1398 &hints, gai_cb, &a_out[3]); |
|
1399 tt_assert(r); |
|
1400 |
|
1401 /* 4: PF_INET6 request for v6assert.example.com should not generate a |
|
1402 * v4 request. The server will fail the test if it does. */ |
|
1403 hints.ai_family = PF_INET6; |
|
1404 r = evdns_getaddrinfo(dns_base, "v6assert.example.com", "8004", |
|
1405 &hints, gai_cb, &a_out[4]); |
|
1406 tt_assert(r); |
|
1407 |
|
1408 /* 5: PF_INET request for nosuchplace.example.com should give NEXIST. */ |
|
1409 hints.ai_family = PF_INET; |
|
1410 r = evdns_getaddrinfo(dns_base, "nosuchplace.example.com", "8005", |
|
1411 &hints, gai_cb, &a_out[5]); |
|
1412 tt_assert(r); |
|
1413 |
|
1414 /* 6: PF_UNSPEC request for nosuchplace.example.com should give NEXIST. |
|
1415 */ |
|
1416 hints.ai_family = PF_UNSPEC; |
|
1417 r = evdns_getaddrinfo(dns_base, "nosuchplace.example.com", "8006", |
|
1418 &hints, gai_cb, &a_out[6]); |
|
1419 tt_assert(r); |
|
1420 |
|
1421 /* 7: PF_UNSPEC request for v6timeout.example.com should give an ipv4 |
|
1422 * address only. */ |
|
1423 hints.ai_family = PF_UNSPEC; |
|
1424 r = evdns_getaddrinfo(dns_base, "v6timeout.example.com", "8007", |
|
1425 &hints, gai_cb, &a_out[7]); |
|
1426 tt_assert(r); |
|
1427 |
|
1428 /* 8: PF_UNSPEC request for v6timeout-nonexist.example.com should give |
|
1429 * a NEXIST */ |
|
1430 hints.ai_family = PF_UNSPEC; |
|
1431 r = evdns_getaddrinfo(dns_base, "v6timeout-nonexist.example.com", |
|
1432 "8008", &hints, gai_cb, &a_out[8]); |
|
1433 tt_assert(r); |
|
1434 |
|
1435 /* 9: AI_ADDRCONFIG should at least not crash. Can't test it more |
|
1436 * without knowing what kind of internet we have. */ |
|
1437 hints.ai_flags |= EVUTIL_AI_ADDRCONFIG; |
|
1438 r = evdns_getaddrinfo(dns_base, "both.example.com", |
|
1439 "8009", &hints, gai_cb, &a_out[9]); |
|
1440 tt_assert(r); |
|
1441 |
|
1442 /* 10: PF_UNSPEC for v4timeout.example.com should give an ipv6 address |
|
1443 * only. */ |
|
1444 hints.ai_family = PF_UNSPEC; |
|
1445 hints.ai_flags = 0; |
|
1446 r = evdns_getaddrinfo(dns_base, "v4timeout.example.com", "8010", |
|
1447 &hints, gai_cb, &a_out[10]); |
|
1448 tt_assert(r); |
|
1449 |
|
1450 /* 11: timeout.example.com: cancel it after 100 msec. */ |
|
1451 r = evdns_getaddrinfo(dns_base, "all-timeout.example.com", "8011", |
|
1452 &hints, gai_cb, &a_out[11]); |
|
1453 tt_assert(r); |
|
1454 { |
|
1455 struct timeval tv; |
|
1456 tv.tv_sec = 0; |
|
1457 tv.tv_usec = 100*1000; /* 100 msec */ |
|
1458 event_base_once(data->base, -1, EV_TIMEOUT, cancel_gai_cb, |
|
1459 r, &tv); |
|
1460 } |
|
1461 |
|
1462 /* XXXXX There are more tests we could do, including: |
|
1463 |
|
1464 - A test to elicit NODATA. |
|
1465 |
|
1466 */ |
|
1467 |
|
1468 n_gai_results_pending = 12; |
|
1469 exit_base_on_no_pending_results = data->base; |
|
1470 |
|
1471 event_base_dispatch(data->base); |
|
1472 |
|
1473 /* 0: both.example.com */ |
|
1474 tt_int_op(a_out[0].err, ==, 0); |
|
1475 tt_assert(a_out[0].ai); |
|
1476 tt_assert(a_out[0].ai->ai_next); |
|
1477 tt_assert(!a_out[0].ai->ai_next->ai_next); |
|
1478 a = ai_find_by_family(a_out[0].ai, PF_INET); |
|
1479 tt_assert(a); |
|
1480 test_ai_eq(a, "80.80.32.32:8000", SOCK_STREAM, IPPROTO_TCP); |
|
1481 a = ai_find_by_family(a_out[0].ai, PF_INET6); |
|
1482 tt_assert(a); |
|
1483 test_ai_eq(a, "[80ff::bbbb]:8000", SOCK_STREAM, IPPROTO_TCP); |
|
1484 tt_assert(a_out[0].ai->ai_canonname); |
|
1485 tt_str_op(a_out[0].ai->ai_canonname, ==, "both-canonical.example.com"); |
|
1486 |
|
1487 /* 1: v4only.example.com */ |
|
1488 tt_int_op(a_out[1].err, ==, 0); |
|
1489 tt_assert(a_out[1].ai); |
|
1490 tt_assert(! a_out[1].ai->ai_next); |
|
1491 test_ai_eq(a_out[1].ai, "18.52.86.120:8001", SOCK_STREAM, IPPROTO_TCP); |
|
1492 tt_assert(a_out[1].ai->ai_canonname == NULL); |
|
1493 |
|
1494 |
|
1495 /* 2: v6only.example.com */ |
|
1496 tt_int_op(a_out[2].err, ==, 0); |
|
1497 tt_assert(a_out[2].ai); |
|
1498 tt_assert(! a_out[2].ai->ai_next); |
|
1499 test_ai_eq(a_out[2].ai, "[b0b::f00d]:8002", SOCK_STREAM, IPPROTO_TCP); |
|
1500 |
|
1501 /* 3: v4assert.example.com */ |
|
1502 tt_int_op(a_out[3].err, ==, 0); |
|
1503 tt_assert(a_out[3].ai); |
|
1504 tt_assert(! a_out[3].ai->ai_next); |
|
1505 test_ai_eq(a_out[3].ai, "18.52.86.120:8003", SOCK_STREAM, IPPROTO_TCP); |
|
1506 |
|
1507 /* 4: v6assert.example.com */ |
|
1508 tt_int_op(a_out[4].err, ==, 0); |
|
1509 tt_assert(a_out[4].ai); |
|
1510 tt_assert(! a_out[4].ai->ai_next); |
|
1511 test_ai_eq(a_out[4].ai, "[b0b::f00d]:8004", SOCK_STREAM, IPPROTO_TCP); |
|
1512 |
|
1513 /* 5: nosuchplace.example.com (inet) */ |
|
1514 tt_int_op(a_out[5].err, ==, EVUTIL_EAI_NONAME); |
|
1515 tt_assert(! a_out[5].ai); |
|
1516 |
|
1517 /* 6: nosuchplace.example.com (unspec) */ |
|
1518 tt_int_op(a_out[6].err, ==, EVUTIL_EAI_NONAME); |
|
1519 tt_assert(! a_out[6].ai); |
|
1520 |
|
1521 /* 7: v6timeout.example.com */ |
|
1522 tt_int_op(a_out[7].err, ==, 0); |
|
1523 tt_assert(a_out[7].ai); |
|
1524 tt_assert(! a_out[7].ai->ai_next); |
|
1525 test_ai_eq(a_out[7].ai, "171.205.239.1:8007", SOCK_STREAM, IPPROTO_TCP); |
|
1526 |
|
1527 /* 8: v6timeout-nonexist.example.com */ |
|
1528 tt_int_op(a_out[8].err, ==, EVUTIL_EAI_NONAME); |
|
1529 tt_assert(! a_out[8].ai); |
|
1530 |
|
1531 /* 9: both (ADDRCONFIG) */ |
|
1532 tt_int_op(a_out[9].err, ==, 0); |
|
1533 tt_assert(a_out[9].ai); |
|
1534 a = ai_find_by_family(a_out[9].ai, PF_INET); |
|
1535 if (a) |
|
1536 test_ai_eq(a, "80.80.32.32:8009", SOCK_STREAM, IPPROTO_TCP); |
|
1537 else |
|
1538 tt_assert(ai_find_by_family(a_out[9].ai, PF_INET6)); |
|
1539 a = ai_find_by_family(a_out[9].ai, PF_INET6); |
|
1540 if (a) |
|
1541 test_ai_eq(a, "[80ff::bbbb]:8009", SOCK_STREAM, IPPROTO_TCP); |
|
1542 else |
|
1543 tt_assert(ai_find_by_family(a_out[9].ai, PF_INET)); |
|
1544 |
|
1545 /* 10: v4timeout.example.com */ |
|
1546 tt_int_op(a_out[10].err, ==, 0); |
|
1547 tt_assert(a_out[10].ai); |
|
1548 tt_assert(! a_out[10].ai->ai_next); |
|
1549 test_ai_eq(a_out[10].ai, "[a0a::ff01]:8010", SOCK_STREAM, IPPROTO_TCP); |
|
1550 |
|
1551 /* 11: cancelled request. */ |
|
1552 tt_int_op(a_out[11].err, ==, EVUTIL_EAI_CANCEL); |
|
1553 tt_assert(a_out[11].ai == NULL); |
|
1554 |
|
1555 end: |
|
1556 if (local_outcome.ai) |
|
1557 evutil_freeaddrinfo(local_outcome.ai); |
|
1558 for (i=0;i<10;++i) { |
|
1559 if (a_out[i].ai) |
|
1560 evutil_freeaddrinfo(a_out[i].ai); |
|
1561 } |
|
1562 if (port) |
|
1563 evdns_close_server_port(port); |
|
1564 if (dns_base) |
|
1565 evdns_base_free(dns_base, 0); |
|
1566 } |
|
1567 |
|
1568 struct gaic_request_status { |
|
1569 int magic; |
|
1570 struct event_base *base; |
|
1571 struct evdns_base *dns_base; |
|
1572 struct evdns_getaddrinfo_request *request; |
|
1573 struct event cancel_event; |
|
1574 int canceled; |
|
1575 }; |
|
1576 |
|
1577 #define GAIC_MAGIC 0x1234abcd |
|
1578 |
|
1579 static int pending = 0; |
|
1580 |
|
1581 static void |
|
1582 gaic_cancel_request_cb(evutil_socket_t fd, short what, void *arg) |
|
1583 { |
|
1584 struct gaic_request_status *status = arg; |
|
1585 |
|
1586 tt_assert(status->magic == GAIC_MAGIC); |
|
1587 status->canceled = 1; |
|
1588 evdns_getaddrinfo_cancel(status->request); |
|
1589 return; |
|
1590 end: |
|
1591 event_base_loopexit(status->base, NULL); |
|
1592 } |
|
1593 |
|
1594 static void |
|
1595 gaic_server_cb(struct evdns_server_request *req, void *arg) |
|
1596 { |
|
1597 ev_uint32_t answer = 0x7f000001; |
|
1598 tt_assert(req->nquestions); |
|
1599 evdns_server_request_add_a_reply(req, req->questions[0]->name, 1, |
|
1600 &answer, 100); |
|
1601 evdns_server_request_respond(req, 0); |
|
1602 return; |
|
1603 end: |
|
1604 evdns_server_request_respond(req, DNS_ERR_REFUSED); |
|
1605 } |
|
1606 |
|
1607 |
|
1608 static void |
|
1609 gaic_getaddrinfo_cb(int result, struct evutil_addrinfo *res, void *arg) |
|
1610 { |
|
1611 struct gaic_request_status *status = arg; |
|
1612 struct event_base *base = status->base; |
|
1613 tt_assert(status->magic == GAIC_MAGIC); |
|
1614 |
|
1615 if (result == EVUTIL_EAI_CANCEL) { |
|
1616 tt_assert(status->canceled); |
|
1617 } |
|
1618 event_del(&status->cancel_event); |
|
1619 |
|
1620 memset(status, 0xf0, sizeof(*status)); |
|
1621 free(status); |
|
1622 |
|
1623 end: |
|
1624 if (--pending <= 0) |
|
1625 event_base_loopexit(base, NULL); |
|
1626 } |
|
1627 |
|
1628 static void |
|
1629 gaic_launch(struct event_base *base, struct evdns_base *dns_base) |
|
1630 { |
|
1631 struct gaic_request_status *status = calloc(1,sizeof(*status)); |
|
1632 struct timeval tv = { 0, 10000 }; |
|
1633 status->magic = GAIC_MAGIC; |
|
1634 status->base = base; |
|
1635 status->dns_base = dns_base; |
|
1636 event_assign(&status->cancel_event, base, -1, 0, gaic_cancel_request_cb, |
|
1637 status); |
|
1638 status->request = evdns_getaddrinfo(dns_base, |
|
1639 "foobar.bazquux.example.com", "80", NULL, gaic_getaddrinfo_cb, |
|
1640 status); |
|
1641 event_add(&status->cancel_event, &tv); |
|
1642 ++pending; |
|
1643 } |
|
1644 |
|
1645 #ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED |
|
1646 /* FIXME: We should move this to regress_main.c if anything else needs it.*/ |
|
1647 |
|
1648 /* Trivial replacements for malloc/free/realloc to check for memory leaks. |
|
1649 * Not threadsafe. */ |
|
1650 static int allocated_chunks = 0; |
|
1651 |
|
1652 static void * |
|
1653 cnt_malloc(size_t sz) |
|
1654 { |
|
1655 allocated_chunks += 1; |
|
1656 return malloc(sz); |
|
1657 } |
|
1658 |
|
1659 static void * |
|
1660 cnt_realloc(void *old, size_t sz) |
|
1661 { |
|
1662 if (!old) |
|
1663 allocated_chunks += 1; |
|
1664 if (!sz) |
|
1665 allocated_chunks -= 1; |
|
1666 return realloc(old, sz); |
|
1667 } |
|
1668 |
|
1669 static void |
|
1670 cnt_free(void *ptr) |
|
1671 { |
|
1672 allocated_chunks -= 1; |
|
1673 free(ptr); |
|
1674 } |
|
1675 |
|
1676 struct testleak_env_t { |
|
1677 struct event_base *base; |
|
1678 struct evdns_base *dns_base; |
|
1679 struct evdns_request *req; |
|
1680 struct generic_dns_callback_result r; |
|
1681 }; |
|
1682 |
|
1683 static void * |
|
1684 testleak_setup(const struct testcase_t *testcase) |
|
1685 { |
|
1686 struct testleak_env_t *env; |
|
1687 |
|
1688 allocated_chunks = 0; |
|
1689 event_set_mem_functions(cnt_malloc, cnt_realloc, cnt_free); |
|
1690 event_enable_debug_mode(); |
|
1691 |
|
1692 /* not mm_calloc: we don't want to mess with the count. */ |
|
1693 env = calloc(1, sizeof(struct testleak_env_t)); |
|
1694 env->base = event_base_new(); |
|
1695 env->dns_base = evdns_base_new(env->base, 0); |
|
1696 env->req = evdns_base_resolve_ipv4( |
|
1697 env->dns_base, "example.com", DNS_QUERY_NO_SEARCH, |
|
1698 generic_dns_callback, &env->r); |
|
1699 return env; |
|
1700 } |
|
1701 |
|
1702 static int |
|
1703 testleak_cleanup(const struct testcase_t *testcase, void *env_) |
|
1704 { |
|
1705 int ok = 0; |
|
1706 struct testleak_env_t *env = env_; |
|
1707 tt_assert(env); |
|
1708 #ifdef _EVENT_DISABLE_DEBUG_MODE |
|
1709 tt_int_op(allocated_chunks, ==, 0); |
|
1710 #else |
|
1711 /* FIXME: that's `1' because of event_debug_map_HT_GROW */ |
|
1712 tt_int_op(allocated_chunks, ==, 1); |
|
1713 #endif |
|
1714 ok = 1; |
|
1715 end: |
|
1716 if (env) { |
|
1717 if (env->dns_base) |
|
1718 evdns_base_free(env->dns_base, 0); |
|
1719 if (env->base) |
|
1720 event_base_free(env->base); |
|
1721 free(env); |
|
1722 } |
|
1723 return ok; |
|
1724 } |
|
1725 |
|
1726 static struct testcase_setup_t testleak_funcs = { |
|
1727 testleak_setup, testleak_cleanup |
|
1728 }; |
|
1729 |
|
1730 static void |
|
1731 test_dbg_leak_cancel(void *env_) |
|
1732 { |
|
1733 /* cancel, loop, free/dns, free/base */ |
|
1734 struct testleak_env_t *env = env_; |
|
1735 int send_err_shutdown = 1; |
|
1736 evdns_cancel_request(env->dns_base, env->req); |
|
1737 env->req = 0; |
|
1738 |
|
1739 /* `req` is freed in callback, that's why one loop is required. */ |
|
1740 event_base_loop(env->base, EVLOOP_NONBLOCK); |
|
1741 |
|
1742 /* send_err_shutdown means nothing as soon as our request is |
|
1743 * already canceled */ |
|
1744 evdns_base_free(env->dns_base, send_err_shutdown); |
|
1745 env->dns_base = 0; |
|
1746 event_base_free(env->base); |
|
1747 env->base = 0; |
|
1748 } |
|
1749 |
|
1750 static void |
|
1751 test_dbg_leak_shutdown(void *env_) |
|
1752 { |
|
1753 /* free/dns, loop, free/base */ |
|
1754 struct testleak_env_t *env = env_; |
|
1755 int send_err_shutdown = 1; |
|
1756 |
|
1757 /* `req` is freed both with `send_err_shutdown` and without it, |
|
1758 * the only difference is `evdns_callback` call */ |
|
1759 env->req = 0; |
|
1760 |
|
1761 evdns_base_free(env->dns_base, send_err_shutdown); |
|
1762 env->dns_base = 0; |
|
1763 |
|
1764 /* `req` is freed in callback, that's why one loop is required */ |
|
1765 event_base_loop(env->base, EVLOOP_NONBLOCK); |
|
1766 event_base_free(env->base); |
|
1767 env->base = 0; |
|
1768 } |
|
1769 #endif |
|
1770 |
|
1771 static void |
|
1772 test_getaddrinfo_async_cancel_stress(void *ptr) |
|
1773 { |
|
1774 struct event_base *base; |
|
1775 struct evdns_base *dns_base = NULL; |
|
1776 struct evdns_server_port *server = NULL; |
|
1777 evutil_socket_t fd = -1; |
|
1778 struct sockaddr_in sin; |
|
1779 struct sockaddr_storage ss; |
|
1780 ev_socklen_t slen; |
|
1781 int i; |
|
1782 |
|
1783 base = event_base_new(); |
|
1784 dns_base = evdns_base_new(base, 0); |
|
1785 |
|
1786 memset(&sin, 0, sizeof(sin)); |
|
1787 sin.sin_family = AF_INET; |
|
1788 sin.sin_port = 0; |
|
1789 sin.sin_addr.s_addr = htonl(0x7f000001); |
|
1790 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { |
|
1791 tt_abort_perror("socket"); |
|
1792 } |
|
1793 evutil_make_socket_nonblocking(fd); |
|
1794 if (bind(fd, (struct sockaddr*)&sin, sizeof(sin))<0) { |
|
1795 tt_abort_perror("bind"); |
|
1796 } |
|
1797 server = evdns_add_server_port_with_base(base, fd, 0, gaic_server_cb, |
|
1798 base); |
|
1799 |
|
1800 memset(&ss, 0, sizeof(ss)); |
|
1801 slen = sizeof(ss); |
|
1802 if (getsockname(fd, (struct sockaddr*)&ss, &slen)<0) { |
|
1803 tt_abort_perror("getsockname"); |
|
1804 } |
|
1805 evdns_base_nameserver_sockaddr_add(dns_base, |
|
1806 (struct sockaddr*)&ss, slen, 0); |
|
1807 |
|
1808 for (i = 0; i < 1000; ++i) { |
|
1809 gaic_launch(base, dns_base); |
|
1810 } |
|
1811 |
|
1812 event_base_dispatch(base); |
|
1813 |
|
1814 end: |
|
1815 if (dns_base) |
|
1816 evdns_base_free(dns_base, 1); |
|
1817 if (server) |
|
1818 evdns_close_server_port(server); |
|
1819 if (fd >= 0) |
|
1820 evutil_closesocket(fd); |
|
1821 } |
|
1822 |
|
1823 |
|
1824 #define DNS_LEGACY(name, flags) \ |
|
1825 { #name, run_legacy_test_fn, flags|TT_LEGACY, &legacy_setup, \ |
|
1826 dns_##name } |
|
1827 |
|
1828 struct testcase_t dns_testcases[] = { |
|
1829 DNS_LEGACY(server, TT_FORK|TT_NEED_BASE), |
|
1830 DNS_LEGACY(gethostbyname, TT_FORK|TT_NEED_BASE|TT_NEED_DNS), |
|
1831 DNS_LEGACY(gethostbyname6, TT_FORK|TT_NEED_BASE|TT_NEED_DNS), |
|
1832 DNS_LEGACY(gethostbyaddr, TT_FORK|TT_NEED_BASE|TT_NEED_DNS), |
|
1833 { "resolve_reverse", dns_resolve_reverse, TT_FORK, NULL, NULL }, |
|
1834 { "search", dns_search_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, |
|
1835 { "search_cancel", dns_search_cancel_test, |
|
1836 TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, |
|
1837 { "retry", dns_retry_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, |
|
1838 { "reissue", dns_reissue_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, |
|
1839 { "inflight", dns_inflight_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, |
|
1840 { "bufferevent_connect_hostname", test_bufferevent_connect_hostname, |
|
1841 TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, |
|
1842 |
|
1843 { "getaddrinfo_async", test_getaddrinfo_async, |
|
1844 TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"" }, |
|
1845 { "getaddrinfo_cancel_stress", test_getaddrinfo_async_cancel_stress, |
|
1846 TT_FORK, NULL, NULL }, |
|
1847 |
|
1848 #ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED |
|
1849 { "leak_shutdown", test_dbg_leak_shutdown, TT_FORK, &testleak_funcs, NULL }, |
|
1850 { "leak_cancel", test_dbg_leak_cancel, TT_FORK, &testleak_funcs, NULL }, |
|
1851 #endif |
|
1852 |
|
1853 END_OF_TESTCASES |
|
1854 }; |
|
1855 |