1 /* $NetBSD: res_init.c,v 1.8 2006/03/19 03:10:08 christos Exp $ */
2
3 /*
4 * Copyright (c) 1985, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 /*
37 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
38 *
39 * Permission to use, copy, modify, and distribute this software for any
40 * purpose with or without fee is hereby granted, provided that the above
41 * copyright notice and this permission notice appear in all copies, and that
42 * the name of Digital Equipment Corporation not be used in advertising or
43 * publicity pertaining to distribution of the document or software without
44 * specific, written prior permission.
45 *
46 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
47 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
48 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
49 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
50 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
51 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
52 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
53 * SOFTWARE.
54 */
55
56 /*
57 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
58 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
59 *
60 * Permission to use, copy, modify, and distribute this software for any
61 * purpose with or without fee is hereby granted, provided that the above
62 * copyright notice and this permission notice appear in all copies.
63 *
64 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
65 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
66 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
67 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
68 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
69 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
70 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
71 */
72
73 #include <sys/cdefs.h>
74 #if defined(LIBC_SCCS) && !defined(lint)
75 #ifdef notdef
76 static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93";
77 static const char rcsid[] = "Id: res_init.c,v 1.9.2.5.4.2 2004/03/16 12:34:18 marka Exp";
78 #else
79 __RCSID("$NetBSD: res_init.c,v 1.8 2006/03/19 03:10:08 christos Exp $");
80 #endif
81 #endif /* LIBC_SCCS and not lint */
82
83
84
85 #include <sys/types.h>
86 #include <sys/param.h>
87 #include <sys/socket.h>
88 #include <sys/time.h>
89
90 #include <netinet/in.h>
91 #include <arpa/inet.h>
92 #include "arpa_nameser.h"
93
94 #include <ctype.h>
95 #include <stdio.h>
96 #include <stdlib.h>
97 #include <string.h>
98 #include <unistd.h>
99 #include <netdb.h>
100
101 #ifdef ANDROID_CHANGES
102 #include <sys/system_properties.h>
103 #endif /* ANDROID_CHANGES */
104
105 #ifndef MIN
106 #define MIN(x,y) ((x)<(y)?(x):(y))
107 #endif
108
109 /* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
110 #ifdef ANDROID_CHANGES
111 #include "resolv_private.h"
112 #define MAX_DNS_PROPERTIES 8
113 #define DNS_PROP_NAME_PREFIX "net.dns"
114 #define DNS_CHANGE_PROP_NAME "net.dnschange"
115 #define DNS_SEARCH_PROP_NAME "net.dns.search"
116 const prop_info *dns_change_prop;
117 int dns_last_change_counter;
118 static int _get_dns_change_count();
119 #else
120 #include <resolv.h>
121 #endif
122
123 #include "res_private.h"
124
125 /* Options. Should all be left alone. */
126 #ifndef DEBUG
127 #define DEBUG
128 #endif
129
130 static void res_setoptions __P((res_state, const char *, const char *));
131
132 static const char sort_mask[] = "/&";
133 #define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
134 static u_int32_t net_mask __P((struct in_addr));
135
136 #if !defined(isascii) /* XXX - could be a function */
137 # define isascii(c) (!(c & 0200))
138 #endif
139
140 /*
141 * Resolver state default settings.
142 */
143
144 /*
145 * Set up default settings. If the configuration file exist, the values
146 * there will have precedence. Otherwise, the server address is set to
147 * INADDR_ANY and the default domain name comes from the gethostname().
148 *
149 * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
150 * rather than INADDR_ANY ("0.0.0.0") as the default name server address
151 * since it was noted that INADDR_ANY actually meant ``the first interface
152 * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
153 * it had to be "up" in order for you to reach your own name server. It
154 * was later decided that since the recommended practice is to always
155 * install local static routes through 127.0.0.1 for all your network
156 * interfaces, that we could solve this problem without a code change.
157 *
158 * The configuration file should always be used, since it is the only way
159 * to specify a default domain. If you are running a server on your local
160 * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
161 * in the configuration file.
162 *
163 * Return 0 if completes successfully, -1 on error
164 */
165 int
res_ninit(res_state statp)166 res_ninit(res_state statp) {
167 extern int __res_vinit(res_state, int);
168
169 return (__res_vinit(statp, 0));
170 }
171
172 #ifdef ANDROID_CHANGES
load_domain_search_list(res_state statp)173 int load_domain_search_list(res_state statp) {
174 char propvalue[PROP_VALUE_MAX];
175 register char *cp, **pp;
176
177 if(__system_property_get(DNS_SEARCH_PROP_NAME, propvalue) >= 1) {
178 strlcpy(statp->defdname, propvalue, sizeof(statp->defdname));
179 if ((cp = strchr(statp->defdname, '\n')) != NULL)
180 *cp = '\0';
181 cp = statp->defdname;
182 pp = statp->dnsrch;
183 while ( pp < statp->dnsrch + MAXDNSRCH ) {
184 while (*cp == ' ' || *cp == '\t') /* skip leading white space */
185 cp++;
186 if (*cp == '\0') /* stop if nothing more */
187 break;
188 *pp++ = cp; /* record this search domain */
189 while (*cp) { /* zero-terminate it */
190 if (*cp == ' ' || *cp == '\t') {
191 *cp++ = '\0';
192 break;
193 }
194 cp++;
195 }
196 }
197 *pp = NULL; /* statp->dnsrch has MAXDNSRCH+1 items */
198 if (pp > statp->dnsrch)
199 return 1;
200 }
201 return 0;
202 }
203 #endif
204
205 /* This function has to be reachable by res_data.c but not publicly. */
206 int
__res_vinit(res_state statp,int preinit)207 __res_vinit(res_state statp, int preinit) {
208 register FILE *fp;
209 register char *cp, **pp;
210 register int n;
211 char buf[BUFSIZ];
212 int nserv = 0; /* number of nameserver records read from file */
213 int haveenv = 0;
214 int havesearch = 0;
215 int nsort = 0;
216 char *net;
217 int dots;
218 union res_sockaddr_union u[2];
219 #ifdef ANDROID_CHANGES
220 pid_t mypid = getpid();
221 int use_proc_props = 0;
222 int found_prop;
223 char dnsProperty[PROP_VALUE_MAX];
224 #endif
225
226 if (!preinit) {
227 statp->retrans = RES_TIMEOUT;
228 statp->retry = RES_DFLRETRY;
229 statp->options = RES_DEFAULT;
230 statp->id = res_randomid();
231 }
232
233 if ((statp->options & RES_INIT) != 0U)
234 res_ndestroy(statp);
235
236 memset(u, 0, sizeof(u));
237 #ifdef USELOOPBACK
238 u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
239 #else
240 u[nserv].sin.sin_addr.s_addr = INADDR_ANY;
241 #endif
242 u[nserv].sin.sin_family = AF_INET;
243 u[nserv].sin.sin_port = htons(NAMESERVER_PORT);
244 #ifdef HAVE_SA_LEN
245 u[nserv].sin.sin_len = sizeof(struct sockaddr_in);
246 #endif
247 nserv++;
248 #ifdef HAS_INET6_STRUCTS
249 #ifdef USELOOPBACK
250 u[nserv].sin6.sin6_addr = in6addr_loopback;
251 #else
252 u[nserv].sin6.sin6_addr = in6addr_any;
253 #endif
254 u[nserv].sin6.sin6_family = AF_INET6;
255 u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT);
256 #ifdef HAVE_SA_LEN
257 u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6);
258 #endif
259 nserv++;
260 #endif
261 statp->nscount = 0;
262 statp->ndots = 1;
263 statp->pfcode = 0;
264 statp->_vcsock = -1;
265 statp->_flags = 0;
266 statp->qhook = NULL;
267 statp->rhook = NULL;
268 statp->_u._ext.nscount = 0;
269 statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext));
270 if (statp->_u._ext.ext != NULL) {
271 memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
272 statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
273 strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
274 strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
275 }
276 statp->nsort = 0;
277 res_setservers(statp, u, nserv);
278
279 #if 0 /* IGNORE THE ENVIRONMENT */
280 /* Allow user to override the local domain definition */
281 if ((cp = getenv("LOCALDOMAIN")) != NULL) {
282 (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
283 statp->defdname[sizeof(statp->defdname) - 1] = '\0';
284 haveenv++;
285
286 /*
287 * Set search list to be blank-separated strings
288 * from rest of env value. Permits users of LOCALDOMAIN
289 * to still have a search list, and anyone to set the
290 * one that they want to use as an individual (even more
291 * important now that the rfc1535 stuff restricts searches)
292 */
293 cp = statp->defdname;
294 pp = statp->dnsrch;
295 *pp++ = cp;
296 for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
297 if (*cp == '\n') /* silly backwards compat */
298 break;
299 else if (*cp == ' ' || *cp == '\t') {
300 *cp = 0;
301 n = 1;
302 } else if (n) {
303 *pp++ = cp;
304 n = 0;
305 havesearch = 1;
306 }
307 }
308 /* null terminate last domain if there are excess */
309 while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
310 cp++;
311 *cp = '\0';
312 *pp++ = 0;
313 }
314 if (nserv > 0)
315 statp->nscount = nserv;
316 #endif
317 #ifdef ANDROID_CHANGES /* READ FROM SYSTEM PROPERTIES */
318 dns_last_change_counter = _get_dns_change_count();
319
320 nserv = 0;
321 for(n = 1; n <= MAX_DNS_PROPERTIES && nserv < MAXNS; n++) {
322 char propname[PROP_NAME_MAX];
323 char propvalue[PROP_VALUE_MAX];
324
325 struct addrinfo hints, *ai;
326 char sbuf[NI_MAXSERV];
327 const size_t minsiz = sizeof(statp->_u._ext.ext->nsaddrs[0]);
328
329 /*
330 * Check first for process-specific properties, and if those don't
331 * exist, try the generic properties.
332 */
333 found_prop = 0;
334 if (n == 1 || use_proc_props) {
335 snprintf(propname, sizeof(propname), "%s%d.%d", DNS_PROP_NAME_PREFIX, n, mypid);
336 if(__system_property_get(propname, propvalue) < 1) {
337 if (use_proc_props) {
338 break;
339 }
340 } else {
341 found_prop = 1;
342 use_proc_props = 1;
343 }
344 }
345 if (!found_prop) {
346 snprintf(propname, sizeof(propname), "%s%d", DNS_PROP_NAME_PREFIX, n);
347 if(__system_property_get(propname, propvalue) < 1) {
348 break;
349 }
350 }
351
352 cp = propvalue;
353
354 while (*cp == ' ' || *cp == '\t')
355 cp++;
356 cp[strcspn(cp, ";# \t\n")] = '\0';
357 if ((*cp != '\0') && (*cp != '\n')) {
358 memset(&hints, 0, sizeof(hints));
359 hints.ai_family = PF_UNSPEC;
360 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
361 hints.ai_flags = AI_NUMERICHOST;
362 sprintf(sbuf, "%u", NAMESERVER_PORT);
363 if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 &&
364 (size_t)ai->ai_addrlen <= minsiz) {
365 if (statp->_u._ext.ext != NULL) {
366 memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
367 ai->ai_addr, ai->ai_addrlen);
368 }
369 if ((size_t)ai->ai_addrlen <=
370 sizeof(statp->nsaddr_list[nserv])) {
371 memcpy(&statp->nsaddr_list[nserv],
372 ai->ai_addr, ai->ai_addrlen);
373 } else {
374 statp->nsaddr_list[nserv].sin_family = 0;
375 }
376 freeaddrinfo(ai);
377 nserv++;
378 }
379 }
380 }
381
382 /* Add the domain search list */
383 havesearch = load_domain_search_list(statp);
384 #else /* IGNORE resolv.conf */
385 #define MATCH(line, name) \
386 (!strncmp(line, name, sizeof(name) - 1) && \
387 (line[sizeof(name) - 1] == ' ' || \
388 line[sizeof(name) - 1] == '\t'))
389
390 nserv = 0;
391 if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
392 /* read the config file */
393 while (fgets(buf, sizeof(buf), fp) != NULL) {
394 /* skip comments */
395 if (*buf == ';' || *buf == '#')
396 continue;
397 /* read default domain name */
398 if (MATCH(buf, "domain")) {
399 if (haveenv) /* skip if have from environ */
400 continue;
401 cp = buf + sizeof("domain") - 1;
402 while (*cp == ' ' || *cp == '\t')
403 cp++;
404 if ((*cp == '\0') || (*cp == '\n'))
405 continue;
406 strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
407 statp->defdname[sizeof(statp->defdname) - 1] = '\0';
408 if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
409 *cp = '\0';
410 havesearch = 0;
411 continue;
412 }
413 /* set search list */
414 if (MATCH(buf, "search")) {
415 if (haveenv) /* skip if have from environ */
416 continue;
417 cp = buf + sizeof("search") - 1;
418 while (*cp == ' ' || *cp == '\t')
419 cp++;
420 if ((*cp == '\0') || (*cp == '\n'))
421 continue;
422 strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
423 statp->defdname[sizeof(statp->defdname) - 1] = '\0';
424 if ((cp = strchr(statp->defdname, '\n')) != NULL)
425 *cp = '\0';
426 /*
427 * Set search list to be blank-separated strings
428 * on rest of line.
429 */
430 cp = statp->defdname;
431 pp = statp->dnsrch;
432 *pp++ = cp;
433 for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
434 if (*cp == ' ' || *cp == '\t') {
435 *cp = 0;
436 n = 1;
437 } else if (n) {
438 *pp++ = cp;
439 n = 0;
440 }
441 }
442 /* null terminate last domain if there are excess */
443 while (*cp != '\0' && *cp != ' ' && *cp != '\t')
444 cp++;
445 *cp = '\0';
446 *pp++ = 0;
447 havesearch = 1;
448 continue;
449 }
450 /* read nameservers to query */
451 if (MATCH(buf, "nameserver") && nserv < MAXNS) {
452 struct addrinfo hints, *ai;
453 char sbuf[NI_MAXSERV];
454 const size_t minsiz =
455 sizeof(statp->_u._ext.ext->nsaddrs[0]);
456
457 cp = buf + sizeof("nameserver") - 1;
458 while (*cp == ' ' || *cp == '\t')
459 cp++;
460 cp[strcspn(cp, ";# \t\n")] = '\0';
461 if ((*cp != '\0') && (*cp != '\n')) {
462 memset(&hints, 0, sizeof(hints));
463 hints.ai_family = PF_UNSPEC;
464 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
465 hints.ai_flags = AI_NUMERICHOST;
466 sprintf(sbuf, "%u", NAMESERVER_PORT);
467 if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 &&
468 ai->ai_addrlen <= minsiz) {
469 if (statp->_u._ext.ext != NULL) {
470 memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
471 ai->ai_addr, ai->ai_addrlen);
472 }
473 if (ai->ai_addrlen <=
474 sizeof(statp->nsaddr_list[nserv])) {
475 memcpy(&statp->nsaddr_list[nserv],
476 ai->ai_addr, ai->ai_addrlen);
477 } else
478 statp->nsaddr_list[nserv].sin_family = 0;
479 freeaddrinfo(ai);
480 nserv++;
481 }
482 }
483 continue;
484 }
485 if (MATCH(buf, "sortlist")) {
486 struct in_addr a;
487
488 cp = buf + sizeof("sortlist") - 1;
489 while (nsort < MAXRESOLVSORT) {
490 while (*cp == ' ' || *cp == '\t')
491 cp++;
492 if (*cp == '\0' || *cp == '\n' || *cp == ';')
493 break;
494 net = cp;
495 while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
496 isascii(*cp) && !isspace((unsigned char)*cp))
497 cp++;
498 n = *cp;
499 *cp = 0;
500 if (inet_aton(net, &a)) {
501 statp->sort_list[nsort].addr = a;
502 if (ISSORTMASK(n)) {
503 *cp++ = n;
504 net = cp;
505 while (*cp && *cp != ';' &&
506 isascii(*cp) &&
507 !isspace((unsigned char)*cp))
508 cp++;
509 n = *cp;
510 *cp = 0;
511 if (inet_aton(net, &a)) {
512 statp->sort_list[nsort].mask = a.s_addr;
513 } else {
514 statp->sort_list[nsort].mask =
515 net_mask(statp->sort_list[nsort].addr);
516 }
517 } else {
518 statp->sort_list[nsort].mask =
519 net_mask(statp->sort_list[nsort].addr);
520 }
521 nsort++;
522 }
523 *cp = n;
524 }
525 continue;
526 }
527 if (MATCH(buf, "options")) {
528 res_setoptions(statp, buf + sizeof("options") - 1, "conf");
529 continue;
530 }
531 }
532 if (nserv > 0)
533 statp->nscount = nserv;
534 statp->nsort = nsort;
535 (void) fclose(fp);
536 }
537 #endif /* ANDROID_CHANGES */
538 /*
539 * Last chance to get a nameserver. This should not normally
540 * be necessary
541 */
542 #ifdef NO_RESOLV_CONF
543 if(nserv == 0)
544 nserv = get_nameservers(statp);
545 #endif
546
547 if (statp->defdname[0] == 0 &&
548 gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
549 (cp = strchr(buf, '.')) != NULL)
550 strcpy(statp->defdname, cp + 1);
551
552 /* find components of local domain that might be searched */
553 if (havesearch == 0) {
554 pp = statp->dnsrch;
555 *pp++ = statp->defdname;
556 *pp = NULL;
557
558 dots = 0;
559 for (cp = statp->defdname; *cp; cp++)
560 dots += (*cp == '.');
561
562 cp = statp->defdname;
563 while (pp < statp->dnsrch + MAXDFLSRCH) {
564 if (dots < LOCALDOMAINPARTS)
565 break;
566 cp = strchr(cp, '.') + 1; /* we know there is one */
567 *pp++ = cp;
568 dots--;
569 }
570 *pp = NULL;
571 #ifdef DEBUG
572 if (statp->options & RES_DEBUG) {
573 printf(";; res_init()... default dnsrch list:\n");
574 for (pp = statp->dnsrch; *pp; pp++)
575 printf(";;\t%s\n", *pp);
576 printf(";;\t..END..\n");
577 }
578 #endif
579 }
580
581 if ((cp = getenv("RES_OPTIONS")) != NULL)
582 res_setoptions(statp, cp, "env");
583 if (nserv > 0) {
584 statp->nscount = nserv;
585 statp->options |= RES_INIT;
586 }
587 return (0);
588 }
589
590 static void
res_setoptions(res_state statp,const char * options,const char * source)591 res_setoptions(res_state statp, const char *options, const char *source)
592 {
593 const char *cp = options;
594 int i;
595 struct __res_state_ext *ext = statp->_u._ext.ext;
596
597 #ifdef DEBUG
598 if (statp->options & RES_DEBUG)
599 printf(";; res_setoptions(\"%s\", \"%s\")...\n",
600 options, source);
601 #endif
602 while (*cp) {
603 /* skip leading and inner runs of spaces */
604 while (*cp == ' ' || *cp == '\t')
605 cp++;
606 /* search for and process individual options */
607 if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
608 i = atoi(cp + sizeof("ndots:") - 1);
609 if (i <= RES_MAXNDOTS)
610 statp->ndots = i;
611 else
612 statp->ndots = RES_MAXNDOTS;
613 #ifdef DEBUG
614 if (statp->options & RES_DEBUG)
615 printf(";;\tndots=%d\n", statp->ndots);
616 #endif
617 } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
618 i = atoi(cp + sizeof("timeout:") - 1);
619 if (i <= RES_MAXRETRANS)
620 statp->retrans = i;
621 else
622 statp->retrans = RES_MAXRETRANS;
623 #ifdef DEBUG
624 if (statp->options & RES_DEBUG)
625 printf(";;\ttimeout=%d\n", statp->retrans);
626 #endif
627 } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
628 i = atoi(cp + sizeof("attempts:") - 1);
629 if (i <= RES_MAXRETRY)
630 statp->retry = i;
631 else
632 statp->retry = RES_MAXRETRY;
633 #ifdef DEBUG
634 if (statp->options & RES_DEBUG)
635 printf(";;\tattempts=%d\n", statp->retry);
636 #endif
637 } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
638 #ifdef DEBUG
639 if (!(statp->options & RES_DEBUG)) {
640 printf(";; res_setoptions(\"%s\", \"%s\")..\n",
641 options, source);
642 statp->options |= RES_DEBUG;
643 }
644 printf(";;\tdebug\n");
645 #endif
646 } else if (!strncmp(cp, "no_tld_query",
647 sizeof("no_tld_query") - 1) ||
648 !strncmp(cp, "no-tld-query",
649 sizeof("no-tld-query") - 1)) {
650 statp->options |= RES_NOTLDQUERY;
651 } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
652 statp->options |= RES_USE_INET6;
653 } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
654 statp->options |= RES_ROTATE;
655 } else if (!strncmp(cp, "no-check-names",
656 sizeof("no-check-names") - 1)) {
657 statp->options |= RES_NOCHECKNAME;
658 }
659 #ifdef RES_USE_EDNS0
660 else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
661 statp->options |= RES_USE_EDNS0;
662 }
663 #endif
664 else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
665 statp->options |= RES_USE_DNAME;
666 }
667 else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) {
668 if (ext == NULL)
669 goto skip;
670 cp += sizeof("nibble:") - 1;
671 i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1);
672 strncpy(ext->nsuffix, cp, (size_t)i);
673 ext->nsuffix[i] = '\0';
674 }
675 else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) {
676 if (ext == NULL)
677 goto skip;
678 cp += sizeof("nibble2:") - 1;
679 i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1);
680 strncpy(ext->nsuffix2, cp, (size_t)i);
681 ext->nsuffix2[i] = '\0';
682 }
683 else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) {
684 cp += sizeof("v6revmode:") - 1;
685 /* "nibble" and "bitstring" used to be valid */
686 if (!strncmp(cp, "single", sizeof("single") - 1)) {
687 statp->options |= RES_NO_NIBBLE2;
688 } else if (!strncmp(cp, "both", sizeof("both") - 1)) {
689 statp->options &=
690 ~RES_NO_NIBBLE2;
691 }
692 }
693 else {
694 /* XXX - print a warning here? */
695 }
696 skip:
697 /* skip to next run of spaces */
698 while (*cp && *cp != ' ' && *cp != '\t')
699 cp++;
700 }
701 }
702
703 /* XXX - should really support CIDR which means explicit masks always. */
704 static u_int32_t
net_mask(in)705 net_mask(in) /* XXX - should really use system's version of this */
706 struct in_addr in;
707 {
708 register u_int32_t i = ntohl(in.s_addr);
709
710 if (IN_CLASSA(i))
711 return (htonl(IN_CLASSA_NET));
712 else if (IN_CLASSB(i))
713 return (htonl(IN_CLASSB_NET));
714 return (htonl(IN_CLASSC_NET));
715 }
716
717 u_int
res_randomid(void)718 res_randomid(void) {
719 struct timeval now;
720
721 gettimeofday(&now, NULL);
722 return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
723 }
724
725 /*
726 * This routine is for closing the socket if a virtual circuit is used and
727 * the program wants to close it. This provides support for endhostent()
728 * which expects to close the socket.
729 *
730 * This routine is not expected to be user visible.
731 */
732 void
res_nclose(res_state statp)733 res_nclose(res_state statp) {
734 int ns;
735
736 if (statp->_vcsock >= 0) {
737 (void) close(statp->_vcsock);
738 statp->_vcsock = -1;
739 statp->_flags &= ~(RES_F_VC | RES_F_CONN);
740 }
741 for (ns = 0; ns < statp->_u._ext.nscount; ns++) {
742 if (statp->_u._ext.nssocks[ns] != -1) {
743 (void) close(statp->_u._ext.nssocks[ns]);
744 statp->_u._ext.nssocks[ns] = -1;
745 }
746 }
747 }
748
749 void
res_ndestroy(res_state statp)750 res_ndestroy(res_state statp) {
751 res_nclose(statp);
752 if (statp->_u._ext.ext != NULL)
753 free(statp->_u._ext.ext);
754 statp->options &= ~RES_INIT;
755 statp->_u._ext.ext = NULL;
756 }
757
758 const char *
res_get_nibblesuffix(res_state statp)759 res_get_nibblesuffix(res_state statp) {
760 if (statp->_u._ext.ext)
761 return (statp->_u._ext.ext->nsuffix);
762 return ("ip6.arpa");
763 }
764
765 const char *
res_get_nibblesuffix2(res_state statp)766 res_get_nibblesuffix2(res_state statp) {
767 if (statp->_u._ext.ext)
768 return (statp->_u._ext.ext->nsuffix2);
769 return ("ip6.int");
770 }
771
772 void
res_setservers(res_state statp,const union res_sockaddr_union * set,int cnt)773 res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
774 int i, nserv;
775 size_t size;
776
777 /* close open servers */
778 res_nclose(statp);
779
780 /* cause rtt times to be forgotten */
781 statp->_u._ext.nscount = 0;
782
783 nserv = 0;
784 for (i = 0; i < cnt && nserv < MAXNS; i++) {
785 switch (set->sin.sin_family) {
786 case AF_INET:
787 size = sizeof(set->sin);
788 if (statp->_u._ext.ext)
789 memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
790 &set->sin, size);
791 if (size <= sizeof(statp->nsaddr_list[nserv]))
792 memcpy(&statp->nsaddr_list[nserv],
793 &set->sin, size);
794 #ifdef notdef
795 else
796 statp->nsaddr_list[nserv].sin_family = 0;
797 #endif
798 nserv++;
799 break;
800
801 #ifdef HAS_INET6_STRUCTS
802 case AF_INET6:
803 size = sizeof(set->sin6);
804 if (statp->_u._ext.ext)
805 memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
806 &set->sin6, size);
807 if (size <= sizeof(statp->nsaddr_list[nserv]))
808 memcpy(&statp->nsaddr_list[nserv],
809 &set->sin6, size);
810 else
811 statp->nsaddr_list[nserv].sin_family = 0;
812 nserv++;
813 break;
814 #endif
815
816 default:
817 break;
818 }
819 set++;
820 }
821 statp->nscount = nserv;
822
823 }
824
825 int
res_getservers(res_state statp,union res_sockaddr_union * set,int cnt)826 res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) {
827 int i;
828 size_t size;
829 u_int16_t family;
830
831 for (i = 0; i < statp->nscount && i < cnt; i++) {
832 if (statp->_u._ext.ext)
833 family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family;
834 else
835 family = statp->nsaddr_list[i].sin_family;
836
837 switch (family) {
838 case AF_INET:
839 size = sizeof(set->sin);
840 if (statp->_u._ext.ext)
841 memcpy(&set->sin,
842 &statp->_u._ext.ext->nsaddrs[i],
843 size);
844 else
845 memcpy(&set->sin, &statp->nsaddr_list[i],
846 size);
847 break;
848
849 #ifdef HAS_INET6_STRUCTS
850 case AF_INET6:
851 size = sizeof(set->sin6);
852 if (statp->_u._ext.ext)
853 memcpy(&set->sin6,
854 &statp->_u._ext.ext->nsaddrs[i],
855 size);
856 else
857 memcpy(&set->sin6, &statp->nsaddr_list[i],
858 size);
859 break;
860 #endif
861
862 default:
863 set->sin.sin_family = 0;
864 break;
865 }
866 set++;
867 }
868 return (statp->nscount);
869 }
870
871 #ifdef ANDROID_CHANGES
_get_dns_change_count()872 static int _get_dns_change_count()
873 {
874 if (dns_change_prop == NULL) {
875 dns_change_prop = __system_property_find(DNS_CHANGE_PROP_NAME);
876 }
877 if (dns_change_prop != NULL) {
878 char propvalue[PROP_VALUE_MAX];
879 if (__system_property_read(dns_change_prop, NULL, propvalue) >= 1) {
880 return atoi(propvalue);
881 }
882 }
883 return -1;
884 }
885
res_get_dns_changed()886 int res_get_dns_changed()
887 {
888 int change_count;
889
890 change_count = _get_dns_change_count();
891 if (change_count != dns_last_change_counter) {
892 if (change_count != -1) {
893 dns_last_change_counter = change_count;
894 }
895 return 1;
896 } else {
897 return 0;
898 }
899 }
900 #endif /* ANDROID_CHANGES */
901