1999-03-07 Mark Kettenis <kettenis@gnu.org>
[kopensolaris-gnu/glibc.git] / resolv / res_init.c
index 98807ff..893072f 100644 (file)
@@ -3,7 +3,7 @@
  * -
  * Copyright (c) 1985, 1989, 1993
  *    The Regents of the University of California.  All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -19,7 +19,7 @@
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * SUCH DAMAGE.
  * -
  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
- * 
+ *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies, and that
  * the name of Digital Equipment Corporation not be used in advertising or
  * publicity pertaining to distribution of the document or software without
  * specific, written prior permission.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
@@ -58,8 +58,10 @@ static char sccsid[] = "@(#)res_init.c       8.1 (Berkeley) 6/7/93";
 static char rcsid[] = "$Id$";
 #endif /* LIBC_SCCS and not lint */
 
+#include <sys/types.h>
 #include <sys/param.h>
 #include <sys/socket.h>
+#include <sys/time.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <arpa/nameser.h>
@@ -75,7 +77,7 @@ static char rcsid[] = "$Id$";
 # include "../conf/portability.h"
 #endif
 
-/*
+/*-------------------------------------- info about "sortlist" --------------
  * Marc Majka          1994/04/16
  * Allan Nathanson     1994/10/29 (BIND 4.9.3.x)
  *
@@ -93,10 +95,9 @@ static char rcsid[] = "$Id$";
  *   "search" property.
  * - The sortlist comprised of IP address netmask pairs are stored as
  *   values of the "sortlist" property. The IP address and optional netmask
- *   should be seperated by a slash (/) character.
+ *   should be separated by a slash (/) or ampersand (&) character.
  * - Internal resolver variables can be set from the value of the "options"
  *   property.
- *
  */
 #if defined(NeXT)
 #  include <netinfo/ni.h>
@@ -109,9 +110,11 @@ static int netinfo_res_init __P((int *haveenv, int *havesearch));
 # include "../conf/options.h"
 #endif
 
-static void res_setoptions __P((char *, char *));
+static void res_setoptions __P((char *, char *)) internal_function;
 
 #ifdef RESOLVSORT
+static const char sort_mask[] = "/&";
+#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
 static u_int32_t net_mask __P((struct in_addr));
 #endif
 
@@ -123,7 +126,11 @@ static u_int32_t net_mask __P((struct in_addr));
  * Resolver state default settings.
  */
 
-struct __res_state _res;
+struct __res_state _res
+# if defined(__BIND_RES_TEXT)
+       = { RES_TIMEOUT, }      /* Motorola, et al. */
+# endif
+       ;
 
 /*
  * Set up default settings.  If the configuration file exist, the values
@@ -135,7 +142,7 @@ struct __res_state _res;
  * since it was noted that INADDR_ANY actually meant ``the first interface
  * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
  * it had to be "up" in order for you to reach your own name server.  It
- * was later decided that since the recommended practice is to always 
+ * was later decided that since the recommended practice is to always
  * install local static routes through 127.0.0.1 for all your network
  * interfaces, that we could solve this problem without a code change.
  *
@@ -146,12 +153,13 @@ struct __res_state _res;
  *
  * Return 0 if completes successfully, -1 on error
  */
