OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2003-2006 Niels Provos <provos@citi.umich.edu> | |
3 * All rights reserved. | |
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 #endif | |
32 | |
33 #ifdef HAVE_CONFIG_H | |
34 #include "config.h" | |
35 #endif | |
36 | |
37 #include <sys/types.h> | |
38 #include <sys/stat.h> | |
39 #ifdef HAVE_SYS_TIME_H | |
40 #include <sys/time.h> | |
41 #endif | |
42 #include <sys/queue.h> | |
43 #ifndef WIN32 | |
44 #include <sys/socket.h> | |
45 #include <signal.h> | |
46 #include <netinet/in.h> | |
47 #include <arpa/inet.h> | |
48 #include <unistd.h> | |
49 #endif | |
50 #ifdef HAVE_NETINET_IN6_H | |
51 #include <netinet/in6.h> | |
52 #endif | |
53 #ifdef HAVE_NETDB_H | |
54 #include <netdb.h> | |
55 #endif | |
56 #include <fcntl.h> | |
57 #include <stdlib.h> | |
58 #include <stdio.h> | |
59 #include <string.h> | |
60 #include <errno.h> | |
61 | |
62 #include "event.h" | |
63 #include "evdns.h" | |
64 #include "log.h" | |
65 | |
66 static int dns_ok = 0; | |
67 static int dns_err = 0; | |
68 | |
69 void dns_suite(void); | |
70 | |
71 static void | |
72 dns_gethostbyname_cb(int result, char type, int count, int ttl, | |
73 void *addresses, void *arg) | |
74 { | |
75 dns_ok = dns_err = 0; | |
76 | |
77 if (result == DNS_ERR_TIMEOUT) { | |
78 fprintf(stdout, "[Timed out] "); | |
79 dns_err = result; | |
80 goto out; | |
81 } | |
82 | |
83 if (result != DNS_ERR_NONE) { | |
84 fprintf(stdout, "[Error code %d] ", result); | |
85 goto out; | |
86 } | |
87 | |
88 fprintf(stderr, "type: %d, count: %d, ttl: %d: ", type, count, ttl); | |
89 | |
90 switch (type) { | |
91 case DNS_IPv6_AAAA: { | |
92 #if defined(HAVE_STRUCT_IN6_ADDR) && defined(HAVE_INET_NTOP) && defined(INET6_AD
DRSTRLEN) | |
93 struct in6_addr *in6_addrs = addresses; | |
94 char buf[INET6_ADDRSTRLEN+1]; | |
95 int i; | |
96 /* a resolution that's not valid does not help */ | |
97 if (ttl < 0) | |
98 goto out; | |
99 for (i = 0; i < count; ++i) { | |
100 const char *b = inet_ntop(AF_INET6, &in6_addrs[i], buf,s
izeof(buf)); | |
101 if (b) | |
102 fprintf(stderr, "%s ", b); | |
103 else | |
104 fprintf(stderr, "%s ", strerror(errno)); | |
105 } | |
106 #endif | |
107 break; | |
108 } | |
109 case DNS_IPv4_A: { | |
110 struct in_addr *in_addrs = addresses; | |
111 int i; | |
112 /* a resolution that's not valid does not help */ | |
113 if (ttl < 0) | |
114 goto out; | |
115 for (i = 0; i < count; ++i) | |
116 fprintf(stderr, "%s ", inet_ntoa(in_addrs[i])); | |
117 break; | |
118 } | |
119 case DNS_PTR: | |
120 /* may get at most one PTR */ | |
121 if (count != 1) | |
122 goto out; | |
123 | |
124 fprintf(stderr, "%s ", *(char **)addresses); | |
125 break; | |
126 default: | |
127 goto out; | |
128 } | |
129 | |
130 dns_ok = type; | |
131 | |
132 out: | |
133 event_loopexit(NULL); | |
134 } | |
135 | |
136 static void | |
137 dns_gethostbyname(void) | |
138 { | |
139 fprintf(stdout, "Simple DNS resolve: "); | |
140 dns_ok = 0; | |
141 evdns_resolve_ipv4("www.monkey.org", 0, dns_gethostbyname_cb, NULL); | |
142 event_dispatch(); | |
143 | |
144 if (dns_ok == DNS_IPv4_A) { | |
145 fprintf(stdout, "OK\n"); | |
146 } else { | |
147 fprintf(stdout, "FAILED\n"); | |
148 exit(1); | |
149 } | |
150 } | |
151 | |
152 static void | |
153 dns_gethostbyname6(void) | |
154 { | |
155 fprintf(stdout, "IPv6 DNS resolve: "); | |
156 dns_ok = 0; | |
157 evdns_resolve_ipv6("www.ietf.org", 0, dns_gethostbyname_cb, NULL); | |
158 event_dispatch(); | |
159 | |
160 if (dns_ok == DNS_IPv6_AAAA) { | |
161 fprintf(stdout, "OK\n"); | |
162 } else if (!dns_ok && dns_err == DNS_ERR_TIMEOUT) { | |
163 fprintf(stdout, "SKIPPED\n"); | |
164 } else { | |
165 fprintf(stdout, "FAILED (%d)\n", dns_ok); | |
166 exit(1); | |
167 } | |
168 } | |
169 | |
170 static void | |
171 dns_gethostbyaddr(void) | |
172 { | |
173 struct in_addr in; | |
174 in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */ | |
175 fprintf(stdout, "Simple reverse DNS resolve: "); | |
176 dns_ok = 0; | |
177 evdns_resolve_reverse(&in, 0, dns_gethostbyname_cb, NULL); | |
178 event_dispatch(); | |
179 | |
180 if (dns_ok == DNS_PTR) { | |
181 fprintf(stdout, "OK\n"); | |
182 } else { | |
183 fprintf(stdout, "FAILED\n"); | |
184 exit(1); | |
185 } | |
186 } | |
187 | |
188 static int n_server_responses = 0; | |
189 | |
190 static void | |
191 dns_server_request_cb(struct evdns_server_request *req, void *data) | |
192 { | |
193 int i, r; | |
194 const char TEST_ARPA[] = "11.11.168.192.in-addr.arpa"; | |
195 for (i = 0; i < req->nquestions; ++i) { | |
196 struct in_addr ans; | |
197 ans.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */ | |
198 if (req->questions[i]->type == EVDNS_TYPE_A && | |
199 req->questions[i]->dns_question_class == EVDNS_CLASS_INE
T && | |
200 !strcmp(req->questions[i]->name, "zz.example.com")) { | |
201 r = evdns_server_request_add_a_reply(req, "zz.example.co
m", | |
202
1, &ans.s_addr, 12345); | |
203 if (r<0) | |
204 dns_ok = 0; | |
205 } else if (req->questions[i]->type == EVDNS_TYPE_AAAA && | |
206 req->questions[i]->dns_question_class == EVDN
S_CLASS_INET && | |
207 !strcmp(req->questions[i]->name, "zz.example.
com")) { | |
208 char addr6[17] = "abcdefghijklmnop"; | |
209 r = evdns_server_request_add_aaaa_reply(req, "zz.example
.com", | |
210
1, addr6, 123); | |
211 if (r<0) | |
212 dns_ok = 0; | |
213 } else if (req->questions[i]->type == EVDNS_TYPE_PTR && | |
214 req->questions[i]->dns_question_class == EVDN
S_CLASS_INET && | |
215 !strcmp(req->questions[i]->name, TEST_ARPA))
{ | |
216 r = evdns_server_request_add_ptr_reply(req, NULL, TEST_A
RPA, | |
217 "ZZ.EXAMPLE.COM", 54321); | |
218 if (r<0) | |
219 dns_ok = 0; | |
220 } else { | |
221 fprintf(stdout, "Unexpected question %d %d \"%s\" ", | |
222 req->questions[i]->type, | |
223 req->questions[i]->dns_question_class, | |
224 req->questions[i]->name); | |
225 dns_ok = 0; | |
226 } | |
227 } | |
228 r = evdns_server_request_respond(req, 0); | |
229 if (r<0) { | |
230 fprintf(stdout, "Couldn't send reply. "); | |
231 dns_ok = 0; | |
232 } | |
233 } | |
234 | |
235 static void | |
236 dns_server_gethostbyname_cb(int result, char type, int count, int ttl, | |
237 void *addresses, void *a
rg) | |
238 { | |
239 if (result != DNS_ERR_NONE) { | |
240 fprintf(stdout, "Unexpected result %d. ", result); | |
241 dns_ok = 0; | |
242 goto out; | |
243 } | |
244 if (count != 1) { | |
245 fprintf(stdout, "Unexpected answer count %d. ", count); | |
246 dns_ok = 0; | |
247 goto out; | |
248 } | |
249 switch (type) { | |
250 case DNS_IPv4_A: { | |
251 struct in_addr *in_addrs = addresses; | |
252 if (in_addrs[0].s_addr != htonl(0xc0a80b0bUL) || ttl != 12345) { | |
253 fprintf(stdout, "Bad IPv4 response \"%s\" %d. ", | |
254 inet_ntoa(in_addrs[0]), ttl); | |
255 dns_ok = 0; | |
256 goto out; | |
257 } | |
258 break; | |
259 } | |
260 case DNS_IPv6_AAAA: { | |
261 #if defined (HAVE_STRUCT_IN6_ADDR) && defined(HAVE_INET_NTOP) && defined(INET6_A
DDRSTRLEN) | |
262 struct in6_addr *in6_addrs = addresses; | |
263 char buf[INET6_ADDRSTRLEN+1]; | |
264 if (memcmp(&in6_addrs[0].s6_addr, "abcdefghijklmnop", 16) | |
265 || ttl != 123) { | |
266 const char *b = inet_ntop(AF_INET6, &in6_addrs[0],buf,si
zeof(buf)); | |
267 fprintf(stdout, "Bad IPv6 response \"%s\" %d. ", b, ttl)
; | |
268 dns_ok = 0; | |
269 goto out; | |
270 } | |
271 #endif | |
272 break; | |
273 } | |
274 case DNS_PTR: { | |
275 char **addrs = addresses; | |
276 if (strcmp(addrs[0], "ZZ.EXAMPLE.COM") || ttl != 54321) { | |
277 fprintf(stdout, "Bad PTR response \"%s\" %d. ", | |
278 addrs[0], ttl); | |
279 dns_ok = 0; | |
280 goto out; | |
281 } | |
282 break; | |
283 } | |
284 default: | |
285 fprintf(stdout, "Bad response type %d. ", type); | |
286 dns_ok = 0; | |
287 } | |
288 | |
289 out: | |
290 if (++n_server_responses == 3) { | |
291 event_loopexit(NULL); | |
292 } | |
293 } | |
294 | |
295 static void | |
296 dns_server(void) | |
297 { | |
298 int sock; | |
299 struct sockaddr_in my_addr; | |
300 struct evdns_server_port *port; | |
301 struct in_addr resolve_addr; | |
302 | |
303 dns_ok = 1; | |
304 fprintf(stdout, "DNS server support: "); | |
305 | |
306 /* Add ourself as the only nameserver, and make sure we really are | |
307 * the only nameserver. */ | |
308 evdns_nameserver_ip_add("127.0.0.1:35353"); | |
309 if (evdns_count_nameservers() != 1) { | |
310 fprintf(stdout, "Couldn't set up.\n"); | |
311 exit(1); | |
312 } | |
313 | |
314 /* Now configure a nameserver port. */ | |
315 sock = socket(AF_INET, SOCK_DGRAM, 0); | |
316 if (sock == -1) { | |
317 perror("socket"); | |
318 exit(1); | |
319 } | |
320 #ifdef WIN32 | |
321 { | |
322 u_long nonblocking = 1; | |
323 ioctlsocket(sock, FIONBIO, &nonblocking); | |
324 } | |
325 #else | |
326 fcntl(sock, F_SETFL, O_NONBLOCK); | |
327 #endif | |
328 memset(&my_addr, 0, sizeof(my_addr)); | |
329 my_addr.sin_family = AF_INET; | |
330 my_addr.sin_port = htons(35353); | |
331 my_addr.sin_addr.s_addr = htonl(0x7f000001UL); | |
332 if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) { | |
333 perror("bind"); | |
334 exit (1); | |
335 } | |
336 port = evdns_add_server_port(sock, 0, dns_server_request_cb, NULL); | |
337 | |
338 /* Send two queries. */ | |
339 evdns_resolve_ipv4("zz.example.com", DNS_QUERY_NO_SEARCH, | |
340 dns_server_gethostbyname_cb, NULL); | |
341 evdns_resolve_ipv6("zz.example.com", DNS_QUERY_NO_SEARCH, | |
342 dns_server_gethostbyname_cb, NULL); | |
343 resolve_addr.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */ | |
344 evdns_resolve_reverse(&resolve_addr, 0, | |
345 dns_server_gethostbyname_cb, N
ULL); | |
346 | |
347 event_dispatch(); | |
348 | |
349 if (dns_ok) { | |
350 fprintf(stdout, "OK\n"); | |
351 } else { | |
352 fprintf(stdout, "FAILED\n"); | |
353 exit(1); | |
354 } | |
355 | |
356 evdns_close_server_port(port); | |
357 evdns_shutdown(0); /* remove ourself as nameserver. */ | |
358 #ifdef WIN32 | |
359 closesocket(sock); | |
360 #else | |
361 close(sock); | |
362 #endif | |
363 } | |
364 | |
365 void | |
366 dns_suite(void) | |
367 { | |
368 dns_server(); /* Do this before we call evdns_init. */ | |
369 | |
370 evdns_init(); | |
371 dns_gethostbyname(); | |
372 dns_gethostbyname6(); | |
373 dns_gethostbyaddr(); | |
374 | |
375 evdns_shutdown(0); | |
376 } | |
OLD | NEW |