Blame resolv/res_init.c

Packit 6c4009
/* Resolver state initialization and resolv.conf parsing.
Packit 6c4009
   Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Copyright (c) 1985, 1989, 1993
Packit 6c4009
 *    The Regents of the University of California.  All rights reserved.
Packit 6c4009
 *
Packit 6c4009
 * Redistribution and use in source and binary forms, with or without
Packit 6c4009
 * modification, are permitted provided that the following conditions
Packit 6c4009
 * are met:
Packit 6c4009
 * 1. Redistributions of source code must retain the above copyright
Packit 6c4009
 *    notice, this list of conditions and the following disclaimer.
Packit 6c4009
 * 2. Redistributions in binary form must reproduce the above copyright
Packit 6c4009
 *    notice, this list of conditions and the following disclaimer in the
Packit 6c4009
 *    documentation and/or other materials provided with the distribution.
Packit 6c4009
 * 4. Neither the name of the University nor the names of its contributors
Packit 6c4009
 *    may be used to endorse or promote products derived from this software
Packit 6c4009
 *    without specific prior written permission.
Packit 6c4009
 *
Packit 6c4009
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
Packit 6c4009
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit 6c4009
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit 6c4009
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
Packit 6c4009
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit 6c4009
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
Packit 6c4009
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit 6c4009
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
Packit 6c4009
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
Packit 6c4009
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
Packit 6c4009
 * SUCH DAMAGE.
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
Packit 6c4009
 *
Packit 6c4009
 * Permission to use, copy, modify, and distribute this software for any
Packit 6c4009
 * purpose with or without fee is hereby granted, provided that the above
Packit 6c4009
 * copyright notice and this permission notice appear in all copies, and that
Packit 6c4009
 * the name of Digital Equipment Corporation not be used in advertising or
Packit 6c4009
 * publicity pertaining to distribution of the document or software without
Packit 6c4009
 * specific, written prior permission.
Packit 6c4009
 *
Packit 6c4009
 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
Packit 6c4009
 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
Packit 6c4009
 * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
Packit 6c4009
 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
Packit 6c4009
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
Packit 6c4009
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
Packit 6c4009
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
Packit 6c4009
 * SOFTWARE.
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
Packit 6c4009
 *
Packit 6c4009
 * Permission to use, copy, modify, and distribute this software for any
Packit 6c4009
 * purpose with or without fee is hereby granted, provided that the above
Packit 6c4009
 * copyright notice and this permission notice appear in all copies.
Packit 6c4009
 *
Packit 6c4009
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
Packit 6c4009
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
Packit 6c4009
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
Packit 6c4009
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
Packit 6c4009
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
Packit 6c4009
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
Packit 6c4009
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
Packit 6c4009
 * SOFTWARE.
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
#include <ctype.h>
Packit 6c4009
#include <netdb.h>
Packit 6c4009
#include <resolv/resolv-internal.h>
Packit 6c4009
#include <res_hconf.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdio_ext.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <arpa/inet.h>
Packit 6c4009
#include <arpa/nameser.h>
Packit 6c4009
#include <net/if.h>
Packit 6c4009
#include <netinet/in.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <sys/socket.h>
Packit 6c4009
#include <sys/time.h>
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
#include <inet/net-internal.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <resolv_conf.h>
Packit Service 70b2a5
#include <file_change_detection.h>
Packit 6c4009
Packit 6c4009
static uint32_t net_mask (struct in_addr);
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
res_ninit (res_state statp)
Packit 6c4009
{
Packit 6c4009
  return __res_vinit (statp, 0);
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (__res_ninit)
Packit 6c4009
Packit 6c4009
/* Return true if CH separates the netmask in the "sortlist"
Packit 6c4009
   directive.  */
