* sysdeps/posix/getaddrinfo.c (defaults_scopes, scopes): New variables.
(get_scope): For IPv4 scope, use scopes table. (fini): Free scopes table if necessary. (free_scopelist): New function. (scopecmp): New function. (gaiconf_init): Also handle scopev4 entries. * posix/tst-rfc3484.c (do_test): Initialize scopes. * posix/tst-rfc3484-2.c (do_test): Likewise. * posix/gai.conf: Document scopev4 defaults. * posix/Makefile (tests): Add tst-rfc3484-3. * posix/tst-rfc3484-3.c: New file.
This commit is contained in:
parent
f4a7976578
commit
ee72b97189
12
ChangeLog
12
ChangeLog
@ -1,5 +1,17 @@
|
||||
2007-11-19 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* sysdeps/posix/getaddrinfo.c (defaults_scopes, scopes): New variables.
|
||||
(get_scope): For IPv4 scope, use scopes table.
|
||||
(fini): Free scopes table if necessary.
|
||||
(free_scopelist): New function.
|
||||
(scopecmp): New function.
|
||||
(gaiconf_init): Also handle scopev4 entries.
|
||||
* posix/tst-rfc3484.c (do_test): Initialize scopes.
|
||||
* posix/tst-rfc3484-2.c (do_test): Likewise.
|
||||
* posix/gai.conf: Document scopev4 defaults.
|
||||
* posix/Makefile (tests): Add tst-rfc3484-3.
|
||||
* posix/tst-rfc3484-3.c: New file.
|
||||
|
||||
* sysdeps/posix/getaddrinfo.c (default_labels): Describe entry for
|
||||
Teredo tunnels.
|
||||
* posix/gai.conf: Update for current default tables.
|
||||
|
@ -90,6 +90,7 @@ tests := tstgetopt testfnm runtests runptests \
|
||||
tst-execv1 tst-execv2 tst-execl1 tst-execl2 \
|
||||
tst-execve1 tst-execve2 tst-execle1 tst-execle2 \
|
||||
tst-execvp3 tst-execvp4 tst-rfc3484 tst-rfc3484-2 \
|
||||
tst-rfc3484-3 \
|
||||
tst-getaddrinfo3 tst-fnmatch2 tst-cpucount tst-cpuset
|
||||
xtests := bug-ga2
|
||||
ifeq (yes,$(build-shared))
|
||||
|
@ -52,3 +52,17 @@
|
||||
# For sites which prefer IPv4 connections change the last line to
|
||||
#
|
||||
#precedence ::ffff:0:0/96 100
|
||||
|
||||
#
|
||||
# scopev4 <mask> <value>
|
||||
# Add another rule to the RFC 3484 scope table for IPv4 addresses.
|
||||
# By default the scope IDs described in section 3.2 in RFC 3484 are
|
||||
# used. Changing these defaults should hardly ever be necessary.
|
||||
# The defaults are equivalent to:
|
||||
#
|
||||
#scopev4 ::ffff:169.254.0.0/112 2
|
||||
#scopev4 ::ffff:127.0.0.0/104 2
|
||||
#scopev4 ::ffff:10.0.0.0/104 5
|
||||
#scopev4 ::ffff:172.16.0.0/108 5
|
||||
#scopev4 ::ffff:192.168.0.0/112 5
|
||||
#scopev4 ::ffff:0.0.0.0 14
|
||||
|
@ -66,6 +66,7 @@ do_test (void)
|
||||
{
|
||||
labels = default_labels;
|
||||
precedence = default_precedence;
|
||||
scopes = default_scopes;
|
||||
|
||||
struct sockaddr_in so1;
|
||||
so1.sin_family = AF_INET;
|
||||
|
137
posix/tst-rfc3484-3.c
Normal file
137
posix/tst-rfc3484-3.c
Normal file
@ -0,0 +1,137 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
/* Internal definitions used in the libc code. */
|
||||
#define __getservbyname_r getservbyname_r
|
||||
#define __socket socket
|
||||
#define __getsockname getsockname
|
||||
#define __inet_aton inet_aton
|
||||
#define __gethostbyaddr_r gethostbyaddr_r
|
||||
#define __gethostbyname2_r gethostbyname2_r
|
||||
|
||||
void
|
||||
attribute_hidden
|
||||
__check_pf (bool *p1, bool *p2, struct in6addrinfo **in6ai, size_t *in6ailen)
|
||||
{
|
||||
*p1 = *p2 = true;
|
||||
*in6ai = NULL;
|
||||
*in6ailen = 0;
|
||||
}
|
||||
void
|
||||
attribute_hidden
|
||||
__check_native (uint32_t a1_index, int *a1_native,
|
||||
uint32_t a2_index, int *a2_native)
|
||||
{
|
||||
}
|
||||
int
|
||||
__idna_to_ascii_lz (const char *input, char **output, int flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int
|
||||
__idna_to_unicode_lzlz (const char *input, char **output, int flags)
|
||||
{
|
||||
*output = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "../sysdeps/posix/getaddrinfo.c"
|
||||
|
||||
service_user *__nss_hosts_database attribute_hidden;
|
||||
|
||||
|
||||
/* This is the beginning of the real test code. The above defines
|
||||
(among other things) the function rfc3484_sort. */
|
||||
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
# define h(n) n
|
||||
#else
|
||||
# define h(n) __bswap_constant_32 (n)
|
||||
#endif
|
||||
|
||||
struct sockaddr_in addrs[] =
|
||||
{
|
||||
{ .sin_family = AF_INET, .sin_addr = { h (0xa0a86d1d) } },
|
||||
{ .sin_family = AF_INET, .sin_addr = { h (0xa0a85d03) } },
|
||||
{ .sin_family = AF_INET, .sin_addr = { h (0xa0a82c3d) } },
|
||||
{ .sin_family = AF_INET, .sin_addr = { h (0xa0a86002) } },
|
||||
{ .sin_family = AF_INET, .sin_addr = { h (0xa0a802f3) } },
|
||||
{ .sin_family = AF_INET, .sin_addr = { h (0xa0a80810) } },
|
||||
{ .sin_family = AF_INET, .sin_addr = { h (0xa0a85e02) } },
|
||||
{ .sin_family = AF_INET, .sin_addr = { h (0xac162311) } },
|
||||
{ .sin_family = AF_INET, .sin_addr = { h (0x0a324572) } }
|
||||
};
|
||||
#define naddrs (sizeof (addrs) / sizeof (addrs[0]))
|
||||
static struct addrinfo ais[naddrs];
|
||||
static struct sort_result results[naddrs];
|
||||
|
||||
static const int expected[naddrs] =
|
||||
{
|
||||
8, 0, 1, 2, 3, 4, 5, 6, 7
|
||||
};
|
||||
|
||||
static const struct scopeentry new_scopes[] =
|
||||
{
|
||||
{ { { 169, 254, 0, 0 } }, h (0xffff0000), 2 },
|
||||
{ { { 127, 0, 0, 0 } }, h (0xff000000), 2 },
|
||||
{ { { 10, 0, 0, 0 } }, h (0xff000000), 5 },
|
||||
{ { { 192, 168, 0, 0 } }, h(0xffff0000), 5 },
|
||||
{ { { 0, 0, 0, 0 } }, h (0x00000000), 14 }
|
||||
};
|
||||
|
||||
|
||||
ssize_t
|
||||
__getline (char **lineptr, size_t *n, FILE *s)
|
||||
{
|
||||
*lineptr = NULL;
|
||||
*n = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
labels = default_labels;
|
||||
precedence = default_precedence;
|
||||
scopes= new_scopes;
|
||||
|
||||
struct sockaddr_in so;
|
||||
so.sin_family = AF_INET;
|
||||
so.sin_addr.s_addr = h (0x0aa85f19);
|
||||
|
||||
for (int i = 0; i < naddrs; ++i)
|
||||
{
|
||||
ais[i].ai_family = AF_INET;
|
||||
ais[i].ai_addr = (struct sockaddr *) &addrs[i];
|
||||
results[i].dest_addr = &ais[i];
|
||||
results[i].got_source_addr = true;
|
||||
memcpy(&results[i].source_addr, &so, sizeof (so));
|
||||
results[i].source_addr_len = sizeof (so);
|
||||
results[i].source_addr_flags = 0;
|
||||
results[i].service_order = i;
|
||||
results[i].prefixlen = 8;
|
||||
results[i].index = 0;
|
||||
}
|
||||
|
||||
struct sort_result_combo combo = { .results = results, .nresults = naddrs };
|
||||
qsort_r (results, naddrs, sizeof (results[0]), rfc3484_sort, &combo);
|
||||
|
||||
int result = 0;
|
||||
for (int i = 0; i < naddrs; ++i)
|
||||
{
|
||||
struct in_addr addr = ((struct sockaddr_in *) (results[i].dest_addr->ai_addr))->sin_addr;
|
||||
|
||||
int here = memcmp (&addr, &addrs[expected[i]].sin_addr,
|
||||
sizeof (struct in_addr));
|
||||
printf ("[%d] = %s: %s\n", i, inet_ntoa (addr), here ? "FAIL" : "OK");
|
||||
result |= here;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
@ -85,6 +85,7 @@ do_test (void)
|
||||
{
|
||||
labels = default_labels;
|
||||
precedence = default_precedence;
|
||||
scopes= default_scopes;
|
||||
|
||||
struct sockaddr_in so;
|
||||
so.sin_family = AF_INET;
|
||||
|
@ -1014,6 +1014,38 @@ struct sort_result_combo
|
||||
};
|
||||
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
# define htonl_c(n) n
|
||||
#else
|
||||
# define htonl_c(n) __bswap_constant_32 (n)
|
||||
#endif
|
||||
|
||||
static const struct scopeentry
|
||||
{
|
||||
union
|
||||
{
|
||||
char addr[4];
|
||||
uint32_t addr32;
|
||||
};
|
||||
uint32_t netmask;
|
||||
int32_t scope;
|
||||
} default_scopes[] =
|
||||
{
|
||||
/* Link-local addresses: scope 2. */
|
||||
{ { { 169, 254, 0, 0 } }, htonl_c (0xffff0000), 2 },
|
||||
{ { { 127, 0, 0, 0 } }, htonl_c (0xff000000), 2 },
|
||||
/* Site-local addresses: scope 5. */
|
||||
{ { { 10, 0, 0, 0 } }, htonl_c (0xff000000), 5 },
|
||||
{ { { 172, 16, 0, 0 } }, htonl_c (0xfff00000), 5 },
|
||||
{ { { 192, 168, 0, 0 } }, htonl_c (0xffff0000), 5 },
|
||||
/* Default: scope 14. */
|
||||
{ { { 0, 0, 0, 0 } }, htonl_c (0x00000000), 14 }
|
||||
};
|
||||
|
||||
/* The label table. */
|
||||
static const struct scopeentry *scopes;
|
||||
|
||||
|
||||
static int
|
||||
get_scope (const struct sockaddr_storage *ss)
|
||||
{
|
||||
@ -1038,17 +1070,17 @@ get_scope (const struct sockaddr_storage *ss)
|
||||
else if (ss->ss_family == PF_INET)
|
||||
{
|
||||
const struct sockaddr_in *in = (const struct sockaddr_in *) ss;
|
||||
const uint8_t *addr = (const uint8_t *) &in->sin_addr;
|
||||
|
||||
/* RFC 3484 specifies how to map IPv6 addresses to scopes.
|
||||
169.254/16 and 127/8 are link-local. */
|
||||
if ((addr[0] == 169 && addr[1] == 254) || addr[0] == 127)
|
||||
scope = 2;
|
||||
else if (addr[0] == 10 || (addr[0] == 172 && (addr[1] & 0xf0) == 16)
|
||||
|| (addr[0] == 192 && addr[1] == 168))
|
||||
scope = 5;
|
||||
else
|
||||
scope = 14;
|
||||
size_t cnt = 0;
|
||||
while (1)
|
||||
{
|
||||
if ((in->sin_addr.s_addr & scopes[cnt].netmask)
|
||||
== scopes[cnt].addr32)
|
||||
return scopes[cnt].scope;
|
||||
|
||||
++cnt;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
else
|
||||
/* XXX What is a good default? */
|
||||
@ -1490,6 +1522,13 @@ libc_freeres_fn(fini)
|
||||
precedence = default_precedence;
|
||||
free ((void *) old);
|
||||
}
|
||||
|
||||
if (scopes != default_scopes)
|
||||
{
|
||||
const struct scopeentry *old = scopes;
|
||||
scopes = default_scopes;
|
||||
free ((void *) old);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1500,6 +1539,13 @@ struct prefixlist
|
||||
};
|
||||
|
||||
|
||||
struct scopelist
|
||||
{
|
||||
struct scopeentry entry;
|
||||
struct scopelist *next;
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
free_prefixlist (struct prefixlist *list)
|
||||
{
|
||||
@ -1512,6 +1558,18 @@ free_prefixlist (struct prefixlist *list)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
free_scopelist (struct scopelist *list)
|
||||
{
|
||||
while (list != NULL)
|
||||
{
|
||||
struct scopelist *oldp = list;
|
||||
list = list->next;
|
||||
free (oldp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
prefixcmp (const void *p1, const void *p2)
|
||||
{
|
||||
@ -1526,6 +1584,20 @@ prefixcmp (const void *p1, const void *p2)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
scopecmp (const void *p1, const void *p2)
|
||||
{
|
||||
const struct scopeentry *e1 = (const struct scopeentry *) p1;
|
||||
const struct scopeentry *e2 = (const struct scopeentry *) p2;
|
||||
|
||||
if (e1->netmask > e2->netmask)
|
||||
return -1;
|
||||
if (e1->netmask == e2->netmask)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gaiconf_init (void)
|
||||
{
|
||||
@ -1535,6 +1607,9 @@ gaiconf_init (void)
|
||||
struct prefixlist *precedencelist = NULL;
|
||||
size_t nprecedencelist = 0;
|
||||
bool precedencelist_nullbits = false;
|
||||
struct scopelist *scopelist = NULL;
|
||||
size_t nscopelist = 0;
|
||||
bool scopelist_nullbits = false;
|
||||
|
||||
FILE *fp = fopen (GAICONF_FNAME, "rc");
|
||||
if (fp != NULL)
|
||||
@ -1625,7 +1700,7 @@ gaiconf_init (void)
|
||||
|| (bits = strtoul (cp, &endp, 10)) != ULONG_MAX
|
||||
|| errno != ERANGE)
|
||||
&& *endp == '\0'
|
||||
&& bits <= INT_MAX
|
||||
&& bits <= 128
|
||||
&& ((val = strtoul (val2, &endp, 10)) != ULONG_MAX
|
||||
|| errno != ERANGE)
|
||||
&& *endp == '\0'
|
||||
@ -1659,6 +1734,73 @@ gaiconf_init (void)
|
||||
}
|
||||
break;
|
||||
|
||||
case 7:
|
||||
if (strcmp (cmd, "scopev4") == 0)
|
||||
{
|
||||
struct in6_addr prefix;
|
||||
unsigned long int bits;
|
||||
unsigned long int val;
|
||||
char *endp;
|
||||
|
||||
bits = 32;
|
||||
__set_errno (0);
|
||||
cp = strchr (val1, '/');
|
||||
if (cp != NULL)
|
||||
*cp++ = '\0';
|
||||
if (inet_pton (AF_INET6, val1, &prefix))
|
||||
{
|
||||
if (IN6_IS_ADDR_V4MAPPED (&prefix)
|
||||
&& (cp == NULL
|
||||
|| (bits = strtoul (cp, &endp, 10)) != ULONG_MAX
|
||||
|| errno != ERANGE)
|
||||
&& *endp == '\0'
|
||||
&& bits >= 96
|
||||
&& bits <= 128
|
||||
&& ((val = strtoul (val2, &endp, 10)) != ULONG_MAX
|
||||
|| errno != ERANGE)
|
||||
&& *endp == '\0'
|
||||
&& val <= INT_MAX)
|
||||
{
|
||||
struct scopelist *newp;
|
||||
new_scope:
|
||||
newp = malloc (sizeof (*newp));
|
||||
if (newp == NULL)
|
||||
{
|
||||
free (line);
|
||||
fclose (fp);
|
||||
goto no_file;
|
||||
}
|
||||
|
||||
newp->entry.netmask = htonl (bits != 96
|
||||
? (0xffffffff
|
||||
<< (128 - bits))
|
||||
: 0);
|
||||
newp->entry.addr32 = (prefix.s6_addr32[3]
|
||||
& newp->entry.netmask);
|
||||
newp->entry.scope = val;
|
||||
newp->next = scopelist;
|
||||
scopelist = newp;
|
||||
++nscopelist;
|
||||
scopelist_nullbits |= bits == 96;
|
||||
}
|
||||
}
|
||||
else if (inet_pton (AF_INET, val1, &prefix.s6_addr32[3])
|
||||
&& (cp == NULL
|
||||
|| (bits = strtoul (cp, &endp, 10)) != ULONG_MAX
|
||||
|| errno != ERANGE)
|
||||
&& *endp == '\0'
|
||||
&& bits <= 32
|
||||
&& ((val = strtoul (val2, &endp, 10)) != ULONG_MAX
|
||||
|| errno != ERANGE)
|
||||
&& *endp == '\0'
|
||||
&& val <= INT_MAX)
|
||||
{
|
||||
bits += 96;
|
||||
goto new_scope;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 10:
|
||||
if (strcmp (cmd, "precedence") == 0)
|
||||
{
|
||||
@ -1742,12 +1884,52 @@ gaiconf_init (void)
|
||||
|
||||
/* Sort the entries so that the most specific ones are at
|
||||
the beginning. */
|
||||
qsort (new_precedence, nprecedencelist, sizeof (*new_labels),
|
||||
qsort (new_precedence, nprecedencelist, sizeof (*new_precedence),
|
||||
prefixcmp);
|
||||
}
|
||||
else
|
||||
new_precedence = (struct prefixentry *) default_precedence;
|
||||
|
||||
struct scopeentry *new_scopes;
|
||||
if (nscopelist > 0)
|
||||
{
|
||||
if (!scopelist_nullbits)
|
||||
++nscopelist;
|
||||
new_scopes = malloc (nscopelist * sizeof (*new_scopes));
|
||||
if (new_scopes == NULL)
|
||||
{
|
||||
if (new_labels != default_labels)
|
||||
free (new_labels);
|
||||
if (new_precedence != default_precedence)
|
||||
free (new_precedence);
|
||||
goto no_file;
|
||||
}
|
||||
|
||||
int i = nscopelist;
|
||||
if (!scopelist_nullbits)
|
||||
{
|
||||
--i;
|
||||
new_scopes[i].addr32 = 0;
|
||||
new_scopes[i].netmask = 0;
|
||||
new_scopes[i].scope = 14;
|
||||
}
|
||||
|
||||
struct scopelist *l = scopelist;
|
||||
while (i-- > 0)
|
||||
{
|
||||
new_scopes[i] = l->entry;
|
||||
l = l->next;
|
||||
}
|
||||
free_scopelist (scopelist);
|
||||
|
||||
/* Sort the entries so that the most specific ones are at
|
||||
the beginning. */
|
||||
qsort (new_scopes, nscopelist, sizeof (*new_scopes),
|
||||
scopecmp);
|
||||
}
|
||||
else
|
||||
new_scopes = (struct scopeentry *) default_scopes;
|
||||
|
||||
/* Now we are ready to replace the values. */
|
||||
const struct prefixentry *old = labels;
|
||||
labels = new_labels;
|
||||
@ -1759,6 +1941,11 @@ gaiconf_init (void)
|
||||
if (old != default_precedence)
|
||||
free ((void *) old);
|
||||
|
||||
const struct scopeentry *oldscope = scopes;
|
||||
scopes = new_scopes;
|
||||
if (oldscope != default_scopes)
|
||||
free ((void *) oldscope);
|
||||
|
||||
gaiconf_mtime = st.st_mtim;
|
||||
}
|
||||
else
|
||||
@ -1766,6 +1953,7 @@ gaiconf_init (void)
|
||||
no_file:
|
||||
free_prefixlist (labellist);
|
||||
free_prefixlist (precedencelist);
|
||||
free_scopelist (scopelist);
|
||||
|
||||
/* If we previously read the file but it is gone now, free the
|
||||
old data and use the builtin one. Leave the reload flag
|
||||
|
Loading…
Reference in New Issue
Block a user