]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/net/res_init.c
This commit was generated by cvs2svn to compensate for changes in r102786,
[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 <resolv.h>
87 #include <stdio.h>
88 #include <stdlib.h>
89 #include <string.h>
90 #include <unistd.h>
91 #include <netdb.h>
92
93 #include "res_config.h"
94
95 static void res_setoptions(char *, char *);
96
97 #ifdef RESOLVSORT
98 static const char sort_mask[] = "/&";
99 #define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
100 static u_int32_t net_mask(struct in_addr);
101 #endif
102
103 #if !defined(isascii) /* XXX - could be a function */
104 # define isascii(c) (!(c & 0200))
105 #endif
106
107 /*
108  * Resolver state default settings.
109  */
110
111 struct __res_state _res
112 # if defined(__BIND_RES_TEXT)
113         = { RES_TIMEOUT, }      /* Motorola, et al. */
114 # endif
115         ;
116
117 struct __res_state_ext _res_ext;
118
119 /*
120  * Set up default settings.  If the configuration file exist, the values
121  * there will have precedence.  Otherwise, the server address is set to
122  * INADDR_ANY and the default domain name comes from the gethostname().
123  *
124  * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
125  * rather than INADDR_ANY ("0.0.0.0") as the default name server address
126  * since it was noted that INADDR_ANY actually meant ``the first interface
127  * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
128  * it had to be "up" in order for you to reach your own name server.  It
129  * was later decided that since the recommended practice is to always 
130  * install local static routes through 127.0.0.1 for all your network
131  * interfaces, that we could solve this problem without a code change.
132  *
133  * The configuration file should always be used, since it is the only way
134  * to specify a default domain.  If you are running a server on your local
135  * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
136  * in the configuration file.
137  *
138  * Return 0 if completes successfully, -1 on error
139  */
140 int
141 res_init()
142 {
143         FILE *fp;
144         char *cp, **pp;
145         int n;
146         char buf[MAXDNAME];
147         int nserv = 0;    /* number of nameserver records read from file */
148         int haveenv = 0;
149         int havesearch = 0;
150 #ifdef RESOLVSORT
151         int nsort = 0;
152         char *net;
153 #endif
154 #ifndef RFC1535
155         int dots;
156 #endif
157
158         /*
159          * These three fields used to be statically initialized.  This made
160          * it hard to use this code in a shared library.  It is necessary,
161          * now that we're doing dynamic initialization here, that we preserve
162          * the old semantics: if an application modifies one of these three
163          * fields of _res before res_init() is called, res_init() will not
164          * alter them.  Of course, if an application is setting them to
165          * _zero_ before calling res_init(), hoping to override what used
166          * to be the static default, we can't detect it and unexpected results
167          * will follow.  Zero for any of these fields would make no sense,
168          * so one can safely assume that the applications were already getting
169          * unexpected results.
170          *
171          * _res.options is tricky since some apps were known to diddle the bits
172          * before res_init() was first called. We can't replicate that semantic
173          * with dynamic initialization (they may have turned bits off that are
174          * set in RES_DEFAULT).  Our solution is to declare such applications
175          * "broken".  They could fool us by setting RES_INIT but none do (yet).
176          */
177         if (!_res.retrans)
178                 _res.retrans = RES_TIMEOUT;
179         if (!_res.retry)
180                 _res.retry = 4;
181         if (!(_res.options & RES_INIT))
182                 _res.options = RES_DEFAULT;
183
184         /*
185          * This one used to initialize implicitly to zero, so unless the app
186          * has set it to something in particular, we can randomize it now.
187          */
188         if (!_res.id)
189                 _res.id = res_randomid();
190
191 #ifdef USELOOPBACK
192         _res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
193 #else
194         _res.nsaddr.sin_addr.s_addr = INADDR_ANY;
195 #endif
196         _res.nsaddr.sin_family = AF_INET;
197         _res.nsaddr.sin_port = htons(NAMESERVER_PORT);
198         _res.nsaddr.sin_len = sizeof(struct sockaddr_in);
199         if (sizeof(_res_ext.nsaddr) >= _res.nsaddr.sin_len)
200                 memcpy(&_res_ext.nsaddr, &_res.nsaddr, _res.nsaddr.sin_len);
201         _res.nscount = 1;
202         _res.ndots = 1;
203         _res.pfcode = 0;
204
205         /* Allow user to override the local domain definition */
206         if (issetugid() == 0 && (cp = getenv("LOCALDOMAIN")) != NULL) {
207                 (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
208                 _res.defdname[sizeof(_res.defdname) - 1] = '\0';
209                 haveenv++;
210
211                 /*
212                  * Set search list to be blank-separated strings
213                  * from rest of env value.  Permits users of LOCALDOMAIN
214                  * to still have a search list, and anyone to set the
215                  * one that they want to use as an individual (even more
216                  * important now that the rfc1535 stuff restricts searches)
217                  */
218                 cp = _res.defdname;
219                 pp = _res.dnsrch;
220                 *pp++ = cp;
221                 for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
222                         if (*cp == '\n')        /* silly backwards compat */
223                                 break;
224                         else if (*cp == ' ' || *cp == '\t') {
225                                 *cp = 0;
226                                 n = 1;
227                         } else if (n) {
228                                 *pp++ = cp;
229                                 n = 0;
230                                 havesearch = 1;
231                         }
232                 }
233                 /* null terminate last domain if there are excess */
234                 while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
235                         cp++;
236                 *cp = '\0';
237                 *pp++ = 0;
238         }
239
240 #define MATCH(line, name) \
241         (!strncmp(line, name, sizeof(name) - 1) && \
242         (line[sizeof(name) - 1] == ' ' || \
243          line[sizeof(name) - 1] == '\t'))
244
245         if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
246             /* read the config file */
247             while (fgets(buf, sizeof(buf), fp) != NULL) {
248                 /* skip comments */
249                 if (*buf == ';' || *buf == '#')
250                         continue;
251                 /* read default domain name */
252                 if (MATCH(buf, "domain")) {
253                     if (haveenv)        /* skip if have from environ */
254                             continue;
255                     cp = buf + sizeof("domain") - 1;
256                     while (*cp == ' ' || *cp == '\t')
257                             cp++;
258                     if ((*cp == '\0') || (*cp == '\n'))
259                             continue;
260                     strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
261                     _res.defdname[sizeof(_res.defdname) - 1] = '\0';
262                     if ((cp = strpbrk(_res.defdname, " \t\n")) != NULL)
263                             *cp = '\0';
264                     havesearch = 0;
265                     continue;
266                 }
267                 /* set search list */
268                 if (MATCH(buf, "search")) {
269                     if (haveenv)        /* skip if have from environ */
270                             continue;
271                     cp = buf + sizeof("search") - 1;
272                     while (*cp == ' ' || *cp == '\t')
273                             cp++;
274                     if ((*cp == '\0') || (*cp == '\n'))
275                             continue;
276                     strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
277                     _res.defdname[sizeof(_res.defdname) - 1] = '\0';
278                     if ((cp = strchr(_res.defdname, '\n')) != NULL)
279                             *cp = '\0';
280                     /*
281                      * Set search list to be blank-separated strings
282                      * on rest of line.
283                      */
284                     cp = _res.defdname;
285                     pp = _res.dnsrch;
286                     *pp++ = cp;
287                     for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
288                             if (*cp == ' ' || *cp == '\t') {
289                                     *cp = 0;
290                                     n = 1;
291                             } else if (n) {
292                                     *pp++ = cp;
293                                     n = 0;
294                             }
295                     }
296                     /* null terminate last domain if there are excess */
297                     while (*cp != '\0' && *cp != ' ' && *cp != '\t')
298                             cp++;
299                     *cp = '\0';
300                     *pp++ = 0;
301                     havesearch = 1;
302                     continue;
303                 }
304                 /* read nameservers to query */
305                 if (MATCH(buf, "nameserver") && nserv < MAXNS) {
306                     char *q;
307                     struct addrinfo hints, *res;
308                     char pbuf[NI_MAXSERV];
309
310                     cp = buf + sizeof("nameserver") - 1;
311                     while (*cp == ' ' || *cp == '\t')
312                         cp++;
313                     if ((*cp == '\0') || (*cp == '\n'))
314                         continue;
315                     for (q = cp; *q; q++) {
316                         if (isspace(*q)) {
317                             *q = '\0';
318                             break;
319                         }
320                     }
321                     memset(&hints, 0, sizeof(hints));
322                     hints.ai_flags = AI_NUMERICHOST;
323                     hints.ai_socktype = SOCK_DGRAM;
324                     snprintf(pbuf, sizeof(pbuf), "%d", NAMESERVER_PORT);
325                     if (getaddrinfo(cp, pbuf, &hints, &res) == 0 &&
326                             res->ai_next == NULL) {
327                         if (res->ai_addrlen <= sizeof(_res_ext.nsaddr_list[nserv])) {
328                             memcpy(&_res_ext.nsaddr_list[nserv], res->ai_addr,
329                                 res->ai_addrlen);
330                         } else {
331                             memset(&_res_ext.nsaddr_list[nserv], 0,
332                                 sizeof(_res_ext.nsaddr_list[nserv]));
333                         }
334                         if (res->ai_addrlen <= sizeof(_res.nsaddr_list[nserv])) {
335                             memcpy(&_res.nsaddr_list[nserv], res->ai_addr,
336                                 res->ai_addrlen);
337                         } else {
338                             memset(&_res.nsaddr_list[nserv], 0,
339                                 sizeof(_res.nsaddr_list[nserv]));
340                         }
341                         nserv++;
342                     }
343                     if (res)
344                             freeaddrinfo(res);
345                     continue;
346                 }
347 #ifdef RESOLVSORT
348                 if (MATCH(buf, "sortlist")) {
349                     struct in_addr a;
350                     struct in6_addr a6;
351                     int m, i;
352                     u_char *u;
353
354                     cp = buf + sizeof("sortlist") - 1;
355                     while (nsort < MAXRESOLVSORT) {
356                         while (*cp == ' ' || *cp == '\t')
357                             cp++;
358                         if (*cp == '\0' || *cp == '\n' || *cp == ';')
359                             break;
360                         net = cp;
361                         while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
362                                isascii(*cp) && !isspace(*cp))
363                                 cp++;
364                         n = *cp;
365                         *cp = 0;
366                         if (inet_aton(net, &a)) {
367                             _res.sort_list[nsort].addr = a;
368                             if (ISSORTMASK(n)) {
369                                 *cp++ = n;
370                                 net = cp;
371                                 while (*cp && *cp != ';' &&
372                                         isascii(*cp) && !isspace(*cp))
373                                     cp++;
374                                 n = *cp;
375                                 *cp = 0;
376                                 if (inet_aton(net, &a)) {
377                                     _res.sort_list[nsort].mask = a.s_addr;
378                                 } else {
379                                     _res.sort_list[nsort].mask = 
380                                         net_mask(_res.sort_list[nsort].addr);
381                                 }
382                             } else {
383                                 _res.sort_list[nsort].mask = 
384                                     net_mask(_res.sort_list[nsort].addr);
385                             }
386                             _res_ext.sort_list[nsort].af = AF_INET;
387                             _res_ext.sort_list[nsort].addr.ina =
388                                 _res.sort_list[nsort].addr;
389                             _res_ext.sort_list[nsort].mask.ina.s_addr =
390                                 _res.sort_list[nsort].mask;
391                             nsort++;
392                         }
393                         else if (inet_pton(AF_INET6, net, &a6) == 1) {
394
395                             _res_ext.sort_list[nsort].af = AF_INET6;
396                             _res_ext.sort_list[nsort].addr.in6a = a6;
397                             u = (u_char *)&_res_ext.sort_list[nsort].mask.in6a;
398                             *cp++ = n;
399                             net = cp;
400                             while (*cp && *cp != ';' &&
401                                     isascii(*cp) && !isspace(*cp))
402                                 cp++;
403                             m = n;
404                             n = *cp;
405                             *cp = 0;
406                             switch (m) {
407                             case '/':
408                                 m = atoi(net);
409                                 break;
410                             case '&':
411                                 if (inet_pton(AF_INET6, net, u) == 1) {
412                                     m = -1;
413                                     break;
414                                 }
415                                 /*FALLTHROUGH*/
416                             default:
417                                 m = sizeof(struct in6_addr) * NBBY;
418                                 break;
419                             }
420                             if (m >= 0) {
421                                 for (i = 0; i < sizeof(struct in6_addr); i++) {
422                                     if (m <= 0) {
423                                         *u = 0;
424                                     } else {
425                                         m -= NBBY;
426                                         *u = (u_char)~0;
427                                         if (m < 0)
428                                             *u <<= -m;
429                                     }
430                                     u++;
431                                 }
432                             }
433                             _res.sort_list[nsort].addr.s_addr =
434                                 (u_int32_t)0xffffffff;
435                             _res.sort_list[nsort].mask = (u_int32_t)0xffffffff;
436                             nsort++;
437                         }
438                         *cp = n;
439                     }
440                     continue;
441                 }
442 #endif
443                 if (MATCH(buf, "options")) {
444                     res_setoptions(buf + sizeof("options") - 1, "conf");
445                     continue;
446                 }
447             }
448             if (nserv > 1) 
449                 _res.nscount = nserv;
450 #ifdef RESOLVSORT
451             _res.nsort = nsort;
452 #endif
453             (void) fclose(fp);
454         }
455         if (_res.defdname[0] == 0 &&
456             gethostname(buf, sizeof(_res.defdname) - 1) == 0 &&
457             (cp = strchr(buf, '.')) != NULL)
458                 strcpy(_res.defdname, cp + 1);
459
460         /* find components of local domain that might be searched */
461         if (havesearch == 0) {
462                 pp = _res.dnsrch;
463                 *pp++ = _res.defdname;
464                 *pp = NULL;
465
466 #ifndef RFC1535
467                 dots = 0;
468                 for (cp = _res.defdname; *cp; cp++)
469                         dots += (*cp == '.');
470
471                 cp = _res.defdname;
472                 while (pp < _res.dnsrch + MAXDFLSRCH) {
473                         if (dots < LOCALDOMAINPARTS)
474                                 break;
475                         cp = strchr(cp, '.') + 1;    /* we know there is one */
476                         *pp++ = cp;
477                         dots--;
478                 }
479                 *pp = NULL;
480 #ifdef DEBUG
481                 if (_res.options & RES_DEBUG) {
482                         printf(";; res_init()... default dnsrch list:\n");
483                         for (pp = _res.dnsrch; *pp; pp++)
484                                 printf(";;\t%s\n", *pp);
485                         printf(";;\t..END..\n");
486                 }
487 #endif
488 #endif /* !RFC1535 */
489         }
490
491         if (issetugid())
492                 _res.options |= RES_NOALIASES;
493         else if ((cp = getenv("RES_OPTIONS")) != NULL)
494                 res_setoptions(cp, "env");
495         _res.options |= RES_INIT;
496         return (0);
497 }
498
499 static void
500 res_setoptions(options, source)
501         char *options, *source;
502 {
503         char *cp = options;
504         int i;
505
506 #ifdef DEBUG
507         if (_res.options & RES_DEBUG)
508                 printf(";; res_setoptions(\"%s\", \"%s\")...\n",
509                        options, source);
510 #endif
511         while (*cp) {
512                 /* skip leading and inner runs of spaces */
513                 while (*cp == ' ' || *cp == '\t')
514                         cp++;
515                 /* search for and process individual options */
516                 if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
517                         i = atoi(cp + sizeof("ndots:") - 1);
518                         if (i <= RES_MAXNDOTS)
519                                 _res.ndots = i;
520                         else
521                                 _res.ndots = RES_MAXNDOTS;
522 #ifdef DEBUG
523                         if (_res.options & RES_DEBUG)
524                                 printf(";;\tndots=%d\n", _res.ndots);
525 #endif
526                 } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
527 #ifdef DEBUG
528                         if (!(_res.options & RES_DEBUG)) {
529                                 printf(";; res_setoptions(\"%s\", \"%s\")..\n",
530                                        options, source);
531                                 _res.options |= RES_DEBUG;
532                         }
533                         printf(";;\tdebug\n");
534 #endif
535                 } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
536                         _res.options |= RES_USE_INET6;
537                 } else if (!strncmp(cp, "insecure1", sizeof("insecure1") - 1)) {
538                        _res.options |= RES_INSECURE1;
539                 } else if (!strncmp(cp, "insecure2", sizeof("insecure2") - 1)) {
540                        _res.options |= RES_INSECURE2;
541                 } else if (!strncmp(cp, "no_tld_query", sizeof("no_tld_query") - 1)) {
542                         _res.options |= RES_NOTLDQUERY;
543                 } else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
544                        _res.options |= RES_USE_EDNS0;
545                 } else {
546                         /* XXX - print a warning here? */
547                 }
548                 /* skip to next run of spaces */
549                 while (*cp && *cp != ' ' && *cp != '\t')
550                         cp++;
551         }
552 }
553
554 #ifdef RESOLVSORT
555 /* XXX - should really support CIDR which means explicit masks always. */
556 static u_int32_t
557 net_mask(in)            /* XXX - should really use system's version of this */
558         struct in_addr in;
559 {
560         u_int32_t i = ntohl(in.s_addr);
561
562         if (IN_CLASSA(i))
563                 return (htonl(IN_CLASSA_NET));
564         else if (IN_CLASSB(i))
565                 return (htonl(IN_CLASSB_NET));
566         return (htonl(IN_CLASSC_NET));
567 }
568 #endif
569
570 u_int
571 res_randomid()
572 {
573         struct timeval now;
574
575         gettimeofday(&now, NULL);
576         return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
577 }
578
579 /*
580  * Weak aliases for applications that use certain private entry points,
581  * and fail to include <resolv.h>.
582  */
583 #undef res_init
584 __weak_reference(__res_init, res_init);