Packit 6c4009
static inline bool
Packit 6c4009
is_sort_mask (char ch)
Packit 6c4009
{
Packit 6c4009
  return ch == '/' || ch == '&';
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Array of name server addresses.  */
Packit 6c4009
#define DYNARRAY_STRUCT nameserver_list
Packit 6c4009
#define DYNARRAY_ELEMENT const struct sockaddr *
Packit 6c4009
#define DYNARRAY_ELEMENT_FREE(e) free ((struct sockaddr *) *(e))
Packit 6c4009
#define DYNARRAY_INITIAL_SIZE 3
Packit 6c4009
#define DYNARRAY_PREFIX nameserver_list_
Packit 6c4009
#include <malloc/dynarray-skeleton.c>
Packit 6c4009
Packit 6c4009
/* Array of strings for the search array.  The backing store is
Packit 6c4009
   managed separately.  */
Packit 6c4009
#define DYNARRAY_STRUCT search_list
Packit 6c4009
#define DYNARRAY_ELEMENT const char *
Packit 6c4009
#define DYNARRAY_INITIAL_SIZE 6
Packit 6c4009
#define DYNARRAY_PREFIX search_list_
Packit 6c4009
#include <malloc/dynarray-skeleton.c>
Packit 6c4009
Packit 6c4009
/* Array of name server addresses.  */
Packit 6c4009
#define DYNARRAY_STRUCT sort_list
Packit 6c4009
#define DYNARRAY_ELEMENT struct resolv_sortlist_entry
Packit 6c4009
#define DYNARRAY_INITIAL_SIZE 0
Packit 6c4009
#define DYNARRAY_PREFIX sort_list_
Packit 6c4009
#include <malloc/dynarray-skeleton.c>
Packit 6c4009
Packit 6c4009
/* resolv.conf parser state and results.  */
Packit 6c4009
struct resolv_conf_parser
Packit 6c4009
{
Packit 6c4009
  char *buffer;            /* Temporary buffer for reading lines.  */
Packit 6c4009
Packit 6c4009
  struct nameserver_list nameserver_list; /* Nameserver addresses.  */
Packit 6c4009
Packit 6c4009
  char *search_list_store; /* Backing storage for search list entries.  */
Packit 6c4009
  struct search_list search_list; /* Points into search_list_store.  */
Packit 6c4009
Packit 6c4009
  struct sort_list sort_list;   /* Address preference sorting list.  */
Packit 6c4009
Packit 6c4009
  /* Configuration template.  The non-array elements are filled in
Packit 6c4009
     directly.  The array elements are updated prior to the call to
Packit 6c4009
     __resolv_conf_attach.  */
Packit 6c4009
  struct resolv_conf template;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* Return true if *PREINIT contains actual preinitialization.  */
Packit 6c4009
static bool
Packit 6c4009
has_preinit_values (const struct __res_state *preinit)
Packit 6c4009
{
Packit 6c4009
  return (preinit->retrans != 0 && preinit->retrans != RES_TIMEOUT)
Packit 6c4009
    || (preinit->retry != 0 && preinit->retry != RES_DFLRETRY)
Packit 6c4009
    || (preinit->options != 0
Packit 6c4009
        && (preinit->options & ~RES_INIT) != RES_DEFAULT);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
resolv_conf_parser_init (struct resolv_conf_parser *parser,
Packit 6c4009
                         const struct __res_state *preinit)
Packit 6c4009
{
Packit 6c4009
  parser->buffer = NULL;
Packit 6c4009
  parser->search_list_store = NULL;
Packit 6c4009
  nameserver_list_init (&parser->nameserver_list);
Packit 6c4009
  search_list_init (&parser->search_list);
Packit 6c4009
  sort_list_init (&parser->sort_list);
Packit 6c4009
Packit 6c4009
  if (preinit != NULL)
Packit 6c4009
    {
Packit 6c4009
      parser->template.retrans = preinit->retrans;
Packit 6c4009
      parser->template.retry = preinit->retry;
Packit 6c4009
      parser->template.options = preinit->options | RES_INIT;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      parser->template.retrans = RES_TIMEOUT;
Packit 6c4009
      parser->template.retry = RES_DFLRETRY;
Packit 6c4009
      parser->template.options = RES_DEFAULT | RES_INIT;
Packit 6c4009
    }
Packit 6c4009
  parser->template.ndots = 1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
resolv_conf_parser_free (struct resolv_conf_parser *parser)
Packit 6c4009
{
Packit 6c4009
  free (parser->buffer);
Packit 6c4009
  free (parser->search_list_store);
Packit 6c4009
  nameserver_list_free (&parser->nameserver_list);
Packit 6c4009
  search_list_free (&parser->search_list);
Packit 6c4009
  sort_list_free (&parser->sort_list);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Allocate a struct sockaddr_in object on the heap, with the
Packit 6c4009
   specified address and port.  */
Packit 6c4009
static struct sockaddr *
Packit 6c4009
allocate_address_v4 (struct in_addr a, uint16_t port)
Packit 6c4009
{
Packit 6c4009
  struct sockaddr_in *sa4 = malloc (sizeof (*sa4));
Packit 6c4009
  if (sa4 == NULL)
Packit 6c4009
    return NULL;
Packit 6c4009
  sa4->sin_family = AF_INET;
Packit 6c4009
  sa4->sin_addr = a;
Packit 6c4009
  sa4->sin_port = htons (port);
Packit 6c4009
  return (struct sockaddr *) sa4;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Try to obtain the domain name from the host name and store it in
Packit 6c4009
   *RESULT.  Return false on memory allocation failure.  If the domain
Packit 6c4009
   name cannot be determined for any other reason, write NULL to
Packit 6c4009
   *RESULT and return true.  */
Packit 6c4009
static bool
Packit 6c4009
domain_from_hostname (char **result)
Packit 6c4009
{
Packit 6c4009
  char buf[256];
Packit 6c4009
  /* gethostbyname may not terminate the buffer.  */
Packit 6c4009
  buf[sizeof (buf) - 1] = '\0';
Packit 6c4009
  if (__gethostname (buf, sizeof (buf) - 1) == 0)
Packit 6c4009
    {
Packit 6c4009
      char *dot = strchr (buf, '.');
Packit 6c4009
      if (dot != NULL)
Packit 6c4009
        {
Packit 6c4009
          *result = __strdup (dot + 1);
Packit 6c4009
          if (*result == NULL)
Packit 6c4009
            return false;
Packit 6c4009
          return true;
Packit 6c4009
        }
Packit 6c4009
    }
Packit 6c4009
  *result = NULL;
Packit 6c4009
  return true;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void res_setoptions (struct resolv_conf_parser *, const char *options);
Packit 6c4009
Packit 6c4009
/* Internal helper function for __res_vinit, to aid with resource
Packit 6c4009
   deallocation and error handling.  Return true on success, false on
Packit 6c4009
   failure.  */
Packit 6c4009
static bool
Packit 6c4009
res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser)
Packit 6c4009
{
Packit 6c4009
  char *cp;
Packit 6c4009
  size_t buffer_size = 0;
Packit 6c4009
  bool haveenv = false;
Packit 6c4009
Packit 6c4009
  /* Allow user to override the local domain definition.  */
Packit 6c4009
  if ((cp = getenv ("LOCALDOMAIN")) != NULL)
Packit 6c4009
    {
Packit 6c4009
      /* The code below splits the string in place.  */
Packit 6c4009
      cp = __strdup (cp);
Packit 6c4009
      if (cp == NULL)
Packit 6c4009
        return false;
Packit 6c4009
      free (parser->search_list_store);
Packit 6c4009
      parser->search_list_store = cp;
Packit 6c4009
      haveenv = true;
Packit 6c4009
Packit 6c4009
      /* The string will be truncated as needed below.  */
Packit 6c4009
      search_list_add (&parser->search_list, cp);
Packit 6c4009
Packit 6c4009
      /* Set search list to be blank-separated strings from rest of
Packit 6c4009
         env value.  Permits users of LOCALDOMAIN to still have a
Packit 6c4009
         search list, and anyone to set the one that they want to use
Packit 6c4009
         as an individual (even more important now that the rfc1535
Packit 6c4009
         stuff restricts searches).  */
Packit 6c4009
      for (bool in_name = true; *cp != '\0'; cp++)
Packit 6c4009
        {
Packit 6c4009
          if (*cp == '\n')
Packit 6c4009
            {
Packit 6c4009
              *cp = '\0';
Packit 6c4009
              break;
Packit 6c4009
            }
Packit 6c4009
          else if (*cp == ' ' || *cp == '\t')
Packit 6c4009
            {
Packit 6c4009
              *cp = '\0';
Packit 6c4009
              in_name = false;
Packit 6c4009
            }
Packit 6c4009
          else if (!in_name)
Packit 6c4009
            {
Packit 6c4009
              search_list_add (&parser->search_list, cp);
Packit 6c4009
              in_name = true;
Packit 6c4009
            }
Packit 6c4009
        }
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
#define MATCH(line, name)                       \
Packit 6c4009
  (!strncmp ((line), name, sizeof (name) - 1)     \
Packit 6c4009
   && ((line)[sizeof (name) - 1] == ' '           \
Packit 6c4009
       || (line)[sizeof (name) - 1] == '\t'))
Packit 6c4009
Packit 6c4009
  if (fp != NULL)
Packit 6c4009
    {
Packit 6c4009
      /* No threads use this stream.  */
Packit 6c4009
      __fsetlocking (fp, FSETLOCKING_BYCALLER);
Packit 6c4009
      /* Read the config file.  */
Packit 6c4009
      while (true)
Packit 6c4009
        {
Packit 6c4009
          {
Packit 6c4009
            ssize_t ret = __getline (&parser->buffer, &buffer_size, fp);
Packit 6c4009
            if (ret <= 0)
Packit 6c4009
              {
Packit 6c4009
                if (_IO_ferror_unlocked (fp))
Packit 6c4009
                  return false;
Packit 6c4009
                else
Packit 6c4009
                  break;
Packit 6c4009
              }
Packit 6c4009
          }
Packit 6c4009
Packit 6c4009
          /* Skip comments.  */
Packit 6c4009
          if (*parser->buffer == ';' || *parser->buffer == '#')
Packit 6c4009
            continue;
Packit 6c4009
          /* Read default domain name.  */
Packit 6c4009
          if (MATCH (parser->buffer, "domain"))
Packit 6c4009
            {
Packit 6c4009
              if (haveenv)
Packit 6c4009
                /* LOCALDOMAIN overrides the configuration file.  */
Packit 6c4009
                continue;
Packit 6c4009
              cp = parser->buffer + sizeof ("domain") - 1;
Packit 6c4009
              while (*cp == ' ' || *cp == '\t')
Packit 6c4009
                cp++;
Packit 6c4009
              if ((*cp == '\0') || (*cp == '\n'))
Packit 6c4009
                continue;
Packit 6c4009
Packit 6c4009
              cp = __strdup (cp);
Packit 6c4009
              if (cp == NULL)
Packit 6c4009
                return false;
Packit 6c4009
              free (parser->search_list_store);
Packit 6c4009
              parser->search_list_store = cp;
Packit 6c4009
              search_list_clear (&parser->search_list);
Packit 6c4009
              search_list_add (&parser->search_list, cp);
Packit 6c4009
              /* Replace trailing whitespace.  */
Packit 6c4009
              if ((cp = strpbrk (cp, " \t\n")) != NULL)
Packit 6c4009
                *cp = '\0';
Packit 6c4009
              continue;
Packit 6c4009
            }
Packit 6c4009
          /* Set search list.  */
Packit 6c4009
          if (MATCH (parser->buffer, "search"))
Packit 6c4009
            {
Packit 6c4009
              if (haveenv)
Packit 6c4009
                /* LOCALDOMAIN overrides the configuration file.  */
Packit 6c4009
                continue;
Packit 6c4009
              cp = parser->buffer + sizeof ("search") - 1;
Packit 6c4009
              while (*cp == ' ' || *cp == '\t')
Packit 6c4009
                cp++;
Packit 6c4009
              if ((*cp == '\0') || (*cp == '\n'))
Packit 6c4009
                continue;
Packit 6c4009
Packit 6c4009
              {
Packit 6c4009
                char *p = strchr (cp, '\n');
Packit 6c4009
                if (p != NULL)
Packit 6c4009
                  *p = '\0';
Packit 6c4009
              }
Packit 6c4009
              cp = __strdup (cp);
Packit 6c4009
              if (cp == NULL)
Packit 6c4009
                return false;
Packit 6c4009
              free (parser->search_list_store);
Packit 6c4009
              parser->search_list_store = cp;
Packit 6c4009
Packit 6c4009
              /* The string is truncated below.  */
Packit 6c4009
              search_list_clear (&parser->search_list);
Packit 6c4009
              search_list_add (&parser->search_list, cp);
Packit 6c4009
Packit 6c4009
              /* Set search list to be blank-separated strings on rest
Packit 6c4009
                 of line.  */
Packit 6c4009
              for (bool in_name = true; *cp != '\0'; cp++)
Packit 6c4009
                {
Packit 6c4009
                  if (*cp == ' ' || *cp == '\t')
Packit 6c4009
                    {
Packit 6c4009
                      *cp = '\0';
Packit 6c4009
                      in_name = false;
Packit 6c4009
                    }
Packit 6c4009
                  else if (!in_name)
Packit 6c4009
                    {
Packit 6c4009
                      search_list_add (&parser->search_list, cp);
Packit 6c4009
                      in_name = true;
Packit 6c4009
                    }
Packit 6c4009
                }
Packit 6c4009
              continue;
Packit 6c4009
            }
Packit 6c4009
          /* Read nameservers to query.  */
Packit 6c4009
          if (MATCH (parser->buffer, "nameserver"))
Packit 6c4009
            {
Packit 6c4009
              struct in_addr a;
Packit 6c4009
Packit 6c4009
              cp = parser->buffer + sizeof ("nameserver") - 1;
Packit 6c4009
              while (*cp == ' ' || *cp == '\t')
Packit 6c4009
                cp++;
Packit Service e0dfe7
Packit Service e0dfe7
              /* Ignore trailing contents on the name server line.  */
Packit Service e0dfe7
              {
Packit Service e0dfe7
                char *el;
Packit Service e0dfe7
                if ((el = strpbrk (cp, " \t\n")) != NULL)
Packit Service e0dfe7
                  *el = '\0';
Packit Service e0dfe7
              }
Packit Service e0dfe7
Packit 6c4009
              struct sockaddr *sa;
Packit Service e0dfe7
              if ((*cp != '\0') && (*cp != '\n') && __inet_aton_exact (cp, &a))
Packit 6c4009
                {
Packit 6c4009
                  sa = allocate_address_v4 (a, NAMESERVER_PORT);
Packit 6c4009
                  if (sa == NULL)
Packit 6c4009
                    return false;
Packit 6c4009
                }
Packit 6c4009
              else
Packit 6c4009
                {
Packit 6c4009
                  struct in6_addr a6;
Packit 6c4009
                  char *el;
Packit 6c4009
                  if ((el = strchr (cp, SCOPE_DELIMITER)) != NULL)
Packit 6c4009
                    *el = '\0';
Packit 6c4009
                  if ((*cp != '\0') && (__inet_pton (AF_INET6, cp, &a6) > 0))
Packit 6c4009
                    {
Packit 6c4009
                      struct sockaddr_in6 *sa6;
Packit 6c4009
Packit 6c4009
                      sa6 = malloc (sizeof (*sa6));
Packit 6c4009
                      if (sa6 == NULL)
Packit 6c4009
                        return false;
Packit 6c4009
Packit 6c4009
                      sa6->sin6_family = AF_INET6;
Packit 6c4009
                      sa6->sin6_port = htons (NAMESERVER_PORT);
Packit 6c4009
                      sa6->sin6_flowinfo = 0;
Packit 6c4009
                      sa6->sin6_addr = a6;
Packit 6c4009
Packit 6c4009
                      sa6->sin6_scope_id = 0;
Packit 6c4009
                      if (__glibc_likely (el != NULL))
Packit 6c4009
                        /* Ignore errors, for backwards
Packit 6c4009
                           compatibility.  */
Packit 6c4009
                        __inet6_scopeid_pton
Packit 6c4009
                          (&a6, el + 1, &sa6->sin6_scope_id);
Packit 6c4009
                      sa = (struct sockaddr *) sa6;
Packit 6c4009
                    }
Packit 6c4009
                  else
Packit 6c4009
                    /* IPv6 address parse failure.  */
Packit 6c4009
                    sa = NULL;
Packit 6c4009
                }
Packit 6c4009
              if (sa != NULL)
Packit 6c4009
                {
Packit 6c4009
                  const struct sockaddr **p = nameserver_list_emplace
Packit 6c4009
                    (&parser->nameserver_list);
Packit 6c4009
                  if (p != NULL)
Packit 6c4009
                    *p = sa;
Packit 6c4009
                  else
Packit 6c4009
                    {
Packit 6c4009
                      free (sa);
Packit 6c4009
                      return false;
Packit 6c4009
                    }
Packit 6c4009
                }
Packit 6c4009
              continue;
Packit 6c4009
            }
Packit 6c4009
          if (MATCH (parser->buffer, "sortlist"))
Packit 6c4009
            {
Packit 6c4009
              struct in_addr a;
Packit 6c4009
Packit 6c4009
              cp = parser->buffer + sizeof ("sortlist") - 1;
Packit 6c4009
              while (true)
Packit 6c4009
                {
Packit 6c4009
                  while (*cp == ' ' || *cp == '\t')
Packit 6c4009
                    cp++;
Packit 6c4009
                  if (*cp == '\0' || *cp == '\n' || *cp == ';')
Packit 6c4009
                    break;
Packit 6c4009
                  char *net = cp;
Packit 6c4009
                  while (*cp && !is_sort_mask (*cp) && *cp != ';'
Packit 6c4009
                         && isascii (*cp) && !isspace (*cp))
Packit 6c4009
                    cp++;
Packit 6c4009
                  char separator = *cp;
Packit 6c4009
                  *cp = 0;
Packit 6c4009
                  struct resolv_sortlist_entry e;
Packit Service e0dfe7
                  if (__inet_aton_exact (net, &a))
Packit 6c4009
                    {
Packit 6c4009
                      e.addr = a;
Packit 6c4009
                      if (is_sort_mask (separator))
Packit 6c4009
                        {
Packit 6c4009
                          *cp++ = separator;
Packit 6c4009
                          net = cp;
Packit 6c4009
                          while (*cp && *cp != ';'
Packit 6c4009
                                 && isascii (*cp) && !isspace (*cp))
Packit 6c4009
                            cp++;
Packit 6c4009
                          separator = *cp;
Packit 6c4009
                          *cp = 0;
Packit Service e0dfe7
                          if (__inet_aton_exact (net, &a))
Packit 6c4009
                            e.mask = a.s_addr;
Packit 6c4009
                          else
Packit 6c4009
                            e.mask = net_mask (e.addr);
Packit 6c4009
                        }
Packit 6c4009
                      else
Packit 6c4009
                        e.mask = net_mask (e.addr);
Packit 6c4009
                      sort_list_add (&parser->sort_list, e);
Packit 6c4009
                    }
Packit 6c4009
                  *cp = separator;
Packit 6c4009
                }
Packit 6c4009
              continue;
Packit 6c4009
            }
Packit 6c4009
          if (MATCH (parser->buffer, "options"))
Packit 6c4009
            {
Packit 6c4009
              res_setoptions (parser, parser->buffer + sizeof ("options") - 1);
Packit 6c4009
              continue;
Packit 6c4009
            }
Packit 6c4009
        }
Packit 6c4009
    }
Packit 6c4009
  if (__glibc_unlikely (nameserver_list_size (&parser->nameserver_list) == 0))
Packit 6c4009
    {
Packit 6c4009
      const struct sockaddr **p
Packit 6c4009
        = nameserver_list_emplace (&parser->nameserver_list);
Packit 6c4009
      if (p == NULL)
Packit 6c4009
        return false;
Packit 6c4009
      *p = allocate_address_v4 (__inet_makeaddr (IN_LOOPBACKNET, 1),
Packit 6c4009
                                NAMESERVER_PORT);
Packit 6c4009
      if (*p == NULL)
Packit 6c4009
        return false;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (search_list_size (&parser->search_list) == 0)
Packit 6c4009
    {
Packit 6c4009
      char *domain;
Packit 6c4009
      if (!domain_from_hostname (&domain))
Packit 6c4009
        return false;
Packit 6c4009
      if (domain != NULL)
Packit 6c4009
        {
Packit 6c4009
          free (parser->search_list_store);
Packit 6c4009
          parser->search_list_store = domain;
Packit 6c4009
          search_list_add (&parser->search_list, domain);
Packit 6c4009
        }
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if ((cp = getenv ("RES_OPTIONS")) != NULL)
Packit 6c4009
    res_setoptions (parser, cp);
Packit 6c4009
Packit 6c4009
  if (nameserver_list_has_failed (&parser->nameserver_list)
Packit 6c4009
      || search_list_has_failed (&parser->search_list)
Packit 6c4009
      || sort_list_has_failed (&parser->sort_list))
Packit 6c4009
    {
Packit 6c4009
      __set_errno (ENOMEM);
Packit 6c4009
      return false;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return true;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
struct resolv_conf *
Packit Service 70b2a5
__resolv_conf_load (struct __res_state *preinit,
Packit Service 70b2a5
                    struct file_change_detection *change)
Packit 6c4009
{
Packit 6c4009
  /* Ensure that /etc/hosts.conf has been loaded (once).  */
Packit 6c4009
  _res_hconf_init ();
Packit 6c4009
Packit 6c4009
  FILE *fp = fopen (_PATH_RESCONF, "rce");
Packit 6c4009
  if (fp == NULL)
Packit 6c4009
    switch (errno)
Packit 6c4009
      {
Packit 6c4009
      case EACCES:
Packit 6c4009
      case EISDIR:
Packit 6c4009
      case ELOOP:
Packit 6c4009
      case ENOENT:
Packit 6c4009
      case ENOTDIR:
Packit 6c4009
      case EPERM:
Packit 6c4009
        /* Ignore these errors.  They are persistent errors caused
Packit 6c4009
           by file system contents.  */
Packit 6c4009
        break;
Packit 6c4009
      default:
Packit 6c4009
        /* Other errors refer to resource allocation problems and
Packit 6c4009
           need to be handled by the application.  */
Packit 6c4009
        return NULL;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  struct resolv_conf_parser parser;
Packit 6c4009
  resolv_conf_parser_init (&parser, preinit);
Packit 6c4009
Packit 6c4009
  struct resolv_conf *conf = NULL;
Packit Service 70b2a5
  bool ok = res_vinit_1 (fp, &parser);
Packit Service 70b2a5
  if (ok && change != NULL)
Packit Service 70b2a5
    /* Update the file change information if the configuration was
Packit Service 70b2a5
       loaded successfully.  */
Packit Service bd84dc
    ok = __file_change_detection_for_fp (change, fp);
Packit Service 70b2a5
Packit Service 70b2a5
  if (ok)
Packit 6c4009
    {
Packit 6c4009
      parser.template.nameserver_list
Packit 6c4009
        = nameserver_list_begin (&parser.nameserver_list);
Packit 6c4009
      parser.template.nameserver_list_size
Packit 6c4009
        = nameserver_list_size (&parser.nameserver_list);
Packit 6c4009
      parser.template.search_list = search_list_begin (&parser.search_list);
Packit 6c4009
      parser.template.search_list_size
Packit 6c4009
        = search_list_size (&parser.search_list);
Packit 6c4009
      parser.template.sort_list = sort_list_begin (&parser.sort_list);
Packit 6c4009
      parser.template.sort_list_size = sort_list_size (&parser.sort_list);
Packit 6c4009
      conf = __resolv_conf_allocate (&parser.template);
Packit 6c4009
    }
Packit 6c4009
  resolv_conf_parser_free (&parser);
Packit 6c4009
Packit Service a34a85
  if (fp != NULL)
Packit Service a34a85
    {
Packit Service a34a85
      int saved_errno = errno;
Packit Service a34a85
      fclose (fp);
Packit Service a34a85
      __set_errno (saved_errno);
Packit Service a34a85
    }
Packit Service a34a85
Packit 6c4009
  return conf;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Set up default settings.  If the /etc/resolv.conf configuration
Packit 6c4009
   file exist, the values there will have precedence.  Otherwise, the
Packit 6c4009
   server address is set to INADDR_LOOPBACK and the default domain
Packit 6c4009
   name comes from gethostname.  The RES_OPTIONS and LOCALDOMAIN
Packit 6c4009
   environment variables can be used to override some settings.
Packit 6c4009
   Return 0 if completes successfully, -1 on error.  */
Packit 6c4009
int
Packit 6c4009
__res_vinit (res_state statp, int preinit)
Packit 6c4009
{
Packit 6c4009
  struct resolv_conf *conf;
Packit 6c4009
  if (preinit && has_preinit_values (statp))
Packit 6c4009
    /* For the preinit case, we cannot use the cached configuration
Packit 6c4009
       because some settings could be different.  */
Packit Service 70b2a5
    conf = __resolv_conf_load (statp, NULL);
Packit 6c4009
  else
Packit 6c4009
    conf = __resolv_conf_get_current ();
Packit 6c4009
  if (conf == NULL)
Packit 6c4009
    return -1;
Packit 6c4009
Packit 6c4009
  bool ok = __resolv_conf_attach (statp, conf);
Packit 6c4009
  __resolv_conf_put (conf);
Packit 6c4009
  if (ok)
Packit 6c4009
    {
Packit 6c4009
      if (preinit)
Packit 6c4009
        statp->id = res_randomid ();
Packit 6c4009
      return 0;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    return -1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
res_setoptions (struct resolv_conf_parser *parser, const char *options)
Packit 6c4009
{
Packit 6c4009
  const char *cp = options;
Packit 6c4009
Packit 6c4009
  while (*cp)
Packit 6c4009
    {
Packit 6c4009
      /* Skip leading and inner runs of spaces.  */
Packit 6c4009
      while (*cp == ' ' || *cp == '\t')
Packit 6c4009
        cp++;
Packit 6c4009
      /* Search for and process individual options.  */
Packit 6c4009
      if (!strncmp (cp, "ndots:", sizeof ("ndots:") - 1))
Packit 6c4009
        {
Packit 6c4009
          int i = atoi (cp + sizeof ("ndots:") - 1);
Packit 6c4009
          if (i <= RES_MAXNDOTS)
Packit 6c4009
            parser->template.ndots = i;
Packit 6c4009
          else
Packit 6c4009
            parser->template.ndots = RES_MAXNDOTS;
Packit 6c4009
        }
Packit 6c4009
      else if (!strncmp (cp, "timeout:", sizeof ("timeout:") - 1))
Packit 6c4009
        {
Packit 6c4009
          int i = atoi (cp + sizeof ("timeout:") - 1);
Packit 6c4009
          if (i <= RES_MAXRETRANS)
Packit 6c4009
            parser->template.retrans = i;
Packit 6c4009
          else
Packit 6c4009
            parser->template.retrans = RES_MAXRETRANS;
Packit 6c4009
        }
Packit 6c4009
      else if (!strncmp (cp, "attempts:", sizeof ("attempts:") - 1))
Packit 6c4009
        {
Packit 6c4009
          int i = atoi (cp + sizeof ("attempts:") - 1);
Packit 6c4009
          if (i <= RES_MAXRETRY)
Packit 6c4009
            parser->template.retry = i;
Packit 6c4009
          else
Packit 6c4009
            parser->template.retry = RES_MAXRETRY;
Packit 6c4009
        }
Packit 6c4009
      else
Packit 6c4009
        {
Packit 6c4009
          static const struct
Packit 6c4009
          {
Packit 6c4009
            char str[22];
Packit 6c4009
            uint8_t len;
Packit 6c4009
            uint8_t clear;
Packit 6c4009
            unsigned long int flag;
Packit 6c4009
          } options[] = {
Packit 6c4009
#define STRnLEN(str) str, sizeof (str) - 1
Packit 6c4009
            { STRnLEN ("inet6"), 0, DEPRECATED_RES_USE_INET6 },
Packit 6c4009
            { STRnLEN ("rotate"), 0, RES_ROTATE },
Packit 6c4009
            { STRnLEN ("edns0"), 0, RES_USE_EDNS0 },
Packit 6c4009
            { STRnLEN ("single-request-reopen"), 0, RES_SNGLKUPREOP },
Packit 6c4009
            { STRnLEN ("single-request"), 0, RES_SNGLKUP },
Packit 6c4009
            { STRnLEN ("no_tld_query"), 0, RES_NOTLDQUERY },
Packit 6c4009
            { STRnLEN ("no-tld-query"), 0, RES_NOTLDQUERY },
Packit 6c4009
            { STRnLEN ("no-reload"), 0, RES_NORELOAD },
Packit 6c4009
            { STRnLEN ("use-vc"), 0, RES_USEVC }
Packit 6c4009
          };
Packit 6c4009
#define noptions (sizeof (options) / sizeof (options[0]))
Packit 6c4009
          for (int i = 0; i < noptions; ++i)
Packit 6c4009
            if (strncmp (cp, options[i].str, options[i].len) == 0)
Packit 6c4009
              {
Packit 6c4009
                if (options[i].clear)
Packit 6c4009
                  parser->template.options &= options[i].flag;
Packit 6c4009
                else
Packit 6c4009
                  parser->template.options |= options[i].flag;
Packit 6c4009
                break;
Packit 6c4009
              }
Packit 6c4009
        }
Packit 6c4009
      /* Skip to next run of spaces.  */
Packit 6c4009
      while (*cp && *cp != ' ' && *cp != '\t')
Packit 6c4009
        cp++;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static uint32_t
Packit 6c4009
net_mask (struct in_addr in)
Packit 6c4009
{
Packit 6c4009
  uint32_t i = ntohl (in.s_addr);
Packit 6c4009
Packit 6c4009
  if (IN_CLASSA (i))
Packit 6c4009
    return htonl (IN_CLASSA_NET);
Packit 6c4009
  else if (IN_CLASSB (i))
Packit 6c4009
    return htonl (IN_CLASSB_NET);
Packit 6c4009
  return htonl (IN_CLASSC_NET);
Packit 6c4009
}