+int
 res_init()
 {
        register FILE *fp;
        register char *cp, **pp;
-       register int n, dots;
-       char buf[BUFSIZ];
+       register int n;
+       char buf[MAXDNAME];
        int nserv = 0;    /* number of nameserver records read from file */
        int haveenv = 0;
        int havesearch = 0;
@@ -159,6 +167,9 @@ res_init()
        int nsort = 0;
        char *net;
 #endif
+#ifndef RFC1535
+       int dots;
+#endif
 
        /*
         * These three fields used to be statically initialized.  This made
@@ -172,27 +183,41 @@ res_init()
         * will follow.  Zero for any of these fields would make no sense,
         * so one can safely assume that the applications were already getting
         * unexpected results.
+        *
+        * _res.options is tricky since some apps were known to diddle the bits
+        * before res_init() was first called. We can't replicate that semantic
+        * with dynamic initialization (they may have turned bits off that are
+        * set in RES_DEFAULT).  Our solution is to declare such applications
+        * "broken".  They could fool us by setting RES_INIT but none do (yet).
         */
        if (!_res.retrans)
                _res.retrans = RES_TIMEOUT;
        if (!_res.retry)
                _res.retry = 4;
        if (!(_res.options & RES_INIT))
-               _res.options |= RES_DEFAULT;
+               _res.options = RES_DEFAULT;
+
+       /*
+        * This one used to initialize implicitly to zero, so unless the app
+        * has set it to something in particular, we can randomize it now.
+        */
+       if (!_res.id)
+               _res.id = res_randomid();
 
 #ifdef USELOOPBACK
        _res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
+       _res.nscount = 1;
 #else
        _res.nsaddr.sin_addr.s_addr = INADDR_ANY;
+       _res.nscount = 0;
 #endif
        _res.nsaddr.sin_family = AF_INET;
        _res.nsaddr.sin_port = htons(NAMESERVER_PORT);
-       _res.nscount = 1;
        _res.ndots = 1;
        _res.pfcode = 0;
 
        /* Allow user to override the local domain definition */
-       if ((cp = getenv("LOCALDOMAIN")) != NULL) {
+       if ((cp = __secure_getenv("LOCALDOMAIN")) != NULL) {
                (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
                haveenv++;
 
@@ -235,7 +260,7 @@ res_init()
 #endif
        if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
            /* read the config file */
-           while (fgets(buf, sizeof(buf), fp) != NULL) {
+           while (fgets_unlocked(buf, sizeof(buf), fp) != NULL) {
                /* skip comments */
                if (*buf == ';' || *buf == '#')
                        continue;
@@ -317,33 +342,34 @@ res_init()
                        if (*cp == '\0' || *cp == '\n' || *cp == ';')
                            break;
                        net = cp;
-                       while (*cp && *cp != '/' &&
+                       while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
                               isascii(*cp) && !isspace(*cp))
                                cp++;
                        n = *cp;
                        *cp = 0;
                        if (inet_aton(net, &a)) {
                            _res.sort_list[nsort].addr = a;
-                           if (n == '/') {
+                           if (ISSORTMASK(n)) {
                                *cp++ = n;
                                net = cp;
-                               while (*cp && isascii(*cp) && !isspace(*cp))
+                               while (*cp && *cp != ';' &&
+                                       isascii(*cp) && !isspace(*cp))
                                    cp++;
                                n = *cp;
                                *cp = 0;
                                if (inet_aton(net, &a)) {
                                    _res.sort_list[nsort].mask = a.s_addr;
                                } else {
-                                   _res.sort_list[nsort].mask = 
+                                   _res.sort_list[nsort].mask =
                                        net_mask(_res.sort_list[nsort].addr);
                                }
                            } else {
-                               _res.sort_list[nsort].mask = 
+                               _res.sort_list[nsort].mask =
                                    net_mask(_res.sort_list[nsort].addr);
                            }
                            nsort++;
                        }
-                       *cp++ = n;
+                       *cp = n;
                    }
                    continue;
                }
@@ -353,7 +379,7 @@ res_init()
                    continue;
                }
            }
-           if (nserv > 1) 
+           if (nserv > _res.nscount)
                _res.nscount = nserv;
 #ifdef RESOLVSORT
            _res.nsort = nsort;
@@ -361,7 +387,7 @@ res_init()
            (void) fclose(fp);
        }
        if (_res.defdname[0] == 0 &&
-           gethostname(buf, sizeof(_res.defdname) - 1) == 0 &&
+           __gethostname(buf, sizeof(_res.defdname) - 1) == 0 &&
            (cp = strchr(buf, '.')) != NULL)
                strcpy(_res.defdname, cp + 1);
 
@@ -396,13 +422,14 @@ res_init()
 #endif /* !RFC1535 */
        }
 
-       if ((cp = getenv("RES_OPTIONS")) != NULL)
+       if ((cp = __secure_getenv("RES_OPTIONS")) != NULL)
                res_setoptions(cp, "env");
        _res.options |= RES_INIT;
        return (0);
 }
 
 static void
+internal_function
 res_setoptions(options, source)
        char *options, *source;
 {
@@ -438,6 +465,8 @@ res_setoptions(options, source)
                        }
                        printf(";;\tdebug\n");
 #endif
+               } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
+                       _res.options |= RES_USE_INET6;
                } else {
                        /* XXX - print a warning here? */
                }
@@ -448,6 +477,7 @@ res_setoptions(options, source)
 }
 
 #ifdef RESOLVSORT
+/* XXX - should really support CIDR which means explicit masks always. */
 static u_int32_t
 net_mask(in)           /* XXX - should really use system's version of this */
        struct in_addr in;
@@ -541,8 +571,8 @@ netinfo_res_init(haveenv, havesearch)
                    }
                    ni_namelist_free(&nl);
                }
-               
-               if (nserv > 1)
+
+               if (nserv > _res.nscount)
                    _res.nscount = nserv;
 
 #ifdef RESOLVSORT
@@ -556,17 +586,26 @@ netinfo_res_init(haveenv, havesearch)
                         n++) {
                        char ch;
                        char *cp;
+                       const char *sp;
                        struct in_addr a;
 
-                       cp = strchr(nl.ni_namelist_val[n], '/');
+                       cp = NULL;
+                       for (sp = sort_mask; *sp; sp++) {
+                               char *cp1;
+                               cp1 = strchr(nl.ni_namelist_val[n], *sp);
+                               if (cp && cp1)
+                                       cp = (cp < cp1)? cp : cp1;
+                               else if (cp1)
+                                       cp = cp1;
+                       }
                        if (cp != NULL) {
-                           ch = *cp;
-                           *cp = '\0';
+                               ch = *cp;
+                               *cp = '\0';
+                               break;
                        }
-                       
                        if (inet_aton(nl.ni_namelist_val[n], &a)) {
                            _res.sort_list[nsort].addr = a;
-                           if (*cp && ch == '/') {
+                           if (*cp && ISSORTMASK(ch)) {
                                *cp++ = ch;
                                if (inet_aton(cp, &a)) {
                                    _res.sort_list[nsort].mask = a.s_addr;
@@ -607,3 +646,12 @@ netinfo_res_init(haveenv, havesearch)
     return(0); /* if not using DNS configuration from NetInfo */
 }
 #endif /* NeXT */
+
+u_int
+res_randomid()
+{
+       struct timeval now;
+
+       __gettimeofday(&now, NULL);
+       return (0xffff & (now.tv_sec ^ now.tv_usec ^ __getpid()));
+}