1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-29 11:41:21 +03:00

resolv: Mirror the entire resolver configuration in struct resolv_conf

This commit adds the remaining unchanging members (which are loaded
from /etc/resolv.conf) to struct resolv_conf.

The extended name server list is currently not used by the stub
resolver.  The switch depends on a cleanup: The _u._ext.nssocks
array stores just a single socket, and needs to be replaced with
a single socket value.

(The compatibility gethostname implementation does not use the
extended addres sort list, either.  Updating the compat code is
not worthwhile.)
This commit is contained in:
Florian Weimer
2017-06-30 20:19:10 +02:00
parent 3f853f22c8
commit a1c4eb8794
7 changed files with 572 additions and 116 deletions

View File

@ -128,11 +128,80 @@ resolv_conf_get_1 (const struct __res_state *resp)
return conf;
}
/* Return true if both IPv4 addresses are equal. */
static bool
same_address_v4 (const struct sockaddr_in *left,
const struct sockaddr_in *right)
{
return left->sin_addr.s_addr == right->sin_addr.s_addr
&& left->sin_port == right->sin_port;
}
/* Return true if both IPv6 addresses are equal. This ignores the
flow label. */
static bool
same_address_v6 (const struct sockaddr_in6 *left,
const struct sockaddr_in6 *right)
{
return memcmp (&left->sin6_addr, &right->sin6_addr,
sizeof (left->sin6_addr)) == 0
&& left->sin6_port == right->sin6_port
&& left->sin6_scope_id == right->sin6_scope_id;
}
static bool
same_address (const struct sockaddr *left, const struct sockaddr *right)
{
if (left->sa_family != right->sa_family)
return false;
switch (left->sa_family)
{
case AF_INET:
return same_address_v4 ((const struct sockaddr_in *) left,
(const struct sockaddr_in *) right);
case AF_INET6:
return same_address_v6 ((const struct sockaddr_in6 *) left,
(const struct sockaddr_in6 *) right);
}
return false;
}
/* Check that *RESP and CONF match. Used by __resolv_conf_get. */
static bool
resolv_conf_matches (const struct __res_state *resp,
const struct resolv_conf *conf)
{
/* NB: Do not compare the options, retrans, retry, ndots. These can
be changed by applicaiton. */
/* Check that the name servers in *RESP have not been modified by
the application. */
{
size_t nserv = conf->nameserver_list_size;
if (nserv > MAXNS)
nserv = MAXNS;
/* _ext.nscount is 0 until initialized by res_send.c. */
if (resp->nscount != nserv
&& (resp->_u._ext.nscount != 0 && resp->_u._ext.nscount != nserv))
return false;
for (size_t i = 0; i < nserv; ++i)
{
if (resp->nsaddr_list[i].sin_family == 0)
{
if (resp->_u._ext.nsaddrs[i]->sin6_family != AF_INET6)
return false;
if (!same_address ((struct sockaddr *) resp->_u._ext.nsaddrs[i],
conf->nameserver_list[i]))
return false;
}
else if (resp->nsaddr_list[i].sin_family != AF_INET)
return false;
else if (!same_address ((struct sockaddr *) &resp->nsaddr_list[i],
conf->nameserver_list[i]))
return false;
}
}
/* Check that the search list in *RESP has not been modified by the
application. */
{
@ -161,6 +230,18 @@ resolv_conf_matches (const struct __res_state *resp,
}
}
}
/* Check that the sort list has not been modified. */
{
size_t nsort = conf->sort_list_size;
if (nsort > MAXRESOLVSORT)
nsort = MAXRESOLVSORT;
for (size_t i = 0; i < nsort; ++i)
if (resp->sort_list[i].addr.s_addr != conf->sort_list[i].addr.s_addr
|| resp->sort_list[i].mask != conf->sort_list[i].mask)
return false;
}
return true;
}
@ -190,7 +271,28 @@ __resolv_conf_put (struct resolv_conf *conf)
struct resolv_conf *
__resolv_conf_allocate (const struct resolv_conf *init)
{
/* Space needed by the strings. */
/* Allocate in decreasing order of alignment. */
_Static_assert (__alignof__ (const char *const *)
<= __alignof__ (struct resolv_conf), "alignment");
_Static_assert (__alignof__ (struct sockaddr_in6)
<= __alignof__ (const char *const *), "alignment");
_Static_assert (__alignof__ (struct sockaddr_in)
== __alignof__ (struct sockaddr_in6), "alignment");
_Static_assert (__alignof__ (struct resolv_sortlist_entry)
<= __alignof__ (struct sockaddr_in), "alignment");
/* Space needed by the nameserver addresses. */
size_t address_space = 0;
for (size_t i = 0; i < init->nameserver_list_size; ++i)
if (init->nameserver_list[i]->sa_family == AF_INET)
address_space += sizeof (struct sockaddr_in);
else
{
assert (init->nameserver_list[i]->sa_family == AF_INET6);
address_space += sizeof (struct sockaddr_in6);
}
/* Space needed by the search list strings. */
size_t string_space = 0;
for (size_t i = 0; i < init->search_list_size; ++i)
string_space += strlen (init->search_list[i]) + 1;
@ -199,7 +301,10 @@ __resolv_conf_allocate (const struct resolv_conf *init)
void *ptr;
struct alloc_buffer buffer = alloc_buffer_allocate
(sizeof (struct resolv_conf)
+ init->nameserver_list_size * sizeof (init->nameserver_list[0])
+ address_space
+ init->search_list_size * sizeof (init->search_list[0])
+ init->sort_list_size * sizeof (init->sort_list[0])
+ string_space,
&ptr);
struct resolv_conf *conf
@ -211,16 +316,57 @@ __resolv_conf_allocate (const struct resolv_conf *init)
/* Initialize the contents. */
conf->__refcount = 1;
conf->retrans = init->retrans;
conf->retry = init->retry;
conf->options = init->options;
conf->ndots = init->ndots;
conf->initstamp = __res_initstamp;
/* Allocate and fill the search list array. */
/* Allocate the arrays with pointers. These must come first because
they have the highets alignment. */
conf->nameserver_list_size = init->nameserver_list_size;
const struct sockaddr **nameserver_array = alloc_buffer_alloc_array
(&buffer, const struct sockaddr *, init->nameserver_list_size);
conf->nameserver_list = nameserver_array;
conf->search_list_size = init->search_list_size;
const char **search_array = alloc_buffer_alloc_array
(&buffer, const char *, init->search_list_size);
conf->search_list = search_array;
/* Fill the name server list array. */
for (size_t i = 0; i < init->nameserver_list_size; ++i)
if (init->nameserver_list[i]->sa_family == AF_INET)
{
struct sockaddr_in *sa = alloc_buffer_alloc
(&buffer, struct sockaddr_in);
*sa = *(struct sockaddr_in *) init->nameserver_list[i];
nameserver_array[i] = (struct sockaddr *) sa;
}
else
{
struct sockaddr_in6 *sa = alloc_buffer_alloc
(&buffer, struct sockaddr_in6);
*sa = *(struct sockaddr_in6 *) init->nameserver_list[i];
nameserver_array[i] = (struct sockaddr *) sa;
}
/* Allocate and fill the sort list array. */
{
conf->sort_list_size = init->sort_list_size;
struct resolv_sortlist_entry *array = alloc_buffer_alloc_array
(&buffer, struct resolv_sortlist_entry, init->sort_list_size);
conf->sort_list = array;
for (size_t i = 0; i < init->sort_list_size; ++i)
array[i] = init->sort_list[i];
}
/* Fill the search list array. This must come last because the
strings are the least aligned part of the allocation. */
{
conf->search_list_size = init->search_list_size;
const char **array = alloc_buffer_alloc_array
(&buffer, const char *, init->search_list_size);
conf->search_list = array;
for (size_t i = 0; i < init->search_list_size; ++i)
array[i] = alloc_buffer_copy_string (&buffer, init->search_list[i]);
search_array[i] = alloc_buffer_copy_string
(&buffer, init->search_list[i]);
}
assert (!alloc_buffer_has_failed (&buffer));
@ -231,6 +377,56 @@ __resolv_conf_allocate (const struct resolv_conf *init)
static __attribute__ ((nonnull (1, 2), warn_unused_result)) bool
update_from_conf (struct __res_state *resp, const struct resolv_conf *conf)
{
resp->defdname[0] = '\0';
resp->pfcode = 0;
resp->_vcsock = -1;
resp->_flags = 0;
resp->ipv6_unavail = false;
resp->__glibc_unused_qhook = NULL;
resp->__glibc_unused_rhook = NULL;
resp->retrans = conf->retrans;
resp->retry = conf->retry;
resp->options = conf->options;
resp->ndots = conf->ndots;
/* Copy the name server addresses. */
{
resp->nscount = 0;
resp->_u._ext.nscount = 0;
size_t nserv = conf->nameserver_list_size;
if (nserv > MAXNS)
nserv = MAXNS;
for (size_t i = 0; i < nserv; i++)
{
if (conf->nameserver_list[i]->sa_family == AF_INET)
{
resp->nsaddr_list[i]
= *(struct sockaddr_in *)conf->nameserver_list[i];
resp->_u._ext.nsaddrs[i] = NULL;
}
else
{
assert (conf->nameserver_list[i]->sa_family == AF_INET6);
resp->nsaddr_list[i].sin_family = 0;
/* Make a defensive copy of the name server address, in
case the application overwrites it. */
struct sockaddr_in6 *sa = malloc (sizeof (*sa));
if (sa == NULL)
{
for (size_t j = 0; j < i; ++j)
free (resp->_u._ext.nsaddrs[j]);
return false;
}
*sa = *(struct sockaddr_in6 *)conf->nameserver_list[i];
resp->_u._ext.nsaddrs[i] = sa;
}
resp->_u._ext.nssocks[i] = -1;
}
resp->nscount = nserv;
/* Leave resp->_u._ext.nscount at 0. res_send.c handles this. */
}
/* Fill in the prefix of the search list. It is truncated either at
MAXDNSRCH, or if reps->defdname has insufficient space. */
{
@ -249,6 +445,19 @@ update_from_conf (struct __res_state *resp, const struct resolv_conf *conf)
resp->dnsrch[i] = NULL;
}
/* Copy the sort list. */
{
size_t nsort = conf->sort_list_size;
if (nsort > MAXRESOLVSORT)
nsort = MAXRESOLVSORT;
for (size_t i = 0; i < nsort; ++i)
{
resp->sort_list[i].addr = conf->sort_list[i].addr;
resp->sort_list[i].mask = conf->sort_list[i].mask;
}
resp->nsort = nsort;
}
/* The overlapping parts of both configurations should agree after
initialization. */
assert (resolv_conf_matches (resp, conf));