]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/net/res_init.c
This commit was generated by cvs2svn to compensate for changes in r140801,
[FreeBSD/FreeBSD.git] / lib / libc / net / res_init.c
1 /*
2  * Copyright (c) 1985, 1989, 1993
3  *    The Regents of the University of California.  All rights reserved.
4  * 
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
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
54 /*
55  * Portions Copyright (c) 1996 by Internet Software Consortium.
56  *
57  * Permission to use, copy, modify, and distribute this software for any
58  * purpose with or without fee is hereby granted, provided that the above
59  * copyright notice and this permission notice appear in all copies.
60  *
61  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
62  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
63  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
64  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
65  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
66  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
67  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
68  * SOFTWARE.
69  */
70
71 #if defined(LIBC_SCCS) && !defined(lint)
72 static char sccsid[] = "@(#)res_init.c  8.1 (Berkeley) 6/7/93";
73 static char orig_rcsid[] = "From: Id: res_init.c,v 8.7 1996/11/18 09:10:04 vixie Exp $";
74 #endif /* LIBC_SCCS and not lint */
75 #include <sys/cdefs.h>
76 __FBSDID("$FreeBSD$");
77
78 #include <sys/types.h>
79 #include <sys/param.h>
80 #include <sys/socket.h>
81 #include <sys/time.h>
82 #include <netinet/in.h>
83 #include <arpa/inet.h>
84 #include <arpa/nameser.h>
85 #include <ctype.h>
86 #include <limits.h>
87 #include <resolv.h>
88 #include <stdio.h>
89 #include <stdlib.h>
90 #include <string.h>
91 #include <unistd.h>
92 #include <netdb.h>
93
94 #include "namespace.h"
95 #include "reentrant.h"
96 #include "un-namespace.h"
97 #include "res_config.h"
98 #include "res_send_private.h"
99
100 #undef h_errno
101 extern int h_errno;
102
103 static void res_setoptions(char *, char *);
104
105 #ifdef RESOLVSORT
106 static const char sort_mask[] = "/&";
107 #define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
108 static u_int32_t net_mask(struct in_addr);
109 #endif
110
111 #if !defined(isascii) /* XXX - could be a function */
112 # define isascii(c) (!(c & 0200))
113 #endif
114
115 /*
116  * Check structure for failed per-thread allocations.
117  */
118 static struct res_per_thread {
119         struct __res_state res_state;
120         struct __res_state_ext res_state_ext;
121         struct __res_send_private res_send_private;
122         int h_errno;
123 } _res_per_thread_bogus = { .res_send_private = { .s = -1 } }; /* socket */
124
125 /*
126  * Set up default settings.  If the configuration file exist, the values
127  * there will have precedence.  Otherwise, the server address is set to
128  * INADDR_ANY and the default domain name comes from the gethostname().
129  *
130  * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
131  * rather than INADDR_ANY ("0.0.0.0") as the default name server address
132  * since it was noted that INADDR_ANY actually meant ``the first interface
133  * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
134  * it had to be "up" in order for you to reach your own name server.  It
135  * was later decided that since the recommended practice is to always 
136  * install local static routes through 127.0.0.1 for all your network
137  * interfaces, that we could solve this problem without a code change.
138  *
139  * The configuration file should always be used, since it is the only way
140  * to specify a default domain.  If you are running a server on your local
141  * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
142  * in the configuration file.
143  *
144  * Return 0 if completes successfully, -1 on error
145  */
146 int
147 res_init()
148 {
149         FILE *fp;
150         struct __res_send_private *rsp;
151         char *cp, **pp;
152         int n;
153         char buf[MAXDNAME];
154         int nserv = 0;    /* number of nameserver records read from file */
155         int haveenv = 0;
156         int havesearch = 0;
157 #ifdef RESOLVSORT
158         int nsort = 0;
159         char *net;
160 #endif
161 #ifndef RFC1535
162         int dots;
163 #endif
164
165         /*
166          * If allocation of memory for this thread's resolver has failed,
167          * return the error to the user.
168          */
169         if (&_res == &_res_per_thread_bogus.res_state)
170                 return (-1);
171         rsp = ___res_send_private();
172         rsp->s = -1;
173         rsp->connected = 0;
174         rsp->vc = 0;
175         rsp->af = 0;
176         rsp->Qhook = NULL;
177         rsp->Rhook = NULL;
178         /*
179          * These three fields used to be statically initialized.  This made
180          * it hard to use this code in a shared library.  It is necessary,
181          * now that we're doing dynamic initialization here, that we preserve
182          * the old semantics: if an application modifies one of these three
183          * fields of _res before res_init() is called, res_init() will not
184          * alter them.  Of course, if an application is setting them to
185          * _zero_ before calling res_init(), hoping to override what used
186          * to be the static default, we can't detect it and unexpected results
187          * will follow.  Zero for any of these fields would make no sense,
188          * so one can safely assume that the applications were already getting
189          * unexpected results.
190          *
191          * _res.options is tricky since some apps were known to diddle the bits
192          * before res_init() was first called. We can't replicate that semantic
193          * with dynamic initialization (they may have turned bits off that are
194          * set in RES_DEFAULT).  Our solution is to declare such applications
195          * "broken".  They could fool us by setting RES_INIT but none do (yet).
196          */
197         if (!_res.retrans)
198                 _res.retrans = RES_TIMEOUT;
199         if (!_res.retry)
200                 _res.retry = RES_DFLRETRY;
201         if (!(_res.options & RES_INIT))
202                 _res.options = RES_DEFAULT;
203
204         /*
205          * This one used to initialize implicitly to zero, so unless the app
206          * has set it to something in particular, we can randomize it now.
207          */
208         if (!_res.id)
209                 _res.id = res_randomid();
210
211 #ifdef USELOOPBACK
212         _res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
213 #else
214         _res.nsaddr.sin_addr.s_addr = INADDR_ANY;
215 #endif
216         _res.nsaddr.sin_family = AF_INET;
217         _res.nsaddr.sin_port = htons(NAMESERVER_PORT);
218         _res.nsaddr.sin_len = sizeof(struct sockaddr_in);
219         if (sizeof(_res_ext.nsaddr) >= _res.nsaddr.sin_len)
220                 memcpy(&_res_ext.nsaddr, &_res.nsaddr, _res.nsaddr.sin_len);
221         _res.nscount = 1;
222         _res.ndots = 1;
223         _res.pfcode = 0;
224
225         /* Allow user to override the local domain definition */
226         if (issetugid() == 0 && (cp = getenv("LOCALDOMAIN")) != NULL) {
227                 (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
228                 _res.defdname[sizeof(_res.defdname) - 1] = '\0';
229                 haveenv++;
230
231                 /*
232                  * Set search list to be blank-separated strings
233                  * from rest of env value.  Permits users of LOCALDOMAIN
234                  * to still have a search list, and anyone to set the
235                  * one that they want to use as an individual (even more
236                  * important now that the rfc1535 stuff restricts searches)
237                  */
238                 cp = _res.defdname;
239                 pp = _res.dnsrch;
240                 *pp++ = cp;
241                 for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
242                         if (*cp == '\n')        /* silly backwards compat */
243                                 break;
244                         else if (*cp == ' ' || *cp == '\t') {
245                                 *cp = 0;
246                                 n = 1;
247                         } else if (n) {
248                                 *pp++ = cp;
249                                 n = 0;
250                                 havesearch = 1;
251                         }
252                 }
253                 /* null terminate last domain if there are excess */
254                 while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
255                         cp++;
256                 *cp = '\0';
257                 *pp++ = 0;
258         }
259
260 #define MATCH(line, name) \
261         (!strncmp(line, name, sizeof(name) - 1) && \
262         (line[sizeof(name) - 1] == ' ' || \
263          line[sizeof(name) - 1] == '\t'))
264
265         if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
266             /* read the config file */
267             while (fgets(buf, sizeof(buf), fp) != NULL) {
268                 /* skip comments */
269                 if (*buf == ';' || *buf == '#')
270                         continue;
271                 /* read default domain name */
272                 if (MATCH(buf, "domain")) {
273                     if (haveenv)        /* skip if have from environ */
274                             continue;
275                     cp = buf + sizeof("domain") - 1;
276                     while (*cp == ' ' || *cp == '\t')
277                             cp++;
278                     if ((*cp == '\0') || (*cp == '\n'))
279                             continue;
280                     strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
281                     _res.defdname[sizeof(_res.defdname) - 1] = '\0';
282                     if ((cp = strpbrk(_res.defdname, " \t\n")) != NULL)
283                             *cp = '\0';
284                     havesearch = 0;
285                     continue;
286                 }
287                 /* set search list */
288                 if (MATCH(buf, "search")) {
289                     if (haveenv)        /* skip if have from environ */
290                             continue;
291                     cp = buf + sizeof("search") - 1;
292                     while (*cp == ' ' || *cp == '\t')
293                             cp++;
294                     if ((*cp == '\0') || (*cp == '\n'))
295                             continue;
296                     strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
297                     _res.defdname[sizeof(_res.defdname) - 1] = '\0';
298                     if ((cp = strchr(_res.defdname, '\n')) != NULL)
299                             *cp = '\0';
300                     /*
301                      * Set search list to be blank-separated strings
302                      * on rest of line.
303                      */
304                     cp = _res.defdname;
305                     pp = _res.dnsrch;
306                     *pp++ = cp;
307                     for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
308                             if (*cp == ' ' || *cp == '\t') {
309                                     *cp = 0;
310                                     n = 1;
311                             } else if (n) {
312                                     *pp++ = cp;
313                                     n = 0;
314                             }
315                     }
316                     /* null terminate last domain if there are excess */
317                     while (*cp != '\0' && *cp != ' ' && *cp != '\t')
318                             cp++;
319                     *cp = '\0';
320                     *pp++ = 0;
321                     havesearch = 1;
322                     continue;
323                 }
324                 /* read nameservers to query */
325                 if (MATCH(buf, "nameserver") && nserv < MAXNS) {
326                     char *q;
327                     struct addrinfo hints, *res;
328                     char pbuf[NI_MAXSERV];
329
330                     cp = buf + sizeof("nameserver") - 1;
331                     while (*cp == ' ' || *cp == '\t')
332                         cp++;
333                     if ((*cp == '\0') || (*cp == '\n'))
334                         continue;
335                     for (q = cp; *q; q++) {
336                         if (isspace(*q)) {
337                             *q = '\0';
338                             break;
339                         }
340                     }
341                     memset(&hints, 0, sizeof(hints));
342                     hints.ai_flags = AI_NUMERICHOST;
343                     hints.ai_socktype = SOCK_DGRAM;
344                     snprintf(pbuf, sizeof(pbuf), "%d", NAMESERVER_PORT);
345                     if (getaddrinfo(cp, pbuf, &hints, &res) == 0 &&
346                             res->ai_next == NULL) {
347                         if (res->ai_addrlen <= sizeof(_res_ext.nsaddr_list[nserv])) {
348                             memcpy(&_res_ext.nsaddr_list[nserv], res->ai_addr,
349                                 res->ai_addrlen);
350                         } else {
351                             memset(&_res_ext.nsaddr_list[nserv], 0,
352                                 sizeof(_res_ext.nsaddr_list[nserv]));
353                         }
354                         if (res->ai_addrlen <= sizeof(_res.nsaddr_list[nserv])) {
355                             memcpy(&_res.nsaddr_list[nserv], res->ai_addr,
356                                 res->ai_addrlen);
357                         } else {
358                             memset(&_res.nsaddr_list[nserv], 0,
359                                 sizeof(_res.nsaddr_list[nserv]));
360                         }
361                         nserv++;
362                     }
363                     if (res)
364                             freeaddrinfo(res);
365                     continue;
366                 }
367 #ifdef RESOLVSORT
368                 if (MATCH(buf, "sortlist")) {
369                     struct in_addr a;
370                     struct in6_addr a6;
371                     int m, i;
372                     u_char *u;
373
374                     cp = buf + sizeof("sortlist") - 1;
375                     while (nsort < MAXRESOLVSORT) {
376                         while (*cp == ' ' || *cp == '\t')
377                             cp++;
378                         if (*cp == '\0' || *cp == '\n' || *cp == ';')
379                             break;
380                         net = cp;
381                         while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
382                                isascii(*cp) && !isspace(*cp))
383                                 cp++;
384                         n = *cp;
385                         *cp = 0;
386                         if (inet_aton(net, &a)) {
387                             _res.sort_list[nsort].addr = a;
388                             if (ISSORTMASK(n)) {
389                                 *cp++ = n;
390                                 net = cp;
391                                 while (*cp && *cp != ';' &&
392                                         isascii(*cp) && !isspace(*cp))
393                                     cp++;
394                                 n = *cp;
395                                 *cp = 0;
396                                 if (inet_aton(net, &a)) {
397                                     _res.sort_list[nsort].mask = a.s_addr;
398                                 } else {
399                                     _res.sort_list[nsort].mask = 
400                                         net_mask(_res.sort_list[nsort].addr);
401                                 }
402                             } else {
403                                 _res.sort_list[nsort].mask = 
404                                     net_mask(_res.sort_list[nsort].addr);
405                             }
406                             _res_ext.sort_list[nsort].af = AF_INET;
407                             _res_ext.sort_list[nsort].addr.ina =
408                                 _res.sort_list[nsort].addr;
409                             _res_ext.sort_list[nsort].mask.ina.s_addr =
410                                 _res.sort_list[nsort].mask;
411                             nsort++;
412                         }
413                         else if (inet_pton(AF_INET6, net, &a6) == 1) {
414
415                             _res_ext.sort_list[nsort].af = AF_INET6;
416                             _res_ext.sort_list[nsort].addr.in6a = a6;
417                             u = (u_char *)&_res_ext.sort_list[nsort].mask.in6a;
418                             *cp++ = n;
419                             net = cp;
420                             while (*cp && *cp != ';' &&
421                                     isascii(*cp) && !isspace(*cp))
422                                 cp++;
423                             m = n;
424                             n = *cp;
425                             *cp = 0;
426                             switch (m) {
427                             case '/':
428                                 m = atoi(net);
429                                 break;
430                             case '&':
431                                 if (inet_pton(AF_INET6, net, u) == 1) {
432                                     m = -1;
433                                     break;
434                                 }
435                                 /*FALLTHROUGH*/
436                             default:
437                                 m = sizeof(struct in6_addr) * CHAR_BIT;
438                                 break;
439                             }
440                             if (m >= 0) {
441                                 for (i = 0; i < sizeof(struct in6_addr); i++) {
442                                     if (m <= 0) {
443                                         *u = 0;
444                                     } else {
445                                         m -= CHAR_BIT;
446                                         *u = (u_char)~0;
447                                         if (m < 0)
448                                             *u <<= -m;
449                                     }
450                                     u++;
451                                 }
452                             }
453                             _res.sort_list[nsort].addr.s_addr =
454                                 (u_int32_t)0xffffffff;
455                             _res.sort_list[nsort].mask = (u_int32_t)0xffffffff;
456                             nsort++;
457                         }
458                         *cp = n;
459                     }
460                     continue;
461                 }
462 #endif
463                 if (MATCH(buf, "options")) {
464                     res_setoptions(buf + sizeof("options") - 1, "conf");
465                     continue;
466                 }
467             }
468             if (nserv > 1) 
469                 _res.nscount = nserv;
470 #ifdef RESOLVSORT
471             _res.nsort = nsort;
472 #endif
473             (void) fclose(fp);
474         }
475         if (_res.defdname[0] == 0 &&
476             gethostname(buf, sizeof(_res.defdname) - 1) == 0 &&
477             (cp = strchr(buf, '.')) != NULL)
478                 strcpy(_res.defdname, cp + 1);
479
480         /* find components of local domain that might be searched */
481         if (havesearch == 0) {
482                 pp = _res.dnsrch;
483                 *pp++ = _res.defdname;
484                 *pp = NULL;
485
486 #ifndef RFC1535
487                 dots = 0;
488                 for (cp = _res.defdname; *cp; cp++)
489                         dots += (*cp == '.');
490
491                 cp = _res.defdname;
492                 while (pp < _res.dnsrch + MAXDFLSRCH) {
493                         if (dots < LOCALDOMAINPARTS)
494                                 break;
495                         cp = strchr(cp, '.') + 1;    /* we know there is one */
496                         *pp++ = cp;
497                         dots--;
498                 }
499                 *pp = NULL;
500 #ifdef DEBUG
501                 if (_res.options & RES_DEBUG) {
502                         printf(";; res_init()... default dnsrch list:\n");
503                         for (pp = _res.dnsrch; *pp; pp++)
504                                 printf(";;\t%s\n", *pp);
505                         printf(";;\t..END..\n");
506                 }
507 #endif
508 #endif /* !RFC1535 */
509         }
510
511         if (issetugid())
512                 _res.options |= RES_NOALIASES;
513         else if ((cp = getenv("RES_OPTIONS")) != NULL)
514                 res_setoptions(cp, "env");
515         _res.options |= RES_INIT;
516         return (0);
517 }
518
519 static void
520 res_setoptions(options, source)
521         char *options, *source;
522 {
523         char *cp = options;
524         int i;
525
526 #ifdef DEBUG
527         if (_res.options & RES_DEBUG)
528                 printf(";; res_setoptions(\"%s\", \"%s\")...\n",
529                        options, source);
530 #endif
531         while (*cp) {
532                 /* skip leading and inner runs of spaces */
533                 while (*cp == ' ' || *cp == '\t')
534                         cp++;
535                 /* search for and process individual options */
536                 if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
537                         i = atoi(cp + sizeof("ndots:") - 1);
538                         if (i <= RES_MAXNDOTS)
539                                 _res.ndots = i;
540                         else
541                                 _res.ndots = RES_MAXNDOTS;
542 #ifdef DEBUG
543                         if (_res.options & RES_DEBUG)
544                                 printf(";;\tndots=%d\n", _res.ndots);
545 #endif
546                 } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
547                         i = atoi(cp + sizeof("timeout:") - 1);
548                         if (i <= RES_MAXRETRANS)
549                                 _res.retrans = i;
550                         else
551                                 _res.retrans = RES_MAXRETRANS;
552 #ifdef DEBUG
553                         if (_res.options & RES_DEBUG)
554                                 printf(";;\ttimeout=%d\n", _res.retrans);
555 #endif
556                 } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
557                         i = atoi(cp + sizeof("attempts:") - 1);
558                         if (i <= RES_MAXRETRY)
559                                 _res.retry = i;
560                         else
561                                 _res.retry = RES_MAXRETRY;
562 #ifdef DEBUG
563                         if (_res.options & RES_DEBUG)
564                                 printf(";;\tretry=%d\n", _res.retry);
565 #endif
566                 } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
567 #ifdef DEBUG
568                         if (!(_res.options & RES_DEBUG)) {
569                                 printf(";; res_setoptions(\"%s\", \"%s\")..\n",
570                                        options, source);
571                                 _res.options |= RES_DEBUG;
572                         }
573                         printf(";;\tdebug\n");
574 #endif
575                 } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
576                         _res.options |= RES_USE_INET6;
577                 } else if (!strncmp(cp, "insecure1", sizeof("insecure1") - 1)) {
578                        _res.options |= RES_INSECURE1;
579                 } else if (!strncmp(cp, "insecure2", sizeof("insecure2") - 1)) {
580                        _res.options |= RES_INSECURE2;
581                 } else if (!strncmp(cp, "no_tld_query", sizeof("no_tld_query") - 1)) {
582                         _res.options |= RES_NOTLDQUERY;
583                 } else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
584                        _res.options |= RES_USE_EDNS0;
585                 } else {
586                         /* XXX - print a warning here? */
587                 }
588                 /* skip to next run of spaces */
589                 while (*cp && *cp != ' ' && *cp != '\t')
590                         cp++;
591         }
592 }
593
594 #ifdef RESOLVSORT
595 /* XXX - should really support CIDR which means explicit masks always. */
596 static u_int32_t
597 net_mask(in)            /* XXX - should really use system's version of this */
598         struct in_addr in;
599 {
600         u_int32_t i = ntohl(in.s_addr);
601
602         if (IN_CLASSA(i))
603                 return (htonl(IN_CLASSA_NET));
604         else if (IN_CLASSB(i))
605                 return (htonl(IN_CLASSB_NET));
606         return (htonl(IN_CLASSC_NET));
607 }
608 #endif
609
610 u_int
611 res_randomid()
612 {
613         struct timeval now;
614
615         gettimeofday(&now, NULL);
616         return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
617 }
618
619 /*
620  * Resolver state default settings.
621  */
622
623 #undef _res
624 #undef _res_ext
625 #ifdef __BIND_RES_TEXT
626 struct __res_state _res = { RES_TIMEOUT };      /* Motorola, et al. */
627 #else
628 struct __res_state _res;
629 #endif
630 struct __res_state_ext _res_ext;
631 static struct __res_send_private _res_send_private = { .s = -1 }; /* socket */
632
633 static thread_key_t res_key;
634 static once_t res_init_once = ONCE_INITIALIZER;
635 static int res_thr_keycreated = 0;
636
637 static void
638 free_res(void *ptr)
639 {
640         struct res_per_thread *myrsp = ptr;
641
642         if (myrsp->res_state.options & RES_INIT)
643                 res_close();
644         free(myrsp);
645 }
646
647 static void
648 res_keycreate(void)
649 {
650         res_thr_keycreated = thr_keycreate(&res_key, free_res) == 0;
651 }
652
653 static struct res_per_thread *
654 allocate_res(void)
655 {
656         struct res_per_thread *myrsp;
657         
658         if (thr_once(&res_init_once, res_keycreate) != 0 ||
659             !res_thr_keycreated)
660                 return (&_res_per_thread_bogus);
661
662         myrsp = thr_getspecific(res_key);
663         if (myrsp != NULL)
664                 return (myrsp);
665         myrsp = calloc(1, sizeof(*myrsp));
666         if (myrsp == NULL)
667                 return (&_res_per_thread_bogus);
668 #ifdef __BIND_RES_TEXT
669         myrsp->res_state.options = RES_TIMEOUT;         /* Motorola, et al. */
670 #endif
671         myrsp->res_send_private.s = -1;                 /* socket */
672         if (thr_setspecific(res_key, myrsp) == 0)
673                 return (myrsp);
674         free(myrsp);
675         return (&_res_per_thread_bogus);
676 }
677
678 struct __res_state *
679 ___res(void)
680 {
681         if (thr_main() != 0)
682                 return (&_res);
683         return (&allocate_res()->res_state);
684 }
685
686 struct __res_state_ext *
687 ___res_ext(void)
688 {
689         if (thr_main() != 0)
690                 return (&_res_ext);
691         return (&allocate_res()->res_state_ext);
692 }
693
694 struct __res_send_private *
695 ___res_send_private(void)
696 {
697         if (thr_main() != 0)
698                 return (&_res_send_private);
699         return (&allocate_res()->res_send_private);
700 }
701
702 int *
703 __h_error(void)
704 {
705         if (thr_main() != 0)
706                 return (&h_errno);
707         return (&allocate_res()->h_errno);
708 }
709
710 /*
711  * Weak aliases for applications that use certain private entry points,
712  * and fail to include <resolv.h>.
713  */
714 #undef res_init
715 __weak_reference(__res_init, res_init);