Sat Jun 15 18:13:43 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
[kopensolaris-gnu/glibc.git] / resolv / res_init.c
1 /*
2  * ++Copyright++ 1985, 1989, 1993
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  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
36  *
37  * Permission to use, copy, modify, and distribute this software for any
38  * purpose with or without fee is hereby granted, provided that the above
39  * copyright notice and this permission notice appear in all copies, and that
40  * the name of Digital Equipment Corporation not be used in advertising or
41  * publicity pertaining to distribution of the document or software without
42  * specific, written prior permission.
43  *
44  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
47  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51  * SOFTWARE.
52  * -
53  * --Copyright--
54  */
55
56 #if defined(LIBC_SCCS) && !defined(lint)
57 static char sccsid[] = "@(#)res_init.c  8.1 (Berkeley) 6/7/93";
58 static char rcsid[] = "$Id$";
59 #endif /* LIBC_SCCS and not lint */
60
61 #include <sys/param.h>
62 #include <sys/socket.h>
63 #include <sys/time.h>
64 #include <netinet/in.h>
65 #include <arpa/inet.h>
66 #include <arpa/nameser.h>
67
68 #include <stdio.h>
69 #include <ctype.h>
70 #include <resolv.h>
71 #if defined(BSD) && (BSD >= 199103)
72 # include <unistd.h>
73 # include <stdlib.h>
74 # include <string.h>
75 #else
76 # include "../conf/portability.h"
77 #endif
78
79 #include "res_hconf.h"
80
81 /*-------------------------------------- info about "sortlist" --------------
82  * Marc Majka           1994/04/16
83  * Allan Nathanson      1994/10/29 (BIND 4.9.3.x)
84  *
85  * NetInfo resolver configuration directory support.
86  *
87  * Allow a NetInfo directory to be created in the hierarchy which
88  * contains the same information as the resolver configuration file.
89  *
90  * - The local domain name is stored as the value of the "domain" property.
91  * - The Internet address(es) of the name server(s) are stored as values
92  *   of the "nameserver" property.
93  * - The name server addresses are stored as values of the "nameserver"
94  *   property.
95  * - The search list for host-name lookup is stored as values of the
96  *   "search" property.
97  * - The sortlist comprised of IP address netmask pairs are stored as
98  *   values of the "sortlist" property. The IP address and optional netmask
99  *   should be seperated by a slash (/) or ampersand (&) character.
100  * - Internal resolver variables can be set from the value of the "options"
101  *   property.
102  */
103 #if defined(NeXT)
104 #  include <netinfo/ni.h>
105 #  define NI_PATH_RESCONF "/locations/resolver"
106 #  define NI_TIMEOUT 10
107 static int netinfo_res_init __P((int *haveenv, int *havesearch));
108 #endif
109
110 #if defined(USE_OPTIONS_H)
111 # include "../conf/options.h"
112 #endif
113
114 static void res_setoptions __P((char *, char *));
115
116 #ifdef RESOLVSORT
117 static const char sort_mask[] = "/&";
118 #define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
119 static u_int32_t net_mask __P((struct in_addr));
120 #endif
121
122 #if !defined(isascii)   /* XXX - could be a function */
123 # define isascii(c) (!(c & 0200))
124 #endif
125
126 /*
127  * Resolver state default settings.
128  */
129
130 struct __res_state _res;
131
132 /*
133  * Set up default settings.  If the configuration file exist, the values
134  * there will have precedence.  Otherwise, the server address is set to
135  * INADDR_ANY and the default domain name comes from the gethostname().
136  *
137  * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
138  * rather than INADDR_ANY ("0.0.0.0") as the default name server address
139  * since it was noted that INADDR_ANY actually meant ``the first interface
140  * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
141  * it had to be "up" in order for you to reach your own name server.  It
142  * was later decided that since the recommended practice is to always
143  * install local static routes through 127.0.0.1 for all your network
144  * interfaces, that we could solve this problem without a code change.
145  *
146  * The configuration file should always be used, since it is the only way
147  * to specify a default domain.  If you are running a server on your local
148  * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
149  * in the configuration file.
150  *
151  * Return 0 if completes successfully, -1 on error
152  */
153 int
154 res_init()
155 {
156         register FILE *fp;
157         register char *cp, **pp;
158         register int n;
159         char buf[BUFSIZ];
160         int nserv = 0;    /* number of nameserver records read from file */
161         int haveenv = 0;
162         int havesearch = 0;
163 #ifdef RESOLVSORT
164         int nsort = 0;
165         char *net;
166 #endif
167 #ifndef RFC1535
168         int dots;
169 #endif
170
171         /*
172          * These three fields used to be statically initialized.  This made
173          * it hard to use this code in a shared library.  It is necessary,
174          * now that we're doing dynamic initialization here, that we preserve
175          * the old semantics: if an application modifies one of these three
176          * fields of _res before res_init() is called, res_init() will not
177          * alter them.  Of course, if an application is setting them to
178          * _zero_ before calling res_init(), hoping to override what used
179          * to be the static default, we can't detect it and unexpected results
180          * will follow.  Zero for any of these fields would make no sense,
181          * so one can safely assume that the applications were already getting
182          * unexpected results.
183          *
184          * _res.options is tricky since some apps were known to diddle the bits
185          * before res_init() was first called. We can't replicate that semantic
186          * with dynamic initialization (they may have turned bits off that are
187          * set in RES_DEFAULT).  Our solution is to declare such applications
188          * "broken".  They could fool us by setting RES_INIT but none do (yet).
189          */
190         if (!_res.retrans)
191                 _res.retrans = RES_TIMEOUT;
192         if (!_res.retry)
193                 _res.retry = 4;
194         if (!(_res.options & RES_INIT))
195                 _res.options = RES_DEFAULT;
196
197         /*
198          * This one used to initialize implicitly to zero, so unless the app
199          * has set it to something in particular, we can randomize it now.
200          */
201         if (!_res.id)
202                 _res.id = res_randomid();
203
204 #ifdef USELOOPBACK
205         _res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
206 #else
207         _res.nsaddr.sin_addr.s_addr = INADDR_ANY;
208 #endif
209         _res.nsaddr.sin_family = AF_INET;
210         _res.nsaddr.sin_port = htons(NAMESERVER_PORT);
211         _res.nscount = 1;
212         _res.ndots = 1;
213         _res.pfcode = 0;
214
215         /* Allow user to override the local domain definition */
216         if ((cp = getenv("LOCALDOMAIN")) != NULL) {
217                 (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
218                 haveenv++;
219
220                 /*
221                  * Set search list to be blank-separated strings
222                  * from rest of env value.  Permits users of LOCALDOMAIN
223                  * to still have a search list, and anyone to set the
224                  * one that they want to use as an individual (even more
225                  * important now that the rfc1535 stuff restricts searches)
226                  */
227                 cp = _res.defdname;
228                 pp = _res.dnsrch;
229                 *pp++ = cp;
230                 for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
231                         if (*cp == '\n')        /* silly backwards compat */
232                                 break;
233                         else if (*cp == ' ' || *cp == '\t') {
234                                 *cp = 0;
235                                 n = 1;
236                         } else if (n) {
237                                 *pp++ = cp;
238                                 n = 0;
239                                 havesearch = 1;
240                         }
241                 }
242                 /* null terminate last domain if there are excess */
243                 while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
244                         cp++;
245                 *cp = '\0';
246                 *pp++ = 0;
247         }
248
249 #define MATCH(line, name) \
250         (!strncmp(line, name, sizeof(name) - 1) && \
251         (line[sizeof(name) - 1] == ' ' || \
252          line[sizeof(name) - 1] == '\t'))
253
254 #ifdef  NeXT
255         if (netinfo_res_init(&haveenv, &havesearch) == 0)
256 #endif
257         if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
258             /* read the config file */
259             while (fgets(buf, sizeof(buf), fp) != NULL) {
260                 /* skip comments */
261                 if (*buf == ';' || *buf == '#')
262                         continue;
263                 /* read default domain name */
264                 if (MATCH(buf, "domain")) {
265                     if (haveenv)        /* skip if have from environ */
266                             continue;
267                     cp = buf + sizeof("domain") - 1;
268                     while (*cp == ' ' || *cp == '\t')
269                             cp++;
270                     if ((*cp == '\0') || (*cp == '\n'))
271                             continue;
272                     strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
273                     if ((cp = strpbrk(_res.defdname, " \t\n")) != NULL)
274                             *cp = '\0';
275                     havesearch = 0;
276                     continue;
277                 }
278                 /* set search list */
279                 if (MATCH(buf, "search")) {
280                     if (haveenv)        /* skip if have from environ */
281                             continue;
282                     cp = buf + sizeof("search") - 1;
283                     while (*cp == ' ' || *cp == '\t')
284                             cp++;
285                     if ((*cp == '\0') || (*cp == '\n'))
286                             continue;
287                     strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
288                     if ((cp = strchr(_res.defdname, '\n')) != NULL)
289                             *cp = '\0';
290                     /*
291                      * Set search list to be blank-separated strings
292                      * on rest of line.
293                      */
294                     cp = _res.defdname;
295                     pp = _res.dnsrch;
296                     *pp++ = cp;
297                     for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
298                             if (*cp == ' ' || *cp == '\t') {
299                                     *cp = 0;
300                                     n = 1;
301                             } else if (n) {
302                                     *pp++ = cp;
303                                     n = 0;
304                             }
305                     }
306                     /* null terminate last domain if there are excess */
307                     while (*cp != '\0' && *cp != ' ' && *cp != '\t')
308                             cp++;
309                     *cp = '\0';
310                     *pp++ = 0;
311                     havesearch = 1;
312                     continue;
313                 }
314                 /* read nameservers to query */
315                 if (MATCH(buf, "nameserver") && nserv < MAXNS) {
316                     struct in_addr a;
317
318                     cp = buf + sizeof("nameserver") - 1;
319                     while (*cp == ' ' || *cp == '\t')
320                         cp++;
321                     if ((*cp != '\0') && (*cp != '\n') && inet_aton(cp, &a)) {
322                         _res.nsaddr_list[nserv].sin_addr = a;
323                         _res.nsaddr_list[nserv].sin_family = AF_INET;
324                         _res.nsaddr_list[nserv].sin_port =
325                                 htons(NAMESERVER_PORT);
326                         nserv++;
327                     }
328                     continue;
329                 }
330 #ifdef RESOLVSORT
331                 if (MATCH(buf, "sortlist")) {
332                     struct in_addr a;
333
334                     cp = buf + sizeof("sortlist") - 1;
335                     while (nsort < MAXRESOLVSORT) {
336                         while (*cp == ' ' || *cp == '\t')
337                             cp++;
338                         if (*cp == '\0' || *cp == '\n' || *cp == ';')
339                             break;
340                         net = cp;
341                         while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
342                                isascii(*cp) && !isspace(*cp))
343                                 cp++;
344                         n = *cp;
345                         *cp = 0;
346                         if (inet_aton(net, &a)) {
347                             _res.sort_list[nsort].addr = a;
348                             if (ISSORTMASK(n)) {
349                                 *cp++ = n;
350                                 net = cp;
351                                 while (*cp && *cp != ';' &&
352                                         isascii(*cp) && !isspace(*cp))
353                                     cp++;
354                                 n = *cp;
355                                 *cp = 0;
356                                 if (inet_aton(net, &a)) {
357                                     _res.sort_list[nsort].mask = a.s_addr;
358                                 } else {
359                                     _res.sort_list[nsort].mask =
360                                         net_mask(_res.sort_list[nsort].addr);
361                                 }
362                             } else {
363                                 _res.sort_list[nsort].mask =
364                                     net_mask(_res.sort_list[nsort].addr);
365                             }
366                             nsort++;
367                         }
368                         *cp = n;
369                     }
370                     continue;
371                 }
372 #endif
373                 if (MATCH(buf, "options")) {
374                     res_setoptions(buf + sizeof("options") - 1, "conf");
375                     continue;
376                 }
377             }
378             if (nserv > 1)
379                 _res.nscount = nserv;
380 #ifdef RESOLVSORT
381             _res.nsort = nsort;
382 #endif
383             (void) fclose(fp);
384         }
385         if (_res.defdname[0] == 0 &&
386             gethostname(buf, sizeof(_res.defdname) - 1) == 0 &&
387             (cp = strchr(buf, '.')) != NULL)
388                 strcpy(_res.defdname, cp + 1);
389
390         /* find components of local domain that might be searched */
391         if (havesearch == 0) {
392                 pp = _res.dnsrch;
393                 *pp++ = _res.defdname;
394                 *pp = NULL;
395
396 #ifndef RFC1535
397                 dots = 0;
398                 for (cp = _res.defdname; *cp; cp++)
399                         dots += (*cp == '.');
400
401                 cp = _res.defdname;
402                 while (pp < _res.dnsrch + MAXDFLSRCH) {
403                         if (dots < LOCALDOMAINPARTS)
404                                 break;
405                         cp = strchr(cp, '.') + 1;    /* we know there is one */
406                         *pp++ = cp;
407                         dots--;
408                 }
409                 *pp = NULL;
410 #ifdef DEBUG
411                 if (_res.options & RES_DEBUG) {
412                         printf(";; res_init()... default dnsrch list:\n");
413                         for (pp = _res.dnsrch; *pp; pp++)
414                                 printf(";;\t%s\n", *pp);
415                         printf(";;\t..END..\n");
416                 }
417 #endif /* DEBUG */
418 #endif /* !RFC1535 */
419         }
420
421         if ((cp = getenv("RES_OPTIONS")) != NULL)
422                 res_setoptions(cp, "env");
423         _res.options |= RES_INIT;
424
425         _res_hconf_init ();
426         return (0);
427 }
428
429 static void
430 res_setoptions(options, source)
431         char *options, *source;
432 {
433         char *cp = options;
434         int i;
435
436 #ifdef DEBUG
437         if (_res.options & RES_DEBUG)
438                 printf(";; res_setoptions(\"%s\", \"%s\")...\n",
439                        options, source);
440 #endif
441         while (*cp) {
442                 /* skip leading and inner runs of spaces */
443                 while (*cp == ' ' || *cp == '\t')
444                         cp++;
445                 /* search for and process individual options */
446                 if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
447                         i = atoi(cp + sizeof("ndots:") - 1);
448                         if (i <= RES_MAXNDOTS)
449                                 _res.ndots = i;
450                         else
451                                 _res.ndots = RES_MAXNDOTS;
452 #ifdef DEBUG
453                         if (_res.options & RES_DEBUG)
454                                 printf(";;\tndots=%d\n", _res.ndots);
455 #endif
456                 } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
457 #ifdef DEBUG
458                         if (!(_res.options & RES_DEBUG)) {
459                                 printf(";; res_setoptions(\"%s\", \"%s\")..\n",
460                                        options, source);
461                                 _res.options |= RES_DEBUG;
462                         }
463                         printf(";;\tdebug\n");
464 #endif
465                 } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
466                         _res.options |= RES_USE_INET6;
467                 } else {
468                         /* XXX - print a warning here? */
469                 }
470                 /* skip to next run of spaces */
471                 while (*cp && *cp != ' ' && *cp != '\t')
472                         cp++;
473         }
474 }
475
476 #ifdef RESOLVSORT
477 /* XXX - should really support CIDR which means explicit masks always. */
478 static u_int32_t
479 net_mask(in)            /* XXX - should really use system's version of this */
480         struct in_addr in;
481 {
482         register u_int32_t i = ntohl(in.s_addr);
483
484         if (IN_CLASSA(i))
485                 return (htonl(IN_CLASSA_NET));
486         else if (IN_CLASSB(i))
487                 return (htonl(IN_CLASSB_NET));
488         return (htonl(IN_CLASSC_NET));
489 }
490 #endif
491
492 #ifdef  NeXT
493 static int
494 netinfo_res_init(haveenv, havesearch)
495         int *haveenv;
496         int *havesearch;
497 {
498     register    int n;
499     void        *domain, *parent;
500     ni_id       dir;
501     ni_status   status;
502     ni_namelist nl;
503     int         nserv = 0;
504 #ifdef RESOLVSORT
505     int         nsort = 0;
506 #endif
507
508     status = ni_open(NULL, ".", &domain);
509     if (status == NI_OK) {
510         ni_setreadtimeout(domain, NI_TIMEOUT);
511         ni_setabort(domain, 1);
512
513         /* climb the NetInfo hierarchy to find a resolver directory */
514         while (status == NI_OK) {
515             status = ni_pathsearch(domain, &dir, NI_PATH_RESCONF);
516             if (status == NI_OK) {
517             /* found a resolver directory */
518
519                 if (*haveenv == 0) {
520                     /* get the default domain name */
521                     status = ni_lookupprop(domain, &dir, "domain", &nl);
522                     if (status == NI_OK && nl.ni_namelist_len > 0) {
523                         (void)strncpy(_res.defdname,
524                                       nl.ni_namelist_val[0],
525                                       sizeof(_res.defdname) - 1);
526                         _res.defdname[sizeof(_res.defdname) - 1] = '\0';
527                         ni_namelist_free(&nl);
528                         *havesearch = 0;
529                     }
530
531                     /* get search list */
532                     status = ni_lookupprop(domain, &dir, "search", &nl);
533                     if (status == NI_OK && nl.ni_namelist_len > 0) {
534                         (void)strncpy(_res.defdname,
535                                       nl.ni_namelist_val[0],
536                                       sizeof(_res.defdname) - 1);
537                         _res.defdname[sizeof(_res.defdname) - 1] = '\0';
538                         /* copy  */
539                         for (n = 0;
540                              n < nl.ni_namelist_len && n < MAXDNSRCH;
541                              n++) {
542                              /* duplicate up to MAXDNSRCH servers */
543                              char *cp = nl.ni_namelist_val[n];
544                             _res.dnsrch[n] =
545                                 strcpy((char *)malloc(strlen(cp) + 1), cp);
546                         }
547                         ni_namelist_free(&nl);
548                         *havesearch = 1;
549                     }
550                 }
551
552                 /* get list of nameservers */
553                 status = ni_lookupprop(domain, &dir, "nameserver", &nl);
554                 if (status == NI_OK && nl.ni_namelist_len > 0) {
555                     /* copy up to MAXNS servers */
556                     for (n = 0;
557                          n < nl.ni_namelist_len && nserv < MAXNS;
558                          n++) {
559                         struct in_addr a;
560
561                         if (inet_aton(nl.ni_namelist_val[n], &a)) {
562                             _res.nsaddr_list[nserv].sin_addr = a;
563                             _res.nsaddr_list[nserv].sin_family = AF_INET;
564                             _res.nsaddr_list[nserv].sin_port =
565                                 htons(NAMESERVER_PORT);
566                             nserv++;
567                         }
568                     }
569                     ni_namelist_free(&nl);
570                 }
571
572                 if (nserv > 1)
573                     _res.nscount = nserv;
574
575 #ifdef RESOLVSORT
576                 /* get sort order */
577                 status = ni_lookupprop(domain, &dir, "sortlist", &nl);
578                 if (status == NI_OK && nl.ni_namelist_len > 0) {
579
580                     /* copy up to MAXRESOLVSORT address/netmask pairs */
581                     for (n = 0;
582                          n < nl.ni_namelist_len && nsort < MAXRESOLVSORT;
583                          n++) {
584                         char ch;
585                         char *cp;
586                         const char *sp;
587                         struct in_addr a;
588
589                         cp = NULL;
590                         for (sp = sort_mask; *sp; sp++) {
591                                 char *cp1;
592                                 cp1 = strchr(nl.ni_namelist_val[n], *sp);
593                                 if (cp && cp1)
594                                         cp = (cp < cp1)? cp : cp1;
595                                 else if (cp1)
596                                         cp = cp1;
597                         }
598                         if (cp != NULL) {
599                                 ch = *cp;
600                                 *cp = '\0';
601                                 break;
602                         }
603                         if (inet_aton(nl.ni_namelist_val[n], &a)) {
604                             _res.sort_list[nsort].addr = a;
605                             if (*cp && ISSORTMASK(ch)) {
606                                 *cp++ = ch;
607                                 if (inet_aton(cp, &a)) {
608                                     _res.sort_list[nsort].mask = a.s_addr;
609                                 } else {
610                                     _res.sort_list[nsort].mask =
611                                         net_mask(_res.sort_list[nsort].addr);
612                                 }
613                             } else {
614                                 _res.sort_list[nsort].mask =
615                                     net_mask(_res.sort_list[nsort].addr);
616                             }
617                             nsort++;
618                         }
619                     }
620                     ni_namelist_free(&nl);
621                 }
622
623                 _res.nsort = nsort;
624 #endif
625
626                 /* get resolver options */
627                 status = ni_lookupprop(domain, &dir, "options", &nl);
628                 if (status == NI_OK && nl.ni_namelist_len > 0) {
629                     res_setoptions(nl.ni_namelist_val[0], "conf");
630                     ni_namelist_free(&nl);
631                 }
632
633                 ni_free(domain);
634                 return(1);      /* using DNS configuration from NetInfo */
635             }
636
637             status = ni_open(domain, "..", &parent);
638             ni_free(domain);
639             if (status == NI_OK)
640                 domain = parent;
641         }
642     }
643     return(0);  /* if not using DNS configuration from NetInfo */
644 }
645 #endif  /* NeXT */
646
647 u_int16_t
648 res_randomid()
649 {
650         struct timeval now;
651
652         gettimeofday(&now, NULL);
653         return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
654 }