Blame resolv/res_hconf.c

Packit 6c4009
/* Copyright (C) 1993-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by David Mosberger (davidm@azstarnet.com).
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
/* This file provides a Linux /etc/host.conf compatible front end to
Packit 6c4009
   the various name resolvers (/etc/hosts, named, NIS server, etc.).
Packit 6c4009
   Though mostly compatibly, the following differences exist compared
Packit 6c4009
   to the original implementation:
Packit 6c4009
Packit 6c4009
	- line comments can appear anywhere (not just at the beginning of
Packit 6c4009
	  a line)
Packit 6c4009
*/
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <ctype.h>
Packit 6c4009
#include <libintl.h>
Packit 6c4009
#include <memory.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 <net/if.h>
Packit 6c4009
#include <sys/ioctl.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <netinet/in.h>
Packit 6c4009
#include <libc-lock.h>
Packit 6c4009
#include "ifreq.h"
Packit 6c4009
#include "res_hconf.h"
Packit 6c4009
#include <wchar.h>
Packit 6c4009
#include <atomic.h>
Packit 6c4009
Packit 6c4009
#if IS_IN (libc)
Packit 6c4009
# define fgets_unlocked __fgets_unlocked
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define _PATH_HOSTCONF	"/etc/host.conf"
Packit 6c4009
Packit 6c4009
/* Environment vars that all user to override default behavior:  */
Packit 6c4009
#define ENV_HOSTCONF	"RESOLV_HOST_CONF"
Packit 6c4009
#define ENV_TRIM_OVERR	"RESOLV_OVERRIDE_TRIM_DOMAINS"
Packit 6c4009
#define ENV_TRIM_ADD	"RESOLV_ADD_TRIM_DOMAINS"
Packit 6c4009
#define ENV_MULTI	"RESOLV_MULTI"
Packit 6c4009
#define ENV_REORDER	"RESOLV_REORDER"
Packit 6c4009
Packit 6c4009
enum parse_cbs
Packit 6c4009
  {
Packit 6c4009
    CB_none,
Packit 6c4009
    CB_arg_trimdomain_list,
Packit 6c4009
    CB_arg_bool
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
static const struct cmd
Packit 6c4009
{
Packit 6c4009
  const char name[11];
Packit 6c4009
  uint8_t cb;
Packit 6c4009
  unsigned int arg;
Packit 6c4009
} cmd[] =
Packit 6c4009
{
Packit 6c4009
  {"order",		CB_none,		0},
Packit 6c4009
  {"trim",		CB_arg_trimdomain_list,	0},
Packit 6c4009
  {"multi",		CB_arg_bool,		HCONF_FLAG_MULTI},
Packit 6c4009
  {"reorder",		CB_arg_bool,		HCONF_FLAG_REORDER}
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* Structure containing the state.  */
Packit 6c4009
struct hconf _res_hconf;
Packit 6c4009
Packit 6c4009
/* Skip white space.  */
Packit 6c4009
static const char *
Packit 6c4009
skip_ws (const char *str)
Packit 6c4009
{
Packit 6c4009
  while (isspace (*str)) ++str;
Packit 6c4009
  return str;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Skip until whitespace, comma, end of line, or comment character.  */
Packit 6c4009
static const char *
Packit 6c4009
skip_string (const char *str)
Packit 6c4009
{
Packit 6c4009
  while (*str && !isspace (*str) && *str != '#' && *str != ',')
Packit 6c4009
    ++str;
Packit 6c4009
  return str;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static const char *
Packit 6c4009
arg_trimdomain_list (const char *fname, int line_num, const char *args)
Packit 6c4009
{
Packit 6c4009
  const char * start;
Packit 6c4009
  size_t len;
Packit 6c4009
Packit 6c4009
  do
Packit 6c4009
    {
Packit 6c4009
      start = args;
Packit 6c4009
      args = skip_string (args);
Packit 6c4009
      len = args - start;
Packit 6c4009
Packit 6c4009
      if (_res_hconf.num_trimdomains >= TRIMDOMAINS_MAX)
Packit 6c4009
	{
Packit 6c4009
	  char *buf;
Packit 6c4009
Packit 6c4009
	  if (__asprintf (&buf, _("\
Packit 6c4009
%s: line %d: cannot specify more than %d trim domains"),
Packit 6c4009
			  fname, line_num, TRIMDOMAINS_MAX) < 0)
Packit 6c4009
	    return 0;
Packit 6c4009
Packit 6c4009
	  __fxprintf (NULL, "%s", buf);
Packit 6c4009
Packit 6c4009
	  free (buf);
Packit 6c4009
	  return 0;
Packit 6c4009
	}
Packit 6c4009
      _res_hconf.trimdomain[_res_hconf.num_trimdomains++] =
Packit 6c4009
	__strndup (start, len);
Packit 6c4009
      args = skip_ws (args);
Packit 6c4009
      switch (*args)
Packit 6c4009
	{
Packit 6c4009
	case ',': case ';': case ':':
Packit 6c4009
	  args = skip_ws (++args);
Packit 6c4009
	  if (!*args || *args == '#')
Packit 6c4009
	    {
Packit 6c4009
	      char *buf;
Packit 6c4009
Packit 6c4009
	      if (__asprintf (&buf, _("\
Packit 6c4009
%s: line %d: list delimiter not followed by domain"),
Packit 6c4009
			      fname, line_num) < 0)
Packit 6c4009
		return 0;
Packit 6c4009
Packit 6c4009
	      __fxprintf (NULL, "%s", buf);
Packit 6c4009
Packit 6c4009
	      free (buf);
Packit 6c4009
	      return 0;
Packit 6c4009
	    }
Packit 6c4009
	default:
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  while (*args && *args != '#');
Packit 6c4009
  return args;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static const char *
Packit 6c4009
arg_bool (const char *fname, int line_num, const char *args, unsigned flag)
Packit 6c4009
{
Packit 6c4009
  if (__strncasecmp (args, "on", 2) == 0)
Packit 6c4009
    {
Packit 6c4009
      args += 2;
Packit 6c4009
      _res_hconf.flags |= flag;
Packit 6c4009
    }
Packit 6c4009
  else if (__strncasecmp (args, "off", 3) == 0)
Packit 6c4009
    {
Packit 6c4009
      args += 3;
Packit 6c4009
      _res_hconf.flags &= ~flag;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      char *buf;
Packit 6c4009
Packit 6c4009
      if (__asprintf (&buf,
Packit 6c4009
		      _("%s: line %d: expected `on' or `off', found `%s'\n"),
Packit 6c4009
		      fname, line_num, args) < 0)
Packit 6c4009
	return 0;
Packit 6c4009
Packit 6c4009
      __fxprintf (NULL, "%s", buf);
Packit 6c4009
Packit 6c4009
      free (buf);
Packit 6c4009
      return 0;
Packit 6c4009
    }
Packit 6c4009
  return args;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
parse_line (const char *fname, int line_num, const char *str)
Packit 6c4009
{
Packit 6c4009
  const char *start;
Packit 6c4009
  const struct cmd *c = 0;
Packit 6c4009
  size_t len;
Packit 6c4009
  size_t i;
Packit 6c4009
Packit 6c4009
  str = skip_ws (str);
Packit 6c4009
Packit 6c4009
  /* skip line comment and empty lines: */
Packit 6c4009
  if (*str == '\0' || *str == '#') return;
Packit 6c4009
Packit 6c4009
  start = str;
Packit 6c4009
  str = skip_string (str);
Packit 6c4009
  len = str - start;
Packit 6c4009
Packit 6c4009
  for (i = 0; i < sizeof (cmd) / sizeof (cmd[0]); ++i)
Packit 6c4009
    {
Packit 6c4009
      if (__strncasecmp (start, cmd[i].name, len) == 0
Packit 6c4009
	  && strlen (cmd[i].name) == len)
Packit 6c4009
	{
Packit 6c4009
	  c = &cmd[i];
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  if (c == NULL)
Packit 6c4009
    {
Packit 6c4009
      char *buf;
Packit 6c4009
Packit 6c4009
      if (__asprintf (&buf, _("%s: line %d: bad command `%s'\n"),
Packit 6c4009
		      fname, line_num, start) < 0)
Packit 6c4009
	return;
Packit 6c4009
Packit 6c4009
      __fxprintf (NULL, "%s", buf);
Packit 6c4009
Packit 6c4009
      free (buf);
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* process args: */
Packit 6c4009
  str = skip_ws (str);
Packit 6c4009
Packit 6c4009
  if (c->cb == CB_arg_trimdomain_list)
Packit 6c4009
    str = arg_trimdomain_list (fname, line_num, str);
Packit 6c4009
  else if (c->cb == CB_arg_bool)
Packit 6c4009
    str = arg_bool (fname, line_num, str, c->arg);
Packit 6c4009
  else
Packit 6c4009
    /* Ignore the line.  */
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  if (!str)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  /* rest of line must contain white space or comment only: */
Packit 6c4009
  while (*str)
Packit 6c4009
    {
Packit 6c4009
      if (!isspace (*str)) {
Packit 6c4009
	if (*str != '#')
Packit 6c4009
	  {
Packit 6c4009
	    char *buf;
Packit 6c4009
Packit 6c4009
	    if (__asprintf (&buf,
Packit 6c4009
			    _("%s: line %d: ignoring trailing garbage `%s'\n"),
Packit 6c4009
			    fname, line_num, str) < 0)
Packit 6c4009
	      break;
Packit 6c4009
Packit 6c4009
	    __fxprintf (NULL, "%s", buf);
Packit 6c4009
Packit 6c4009
	    free (buf);
Packit 6c4009
	  }
Packit 6c4009
	break;
Packit 6c4009
      }
Packit 6c4009
      ++str;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
do_init (void)
Packit 6c4009
{
Packit 6c4009
  const char *hconf_name;
Packit 6c4009
  int line_num = 0;
Packit 6c4009
  char buf[256], *envval;
Packit 6c4009
  FILE *fp;
Packit 6c4009
Packit 6c4009
  memset (&_res_hconf, '\0', sizeof (_res_hconf));
Packit 6c4009
Packit 6c4009
  hconf_name = getenv (ENV_HOSTCONF);
Packit 6c4009
  if (hconf_name == NULL)
Packit 6c4009
    hconf_name = _PATH_HOSTCONF;
Packit 6c4009
Packit 6c4009
  fp = fopen (hconf_name, "rce");
Packit 6c4009
  if (fp)
Packit 6c4009
    {
Packit 6c4009
      /* No threads using this stream.  */
Packit 6c4009
      __fsetlocking (fp, FSETLOCKING_BYCALLER);
Packit 6c4009
Packit 6c4009
      while (fgets_unlocked (buf, sizeof (buf), fp))
Packit 6c4009
	{
Packit 6c4009
	  ++line_num;
Packit 6c4009
	  *__strchrnul (buf, '\n') = '\0';
Packit 6c4009
	  parse_line (hconf_name, line_num, buf);
Packit 6c4009
	}
Packit 6c4009
      fclose (fp);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  envval = getenv (ENV_MULTI);
Packit 6c4009
  if (envval)
Packit 6c4009
    arg_bool (ENV_MULTI, 1, envval, HCONF_FLAG_MULTI);
Packit 6c4009
Packit 6c4009
  envval = getenv (ENV_REORDER);
Packit 6c4009
  if (envval)
Packit 6c4009
    arg_bool (ENV_REORDER, 1, envval, HCONF_FLAG_REORDER);
Packit 6c4009
Packit 6c4009
  envval = getenv (ENV_TRIM_ADD);
Packit 6c4009
  if (envval)
Packit 6c4009
    arg_trimdomain_list (ENV_TRIM_ADD, 1, envval);
Packit 6c4009
Packit 6c4009
  envval = getenv (ENV_TRIM_OVERR);
Packit 6c4009
  if (envval)
Packit 6c4009
    {
Packit 6c4009
      _res_hconf.num_trimdomains = 0;
Packit 6c4009
      arg_trimdomain_list (ENV_TRIM_OVERR, 1, envval);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* See comments on the declaration of _res_hconf.  */
Packit 6c4009
  atomic_store_release (&_res_hconf.initialized, 1);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Initialize hconf datastructure by reading host.conf file and
Packit 6c4009
   environment variables.  */
Packit 6c4009
void
Packit 6c4009
_res_hconf_init (void)
Packit 6c4009
{
Packit 6c4009
  __libc_once_define (static, once);
Packit 6c4009
Packit 6c4009
  __libc_once (once, do_init);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
#if IS_IN (libc)
Packit 6c4009
# if defined SIOCGIFCONF && defined SIOCGIFNETMASK
Packit 6c4009
/* List of known interfaces.  */
Packit 6c4009
libc_freeres_ptr (
Packit 6c4009
static struct netaddr
Packit 6c4009
{
Packit 6c4009
  int addrtype;
Packit 6c4009
  union
Packit 6c4009
  {
Packit 6c4009
    struct
Packit 6c4009
    {
Packit 6c4009
      uint32_t	addr;
Packit 6c4009
      uint32_t	mask;
Packit 6c4009
    } ipv4;
Packit 6c4009
  } u;
Packit 6c4009
} *ifaddrs);
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
/* Reorder addresses returned in a hostent such that the first address
Packit 6c4009
   is an address on the local subnet, if there is such an address.
Packit 6c4009
   Otherwise, nothing is changed.
Packit 6c4009
Packit 6c4009
   Note that this function currently only handles IPv4 addresses.  */
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_res_hconf_reorder_addrs (struct hostent *hp)
Packit 6c4009
{
Packit 6c4009
#if defined SIOCGIFCONF && defined SIOCGIFNETMASK
Packit 6c4009
  int i, j;
Packit 6c4009
  /* Number of interfaces.  Also serves as a flag for the
Packit 6c4009
     double-checked locking idiom.  */
Packit 6c4009
  static int num_ifs = -1;
Packit 6c4009
  /* Local copy of num_ifs, for non-atomic access.  */
Packit 6c4009
  int num_ifs_local;
Packit 6c4009
  /* We need to protect the dynamic buffer handling.  The lock is only
Packit 6c4009
     acquired during initialization.  Afterwards, a positive num_ifs
Packit 6c4009
     value indicates completed initialization.  */
Packit 6c4009
  __libc_lock_define_initialized (static, lock);
Packit 6c4009
Packit 6c4009
  /* Only reorder if we're supposed to.  */
Packit 6c4009
  if ((_res_hconf.flags & HCONF_FLAG_REORDER) == 0)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  /* Can't deal with anything but IPv4 for now...  */
Packit 6c4009
  if (hp->h_addrtype != AF_INET)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  /* This load synchronizes with the release MO store in the
Packit 6c4009
     initialization block below.  */
Packit 6c4009
  num_ifs_local = atomic_load_acquire (&num_ifs);
Packit 6c4009
  if (num_ifs_local <= 0)
Packit 6c4009
    {
Packit 6c4009
      struct ifreq *ifr, *cur_ifr;
Packit 6c4009
      int sd, num, i;
Packit 6c4009
      /* Save errno.  */
Packit 6c4009
      int save = errno;
Packit 6c4009
Packit 6c4009
      /* Initialize interface table.  */
Packit 6c4009
Packit 6c4009
      /* The SIOCGIFNETMASK ioctl will only work on an AF_INET socket.  */
Packit 6c4009
      sd = __socket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
Packit 6c4009
      if (sd < 0)
Packit 6c4009
	return;
Packit 6c4009
Packit 6c4009
      /* Get lock.  */
Packit 6c4009
      __libc_lock_lock (lock);
Packit 6c4009
Packit 6c4009
      /* Recheck, somebody else might have done the work by now.  No
Packit 6c4009
	 ordering is required for the load because we have the lock,
Packit 6c4009
	 and num_ifs is only updated under the lock.  Also see (3) in
Packit 6c4009
	 the analysis below.  */
Packit 6c4009
      num_ifs_local = atomic_load_relaxed (&num_ifs);
Packit 6c4009
      if (num_ifs_local <= 0)
Packit 6c4009
	{
Packit 6c4009
	  /* This is the only block which writes to num_ifs.  It can
Packit 6c4009
	     be executed several times (sequentially) if
Packit 6c4009
	     initialization does not yield any interfaces, and num_ifs
Packit 6c4009
	     remains zero.  However, once we stored a positive value
Packit 6c4009
	     in num_ifs below, this block cannot be entered again due
Packit 6c4009
	     to the condition above.  */
Packit 6c4009
	  int new_num_ifs = 0;
Packit 6c4009
Packit 6c4009
	  /* Get a list of interfaces.  */
Packit 6c4009
	  __ifreq (&ifr, &num, sd);
Packit 6c4009
	  if (!ifr)
Packit 6c4009
	    goto cleanup;
Packit 6c4009
Packit 6c4009
	  ifaddrs = malloc (num * sizeof (ifaddrs[0]));
Packit 6c4009
	  if (!ifaddrs)
Packit 6c4009
	    goto cleanup1;
Packit 6c4009
Packit 6c4009
	  /* Copy usable interfaces in ifaddrs structure.  */
Packit 6c4009
	  for (cur_ifr = ifr, i = 0; i < num;
Packit 6c4009
	       cur_ifr = __if_nextreq (cur_ifr), ++i)
Packit 6c4009
	    {
Packit 6c4009
	      union
Packit 6c4009
	      {
Packit 6c4009
		struct sockaddr sa;
Packit 6c4009
		struct sockaddr_in sin;
Packit 6c4009
	      } ss;
Packit 6c4009
Packit 6c4009
	      if (cur_ifr->ifr_addr.sa_family != AF_INET)
Packit 6c4009
		continue;
Packit 6c4009
Packit 6c4009
	      ifaddrs[new_num_ifs].addrtype = AF_INET;
Packit 6c4009
	      ss.sa = cur_ifr->ifr_addr;
Packit 6c4009
	      ifaddrs[new_num_ifs].u.ipv4.addr = ss.sin.sin_addr.s_addr;
Packit 6c4009
Packit 6c4009
	      if (__ioctl (sd, SIOCGIFNETMASK, cur_ifr) < 0)
Packit 6c4009
		continue;
Packit 6c4009
Packit 6c4009
	      ss.sa = cur_ifr->ifr_netmask;
Packit 6c4009
	      ifaddrs[new_num_ifs].u.ipv4.mask = ss.sin.sin_addr.s_addr;
Packit 6c4009
Packit 6c4009
	      /* Now we're committed to this entry.  */
Packit 6c4009
	      ++new_num_ifs;
Packit 6c4009
	    }
Packit 6c4009
	  /* Just keep enough memory to hold all the interfaces we want.  */
Packit 6c4009
	  ifaddrs = realloc (ifaddrs, new_num_ifs * sizeof (ifaddrs[0]));
Packit 6c4009
	  assert (ifaddrs != NULL);
Packit 6c4009
Packit 6c4009
	cleanup1:
Packit 6c4009
	  __if_freereq (ifr, num);
Packit 6c4009
Packit 6c4009
	cleanup:
Packit 6c4009
	  /* Release lock, preserve error value, and close socket.  */
Packit 6c4009
	  errno = save;
Packit 6c4009
Packit 6c4009
	  /* Advertise successful initialization if new_num_ifs is
Packit 6c4009
	     positive (and no updates to ifaddrs are permitted after
Packit 6c4009
	     that).  Otherwise, num_ifs remains unchanged, at zero.
Packit 6c4009
	     This store synchronizes with the initial acquire MO
Packit 6c4009
	     load.  */
Packit 6c4009
	  atomic_store_release (&num_ifs, new_num_ifs);
Packit 6c4009
	  /* Keep the local copy current, to save another load.  */
Packit 6c4009
	  num_ifs_local = new_num_ifs;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      __libc_lock_unlock (lock);
Packit 6c4009
Packit 6c4009
      __close (sd);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* num_ifs_local cannot be negative because the if statement above
Packit 6c4009
     covered this case.  It can still be zero if we just performed
Packit 6c4009
     initialization, but could not find any interfaces.  */
Packit 6c4009
  if (num_ifs_local == 0)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  /* The code below accesses ifaddrs, so we need to ensure that the
Packit 6c4009
     initialization happens-before this point.
Packit 6c4009
Packit 6c4009
     The actual initialization is sequenced-before the release store
Packit 6c4009
     to num_ifs, and sequenced-before the end of the critical section.
Packit 6c4009
Packit 6c4009
     This means there are three possible executions:
Packit 6c4009
Packit 6c4009
     (1) The thread that initialized the data also uses it, so
Packit 6c4009
         sequenced-before is sufficient to ensure happens-before.
Packit 6c4009
Packit 6c4009
     (2) The release MO store of num_ifs synchronizes-with the acquire
Packit 6c4009
         MO load, and the acquire MO load is sequenced before the use
Packit 6c4009
         of the initialized data below.
Packit 6c4009
Packit 6c4009
     (3) We enter the critical section, and the relaxed MO load of
Packit 6c4009
         num_ifs yields a positive value.  The write to ifaddrs is
Packit 6c4009
         sequenced-before leaving the critical section.  Leaving the
Packit 6c4009
         critical section happens-before we entered the critical
Packit 6c4009
         section ourselves, which means that the write to ifaddrs
Packit 6c4009
         happens-before this point.
Packit 6c4009
Packit 6c4009
     Consequently, all potential writes to ifaddrs (and the data it
Packit 6c4009
     points to) happens-before this point.  */
Packit 6c4009
Packit 6c4009
  /* Find an address for which we have a direct connection.  */
Packit 6c4009
  for (i = 0; hp->h_addr_list[i]; ++i)
Packit 6c4009
    {
Packit 6c4009
      struct in_addr *haddr = (struct in_addr *) hp->h_addr_list[i];
Packit 6c4009
Packit 6c4009
      for (j = 0; j < num_ifs_local; ++j)
Packit 6c4009
	{
Packit 6c4009
	  uint32_t if_addr    = ifaddrs[j].u.ipv4.addr;
Packit 6c4009
	  uint32_t if_netmask = ifaddrs[j].u.ipv4.mask;
Packit 6c4009
Packit 6c4009
	  if (((haddr->s_addr ^ if_addr) & if_netmask) == 0)
Packit 6c4009
	    {
Packit 6c4009
	      void *tmp;
Packit 6c4009
Packit 6c4009
	      tmp = hp->h_addr_list[i];
Packit 6c4009
	      hp->h_addr_list[i] = hp->h_addr_list[0];
Packit 6c4009
	      hp->h_addr_list[0] = tmp;
Packit 6c4009
	      return;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
#endif /* defined(SIOCGIFCONF) && ... */
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* If HOSTNAME has a postfix matching any of the trimdomains, trim away
Packit 6c4009
   that postfix.  Notice that HOSTNAME is modified inplace.  Also, the
Packit 6c4009
   original code applied all trimdomains in order, meaning that the
Packit 6c4009
   same domainname could be trimmed multiple times.  I believe this
Packit 6c4009
   was unintentional.  */
Packit 6c4009
void
Packit 6c4009
_res_hconf_trim_domain (char *hostname)
Packit 6c4009
{
Packit 6c4009
  size_t hostname_len, trim_len;
Packit 6c4009
  int i;
Packit 6c4009
Packit 6c4009
  hostname_len = strlen (hostname);
Packit 6c4009
Packit 6c4009
  for (i = 0; i < _res_hconf.num_trimdomains; ++i)
Packit 6c4009
    {
Packit 6c4009
      const char *trim = _res_hconf.trimdomain[i];
Packit 6c4009
Packit 6c4009
      trim_len = strlen (trim);
Packit 6c4009
      if (hostname_len > trim_len
Packit 6c4009
	  && __strcasecmp (&hostname[hostname_len - trim_len], trim) == 0)
Packit 6c4009
	{
Packit 6c4009
	  hostname[hostname_len - trim_len] = '\0';
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Trim all hostnames/aliases in HP according to the trimdomain list.
Packit 6c4009
   Notice that HP is modified inplace!  */
Packit 6c4009
void
Packit 6c4009
_res_hconf_trim_domains (struct hostent *hp)
Packit 6c4009
{
Packit 6c4009
  int i;
Packit 6c4009
Packit 6c4009
  if (_res_hconf.num_trimdomains == 0)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  _res_hconf_trim_domain (hp->h_name);
Packit 6c4009
  for (i = 0; hp->h_aliases[i]; ++i)
Packit 6c4009
    _res_hconf_trim_domain (hp->h_aliases[i]);
Packit 6c4009
}
Packit 6c4009
#endif