(root)/
glibc-2.38/
resolv/
res_init.c
       1  /* Resolver state initialization and resolv.conf parsing.
       2     Copyright (C) 1995-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  /*
      20   * Copyright (c) 1985, 1989, 1993
      21   *    The Regents of the University of California.  All rights reserved.
      22   *
      23   * Redistribution and use in source and binary forms, with or without
      24   * modification, are permitted provided that the following conditions
      25   * are met:
      26   * 1. Redistributions of source code must retain the above copyright
      27   *    notice, this list of conditions and the following disclaimer.
      28   * 2. Redistributions in binary form must reproduce the above copyright
      29   *    notice, this list of conditions and the following disclaimer in the
      30   *    documentation and/or other materials provided with the distribution.
      31   * 4. Neither the name of the University nor the names of its contributors
      32   *    may be used to endorse or promote products derived from this software
      33   *    without specific prior written permission.
      34   *
      35   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      36   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      37   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      38   * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      39   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      40   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      41   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      42   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      43   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      44   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      45   * SUCH DAMAGE.
      46   */
      47  
      48  /*
      49   * Portions Copyright (c) 1993 by Digital Equipment Corporation.
      50   *
      51   * Permission to use, copy, modify, and distribute this software for any
      52   * purpose with or without fee is hereby granted, provided that the above
      53   * copyright notice and this permission notice appear in all copies, and that
      54   * the name of Digital Equipment Corporation not be used in advertising or
      55   * publicity pertaining to distribution of the document or software without
      56   * specific, written prior permission.
      57   *
      58   * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
      59   * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
      60   * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
      61   * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
      62   * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
      63   * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
      64   * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
      65   * SOFTWARE.
      66   */
      67  
      68  /*
      69   * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
      70   *
      71   * Permission to use, copy, modify, and distribute this software for any
      72   * purpose with or without fee is hereby granted, provided that the above
      73   * copyright notice and this permission notice appear in all copies.
      74   *
      75   * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
      76   * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
      77   * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
      78   * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
      79   * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
      80   * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
      81   * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
      82   * SOFTWARE.
      83   */
      84  
      85  #include <ctype.h>
      86  #include <netdb.h>
      87  #include <resolv/resolv-internal.h>
      88  #include <res_hconf.h>
      89  #include <stdio.h>
      90  #include <stdio_ext.h>
      91  #include <stdlib.h>
      92  #include <string.h>
      93  #include <unistd.h>
      94  #include <stdint.h>
      95  #include <arpa/inet.h>
      96  #include <arpa/nameser.h>
      97  #include <net/if.h>
      98  #include <netinet/in.h>
      99  #include <sys/param.h>
     100  #include <sys/socket.h>
     101  #include <sys/time.h>
     102  #include <sys/types.h>
     103  #include <inet/net-internal.h>
     104  #include <errno.h>
     105  #include <resolv_conf.h>
     106  #include <file_change_detection.h>
     107  
     108  static uint32_t net_mask (struct in_addr);
     109  
     110  int
     111  res_ninit (res_state statp)
     112  {
     113    return __res_vinit (statp, 0);
     114  }
     115  libc_hidden_def (__res_ninit)
     116  
     117  /* Return true if CH separates the netmask in the "sortlist"
     118     directive.  */
     119  static inline bool
     120  is_sort_mask (char ch)
     121  {
     122    return ch == '/' || ch == '&';
     123  }
     124  
     125  /* Array of name server addresses.  */
     126  #define DYNARRAY_STRUCT nameserver_list
     127  #define DYNARRAY_ELEMENT const struct sockaddr *
     128  #define DYNARRAY_ELEMENT_FREE(e) free ((struct sockaddr *) *(e))
     129  #define DYNARRAY_INITIAL_SIZE 3
     130  #define DYNARRAY_PREFIX nameserver_list_
     131  #include <malloc/dynarray-skeleton.c>
     132  
     133  /* Array of strings for the search array.  The backing store is
     134     managed separately.  */
     135  #define DYNARRAY_STRUCT search_list
     136  #define DYNARRAY_ELEMENT const char *
     137  #define DYNARRAY_INITIAL_SIZE 6
     138  #define DYNARRAY_PREFIX search_list_
     139  #include <malloc/dynarray-skeleton.c>
     140  
     141  /* Array of name server addresses.  */
     142  #define DYNARRAY_STRUCT sort_list
     143  #define DYNARRAY_ELEMENT struct resolv_sortlist_entry
     144  #define DYNARRAY_INITIAL_SIZE 0
     145  #define DYNARRAY_PREFIX sort_list_
     146  #include <malloc/dynarray-skeleton.c>
     147  
     148  /* resolv.conf parser state and results.  */
     149  struct resolv_conf_parser
     150  {
     151    char *buffer;            /* Temporary buffer for reading lines.  */
     152  
     153    struct nameserver_list nameserver_list; /* Nameserver addresses.  */
     154  
     155    char *search_list_store; /* Backing storage for search list entries.  */
     156    struct search_list search_list; /* Points into search_list_store.  */
     157  
     158    struct sort_list sort_list;   /* Address preference sorting list.  */
     159  
     160    /* Configuration template.  The non-array elements are filled in
     161       directly.  The array elements are updated prior to the call to
     162       __resolv_conf_attach.  */
     163    struct resolv_conf template;
     164  };
     165  
     166  /* Return true if *PREINIT contains actual preinitialization.  */
     167  static bool
     168  has_preinit_values (const struct __res_state *preinit)
     169  {
     170    return (preinit->retrans != 0 && preinit->retrans != RES_TIMEOUT)
     171      || (preinit->retry != 0 && preinit->retry != RES_DFLRETRY)
     172      || (preinit->options != 0
     173          && (preinit->options & ~RES_INIT) != RES_DEFAULT);
     174  }
     175  
     176  static void
     177  resolv_conf_parser_init (struct resolv_conf_parser *parser,
     178                           const struct __res_state *preinit)
     179  {
     180    parser->buffer = NULL;
     181    parser->search_list_store = NULL;
     182    nameserver_list_init (&parser->nameserver_list);
     183    search_list_init (&parser->search_list);
     184    sort_list_init (&parser->sort_list);
     185  
     186    if (preinit != NULL)
     187      {
     188        parser->template.retrans = preinit->retrans;
     189        parser->template.retry = preinit->retry;
     190        parser->template.options = preinit->options | RES_INIT;
     191      }
     192    else
     193      {
     194        parser->template.retrans = RES_TIMEOUT;
     195        parser->template.retry = RES_DFLRETRY;
     196        parser->template.options = RES_DEFAULT | RES_INIT;
     197      }
     198    parser->template.ndots = 1;
     199  }
     200  
     201  static void
     202  resolv_conf_parser_free (struct resolv_conf_parser *parser)
     203  {
     204    free (parser->buffer);
     205    free (parser->search_list_store);
     206    nameserver_list_free (&parser->nameserver_list);
     207    search_list_free (&parser->search_list);
     208    sort_list_free (&parser->sort_list);
     209  }
     210  
     211  /* Allocate a struct sockaddr_in object on the heap, with the
     212     specified address and port.  */
     213  static struct sockaddr *
     214  allocate_address_v4 (struct in_addr a, uint16_t port)
     215  {
     216    struct sockaddr_in *sa4 = malloc (sizeof (*sa4));
     217    if (sa4 == NULL)
     218      return NULL;
     219    sa4->sin_family = AF_INET;
     220    sa4->sin_addr = a;
     221    sa4->sin_port = htons (port);
     222    return (struct sockaddr *) sa4;
     223  }
     224  
     225  /* Try to obtain the domain name from the host name and store it in
     226     *RESULT.  Return false on memory allocation failure.  If the domain
     227     name cannot be determined for any other reason, write NULL to
     228     *RESULT and return true.  */
     229  static bool
     230  domain_from_hostname (char **result)
     231  {
     232    char buf[256];
     233    /* gethostbyname may not terminate the buffer.  */
     234    buf[sizeof (buf) - 1] = '\0';
     235    if (__gethostname (buf, sizeof (buf) - 1) == 0)
     236      {
     237        char *dot = strchr (buf, '.');
     238        if (dot != NULL)
     239          {
     240            *result = __strdup (dot + 1);
     241            if (*result == NULL)
     242              return false;
     243            return true;
     244          }
     245      }
     246    *result = NULL;
     247    return true;
     248  }
     249  
     250  static void res_setoptions (struct resolv_conf_parser *, const char *options);
     251  
     252  /* Internal helper function for __res_vinit, to aid with resource
     253     deallocation and error handling.  Return true on success, false on
     254     failure.  */
     255  static bool
     256  res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser)
     257  {
     258    char *cp;
     259    size_t buffer_size = 0;
     260    bool haveenv = false;
     261  
     262    /* Allow user to override the local domain definition.  */
     263    if ((cp = getenv ("LOCALDOMAIN")) != NULL)
     264      {
     265        /* The code below splits the string in place.  */
     266        cp = __strdup (cp);
     267        if (cp == NULL)
     268          return false;
     269        free (parser->search_list_store);
     270        parser->search_list_store = cp;
     271        haveenv = true;
     272  
     273        /* The string will be truncated as needed below.  */
     274        search_list_add (&parser->search_list, cp);
     275  
     276        /* Set search list to be blank-separated strings from rest of
     277           env value.  Permits users of LOCALDOMAIN to still have a
     278           search list, and anyone to set the one that they want to use
     279           as an individual (even more important now that the rfc1535
     280           stuff restricts searches).  */
     281        for (bool in_name = true; *cp != '\0'; cp++)
     282          {
     283            if (*cp == '\n')
     284              {
     285                *cp = '\0';
     286                break;
     287              }
     288            else if (*cp == ' ' || *cp == '\t')
     289              {
     290                *cp = '\0';
     291                in_name = false;
     292              }
     293            else if (!in_name)
     294              {
     295                search_list_add (&parser->search_list, cp);
     296                in_name = true;
     297              }
     298          }
     299      }
     300  
     301  #define MATCH(line, name)                       \
     302    (!strncmp ((line), name, sizeof (name) - 1)     \
     303     && ((line)[sizeof (name) - 1] == ' '           \
     304         || (line)[sizeof (name) - 1] == '\t'))
     305  
     306    if (fp != NULL)
     307      {
     308        /* No threads use this stream.  */
     309        __fsetlocking (fp, FSETLOCKING_BYCALLER);
     310        /* Read the config file.  */
     311        while (true)
     312          {
     313            {
     314              ssize_t ret = __getline (&parser->buffer, &buffer_size, fp);
     315              if (ret <= 0)
     316                {
     317                  if (_IO_ferror_unlocked (fp))
     318                    return false;
     319                  else
     320                    break;
     321                }
     322            }
     323  
     324            /* Skip comments.  */
     325            if (*parser->buffer == ';' || *parser->buffer == '#')
     326              continue;
     327            /* Read default domain name.  */
     328            if (MATCH (parser->buffer, "domain"))
     329              {
     330                if (haveenv)
     331                  /* LOCALDOMAIN overrides the configuration file.  */
     332                  continue;
     333                cp = parser->buffer + sizeof ("domain") - 1;
     334                while (*cp == ' ' || *cp == '\t')
     335                  cp++;
     336                if ((*cp == '\0') || (*cp == '\n'))
     337                  continue;
     338  
     339                cp = __strdup (cp);
     340                if (cp == NULL)
     341                  return false;
     342                free (parser->search_list_store);
     343                parser->search_list_store = cp;
     344                search_list_clear (&parser->search_list);
     345                search_list_add (&parser->search_list, cp);
     346                /* Replace trailing whitespace.  */
     347                if ((cp = strpbrk (cp, " \t\n")) != NULL)
     348                  *cp = '\0';
     349                continue;
     350              }
     351            /* Set search list.  */
     352            if (MATCH (parser->buffer, "search"))
     353              {
     354                if (haveenv)
     355                  /* LOCALDOMAIN overrides the configuration file.  */
     356                  continue;
     357                cp = parser->buffer + sizeof ("search") - 1;
     358                while (*cp == ' ' || *cp == '\t')
     359                  cp++;
     360                if ((*cp == '\0') || (*cp == '\n'))
     361                  continue;
     362  
     363                {
     364                  char *p = strchr (cp, '\n');
     365                  if (p != NULL)
     366                    *p = '\0';
     367                }
     368                cp = __strdup (cp);
     369                if (cp == NULL)
     370                  return false;
     371                free (parser->search_list_store);
     372                parser->search_list_store = cp;
     373  
     374                /* The string is truncated below.  */
     375                search_list_clear (&parser->search_list);
     376                search_list_add (&parser->search_list, cp);
     377  
     378                /* Set search list to be blank-separated strings on rest
     379                   of line.  */
     380                for (bool in_name = true; *cp != '\0'; cp++)
     381                  {
     382                    if (*cp == ' ' || *cp == '\t')
     383                      {
     384                        *cp = '\0';
     385                        in_name = false;
     386                      }
     387                    else if (!in_name)
     388                      {
     389                        search_list_add (&parser->search_list, cp);
     390                        in_name = true;
     391                      }
     392                  }
     393                continue;
     394              }
     395            /* Read nameservers to query.  */
     396            if (MATCH (parser->buffer, "nameserver"))
     397              {
     398                struct in_addr a;
     399  
     400                cp = parser->buffer + sizeof ("nameserver") - 1;
     401                while (*cp == ' ' || *cp == '\t')
     402                  cp++;
     403  
     404                /* Ignore trailing contents on the name server line.  */
     405                {
     406                  char *el;
     407                  if ((el = strpbrk (cp, " \t\n")) != NULL)
     408                    *el = '\0';
     409                }
     410  
     411                struct sockaddr *sa;
     412                if ((*cp != '\0') && (*cp != '\n') && __inet_aton_exact (cp, &a))
     413                  {
     414                    sa = allocate_address_v4 (a, NAMESERVER_PORT);
     415                    if (sa == NULL)
     416                      return false;
     417                  }
     418                else
     419                  {
     420                    struct in6_addr a6;
     421                    char *el;
     422                    if ((el = strchr (cp, SCOPE_DELIMITER)) != NULL)
     423                      *el = '\0';
     424                    if ((*cp != '\0') && (__inet_pton (AF_INET6, cp, &a6) > 0))
     425                      {
     426                        struct sockaddr_in6 *sa6;
     427  
     428                        sa6 = malloc (sizeof (*sa6));
     429                        if (sa6 == NULL)
     430                          return false;
     431  
     432                        sa6->sin6_family = AF_INET6;
     433                        sa6->sin6_port = htons (NAMESERVER_PORT);
     434                        sa6->sin6_flowinfo = 0;
     435                        sa6->sin6_addr = a6;
     436  
     437                        sa6->sin6_scope_id = 0;
     438                        if (__glibc_likely (el != NULL))
     439                          /* Ignore errors, for backwards
     440                             compatibility.  */
     441                          __inet6_scopeid_pton
     442                            (&a6, el + 1, &sa6->sin6_scope_id);
     443                        sa = (struct sockaddr *) sa6;
     444                      }
     445                    else
     446                      /* IPv6 address parse failure.  */
     447                      sa = NULL;
     448                  }
     449                if (sa != NULL)
     450                  {
     451                    const struct sockaddr **p = nameserver_list_emplace
     452                      (&parser->nameserver_list);
     453                    if (p != NULL)
     454                      *p = sa;
     455                    else
     456                      {
     457                        free (sa);
     458                        return false;
     459                      }
     460                  }
     461                continue;
     462              }
     463            if (MATCH (parser->buffer, "sortlist"))
     464              {
     465                struct in_addr a;
     466  
     467                cp = parser->buffer + sizeof ("sortlist") - 1;
     468                while (true)
     469                  {
     470                    while (*cp == ' ' || *cp == '\t')
     471                      cp++;
     472                    if (*cp == '\0' || *cp == '\n' || *cp == ';')
     473                      break;
     474                    char *net = cp;
     475                    while (*cp && !is_sort_mask (*cp) && *cp != ';'
     476                           && isascii (*cp) && !isspace (*cp))
     477                      cp++;
     478                    char separator = *cp;
     479                    *cp = 0;
     480                    struct resolv_sortlist_entry e;
     481                    if (__inet_aton_exact (net, &a))
     482                      {
     483                        e.addr = a;
     484                        if (is_sort_mask (separator))
     485                          {
     486                            *cp++ = separator;
     487                            net = cp;
     488                            while (*cp && *cp != ';'
     489                                   && isascii (*cp) && !isspace (*cp))
     490                              cp++;
     491                            separator = *cp;
     492                            *cp = 0;
     493                            if (__inet_aton_exact (net, &a))
     494                              e.mask = a.s_addr;
     495                            else
     496                              e.mask = net_mask (e.addr);
     497                          }
     498                        else
     499                          e.mask = net_mask (e.addr);
     500                        sort_list_add (&parser->sort_list, e);
     501                      }
     502                    *cp = separator;
     503                  }
     504                continue;
     505              }
     506            if (MATCH (parser->buffer, "options"))
     507              {
     508                res_setoptions (parser, parser->buffer + sizeof ("options") - 1);
     509                continue;
     510              }
     511          }
     512      }
     513    if (__glibc_unlikely (nameserver_list_size (&parser->nameserver_list) == 0))
     514      {
     515        const struct sockaddr **p
     516          = nameserver_list_emplace (&parser->nameserver_list);
     517        if (p == NULL)
     518          return false;
     519        *p = allocate_address_v4 (__inet_makeaddr (IN_LOOPBACKNET, 1),
     520                                  NAMESERVER_PORT);
     521        if (*p == NULL)
     522          return false;
     523      }
     524  
     525    if (search_list_size (&parser->search_list) == 0)
     526      {
     527        char *domain;
     528        if (!domain_from_hostname (&domain))
     529          return false;
     530        if (domain != NULL)
     531          {
     532            free (parser->search_list_store);
     533            parser->search_list_store = domain;
     534            search_list_add (&parser->search_list, domain);
     535          }
     536      }
     537  
     538    if ((cp = getenv ("RES_OPTIONS")) != NULL)
     539      res_setoptions (parser, cp);
     540  
     541    if (nameserver_list_has_failed (&parser->nameserver_list)
     542        || search_list_has_failed (&parser->search_list)
     543        || sort_list_has_failed (&parser->sort_list))
     544      {
     545        __set_errno (ENOMEM);
     546        return false;
     547      }
     548  
     549    return true;
     550  }
     551  
     552  struct resolv_conf *
     553  __resolv_conf_load (struct __res_state *preinit,
     554                      struct file_change_detection *change)
     555  {
     556    /* Ensure that /etc/hosts.conf has been loaded (once).  */
     557    _res_hconf_init ();
     558  
     559    FILE *fp = fopen (_PATH_RESCONF, "rce");
     560    if (fp == NULL)
     561      switch (errno)
     562        {
     563        case EACCES:
     564        case EISDIR:
     565        case ELOOP:
     566        case ENOENT:
     567        case ENOTDIR:
     568        case EPERM:
     569          /* Ignore these errors.  They are persistent errors caused
     570             by file system contents.  */
     571          break;
     572        default:
     573          /* Other errors refer to resource allocation problems and
     574             need to be handled by the application.  */
     575          return NULL;
     576        }
     577  
     578    struct resolv_conf_parser parser;
     579    resolv_conf_parser_init (&parser, preinit);
     580  
     581    struct resolv_conf *conf = NULL;
     582    bool ok = res_vinit_1 (fp, &parser);
     583    if (ok && change != NULL)
     584      /* Update the file change information if the configuration was
     585         loaded successfully.  */
     586      ok = __file_change_detection_for_fp (change, fp);
     587  
     588    if (ok)
     589      {
     590        parser.template.nameserver_list
     591          = nameserver_list_begin (&parser.nameserver_list);
     592        parser.template.nameserver_list_size
     593          = nameserver_list_size (&parser.nameserver_list);
     594        parser.template.search_list = search_list_begin (&parser.search_list);
     595        parser.template.search_list_size
     596          = search_list_size (&parser.search_list);
     597        parser.template.sort_list = sort_list_begin (&parser.sort_list);
     598        parser.template.sort_list_size = sort_list_size (&parser.sort_list);
     599        conf = __resolv_conf_allocate (&parser.template);
     600      }
     601    resolv_conf_parser_free (&parser);
     602  
     603    if (fp != NULL)
     604      {
     605        int saved_errno = errno;
     606        fclose (fp);
     607        __set_errno (saved_errno);
     608      }
     609  
     610    return conf;
     611  }
     612  
     613  /* Set up default settings.  If the /etc/resolv.conf configuration
     614     file exist, the values there will have precedence.  Otherwise, the
     615     server address is set to INADDR_LOOPBACK and the default domain
     616     name comes from gethostname.  The RES_OPTIONS and LOCALDOMAIN
     617     environment variables can be used to override some settings.
     618     Return 0 if completes successfully, -1 on error.  */
     619  int
     620  __res_vinit (res_state statp, int preinit)
     621  {
     622    struct resolv_conf *conf;
     623    if (preinit && has_preinit_values (statp))
     624      /* For the preinit case, we cannot use the cached configuration
     625         because some settings could be different.  */
     626      conf = __resolv_conf_load (statp, NULL);
     627    else
     628      conf = __resolv_conf_get_current ();
     629    if (conf == NULL)
     630      return -1;
     631  
     632    bool ok = __resolv_conf_attach (statp, conf);
     633    __resolv_conf_put (conf);
     634    if (ok)
     635      {
     636        if (preinit)
     637          statp->id = res_randomid ();
     638        return 0;
     639      }
     640    else
     641      return -1;
     642  }
     643  
     644  static void
     645  res_setoptions (struct resolv_conf_parser *parser, const char *options)
     646  {
     647    const char *cp = options;
     648  
     649    while (*cp)
     650      {
     651        /* Skip leading and inner runs of spaces.  */
     652        while (*cp == ' ' || *cp == '\t')
     653          cp++;
     654        /* Search for and process individual options.  */
     655        if (!strncmp (cp, "ndots:", sizeof ("ndots:") - 1))
     656          {
     657            int i = strtol (cp + sizeof ("ndots:") - 1, NULL, 10);
     658            if (i <= RES_MAXNDOTS)
     659              parser->template.ndots = i;
     660            else
     661              parser->template.ndots = RES_MAXNDOTS;
     662          }
     663        else if (!strncmp (cp, "timeout:", sizeof ("timeout:") - 1))
     664          {
     665            int i = strtol (cp + sizeof ("timeout:") - 1, NULL, 10);
     666            if (i <= RES_MAXRETRANS)
     667              parser->template.retrans = i;
     668            else
     669              parser->template.retrans = RES_MAXRETRANS;
     670          }
     671        else if (!strncmp (cp, "attempts:", sizeof ("attempts:") - 1))
     672          {
     673            int i = strtol (cp + sizeof ("attempts:") - 1, NULL, 10);
     674            if (i <= RES_MAXRETRY)
     675              parser->template.retry = i;
     676            else
     677              parser->template.retry = RES_MAXRETRY;
     678          }
     679        else
     680          {
     681            static const struct
     682            {
     683              char str[22];
     684              uint8_t len;
     685              uint8_t clear;
     686              unsigned long int flag;
     687            } options[] = {
     688  #define STRnLEN(str) str, sizeof (str) - 1
     689              { STRnLEN ("rotate"), 0, RES_ROTATE },
     690              { STRnLEN ("edns0"), 0, RES_USE_EDNS0 },
     691              { STRnLEN ("single-request-reopen"), 0, RES_SNGLKUPREOP },
     692              { STRnLEN ("single-request"), 0, RES_SNGLKUP },
     693              { STRnLEN ("no_tld_query"), 0, RES_NOTLDQUERY },
     694              { STRnLEN ("no-tld-query"), 0, RES_NOTLDQUERY },
     695              { STRnLEN ("no-reload"), 0, RES_NORELOAD },
     696              { STRnLEN ("use-vc"), 0, RES_USEVC },
     697              { STRnLEN ("trust-ad"), 0, RES_TRUSTAD },
     698              { STRnLEN ("no-aaaa"), 0, RES_NOAAAA },
     699            };
     700  #define noptions (sizeof (options) / sizeof (options[0]))
     701            for (int i = 0; i < noptions; ++i)
     702              if (strncmp (cp, options[i].str, options[i].len) == 0)
     703                {
     704                  if (options[i].clear)
     705                    parser->template.options &= options[i].flag;
     706                  else
     707                    parser->template.options |= options[i].flag;
     708                  break;
     709                }
     710          }
     711        /* Skip to next run of spaces.  */
     712        while (*cp && *cp != ' ' && *cp != '\t')
     713          cp++;
     714      }
     715  }
     716  
     717  static uint32_t
     718  net_mask (struct in_addr in)
     719  {
     720    uint32_t i = ntohl (in.s_addr);
     721  
     722    if (IN_CLASSA (i))
     723      return htonl (IN_CLASSA_NET);
     724    else if (IN_CLASSB (i))
     725      return htonl (IN_CLASSB_NET);
     726    return htonl (IN_CLASSC_NET);
     727  }