(__res_initstamp, lock): New variables.
[kopensolaris-gnu/glibc.git] / resolv / 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  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 /*
31  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
32  *
33  * Permission to use, copy, modify, and distribute this software for any
34  * purpose with or without fee is hereby granted, provided that the above
35  * copyright notice and this permission notice appear in all copies, and that
36  * the name of Digital Equipment Corporation not be used in advertising or
37  * publicity pertaining to distribution of the document or software without
38  * specific, written prior permission.
39  *
40  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
43  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47  * SOFTWARE.
48  */
49
50 /*
51  * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
52  *
53  * Permission to use, copy, modify, and distribute this software for any
54  * purpose with or without fee is hereby granted, provided that the above
55  * copyright notice and this permission notice appear in all copies.
56  *
57  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
58  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
59  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
60  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
61  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
62  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
63  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
64  * SOFTWARE.
65  */
66
67 #if defined(LIBC_SCCS) && !defined(lint)
68 static const char sccsid[] = "@(#)res_init.c    8.1 (Berkeley) 6/7/93";
69 static const char rcsid[] = "$BINDId: res_init.c,v 8.16 2000/05/09 07:10:12 vixie Exp $";
70 #endif /* LIBC_SCCS and not lint */
71
72 #include <sys/types.h>
73 #include <sys/param.h>
74 #include <sys/socket.h>
75 #include <sys/time.h>
76
77 #include <netinet/in.h>
78 #include <arpa/inet.h>
79 #include <arpa/nameser.h>
80
81 #include <ctype.h>
82 #include <resolv.h>
83 #include <stdio.h>
84 #include <stdio_ext.h>
85 #include <stdlib.h>
86 #include <string.h>
87 #include <unistd.h>
88
89 #include <not-cancel.h>
90
91 /* Options.  Should all be left alone. */
92 #define RESOLVSORT
93 #define RFC1535
94 /* #undef DEBUG */
95
96 static void res_setoptions (res_state, const char *, const char *)
97      internal_function;
98
99 #ifdef RESOLVSORT
100 static const char sort_mask_chars[] = "/&";
101 #define ISSORTMASK(ch) (strchr(sort_mask_chars, ch) != NULL)
102 static u_int32_t net_mask __P((struct in_addr));
103 #endif
104
105 #if !defined(isascii)   /* XXX - could be a function */
106 # define isascii(c) (!(c & 0200))
107 #endif
108
109 /*
110  * Resolver state default settings.
111  */
112
113 /*
114  * Set up default settings.  If the configuration file exist, the values
115  * there will have precedence.  Otherwise, the server address is set to
116  * INADDR_ANY and the default domain name comes from the gethostname().
117  *
118  * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
119  * rather than INADDR_ANY ("0.0.0.0") as the default name server address
120  * since it was noted that INADDR_ANY actually meant ``the first interface
121  * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
122  * it had to be "up" in order for you to reach your own name server.  It
123  * was later decided that since the recommended practice is to always
124  * install local static routes through 127.0.0.1 for all your network
125  * interfaces, that we could solve this problem without a code change.
126  *
127  * The configuration file should always be used, since it is the only way
128  * to specify a default domain.  If you are running a server on your local
129  * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
130  * in the configuration file.
131  *
132  * Return 0 if completes successfully, -1 on error
133  */
134 int
135 res_ninit(res_state statp) {
136         extern int __res_vinit(res_state, int);
137
138         return (__res_vinit(statp, 0));
139 }
140 #ifdef _LIBC
141 libc_hidden_def (__res_ninit)
142 #endif
143
144 /* This function has to be reachable by res_data.c but not publically. */
145 int
146 __res_vinit(res_state statp, int preinit) {
147         register FILE *fp;
148         register char *cp, **pp;
149         register int n;
150         char buf[BUFSIZ];
151         int nserv = 0;    /* number of nameserver records read from file */
152 #ifdef _LIBC
153         int nservall = 0; /* number of NS records read, nserv IPv4 only */
154 #endif
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         if (!preinit) {
166                 statp->retrans = RES_TIMEOUT;
167                 statp->retry = RES_DFLRETRY;
168                 statp->options = RES_DEFAULT;
169                 statp->id = res_randomid();
170         }
171
172 #ifdef USELOOPBACK
173         statp->nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
174 #else
175         statp->nsaddr.sin_addr.s_addr = INADDR_ANY;
176 #endif
177         statp->nsaddr.sin_family = AF_INET;
178         statp->nsaddr.sin_port = htons(NAMESERVER_PORT);
179         statp->nscount = 1;
180         statp->ndots = 1;
181         statp->pfcode = 0;
182         statp->_vcsock = -1;
183         statp->_flags = 0;
184         statp->qhook = NULL;
185         statp->rhook = NULL;
186         statp->_u._ext.nsinit = 0;
187         statp->_u._ext.nscount = 0;
188 #ifdef _LIBC
189         statp->_u._ext.nscount6 = 0;
190         for (n = 0; n < MAXNS; n++) {
191                 statp->_u._ext.nsaddrs[n] = NULL;
192                 statp->_u._ext.nsmap[n] = MAXNS;
193         }
194 #endif
195
196         /* Allow user to override the local domain definition */
197         if ((cp = getenv("LOCALDOMAIN")) != NULL) {
198                 (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
199                 statp->defdname[sizeof(statp->defdname) - 1] = '\0';
200                 haveenv++;
201
202                 /*
203                  * Set search list to be blank-separated strings
204                  * from rest of env value.  Permits users of LOCALDOMAIN
205                  * to still have a search list, and anyone to set the
206                  * one that they want to use as an individual (even more
207                  * important now that the rfc1535 stuff restricts searches)
208                  */
209                 cp = statp->defdname;
210                 pp = statp->dnsrch;
211                 *pp++ = cp;
212                 for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
213                         if (*cp == '\n')        /* silly backwards compat */
214                                 break;
215                         else if (*cp == ' ' || *cp == '\t') {
216                                 *cp = 0;
217                                 n = 1;
218                         } else if (n) {
219                                 *pp++ = cp;
220                                 n = 0;
221                                 havesearch = 1;
222                         }
223                 }
224                 /* null terminate last domain if there are excess */
225                 while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
226                         cp++;
227                 *cp = '\0';
228                 *pp++ = 0;
229         }
230
231 #define MATCH(line, name) \
232         (!strncmp(line, name, sizeof(name) - 1) && \
233         (line[sizeof(name) - 1] == ' ' || \
234          line[sizeof(name) - 1] == '\t'))
235
236         if ((fp = fopen(_PATH_RESCONF, "rc")) != NULL) {
237                 /* No threads use this stream.  */
238                 __fsetlocking (fp, FSETLOCKING_BYCALLER);
239             /* read the config file */
240             while (fgets_unlocked(buf, sizeof(buf), fp) != NULL) {
241                 /* skip comments */
242                 if (*buf == ';' || *buf == '#')
243                         continue;
244                 /* read default domain name */
245                 if (MATCH(buf, "domain")) {
246                     if (haveenv)        /* skip if have from environ */
247                             continue;
248                     cp = buf + sizeof("domain") - 1;
249                     while (*cp == ' ' || *cp == '\t')
250                             cp++;
251                     if ((*cp == '\0') || (*cp == '\n'))
252                             continue;
253                     strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
254                     statp->defdname[sizeof(statp->defdname) - 1] = '\0';
255                     if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
256                             *cp = '\0';
257                     havesearch = 0;
258                     continue;
259                 }
260                 /* set search list */
261                 if (MATCH(buf, "search")) {
262                     if (haveenv)        /* skip if have from environ */
263                             continue;
264                     cp = buf + sizeof("search") - 1;
265                     while (*cp == ' ' || *cp == '\t')
266                             cp++;
267                     if ((*cp == '\0') || (*cp == '\n'))
268                             continue;
269                     strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
270                     statp->defdname[sizeof(statp->defdname) - 1] = '\0';
271                     if ((cp = strchr(statp->defdname, '\n')) != NULL)
272                             *cp = '\0';
273                     /*
274                      * Set search list to be blank-separated strings
275                      * on rest of line.
276                      */
277                     cp = statp->defdname;
278                     pp = statp->dnsrch;
279                     *pp++ = cp;
280                     for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
281                             if (*cp == ' ' || *cp == '\t') {
282                                     *cp = 0;
283                                     n = 1;
284                             } else if (n) {
285                                     *pp++ = cp;
286                                     n = 0;
287                             }
288                     }
289                     /* null terminate last domain if there are excess */
290                     while (*cp != '\0' && *cp != ' ' && *cp != '\t')
291                             cp++;
292                     *cp = '\0';
293                     *pp++ = 0;
294                     havesearch = 1;
295                     continue;
296                 }
297                 /* read nameservers to query */
298 #ifdef _LIBC
299                 if (MATCH(buf, "nameserver") && nservall < MAXNS) {
300 #else
301                 if (MATCH(buf, "nameserver") && nserv < MAXNS) {
302 #endif
303                     struct in_addr a;
304
305                     cp = buf + sizeof("nameserver") - 1;
306                     while (*cp == ' ' || *cp == '\t')
307                         cp++;
308                     if ((*cp != '\0') && (*cp != '\n')
309                         && __inet_aton(cp, &a)) {
310                         statp->nsaddr_list[nserv].sin_addr = a;
311                         statp->nsaddr_list[nserv].sin_family = AF_INET;
312                         statp->nsaddr_list[nserv].sin_port =
313                                 htons(NAMESERVER_PORT);
314                         nserv++;
315 #ifdef _LIBC
316                         nservall++;
317                     } else {
318                         struct in6_addr a6;
319                         char *el;
320
321                         if ((el = strchr(cp, '\n')) != NULL)
322                             *el = '\0';
323                         if ((*cp != '\0') &&
324                             (inet_pton(AF_INET6, cp, &a6) > 0)) {
325                             struct sockaddr_in6 *sa6;
326
327                             sa6 = malloc(sizeof(*sa6));
328                             if (sa6 != NULL) {
329                                 sa6->sin6_addr = a6;
330                                 sa6->sin6_family = AF_INET6;
331                                 sa6->sin6_port = htons(NAMESERVER_PORT);
332                                 statp->_u._ext.nsaddrs[nservall] = sa6;
333                                 statp->_u._ext.nssocks[nservall] = -1;
334                                 statp->_u._ext.nsmap[nservall] = MAXNS + 1;
335                                 nservall++;
336                             }
337                         }
338 #endif
339                     }
340                     continue;
341                 }
342 #ifdef RESOLVSORT
343                 if (MATCH(buf, "sortlist")) {
344                     struct in_addr a;
345
346                     cp = buf + sizeof("sortlist") - 1;
347                     while (nsort < MAXRESOLVSORT) {
348                         while (*cp == ' ' || *cp == '\t')
349                             cp++;
350                         if (*cp == '\0' || *cp == '\n' || *cp == ';')
351                             break;
352                         net = cp;
353                         while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
354                                isascii(*cp) && !isspace(*cp))
355                                 cp++;
356                         n = *cp;
357                         *cp = 0;
358                         if (__inet_aton(net, &a)) {
359                             statp->sort_list[nsort].addr = a;
360                             if (ISSORTMASK(n)) {
361                                 *cp++ = n;
362                                 net = cp;
363                                 while (*cp && *cp != ';' &&
364                                         isascii(*cp) && !isspace(*cp))
365                                     cp++;
366                                 n = *cp;
367                                 *cp = 0;
368                                 if (__inet_aton(net, &a)) {
369                                     statp->sort_list[nsort].mask = a.s_addr;
370                                 } else {
371                                     statp->sort_list[nsort].mask =
372                                         net_mask(statp->sort_list[nsort].addr);
373                                 }
374                             } else {
375                                 statp->sort_list[nsort].mask =
376                                     net_mask(statp->sort_list[nsort].addr);
377                             }
378                             nsort++;
379                         }
380                         *cp = n;
381                     }
382                     continue;
383                 }
384 #endif
385                 if (MATCH(buf, "options")) {
386                     res_setoptions(statp, buf + sizeof("options") - 1, "conf");
387                     continue;
388                 }
389             }
390             if (nserv > 1)
391                 statp->nscount = nserv;
392 #ifdef _LIBC
393             if (nservall - nserv > 0)
394                 statp->_u._ext.nscount6 = nservall - nserv;
395 #endif
396 #ifdef RESOLVSORT
397             statp->nsort = nsort;
398 #endif
399             (void) fclose(fp);
400         }
401         if (statp->defdname[0] == 0 &&
402             __gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
403             (cp = strchr(buf, '.')) != NULL)
404                 strcpy(statp->defdname, cp + 1);
405
406         /* find components of local domain that might be searched */
407         if (havesearch == 0) {
408                 pp = statp->dnsrch;
409                 *pp++ = statp->defdname;
410                 *pp = NULL;
411
412 #ifndef RFC1535
413                 dots = 0;
414                 for (cp = statp->defdname; *cp; cp++)
415                         dots += (*cp == '.');
416
417                 cp = statp->defdname;
418                 while (pp < statp->dnsrch + MAXDFLSRCH) {
419                         if (dots < LOCALDOMAINPARTS)
420                                 break;
421                         cp = __rawmemchr(cp, '.') + 1;    /* we know there is one */
422                         *pp++ = cp;
423                         dots--;
424                 }
425                 *pp = NULL;
426 #ifdef DEBUG
427                 if (statp->options & RES_DEBUG) {
428                         printf(";; res_init()... default dnsrch list:\n");
429                         for (pp = statp->dnsrch; *pp; pp++)
430                                 printf(";;\t%s\n", *pp);
431                         printf(";;\t..END..\n");
432                 }
433 #endif
434 #endif /* !RFC1535 */
435         }
436
437         if ((cp = getenv("RES_OPTIONS")) != NULL)
438                 res_setoptions(statp, cp, "env");
439         statp->options |= RES_INIT;
440         return (0);
441 }
442
443 static void
444 internal_function
445 res_setoptions(res_state statp, const char *options, const char *source) {
446         const char *cp = options;
447         int i;
448
449 #ifdef DEBUG
450         if (statp->options & RES_DEBUG)
451                 printf(";; res_setoptions(\"%s\", \"%s\")...\n",
452                        options, source);
453 #endif
454         while (*cp) {
455                 /* skip leading and inner runs of spaces */
456                 while (*cp == ' ' || *cp == '\t')
457                         cp++;
458                 /* search for and process individual options */
459                 if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
460                         i = atoi(cp + sizeof("ndots:") - 1);
461                         if (i <= RES_MAXNDOTS)
462                                 statp->ndots = i;
463                         else
464                                 statp->ndots = RES_MAXNDOTS;
465 #ifdef DEBUG
466                         if (statp->options & RES_DEBUG)
467                                 printf(";;\tndots=%d\n", statp->ndots);
468 #endif
469                 } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
470                         i = atoi(cp + sizeof("timeout:") - 1);
471                         if (i <= RES_MAXRETRANS)
472                                 statp->retrans = i;
473                         else
474                                 statp->retrans = RES_MAXRETRANS;
475                 } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
476                         i = atoi(cp + sizeof("attempts:") - 1);
477                         if (i <= RES_MAXRETRY)
478                                 statp->retry = i;
479                         else
480                                 statp->retry = RES_MAXRETRY;
481                 } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
482 #ifdef DEBUG
483                         if (!(statp->options & RES_DEBUG)) {
484                                 printf(";; res_setoptions(\"%s\", \"%s\")..\n",
485                                        options, source);
486                                 statp->options |= RES_DEBUG;
487                         }
488                         printf(";;\tdebug\n");
489 #endif
490                 } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
491                         statp->options |= RES_USE_INET6;
492                 } else if (!strncmp(cp, "ip6-bytestring",
493                                     sizeof("ip6-bytestring") - 1)) {
494                         statp->options |= RES_USEBSTRING;
495                 } else if (!strncmp(cp, "no-ip6-dotint",
496                                     sizeof("no-ip6-dotint") - 1)) {
497                         statp->options |= RES_NOIP6DOTINT;
498                 } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
499                         statp->options |= RES_ROTATE;
500                 } else if (!strncmp(cp, "no-check-names",
501                                     sizeof("no-check-names") - 1)) {
502                         statp->options |= RES_NOCHECKNAME;
503                 } else {
504                         /* XXX - print a warning here? */
505                 }
506                 /* skip to next run of spaces */
507                 while (*cp && *cp != ' ' && *cp != '\t')
508                         cp++;
509         }
510 }
511
512 #ifdef RESOLVSORT
513 /* XXX - should really support CIDR which means explicit masks always. */
514 static u_int32_t
515 net_mask(in)            /* XXX - should really use system's version of this */
516         struct in_addr in;
517 {
518         register u_int32_t i = ntohl(in.s_addr);
519
520         if (IN_CLASSA(i))
521                 return (htonl(IN_CLASSA_NET));
522         else if (IN_CLASSB(i))
523                 return (htonl(IN_CLASSB_NET));
524         return (htonl(IN_CLASSC_NET));
525 }
526 #endif
527
528 u_int
529 res_randomid(void) {
530         struct timeval now;
531
532         __gettimeofday(&now, NULL);
533         return (0xffff & (now.tv_sec ^ now.tv_usec ^ __getpid()));
534 }
535 #ifdef _LIBC
536 libc_hidden_def (__res_randomid)
537 #endif
538
539
540 /*
541  * This routine is for closing the socket if a virtual circuit is used and
542  * the program wants to close it.  This provides support for endhostent()
543  * which expects to close the socket.
544  *
545  * This routine is not expected to be user visible.
546  */
547 void
548 res_nclose(res_state statp) {
549         int ns;
550
551         if (statp->_vcsock >= 0) {
552                 close_not_cancel_no_status(statp->_vcsock);
553                 statp->_vcsock = -1;
554                 statp->_flags &= ~(RES_F_VC | RES_F_CONN);
555         }
556 #ifdef _LIBC
557         for (ns = 0; ns < MAXNS; ns++)
558 #else
559         for (ns = 0; ns < statp->_u._ext.nscount; ns++)
560 #endif
561                 if (statp->_u._ext.nsaddrs[ns]
562                     && statp->_u._ext.nssocks[ns] != -1) {
563                         close_not_cancel_no_status(statp->_u._ext.nssocks[ns]);
564                         statp->_u._ext.nssocks[ns] = -1;
565                 }
566         statp->_u._ext.nsinit = 0;
567 }
568 #ifdef _LIBC
569 libc_hidden_def (__res_nclose)
570 #endif
571
572 #ifdef _LIBC
573 # ifdef _LIBC_REENTRANT
574 /* This is called when a thread is exiting to free resources held in _res.  */
575 static void __attribute__ ((section ("__libc_thread_freeres_fn")))
576 res_thread_freeres (void)
577 {
578   if (_res.nscount == 0)
579     /* Never called res_ninit.  */
580     return;
581
582   __res_nclose (&_res);         /* Close any VC sockets.  */
583
584   for (int ns = 0; ns < MAXNS; ns++)
585     if (_res._u._ext.nsaddrs[ns] != NULL)
586       {
587         free (_res._u._ext.nsaddrs[ns]);
588         _res._u._ext.nsaddrs[ns] = NULL;
589       }
590 }
591 text_set_element (__libc_thread_subfreeres, res_thread_freeres);
592 text_set_element (__libc_subfreeres, res_thread_freeres);
593 # endif
594 #endif