1 /* $NetBSD: regress_dns.c,v 1.2 2010/06/03 07:08:41 plunky Exp $ */ 2 /* 3 * Copyright (c) 2003-2006 Niels Provos <provos@citi.umich.edu> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #ifdef WIN32 30 #include <winsock2.h> 31 #include <windows.h> 32 #endif 33 34 #ifdef HAVE_CONFIG_H 35 #include "config.h" 36 #endif 37 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 #ifdef HAVE_SYS_TIME_H 41 #include <sys/time.h> 42 #endif 43 #include <sys/queue.h> 44 #ifndef WIN32 45 #include <sys/socket.h> 46 #include <signal.h> 47 #include <netinet/in.h> 48 #include <arpa/inet.h> 49 #include <unistd.h> 50 #endif 51 #ifdef HAVE_NETINET_IN6_H 52 #include <netinet/in6.h> 53 #endif 54 #ifdef HAVE_NETDB_H 55 #include <netdb.h> 56 #endif 57 #include <fcntl.h> 58 #include <stdlib.h> 59 #include <stdio.h> 60 #include <string.h> 61 #include <errno.h> 62 63 #include "event.h" 64 #include "evdns.h" 65 #include "log.h" 66 67 static int dns_ok = 0; 68 #if 0 69 static int dns_err = 0; 70 #endif 71 72 void dns_suite(void); 73 74 #if 0 75 static void 76 dns_gethostbyname_cb(int result, char type, int count, int ttl, 77 void *addresses, void *arg) 78 { 79 dns_ok = dns_err = 0; 80 81 if (result == DNS_ERR_TIMEOUT) { 82 fprintf(stdout, "[Timed out] "); 83 dns_err = result; 84 goto out; 85 } 86 87 if (result != DNS_ERR_NONE) { 88 fprintf(stdout, "[Error code %d] ", result); 89 goto out; 90 } 91 92 fprintf(stderr, "type: %d, count: %d, ttl: %d: ", type, count, ttl); 93 94 switch (type) { 95 case DNS_IPv6_AAAA: { 96 #if defined(HAVE_STRUCT_IN6_ADDR) && defined(HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN) 97 struct in6_addr *in6_addrs = addresses; 98 char buf[INET6_ADDRSTRLEN+1]; 99 int i; 100 /* a resolution that's not valid does not help */ 101 if (ttl < 0) 102 goto out; 103 for (i = 0; i < count; ++i) { 104 const char *b = inet_ntop(AF_INET6, &in6_addrs[i], buf,sizeof(buf)); 105 if (b) 106 fprintf(stderr, "%s ", b); 107 else 108 fprintf(stderr, "%s ", strerror(errno)); 109 } 110 #endif 111 break; 112 } 113 case DNS_IPv4_A: { 114 struct in_addr *in_addrs = addresses; 115 int i; 116 /* a resolution that's not valid does not help */ 117 if (ttl < 0) 118 goto out; 119 for (i = 0; i < count; ++i) 120 fprintf(stderr, "%s ", inet_ntoa(in_addrs[i])); 121 break; 122 } 123 case DNS_PTR: 124 /* may get at most one PTR */ 125 if (count != 1) 126 goto out; 127 128 fprintf(stderr, "%s ", *(char **)addresses); 129 break; 130 default: 131 goto out; 132 } 133 134 dns_ok = type; 135 136 out: 137 event_loopexit(NULL); 138 } 139 140 static void 141 dns_gethostbyname(void) 142 { 143 fprintf(stdout, "Simple DNS resolve: "); 144 dns_ok = 0; 145 evdns_resolve_ipv4("www.monkey.org", 0, dns_gethostbyname_cb, NULL); 146 event_dispatch(); 147 148 if (dns_ok == DNS_IPv4_A) { 149 fprintf(stdout, "OK\n"); 150 } else { 151 fprintf(stdout, "FAILED\n"); 152 exit(1); 153 } 154 } 155 156 static void 157 dns_gethostbyname6(void) 158 { 159 fprintf(stdout, "IPv6 DNS resolve: "); 160 dns_ok = 0; 161 evdns_resolve_ipv6("www.ietf.org", 0, dns_gethostbyname_cb, NULL); 162 event_dispatch(); 163 164 if (dns_ok == DNS_IPv6_AAAA) { 165 fprintf(stdout, "OK\n"); 166 } else if (!dns_ok && dns_err == DNS_ERR_TIMEOUT) { 167 fprintf(stdout, "SKIPPED\n"); 168 } else { 169 fprintf(stdout, "FAILED (%d)\n", dns_ok); 170 exit(1); 171 } 172 } 173 174 static void 175 dns_gethostbyaddr(void) 176 { 177 struct in_addr in; 178 in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */ 179 fprintf(stdout, "Simple reverse DNS resolve: "); 180 dns_ok = 0; 181 evdns_resolve_reverse(&in, 0, dns_gethostbyname_cb, NULL); 182 event_dispatch(); 183 184 if (dns_ok == DNS_PTR) { 185 fprintf(stdout, "OK\n"); 186 } else { 187 fprintf(stdout, "FAILED\n"); 188 exit(1); 189 } 190 } 191 #endif 192 193 static int n_server_responses = 0; 194 195 static void 196 dns_server_request_cb(struct evdns_server_request *req, void *data) 197 { 198 int i, r; 199 const char TEST_ARPA[] = "11.11.168.192.in-addr.arpa"; 200 for (i = 0; i < req->nquestions; ++i) { 201 struct in_addr ans; 202 ans.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */ 203 if (req->questions[i]->type == EVDNS_TYPE_A && 204 req->questions[i]->dns_question_class == EVDNS_CLASS_INET && 205 !strcmp(req->questions[i]->name, "zz.example.com")) { 206 r = evdns_server_request_add_a_reply(req, "zz.example.com", 207 1, &ans.s_addr, 12345); 208 if (r<0) 209 dns_ok = 0; 210 } else if (req->questions[i]->type == EVDNS_TYPE_AAAA && 211 req->questions[i]->dns_question_class == EVDNS_CLASS_INET && 212 !strcmp(req->questions[i]->name, "zz.example.com")) { 213 char addr6[17] = "abcdefghijklmnop"; 214 r = evdns_server_request_add_aaaa_reply(req, "zz.example.com", 215 1, addr6, 123); 216 if (r<0) 217 dns_ok = 0; 218 } else if (req->questions[i]->type == EVDNS_TYPE_PTR && 219 req->questions[i]->dns_question_class == EVDNS_CLASS_INET && 220 !strcmp(req->questions[i]->name, TEST_ARPA)) { 221 r = evdns_server_request_add_ptr_reply(req, NULL, TEST_ARPA, 222 "ZZ.EXAMPLE.COM", 54321); 223 if (r<0) 224 dns_ok = 0; 225 } else { 226 fprintf(stdout, "Unexpected question %d %d \"%s\" ", 227 req->questions[i]->type, 228 req->questions[i]->dns_question_class, 229 req->questions[i]->name); 230 dns_ok = 0; 231 } 232 } 233 r = evdns_server_request_respond(req, 0); 234 if (r<0) { 235 fprintf(stdout, "Couldn't send reply. "); 236 dns_ok = 0; 237 } 238 } 239 240 static void 241 dns_server_gethostbyname_cb(int result, char type, int count, int ttl, 242 void *addresses, void *arg) 243 { 244 if (result != DNS_ERR_NONE) { 245 fprintf(stdout, "Unexpected result %d. ", result); 246 dns_ok = 0; 247 goto out; 248 } 249 if (count != 1) { 250 fprintf(stdout, "Unexpected answer count %d. ", count); 251 dns_ok = 0; 252 goto out; 253 } 254 switch (type) { 255 case DNS_IPv4_A: { 256 struct in_addr *in_addrs = addresses; 257 if (in_addrs[0].s_addr != htonl(0xc0a80b0bUL) || ttl != 12345) { 258 fprintf(stdout, "Bad IPv4 response \"%s\" %d. ", 259 inet_ntoa(in_addrs[0]), ttl); 260 dns_ok = 0; 261 goto out; 262 } 263 break; 264 } 265 case DNS_IPv6_AAAA: { 266 #if defined (HAVE_STRUCT_IN6_ADDR) && defined(HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN) 267 struct in6_addr *in6_addrs = addresses; 268 char buf[INET6_ADDRSTRLEN+1]; 269 if (memcmp(&in6_addrs[0].s6_addr, "abcdefghijklmnop", 16) 270 || ttl != 123) { 271 const char *b = inet_ntop(AF_INET6, &in6_addrs[0],buf,sizeof(buf)); 272 fprintf(stdout, "Bad IPv6 response \"%s\" %d. ", b, ttl); 273 dns_ok = 0; 274 goto out; 275 } 276 #endif 277 break; 278 } 279 case DNS_PTR: { 280 char **addrs = addresses; 281 if (strcmp(addrs[0], "ZZ.EXAMPLE.COM") || ttl != 54321) { 282 fprintf(stdout, "Bad PTR response \"%s\" %d. ", 283 addrs[0], ttl); 284 dns_ok = 0; 285 goto out; 286 } 287 break; 288 } 289 default: 290 fprintf(stdout, "Bad response type %d. ", type); 291 dns_ok = 0; 292 } 293 294 out: 295 if (++n_server_responses == 3) { 296 event_loopexit(NULL); 297 } 298 } 299 300 static void 301 dns_server(void) 302 { 303 int sock; 304 struct sockaddr_in my_addr; 305 struct evdns_server_port *port; 306 struct in_addr resolve_addr; 307 308 dns_ok = 1; 309 fprintf(stdout, "DNS server support: "); 310 311 /* Add ourself as the only nameserver, and make sure we really are 312 * the only nameserver. */ 313 evdns_nameserver_ip_add("127.0.0.1:35353"); 314 if (evdns_count_nameservers() != 1) { 315 fprintf(stdout, "Couldn't set up.\n"); 316 exit(1); 317 } 318 319 /* Now configure a nameserver port. */ 320 sock = socket(AF_INET, SOCK_DGRAM, 0); 321 if (sock == -1) { 322 perror("socket"); 323 exit(1); 324 } 325 #ifdef WIN32 326 { 327 u_long nonblocking = 1; 328 ioctlsocket(sock, FIONBIO, &nonblocking); 329 } 330 #else 331 fcntl(sock, F_SETFL, O_NONBLOCK); 332 #endif 333 memset(&my_addr, 0, sizeof(my_addr)); 334 my_addr.sin_family = AF_INET; 335 my_addr.sin_port = htons(35353); 336 my_addr.sin_addr.s_addr = htonl(0x7f000001UL); 337 if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) { 338 perror("bind"); 339 exit (1); 340 } 341 port = evdns_add_server_port(sock, 0, dns_server_request_cb, NULL); 342 343 /* Send two queries. */ 344 evdns_resolve_ipv4("zz.example.com", DNS_QUERY_NO_SEARCH, 345 dns_server_gethostbyname_cb, NULL); 346 evdns_resolve_ipv6("zz.example.com", DNS_QUERY_NO_SEARCH, 347 dns_server_gethostbyname_cb, NULL); 348 resolve_addr.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */ 349 evdns_resolve_reverse(&resolve_addr, 0, 350 dns_server_gethostbyname_cb, NULL); 351 352 event_dispatch(); 353 354 if (dns_ok) { 355 fprintf(stdout, "OK\n"); 356 } else { 357 fprintf(stdout, "FAILED\n"); 358 exit(1); 359 } 360 361 evdns_close_server_port(port); 362 evdns_shutdown(0); /* remove ourself as nameserver. */ 363 #ifdef WIN32 364 closesocket(sock); 365 #else 366 close(sock); 367 #endif 368 } 369 370 void 371 dns_suite(void) 372 { 373 dns_server(); /* Do this before we call evdns_init. */ 374 375 #if 0 376 evdns_init(); 377 dns_gethostbyname(); 378 dns_gethostbyname6(); 379 dns_gethostbyaddr(); 380 381 evdns_shutdown(0); 382 #endif 383 } 384