]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/platform-bionic.git/blob - libc/dns/resolv/res_init.c
am 4a46a689: Merge "Moved private dns header to their own dir."
[android-sdk/platform-bionic.git] / libc / dns / resolv / res_init.c
1 /*      $NetBSD: res_init.c,v 1.8 2006/03/19 03:10:08 christos Exp $    */
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  */
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  */
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  */
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 */
85 #include <sys/types.h>
86 #include <sys/param.h>
87 #include <sys/socket.h>
88 #include <sys/time.h>
90 #include <netinet/in.h>
91 #include <arpa/inet.h>
92 #include "arpa_nameser.h"
94 #include <ctype.h>
95 #include <stdio.h>
96 #include <stdlib.h>
97 #include <string.h>
98 #include <unistd.h>
99 #include <netdb.h>
101 #ifdef ANDROID_CHANGES
102 #include <errno.h>
103 #include <fcntl.h>
104 #include <sys/system_properties.h>
105 #endif /* ANDROID_CHANGES */
107 #ifndef MIN
108 #define MIN(x,y)        ((x)<(y)?(x):(y))
109 #endif
111 /* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
112 #ifdef ANDROID_CHANGES
113 #include "resolv_private.h"
114 #else
115 #include <resolv.h>
116 #endif
118 #include "res_private.h"
120 /* Options.  Should all be left alone. */
121 #ifndef DEBUG
122 #define DEBUG
123 #endif
125 static void res_setoptions __P((res_state, const char *, const char *));
127 static const char sort_mask[] = "/&";
128 #define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
129 static u_int32_t net_mask __P((struct in_addr));
131 #if !defined(isascii)   /* XXX - could be a function */
132 # define isascii(c) (!(c & 0200))
133 #endif
135 /*
136  * Resolver state default settings.
137  */
139 /*
140  * Set up default settings.  If the configuration file exist, the values
141  * there will have precedence.  Otherwise, the server address is set to
142  * INADDR_ANY and the default domain name comes from the gethostname().
143  *
144  * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
145  * rather than INADDR_ANY ("0.0.0.0") as the default name server address
146  * since it was noted that INADDR_ANY actually meant ``the first interface
147  * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
148  * it had to be "up" in order for you to reach your own name server.  It
149  * was later decided that since the recommended practice is to always
150  * install local static routes through 127.0.0.1 for all your network
151  * interfaces, that we could solve this problem without a code change.
152  *
153  * The configuration file should always be used, since it is the only way
154  * to specify a default domain.  If you are running a server on your local
155  * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
156  * in the configuration file.
157  *
158  * Return 0 if completes successfully, -1 on error
159  */
160 int
161 res_ninit(res_state statp) {
162         extern int __res_vinit(res_state, int);
164         return (__res_vinit(statp, 0));
167 /* This function has to be reachable by res_data.c but not publicly. */
168 int
169 __res_vinit(res_state statp, int preinit) {
170         register FILE *fp;
171         register char *cp, **pp;
172         register int n;
173         char buf[BUFSIZ];
174         int nserv = 0;    /* number of nameserver records read from file */
175         int haveenv = 0;
176         int havesearch = 0;
177         int nsort = 0;
178         char *net;
179         int dots;
180         union res_sockaddr_union u[2];
182         if ((statp->options & RES_INIT) != 0U)
183                 res_ndestroy(statp);
185         if (!preinit) {
186                 statp->retrans = RES_TIMEOUT;
187                 statp->retry = RES_DFLRETRY;
188                 statp->options = RES_DEFAULT;
189                 statp->id = res_randomid();
190         }
192         memset(u, 0, sizeof(u));
193 #ifdef USELOOPBACK
194         u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
195 #else
196         u[nserv].sin.sin_addr.s_addr = INADDR_ANY;
197 #endif
198         u[nserv].sin.sin_family = AF_INET;
199         u[nserv].sin.sin_port = htons(NAMESERVER_PORT);
200 #ifdef HAVE_SA_LEN
201         u[nserv].sin.sin_len = sizeof(struct sockaddr_in);
202 #endif
203         nserv++;
204 #ifdef HAS_INET6_STRUCTS
205 #ifdef USELOOPBACK
206         u[nserv].sin6.sin6_addr = in6addr_loopback;
207 #else
208         u[nserv].sin6.sin6_addr = in6addr_any;
209 #endif
210         u[nserv].sin6.sin6_family = AF_INET6;
211         u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT);
212 #ifdef HAVE_SA_LEN
213         u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6);
214 #endif
215         nserv++;
216 #endif
217         statp->nscount = 0;
218         statp->ndots = 1;
219         statp->pfcode = 0;
220         statp->_vcsock = -1;
221         statp->_flags = 0;
222         statp->qhook = NULL;
223         statp->rhook = NULL;
224         statp->_u._ext.nscount = 0;
225         statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext));
226         if (statp->_u._ext.ext != NULL) {
227                 memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
228                 statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
229                 strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
230                 strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
231         }
232         statp->nsort = 0;
233         res_setservers(statp, u, nserv);
235 #if 0 /* IGNORE THE ENVIRONMENT */
236         /* Allow user to override the local domain definition */
237         if ((cp = getenv("LOCALDOMAIN")) != NULL) {
238                 (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
239                 statp->defdname[sizeof(statp->defdname) - 1] = '\0';
240                 haveenv++;
242                 /*
243                  * Set search list to be blank-separated strings
244                  * from rest of env value.  Permits users of LOCALDOMAIN
245                  * to still have a search list, and anyone to set the
246                  * one that they want to use as an individual (even more
247                  * important now that the rfc1535 stuff restricts searches)
248                  */
249                 cp = statp->defdname;
250                 pp = statp->dnsrch;
251                 *pp++ = cp;
252                 for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
253                         if (*cp == '\n')        /* silly backwards compat */
254                                 break;
255                         else if (*cp == ' ' || *cp == '\t') {
256                                 *cp = 0;
257                                 n = 1;
258                         } else if (n) {
259                                 *pp++ = cp;
260                                 n = 0;
261                                 havesearch = 1;
262                         }
263                 }
264                 /* null terminate last domain if there are excess */
265                 while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
266                         cp++;
267                 *cp = '\0';
268                 *pp++ = 0;
269         }
270         if (nserv > 0)
271                 statp->nscount = nserv;
272 #endif
274 #ifndef ANDROID_CHANGES /* !ANDROID_CHANGES - IGNORE resolv.conf in Android */
275 #define MATCH(line, name) \
276         (!strncmp(line, name, sizeof(name) - 1) && \
277         (line[sizeof(name) - 1] == ' ' || \
278          line[sizeof(name) - 1] == '\t'))
280         nserv = 0;
281         if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
282             /* read the config file */
283             while (fgets(buf, sizeof(buf), fp) != NULL) {
284                 /* skip comments */
285                 if (*buf == ';' || *buf == '#')
286                         continue;
287                 /* read default domain name */
288                 if (MATCH(buf, "domain")) {
289                     if (haveenv)        /* skip if have from environ */
290                             continue;
291                     cp = buf + sizeof("domain") - 1;
292                     while (*cp == ' ' || *cp == '\t')
293                             cp++;
294                     if ((*cp == '\0') || (*cp == '\n'))
295                             continue;
296                     strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
297                     statp->defdname[sizeof(statp->defdname) - 1] = '\0';
298                     if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
299                             *cp = '\0';
300                     havesearch = 0;
301                     continue;
302                 }
303                 /* set search list */
304                 if (MATCH(buf, "search")) {
305                     if (haveenv)        /* skip if have from environ */
306                             continue;
307                     cp = buf + sizeof("search") - 1;
308                     while (*cp == ' ' || *cp == '\t')
309                             cp++;
310                     if ((*cp == '\0') || (*cp == '\n'))
311                             continue;
312                     strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
313                     statp->defdname[sizeof(statp->defdname) - 1] = '\0';
314                     if ((cp = strchr(statp->defdname, '\n')) != NULL)
315                             *cp = '\0';
316                     /*
317                      * Set search list to be blank-separated strings
318                      * on rest of line.
319                      */
320                     cp = statp->defdname;
321                     pp = statp->dnsrch;
322                     *pp++ = cp;
323                     for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
324                             if (*cp == ' ' || *cp == '\t') {
325                                     *cp = 0;
326                                     n = 1;
327                             } else if (n) {
328                                     *pp++ = cp;
329                                     n = 0;
330                             }
331                     }
332                     /* null terminate last domain if there are excess */
333                     while (*cp != '\0' && *cp != ' ' && *cp != '\t')
334                             cp++;
335                     *cp = '\0';
336                     *pp++ = 0;
337                     havesearch = 1;
338                     continue;
339                 }
340                 /* read nameservers to query */
341                 if (MATCH(buf, "nameserver") && nserv < MAXNS) {
342                     struct addrinfo hints, *ai;
343                     char sbuf[NI_MAXSERV];
344                     const size_t minsiz =
345                         sizeof(statp->_u._ext.ext->nsaddrs[0]);
347                     cp = buf + sizeof("nameserver") - 1;
348                     while (*cp == ' ' || *cp == '\t')
349                         cp++;
350                     cp[strcspn(cp, ";# \t\n")] = '\0';
351                     if ((*cp != '\0') && (*cp != '\n')) {
352                         memset(&hints, 0, sizeof(hints));
353                         hints.ai_family = PF_UNSPEC;
354                         hints.ai_socktype = SOCK_DGRAM; /*dummy*/
355                         hints.ai_flags = AI_NUMERICHOST;
356                         sprintf(sbuf, "%u", NAMESERVER_PORT);
357                         if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 &&
358                             ai->ai_addrlen <= minsiz) {
359                             if (statp->_u._ext.ext != NULL) {
360                                 memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
361                                     ai->ai_addr, ai->ai_addrlen);
362                             }
363                             if (ai->ai_addrlen <=
364                                 sizeof(statp->nsaddr_list[nserv])) {
365                                 memcpy(&statp->nsaddr_list[nserv],
366                                     ai->ai_addr, ai->ai_addrlen);
367                             } else
368                                 statp->nsaddr_list[nserv].sin_family = 0;
369                             freeaddrinfo(ai);
370                             nserv++;
371                         }
372                     }
373                     continue;
374                 }
375                 if (MATCH(buf, "sortlist")) {
376                     struct in_addr a;
378                     cp = buf + sizeof("sortlist") - 1;
379                     while (nsort < MAXRESOLVSORT) {
380                         while (*cp == ' ' || *cp == '\t')
381                             cp++;
382                         if (*cp == '\0' || *cp == '\n' || *cp == ';')
383                             break;
384                         net = cp;
385                         while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
386                                isascii(*cp) && !isspace((unsigned char)*cp))
387                                 cp++;
388                         n = *cp;
389                         *cp = 0;
390                         if (inet_aton(net, &a)) {
391                             statp->sort_list[nsort].addr = a;
392                             if (ISSORTMASK(n)) {
393                                 *cp++ = n;
394                                 net = cp;
395                                 while (*cp && *cp != ';' &&
396                                         isascii(*cp) &&
397                                         !isspace((unsigned char)*cp))
398                                     cp++;
399                                 n = *cp;
400                                 *cp = 0;
401                                 if (inet_aton(net, &a)) {
402                                     statp->sort_list[nsort].mask = a.s_addr;
403                                 } else {
404                                     statp->sort_list[nsort].mask =
405                                         net_mask(statp->sort_list[nsort].addr);
406                                 }
407                             } else {
408                                 statp->sort_list[nsort].mask =
409                                     net_mask(statp->sort_list[nsort].addr);
410                             }
411                             nsort++;
412                         }
413                         *cp = n;
414                     }
415                     continue;
416                 }
417                 if (MATCH(buf, "options")) {
418                     res_setoptions(statp, buf + sizeof("options") - 1, "conf");
419                     continue;
420                 }
421             }
422             if (nserv > 0)
423                 statp->nscount = nserv;
424             statp->nsort = nsort;
425             (void) fclose(fp);
426         }
427 #endif /* !ANDROID_CHANGES */
428 /*
429  * Last chance to get a nameserver.  This should not normally
430  * be necessary
431  */
432 #ifdef NO_RESOLV_CONF
433         if(nserv == 0)
434                 nserv = get_nameservers(statp);
435 #endif
437         if (statp->defdname[0] == 0 &&
438             gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
439             (cp = strchr(buf, '.')) != NULL)
440                 strcpy(statp->defdname, cp + 1);
442         /* find components of local domain that might be searched */
443         if (havesearch == 0) {
444                 pp = statp->dnsrch;
445                 *pp++ = statp->defdname;
446                 *pp = NULL;
448                 dots = 0;
449                 for (cp = statp->defdname; *cp; cp++)
450                         dots += (*cp == '.');
452                 cp = statp->defdname;
453                 while (pp < statp->dnsrch + MAXDFLSRCH) {
454                         if (dots < LOCALDOMAINPARTS)
455                                 break;
456                         cp = strchr(cp, '.') + 1;    /* we know there is one */
457                         *pp++ = cp;
458                         dots--;
459                 }
460                 *pp = NULL;
461 #ifdef DEBUG
462                 if (statp->options & RES_DEBUG) {
463                         printf(";; res_init()... default dnsrch list:\n");
464                         for (pp = statp->dnsrch; *pp; pp++)
465                                 printf(";;\t%s\n", *pp);
466                         printf(";;\t..END..\n");
467                 }
468 #endif
469         }
471         if ((cp = getenv("RES_OPTIONS")) != NULL)
472                 res_setoptions(statp, cp, "env");
473         if (nserv > 0) {
474                 statp->nscount = nserv;
475                 statp->options |= RES_INIT;
476         }
477         return (0);
480 static void
481 res_setoptions(res_state statp, const char *options, const char *source)
483         const char *cp = options;
484         int i;
485         struct __res_state_ext *ext = statp->_u._ext.ext;
487 #ifdef DEBUG
488         if (statp->options & RES_DEBUG)
489                 printf(";; res_setoptions(\"%s\", \"%s\")...\n",
490                        options, source);
491 #endif
492         while (*cp) {
493                 /* skip leading and inner runs of spaces */
494                 while (*cp == ' ' || *cp == '\t')
495                         cp++;
496                 /* search for and process individual options */
497                 if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
498                         i = atoi(cp + sizeof("ndots:") - 1);
499                         if (i <= RES_MAXNDOTS)
500                                 statp->ndots = i;
501                         else
502                                 statp->ndots = RES_MAXNDOTS;
503 #ifdef DEBUG
504                         if (statp->options & RES_DEBUG)
505                                 printf(";;\tndots=%d\n", statp->ndots);
506 #endif
507                 } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
508                         i = atoi(cp + sizeof("timeout:") - 1);
509                         if (i <= RES_MAXRETRANS)
510                                 statp->retrans = i;
511                         else
512                                 statp->retrans = RES_MAXRETRANS;
513 #ifdef DEBUG
514                         if (statp->options & RES_DEBUG)
515                                 printf(";;\ttimeout=%d\n", statp->retrans);
516 #endif
517                 } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
518                         i = atoi(cp + sizeof("attempts:") - 1);
519                         if (i <= RES_MAXRETRY)
520                                 statp->retry = i;
521                         else
522                                 statp->retry = RES_MAXRETRY;
523 #ifdef DEBUG
524                         if (statp->options & RES_DEBUG)
525                                 printf(";;\tattempts=%d\n", statp->retry);
526 #endif
527                 } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
528 #ifdef DEBUG
529                         if (!(statp->options & RES_DEBUG)) {
530                                 printf(";; res_setoptions(\"%s\", \"%s\")..\n",
531                                        options, source);
532                                 statp->options |= RES_DEBUG;
533                         }
534                         printf(";;\tdebug\n");
535 #endif
536                 } else if (!strncmp(cp, "no_tld_query",
537                                     sizeof("no_tld_query") - 1) ||
538                            !strncmp(cp, "no-tld-query",
539                                     sizeof("no-tld-query") - 1)) {
540                         statp->options |= RES_NOTLDQUERY;
541                 } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
542                         statp->options |= RES_USE_INET6;
543                 } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
544                         statp->options |= RES_ROTATE;
545                 } else if (!strncmp(cp, "no-check-names",
546                                     sizeof("no-check-names") - 1)) {
547                         statp->options |= RES_NOCHECKNAME;
548                 }
549 #ifdef RES_USE_EDNS0
550                 else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
551                         statp->options |= RES_USE_EDNS0;
552                 }
553 #endif
554                 else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
555                         statp->options |= RES_USE_DNAME;
556                 }
557                 else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) {
558                         if (ext == NULL)
559                                 goto skip;
560                         cp += sizeof("nibble:") - 1;
561                         i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1);
562                         strncpy(ext->nsuffix, cp, (size_t)i);
563                         ext->nsuffix[i] = '\0';
564                 }
565                 else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) {
566                         if (ext == NULL)
567                                 goto skip;
568                         cp += sizeof("nibble2:") - 1;
569                         i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1);
570                         strncpy(ext->nsuffix2, cp, (size_t)i);
571                         ext->nsuffix2[i] = '\0';
572                 }
573                 else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) {
574                         cp += sizeof("v6revmode:") - 1;
575                         /* "nibble" and "bitstring" used to be valid */
576                         if (!strncmp(cp, "single", sizeof("single") - 1)) {
577                                 statp->options |= RES_NO_NIBBLE2;
578                         } else if (!strncmp(cp, "both", sizeof("both") - 1)) {
579                                 statp->options &=
580                                          ~RES_NO_NIBBLE2;
581                         }
582                 }
583                 else {
584                         /* XXX - print a warning here? */
585                 }
586    skip:
587                 /* skip to next run of spaces */
588                 while (*cp && *cp != ' ' && *cp != '\t')
589                         cp++;
590         }
593 /* XXX - should really support CIDR which means explicit masks always. */
594 static u_int32_t
595 net_mask(in)            /* XXX - should really use system's version of this */
596         struct in_addr in;
598         register u_int32_t i = ntohl(in.s_addr);
600         if (IN_CLASSA(i))
601                 return (htonl(IN_CLASSA_NET));
602         else if (IN_CLASSB(i))
603                 return (htonl(IN_CLASSB_NET));
604         return (htonl(IN_CLASSC_NET));
607 #ifdef ANDROID_CHANGES
608 static int
609 real_randomid(u_int *random_value) {
610         /* open the nonblocking random device, returning -1 on failure */
611         int random_device = open("/dev/urandom", O_RDONLY);
612         if (random_device < 0) {
613                 return -1;
614         }
616         /* read from the random device, returning -1 on failure (or too many retries)*/
617         u_int retry = 5;
618         for (retry; retry > 0; retry--) {
619                 int retval = read(random_device, random_value, sizeof(u_int));
620                 if (retval == sizeof(u_int)) {
621                         *random_value &= 0xffff;
622                         close(random_device);
623                         return 0;
624                 } else if ((retval < 0) && (errno != EINTR)) {
625                         break;
626                 }
627         }
629         close(random_device);
630         return -1;
632 #endif /* ANDROID_CHANGES */
634 u_int
635 res_randomid(void) {
636 #ifdef ANDROID_CHANGES
637         int status = 0;
638         u_int output = 0;
639         status = real_randomid(&output);
640         if (status != -1) {
641                 return output;
642         }
643 #endif /* ANDROID_CHANGES */
644         struct timeval now;
645         gettimeofday(&now, NULL);
646         return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
649 /*
650  * This routine is for closing the socket if a virtual circuit is used and
651  * the program wants to close it.  This provides support for endhostent()
652  * which expects to close the socket.
653  *
654  * This routine is not expected to be user visible.
655  */
656 void
657 res_nclose(res_state statp) {
658         int ns;
660         if (statp->_vcsock >= 0) {
661                 (void) close(statp->_vcsock);
662                 statp->_vcsock = -1;
663                 statp->_flags &= ~(RES_F_VC | RES_F_CONN);
664         }
665         for (ns = 0; ns < statp->_u._ext.nscount; ns++) {
666                 if (statp->_u._ext.nssocks[ns] != -1) {
667                         (void) close(statp->_u._ext.nssocks[ns]);
668                         statp->_u._ext.nssocks[ns] = -1;
669                 }
670         }
673 void
674 res_ndestroy(res_state statp) {
675         res_nclose(statp);
676         if (statp->_u._ext.ext != NULL)
677                 free(statp->_u._ext.ext);
678         statp->options &= ~RES_INIT;
679         statp->_u._ext.ext = NULL;
682 const char *
683 res_get_nibblesuffix(res_state statp) {
684         if (statp->_u._ext.ext)
685                 return (statp->_u._ext.ext->nsuffix);
686         return ("ip6.arpa");
689 const char *
690 res_get_nibblesuffix2(res_state statp) {
691         if (statp->_u._ext.ext)
692                 return (statp->_u._ext.ext->nsuffix2);
693         return ("ip6.int");
696 void
697 res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
698         int i, nserv;
699         size_t size;
701         /* close open servers */
702         res_nclose(statp);
704         /* cause rtt times to be forgotten */
705         statp->_u._ext.nscount = 0;
707         nserv = 0;
708         for (i = 0; i < cnt && nserv < MAXNS; i++) {
709                 switch (set->sin.sin_family) {
710                 case AF_INET:
711                         size = sizeof(set->sin);
712                         if (statp->_u._ext.ext)
713                                 memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
714                                         &set->sin, size);
715                         if (size <= sizeof(statp->nsaddr_list[nserv]))
716                                 memcpy(&statp->nsaddr_list[nserv],
717                                         &set->sin, size);
718 #ifdef notdef
719                         else
720                                 statp->nsaddr_list[nserv].sin_family = 0;
721 #endif
722                         nserv++;
723                         break;
725 #ifdef HAS_INET6_STRUCTS
726                 case AF_INET6:
727                         size = sizeof(set->sin6);
728                         if (statp->_u._ext.ext)
729                                 memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
730                                         &set->sin6, size);
731                         if (size <= sizeof(statp->nsaddr_list[nserv]))
732                                 memcpy(&statp->nsaddr_list[nserv],
733                                         &set->sin6, size);
734                         else
735                                 statp->nsaddr_list[nserv].sin_family = 0;
736                         nserv++;
737                         break;
738 #endif
740                 default:
741                         break;
742                 }
743                 set++;
744         }
745         statp->nscount = nserv;
749 int
750 res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) {
751         int i;
752         size_t size;
753         u_int16_t family;
755         for (i = 0; i < statp->nscount && i < cnt; i++) {
756                 if (statp->_u._ext.ext)
757                         family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family;
758                 else
759                         family = statp->nsaddr_list[i].sin_family;
761                 switch (family) {
762                 case AF_INET:
763                         size = sizeof(set->sin);
764                         if (statp->_u._ext.ext)
765                                 memcpy(&set->sin,
766                                        &statp->_u._ext.ext->nsaddrs[i],
767                                        size);
768                         else
769                                 memcpy(&set->sin, &statp->nsaddr_list[i],
770                                        size);
771                         break;
773 #ifdef HAS_INET6_STRUCTS
774                 case AF_INET6:
775                         size = sizeof(set->sin6);
776                         if (statp->_u._ext.ext)
777                                 memcpy(&set->sin6,
778                                        &statp->_u._ext.ext->nsaddrs[i],
779                                        size);
780                         else
781                                 memcpy(&set->sin6, &statp->nsaddr_list[i],
782                                        size);
783                         break;
784 #endif
786                 default:
787                         set->sin.sin_family = 0;
788                         break;
789                 }
790                 set++;
791         }
792         return (statp->nscount);
795 #ifdef ANDROID_CHANGES
796 void res_setiface(res_state statp, const char* iface)
798         if (statp != NULL) {
799                 // set interface
800                 if (iface && iface[0] != '\0') {
801                         int len = sizeof(statp->iface);
802                         strncpy(statp->iface, iface, len - 1);
803                         statp->iface[len - 1] = '\0';
804                 } else {
805                         statp->iface[0] = '\0';
806                 }
807         }
810 void res_setmark(res_state statp, int mark)
812         if (statp != NULL) {
813                 statp->_mark = mark;
814         }
816 #endif /* ANDROID_CHANGES */