|
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
|