(linenum→info "unix/slp.c:2238")

glibc/2.7/resolv/res_hconf.c

    1: /* Copyright (C) 1993, 1995-2006, 2007 Free Software Foundation, Inc.
    2:    This file is part of the GNU C Library.
    3:    Contributed by David Mosberger (davidm@azstarnet.com).
    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, write to the Free
   17:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   18:    02111-1307 USA.  */
   19: 
   20: /* This file provides a Linux /etc/host.conf compatible front end to
   21:    the various name resolvers (/etc/hosts, named, NIS server, etc.).
   22:    Though mostly compatibly, the following differences exist compared
   23:    to the original implementation:
   24: 
   25:         - new command "spoof" takes an arguments like RESOLV_SPOOF_CHECK
   26:           environment variable (i.e., `off', `nowarn', or `warn').
   27: 
   28:         - line comments can appear anywhere (not just at the beginning of
   29:           a line)
   30: */
   31: 
   32: #include <assert.h>
   33: #include <errno.h>
   34: #include <ctype.h>
   35: #include <libintl.h>
   36: #include <memory.h>
   37: #include <stdio.h>
   38: #include <stdio_ext.h>
   39: #include <stdlib.h>
   40: #include <string.h>
   41: #include <net/if.h>
   42: #include <sys/ioctl.h>
   43: #include <unistd.h>
   44: #include <netinet/in.h>
   45: #include <bits/libc-lock.h>
   46: #include "ifreq.h"
   47: #include "res_hconf.h"
   48: #ifdef USE_IN_LIBIO
   49: # include <wchar.h>
   50: #endif
   51: 
   52: #define _PATH_HOSTCONF  "/etc/host.conf"
   53: 
   54: /* Environment vars that all user to override default behavior:  */
   55: #define ENV_HOSTCONF    "RESOLV_HOST_CONF"
   56: #define ENV_SPOOF       "RESOLV_SPOOF_CHECK"
   57: #define ENV_TRIM_OVERR  "RESOLV_OVERRIDE_TRIM_DOMAINS"
   58: #define ENV_TRIM_ADD    "RESOLV_ADD_TRIM_DOMAINS"
   59: #define ENV_MULTI       "RESOLV_MULTI"
   60: #define ENV_REORDER     "RESOLV_REORDER"
   61: 
   62: enum parse_cbs
   63:   {
   64:     CB_none,
   65:     CB_arg_trimdomain_list,
   66:     CB_arg_spoof,
   67:     CB_arg_bool
   68:   };
   69: 
   70: static const struct cmd
   71: {
   72:   const char name[11];
   73:   uint8_t cb;
   74:   unsigned int arg;
   75: } cmd[] =
   76: {
   77:   {"order",             CB_none,           0},
   78:   {"trim",              CB_arg_trimdomain_list,     0},
   79:   {"spoof",             CB_arg_spoof,              0},
   80:   {"multi",             CB_arg_bool,               HCONF_FLAG_MULTI},
   81:   {"nospoof",           CB_arg_bool,             HCONF_FLAG_SPOOF},
   82:   {"spoofalert",        CB_arg_bool,           HCONF_FLAG_SPOOFALERT},
   83:   {"reorder",           CB_arg_bool,             HCONF_FLAG_REORDER}
   84: };
   85: 
   86: /* Structure containing the state.  */
   87: struct hconf _res_hconf;
   88: 
   89: /* Skip white space.  */
   90: static const char *
   91: skip_ws (const char *str)
   92: {
   93:   while (isspace (*str)) ++str;
   94:   return str;
   95: }
   96: 
   97: 
   98: /* Skip until whitespace, comma, end of line, or comment character.  */
   99: static const char *
  100: skip_string (const char *str)
  101: {
  102:   while (*str && !isspace (*str) && *str != '#' && *str != ',')
  103:     ++str;
  104:   return str;
  105: }
  106: 
  107: 
  108: static const char *
  109: arg_trimdomain_list (const char *fname, int line_num, const char *args)
  110: {
  111:   const char * start;
  112:   size_t len;
  113: 
  114:   do
  115:     {
  116:       start = args;
  117:       args = skip_string (args);
  118:       len = args - start;
  119: 
  120:       if (_res_hconf.num_trimdomains >= TRIMDOMAINS_MAX)
  121:         {
  122:           char *buf;
  123: 
  124:           if (__asprintf (&buf, _("\
  125: %s: line %d: cannot specify more than %d trim domains"),
  126:                           fname, line_num, TRIMDOMAINS_MAX) < 0)
  127:             return 0;
  128: 
  129:           __fxprintf (NULL, "%s", buf);
  130: 
  131:           free (buf);
  132:           return 0;
  133:         }
  134:       _res_hconf.trimdomain[_res_hconf.num_trimdomains++] =
  135:         __strndup (start, len);
  136:       args = skip_ws (args);
  137:       switch (*args)
  138:         {
  139:         case ',': case ';': case ':':
  140:           args = skip_ws (++args);
  141:           if (!*args || *args == '#')
  142:             {
  143:               char *buf;
  144: 
  145:               if (__asprintf (&buf, _("\
  146: %s: line %d: list delimiter not followed by domain"),
  147:                               fname, line_num) < 0)
  148:                 return 0;
  149: 
  150:               __fxprintf (NULL, "%s", buf);
  151: 
  152:               free (buf);
  153:               return 0;
  154:             }
  155:         default:
  156:           break;
  157:         }
  158:     }
  159:   while (*args && *args != '#');
  160:   return args;
  161: }
  162: 
  163: 
  164: static const char *
  165: arg_spoof (const char *fname, int line_num, const char *args)
  166: {
  167:   const char *start = args;
  168:   size_t len;
  169: 
  170:   args = skip_string (args);
  171:   len = args - start;
  172: 
  173:   if (len == 3 && __strncasecmp (start, "off", len) == 0)
  174:     _res_hconf.flags &= ~(HCONF_FLAG_SPOOF | HCONF_FLAG_SPOOFALERT);
  175:   else
  176:     {
  177:       _res_hconf.flags |= (HCONF_FLAG_SPOOF | HCONF_FLAG_SPOOFALERT);
  178:       if ((len == 6 && __strncasecmp (start, "nowarn", len) == 0)
  179:           || !(len == 4 && __strncasecmp (start, "warn", len) == 0))
  180:         _res_hconf.flags &= ~HCONF_FLAG_SPOOFALERT;
  181:     }
  182:   return args;
  183: }
  184: 
  185: 
  186: static const char *
  187: arg_bool (const char *fname, int line_num, const char *args, unsigned flag)
  188: {
  189:   if (__strncasecmp (args, "on", 2) == 0)
  190:     {
  191:       args += 2;
  192:       _res_hconf.flags |= flag;
  193:     }
  194:   else if (__strncasecmp (args, "off", 3) == 0)
  195:     {
  196:       args += 3;
  197:       _res_hconf.flags &= ~flag;
  198:     }
  199:   else
  200:     {
  201:       char *buf;
  202: 
  203:       if (__asprintf (&buf,
  204:                       _("%s: line %d: expected `on' or `off', found `%s'\n"),
  205:                       fname, line_num, args) < 0)
  206:         return 0;
  207: 
  208:       __fxprintf (NULL, "%s", buf);
  209: 
  210:       free (buf);
  211:       return 0;
  212:     }
  213:   return args;
  214: }
  215: 
  216: 
  217: static void
  218: parse_line (const char *fname, int line_num, const char *str)
  219: {
  220:   const char *start;
  221:   const struct cmd *c = 0;
  222:   size_t len;
  223:   size_t i;
  224: 
  225:   str = skip_ws (str);
  226: 
  227:   /* skip line comment and empty lines: */
  228:   if (*str == '\0' || *str == '#') return;
  229: 
  230:   start = str;
  231:   str = skip_string (str);
  232:   len = str - start;
  233: 
  234:   for (i = 0; i < sizeof (cmd) / sizeof (cmd[0]); ++i)
  235:     {
  236:       if (__strncasecmp (start, cmd[i].name, len) == 0
  237:           && strlen (cmd[i].name) == len)
  238:         {
  239:           c = &cmd[i];
  240:           break;
  241:         }
  242:     }
  243:   if (c == NULL)
  244:     {
  245:       char *buf;
  246: 
  247:       if (__asprintf (&buf, _("%s: line %d: bad command `%s'\n"),
  248:                       fname, line_num, start) < 0)
  249:         return;
  250: 
  251:       __fxprintf (NULL, "%s", buf);
  252: 
  253:       free (buf);
  254:       return;
  255:     }
  256: 
  257:   /* process args: */
  258:   str = skip_ws (str);
  259: 
  260:   if (c->cb == CB_arg_trimdomain_list)
  261:     str = arg_trimdomain_list (fname, line_num, str);
  262:   else if (c->cb == CB_arg_spoof)
  263:     str = arg_spoof (fname, line_num, str);
  264:   else if (c->cb == CB_arg_bool)
  265:     str = arg_bool (fname, line_num, str, c->arg);
  266:   else
  267:     /* Ignore the line.  */
  268:     return;
  269: 
  270:   if (!str)
  271:     return;
  272: 
  273:   /* rest of line must contain white space or comment only: */
  274:   while (*str)
  275:     {
  276:       if (!isspace (*str)) {
  277:         if (*str != '#')
  278:           {
  279:             char *buf;
  280: 
  281:             if (__asprintf (&buf,
  282:                             _("%s: line %d: ignoring trailing garbage `%s'\n"),
  283:                             fname, line_num, str) < 0)
  284:               break;
  285: 
  286:             __fxprintf (NULL, "%s", buf);
  287: 
  288:             free (buf);
  289:           }
  290:         break;
  291:       }
  292:       ++str;
  293:     }
  294: }
  295: 
  296: 
  297: static void
  298: do_init (void)
  299: {
  300:   const char *hconf_name;
  301:   int line_num = 0;
  302:   char buf[256], *envval;
  303:   FILE *fp;
  304: 
  305:   memset (&_res_hconf, '\0', sizeof (_res_hconf));
  306: 
  307:   hconf_name = getenv (ENV_HOSTCONF);
  308:   if (hconf_name == NULL)
  309:     hconf_name = _PATH_HOSTCONF;
  310: 
  311:   fp = fopen (hconf_name, "rc");
  312:   if (fp)
  313:     {
  314:       /* No threads using this stream.  */
  315:       __fsetlocking (fp, FSETLOCKING_BYCALLER);
  316: 
  317:       while (fgets_unlocked (buf, sizeof (buf), fp))
  318:         {
  319:           ++line_num;
  320:           *__strchrnul (buf, '\n') = '\0';
  321:           parse_line (hconf_name, line_num, buf);
  322:         }
  323:       fclose (fp);
  324:     }
  325: 
  326:   envval = getenv (ENV_SPOOF);
  327:   if (envval)
  328:     arg_spoof (ENV_SPOOF, 1, envval);
  329: 
  330:   envval = getenv (ENV_MULTI);
  331:   if (envval)
  332:     arg_bool (ENV_MULTI, 1, envval, HCONF_FLAG_MULTI);
  333: 
  334:   envval = getenv (ENV_REORDER);
  335:   if (envval)
  336:     arg_bool (ENV_REORDER, 1, envval, HCONF_FLAG_REORDER);
  337: 
  338:   envval = getenv (ENV_TRIM_ADD);
  339:   if (envval)
  340:     arg_trimdomain_list (ENV_TRIM_ADD, 1, envval);
  341: 
  342:   envval = getenv (ENV_TRIM_OVERR);
  343:   if (envval)
  344:     {
  345:       _res_hconf.num_trimdomains = 0;
  346:       arg_trimdomain_list (ENV_TRIM_OVERR, 1, envval);
  347:     }
  348: 
  349:   _res_hconf.initialized = 1;
  350: }
  351: 
  352: 
  353: /* Initialize hconf datastructure by reading host.conf file and
  354:    environment variables.  */
  355: void
  356: _res_hconf_init (void)
  357: {
  358:   __libc_once_define (static, once);
  359: 
  360:   __libc_once (once, do_init);
  361: }
  362: 
  363: 
  364: #ifndef NOT_IN_libc
  365: /* List of known interfaces.  */
  366: libc_freeres_ptr (
  367: static struct netaddr
  368: {
  369:   int addrtype;
  370:   union
  371:   {
  372:     struct
  373:     {
  374:       u_int32_t addr;
  375:       u_int32_t mask;
  376:     } ipv4;
  377:   } u;
  378: } *ifaddrs);
  379: 
  380: /* We need to protect the dynamic buffer handling.  */
  381: __libc_lock_define_initialized (static, lock);
  382: 
  383: /* Reorder addresses returned in a hostent such that the first address
  384:    is an address on the local subnet, if there is such an address.
  385:    Otherwise, nothing is changed.
  386: 
  387:    Note that this function currently only handles IPv4 addresses.  */
  388: 
  389: void
  390: _res_hconf_reorder_addrs (struct hostent *hp)
  391: {
  392: #if defined SIOCGIFCONF && defined SIOCGIFNETMASK
  393:   int i, j;
  394:   /* Number of interfaces.  */
  395:   static int num_ifs = -1;
  396: 
  397:   /* Only reorder if we're supposed to.  */
  398:   if ((_res_hconf.flags & HCONF_FLAG_REORDER) == 0)
  399:     return;
  400: 
  401:   /* Can't deal with anything but IPv4 for now...  */
  402:   if (hp->h_addrtype != AF_INET)
  403:     return;
  404: 
  405:   if (num_ifs <= 0)
  406:     {
  407:       struct ifreq *ifr, *cur_ifr;
  408:       int sd, num, i;
  409:       /* Save errno.  */
  410:       int save = errno;
  411: 
  412:       /* Initialize interface table.  */
  413: 
  414:       num_ifs = 0;
  415: 
  416:       /* The SIOCGIFNETMASK ioctl will only work on an AF_INET socket.  */
  417:       sd = __socket (AF_INET, SOCK_DGRAM, 0);
  418:       if (sd < 0)
  419:         return;
  420: 
  421:       /* Get lock.  */
  422:       __libc_lock_lock (lock);
  423: 
  424:       /* Get a list of interfaces.  */
  425:       __ifreq (&ifr, &num, sd);
  426:       if (!ifr)
  427:         goto cleanup;
  428: 
  429:       ifaddrs = malloc (num * sizeof (ifaddrs[0]));
  430:       if (!ifaddrs)
  431:         goto cleanup1;
  432: 
  433:       /* Copy usable interfaces in ifaddrs structure.  */
  434:       for (cur_ifr = ifr, i = 0; i < num; cur_ifr = __if_nextreq (cur_ifr), ++i)
  435:         {
  436:           if (cur_ifr->ifr_addr.sa_family != AF_INET)
  437:             continue;
  438: 
  439:           ifaddrs[num_ifs].addrtype = AF_INET;
  440:           ifaddrs[num_ifs].u.ipv4.addr =
  441:             ((struct sockaddr_in *) &cur_ifr->ifr_addr)->sin_addr.s_addr;
  442: 
  443:           if (__ioctl (sd, SIOCGIFNETMASK, cur_ifr) < 0)
  444:             continue;
  445: 
  446:           ifaddrs[num_ifs].u.ipv4.mask =
  447:             ((struct sockaddr_in *) &cur_ifr->ifr_netmask)->sin_addr.s_addr;
  448: 
  449:           /* Now we're committed to this entry.  */
  450:           ++num_ifs;
  451:         }
  452:       /* Just keep enough memory to hold all the interfaces we want.  */
  453:       ifaddrs = realloc (ifaddrs, num_ifs * sizeof (ifaddrs[0]));
  454:       assert (ifaddrs != NULL);
  455: 
  456:     cleanup1:
  457:       __if_freereq (ifr, num);
  458: 
  459:     cleanup:
  460:       /* Release lock, preserve error value, and close socket.  */
  461:       save = errno;
  462:       __libc_lock_unlock (lock);
  463:       __close (sd);
  464:     }
  465: 
  466:   if (num_ifs == 0)
  467:     return;
  468: 
  469:   /* Find an address for which we have a direct connection.  */
  470:   for (i = 0; hp->h_addr_list[i]; ++i)
  471:     {
  472:       struct in_addr *haddr = (struct in_addr *) hp->h_addr_list[i];
  473: 
  474:       for (j = 0; j < num_ifs; ++j)
  475:         {
  476:           u_int32_t if_addr    = ifaddrs[j].u.ipv4.addr;
  477:           u_int32_t if_netmask = ifaddrs[j].u.ipv4.mask;
  478: 
  479:           if (((haddr->s_addr ^ if_addr) & if_netmask) == 0)
  480:             {
  481:               void *tmp;
  482: 
  483:               tmp = hp->h_addr_list[i];
  484:               hp->h_addr_list[i] = hp->h_addr_list[0];
  485:               hp->h_addr_list[0] = tmp;
  486:               return;
  487:             }
  488:         }
  489:     }
  490: #endif /* defined(SIOCGIFCONF) && ... */
  491: }
  492: 
  493: 
  494: /* If HOSTNAME has a postfix matching any of the trimdomains, trim away
  495:    that postfix.  Notice that HOSTNAME is modified inplace.  Also, the
  496:    original code applied all trimdomains in order, meaning that the
  497:    same domainname could be trimmed multiple times.  I believe this
  498:    was unintentional.  */
  499: void
  500: _res_hconf_trim_domain (char *hostname)
  501: {
  502:   size_t hostname_len, trim_len;
  503:   int i;
  504: 
  505:   hostname_len = strlen (hostname);
  506: 
  507:   for (i = 0; i < _res_hconf.num_trimdomains; ++i)
  508:     {
  509:       const char *trim = _res_hconf.trimdomain[i];
  510: 
  511:       trim_len = strlen (trim);
  512:       if (hostname_len > trim_len
  513:           && __strcasecmp (&hostname[hostname_len - trim_len], trim) == 0)
  514:         {
  515:           hostname[hostname_len - trim_len] = '\0';
  516:           break;
  517:         }
  518:     }
  519: }
  520: 
  521: 
  522: /* Trim all hostnames/aliases in HP according to the trimdomain list.
  523:    Notice that HP is modified inplace!  */
  524: void
  525: _res_hconf_trim_domains (struct hostent *hp)
  526: {
  527:   int i;
  528: 
  529:   if (_res_hconf.num_trimdomains == 0)
  530:     return;
  531: 
  532:   _res_hconf_trim_domain (hp->h_name);
  533:   for (i = 0; hp->h_aliases[i]; ++i)
  534:     _res_hconf_trim_domain (hp->h_aliases[i]);
  535: }
  536: #endif
1
Syntax (Markdown)