* 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:
Ulrich Drepper 2007-11-20 00:41:22 +00:00
parent f4a7976578
commit ee72b97189
7 changed files with 366 additions and 12 deletions

View File

@ -1,5 +1,17 @@
2007-11-19 Ulrich Drepper <drepper@redhat.com> 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 * sysdeps/posix/getaddrinfo.c (default_labels): Describe entry for
Teredo tunnels. Teredo tunnels.
* posix/gai.conf: Update for current default tables. * posix/gai.conf: Update for current default tables.

View File

@ -90,6 +90,7 @@ tests := tstgetopt testfnm runtests runptests \
tst-execv1 tst-execv2 tst-execl1 tst-execl2 \ tst-execv1 tst-execv2 tst-execl1 tst-execl2 \
tst-execve1 tst-execve2 tst-execle1 tst-execle2 \ tst-execve1 tst-execve2 tst-execle1 tst-execle2 \
tst-execvp3 tst-execvp4 tst-rfc3484 tst-rfc3484-2 \ tst-execvp3 tst-execvp4 tst-rfc3484 tst-rfc3484-2 \
tst-rfc3484-3 \
tst-getaddrinfo3 tst-fnmatch2 tst-cpucount tst-cpuset tst-getaddrinfo3 tst-fnmatch2 tst-cpucount tst-cpuset
xtests := bug-ga2 xtests := bug-ga2
ifeq (yes,$(build-shared)) ifeq (yes,$(build-shared))

View File

@ -52,3 +52,17 @@
# For sites which prefer IPv4 connections change the last line to # For sites which prefer IPv4 connections change the last line to
# #
#precedence ::ffff:0:0/96 100 #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

View File

@ -66,6 +66,7 @@ do_test (void)
{ {
labels = default_labels; labels = default_labels;
precedence = default_precedence; precedence = default_precedence;
scopes = default_scopes;
struct sockaddr_in so1; struct sockaddr_in so1;
so1.sin_family = AF_INET; so1.sin_family = AF_INET;

137
posix/tst-rfc3484-3.c Normal file
View 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"

View File

@ -85,6 +85,7 @@ do_test (void)
{ {
labels = default_labels; labels = default_labels;
precedence = default_precedence; precedence = default_precedence;
scopes= default_scopes;
struct sockaddr_in so; struct sockaddr_in so;
so.sin_family = AF_INET; so.sin_family = AF_INET;

View File

@ -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 static int
get_scope (const struct sockaddr_storage *ss) 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) else if (ss->ss_family == PF_INET)
{ {
const struct sockaddr_in *in = (const struct sockaddr_in *) ss; 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. size_t cnt = 0;
169.254/16 and 127/8 are link-local. */ while (1)
if ((addr[0] == 169 && addr[1] == 254) || addr[0] == 127) {
scope = 2; if ((in->sin_addr.s_addr & scopes[cnt].netmask)
else if (addr[0] == 10 || (addr[0] == 172 && (addr[1] & 0xf0) == 16) == scopes[cnt].addr32)
|| (addr[0] == 192 && addr[1] == 168)) return scopes[cnt].scope;
scope = 5;
else ++cnt;
scope = 14; }
/* NOTREACHED */
} }
else else
/* XXX What is a good default? */ /* XXX What is a good default? */
@ -1490,6 +1522,13 @@ libc_freeres_fn(fini)
precedence = default_precedence; precedence = default_precedence;
free ((void *) old); 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 static void
free_prefixlist (struct prefixlist *list) 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 static int
prefixcmp (const void *p1, const void *p2) 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 static void
gaiconf_init (void) gaiconf_init (void)
{ {
@ -1535,6 +1607,9 @@ gaiconf_init (void)
struct prefixlist *precedencelist = NULL; struct prefixlist *precedencelist = NULL;
size_t nprecedencelist = 0; size_t nprecedencelist = 0;
bool precedencelist_nullbits = false; bool precedencelist_nullbits = false;
struct scopelist *scopelist = NULL;
size_t nscopelist = 0;
bool scopelist_nullbits = false;
FILE *fp = fopen (GAICONF_FNAME, "rc"); FILE *fp = fopen (GAICONF_FNAME, "rc");
if (fp != NULL) if (fp != NULL)
@ -1625,7 +1700,7 @@ gaiconf_init (void)
|| (bits = strtoul (cp, &endp, 10)) != ULONG_MAX || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX
|| errno != ERANGE) || errno != ERANGE)
&& *endp == '\0' && *endp == '\0'
&& bits <= INT_MAX && bits <= 128
&& ((val = strtoul (val2, &endp, 10)) != ULONG_MAX && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX
|| errno != ERANGE) || errno != ERANGE)
&& *endp == '\0' && *endp == '\0'
@ -1659,6 +1734,73 @@ gaiconf_init (void)
} }
break; 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: case 10:
if (strcmp (cmd, "precedence") == 0) if (strcmp (cmd, "precedence") == 0)
{ {
@ -1742,12 +1884,52 @@ gaiconf_init (void)
/* Sort the entries so that the most specific ones are at /* Sort the entries so that the most specific ones are at
the beginning. */ the beginning. */
qsort (new_precedence, nprecedencelist, sizeof (*new_labels), qsort (new_precedence, nprecedencelist, sizeof (*new_precedence),
prefixcmp); prefixcmp);
} }
else else
new_precedence = (struct prefixentry *) default_precedence; 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. */ /* Now we are ready to replace the values. */
const struct prefixentry *old = labels; const struct prefixentry *old = labels;
labels = new_labels; labels = new_labels;
@ -1759,6 +1941,11 @@ gaiconf_init (void)
if (old != default_precedence) if (old != default_precedence)
free ((void *) old); free ((void *) old);
const struct scopeentry *oldscope = scopes;
scopes = new_scopes;
if (oldscope != default_scopes)
free ((void *) oldscope);
gaiconf_mtime = st.st_mtim; gaiconf_mtime = st.st_mtim;
} }
else else
@ -1766,6 +1953,7 @@ gaiconf_init (void)
no_file: no_file:
free_prefixlist (labellist); free_prefixlist (labellist);
free_prefixlist (precedencelist); free_prefixlist (precedencelist);
free_scopelist (scopelist);
/* If we previously read the file but it is gone now, free the /* If we previously read the file but it is gone now, free the
old data and use the builtin one. Leave the reload flag old data and use the builtin one. Leave the reload flag