mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-10 23:30:07 +00:00
Update.
2003-11-17 Ulrich Drepper <drepper@redhat.com> * sysdeps/posix/getaddrinfo.c: Add support for destination address selection according to RFC 3484.
This commit is contained in:
parent
9780c971fb
commit
5ddb5bf5fb
@ -1,3 +1,8 @@
|
||||
2003-11-17 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* sysdeps/posix/getaddrinfo.c: Add support for destination address
|
||||
selection according to RFC 3484.
|
||||
|
||||
2003-11-15 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* posix/regex_internal.h: Add forward declaration of re_dfa_t.
|
||||
|
40
nptl/sysdeps/pthread/configure
vendored
40
nptl/sysdeps/pthread/configure
vendored
@ -30,7 +30,6 @@ if test "${libc_cv_forced_unwind+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
#line $LINENO "configure"
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
@ -50,11 +49,21 @@ _Unwind_GetCFA (context)
|
||||
_ACEOF
|
||||
rm -f conftest.$ac_objext conftest$ac_exeext
|
||||
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
|
||||
(eval $ac_link) 2>&5
|
||||
(eval $ac_link) 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } &&
|
||||
{ ac_try='test -s conftest$ac_exeext'
|
||||
{ ac_try='test -z "$ac_c_werror_flag"
|
||||
|| test ! -s conftest.err'
|
||||
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); }; } &&
|
||||
{ ac_try='test -s conftest$ac_exeext'
|
||||
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
@ -67,7 +76,8 @@ sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
libc_cv_forced_unwind=no
|
||||
fi
|
||||
rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
|
||||
rm -f conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
fi
|
||||
echo "$as_me:$LINENO: result: $libc_cv_forced_unwind" >&5
|
||||
echo "${ECHO_T}$libc_cv_forced_unwind" >&6
|
||||
@ -84,7 +94,6 @@ if test "${libc_cv_c_cleanup+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
#line $LINENO "configure"
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
@ -106,11 +115,21 @@ main ()
|
||||
_ACEOF
|
||||
rm -f conftest.$ac_objext conftest$ac_exeext
|
||||
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
|
||||
(eval $ac_link) 2>&5
|
||||
(eval $ac_link) 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } &&
|
||||
{ ac_try='test -s conftest$ac_exeext'
|
||||
{ ac_try='test -z "$ac_c_werror_flag"
|
||||
|| test ! -s conftest.err'
|
||||
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); }; } &&
|
||||
{ ac_try='test -s conftest$ac_exeext'
|
||||
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
@ -123,7 +142,8 @@ sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
libc_cv_c_cleanup=no
|
||||
fi
|
||||
rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
|
||||
rm -f conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
fi
|
||||
echo "$as_me:$LINENO: result: $libc_cv_c_cleanup" >&5
|
||||
echo "${ECHO_T}$libc_cv_c_cleanup" >&6
|
||||
@ -133,4 +153,8 @@ echo "${ECHO_T}$libc_cv_c_cleanup" >&6
|
||||
echo "$as_me: error: the compiler must support C cleanup handling" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi
|
||||
else
|
||||
{ { echo "$as_me:$LINENO: error: forced unwind support is required" >&5
|
||||
echo "$as_me: error: forced unwind support is required" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi
|
||||
|
@ -53,6 +53,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <sys/utsname.h>
|
||||
#include <net/if.h>
|
||||
#include <nsswitch.h>
|
||||
#include <not-cancel.h>
|
||||
|
||||
#define GAIH_OKIFUNSPEC 0x0100
|
||||
#define GAIH_EAI ~(GAIH_OKIFUNSPEC)
|
||||
@ -894,11 +895,342 @@ static struct gaih gaih[] =
|
||||
{ PF_UNSPEC, NULL }
|
||||
};
|
||||
|
||||
struct sort_result
|
||||
{
|
||||
struct addrinfo *dest_addr;
|
||||
struct sockaddr_storage source_addr;
|
||||
bool got_source_addr;
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
get_scope (const struct sockaddr_storage *ss)
|
||||
{
|
||||
int scope;
|
||||
if (ss->ss_family == PF_INET6)
|
||||
{
|
||||
const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *) ss;
|
||||
|
||||
if (! IN6_IS_ADDR_MULTICAST (&in6->sin6_addr))
|
||||
{
|
||||
if (IN6_IS_ADDR_LINKLOCAL (&in6->sin6_addr))
|
||||
scope = 2;
|
||||
else if (IN6_IS_ADDR_SITELOCAL (&in6->sin6_addr))
|
||||
scope = 5;
|
||||
else
|
||||
/* XXX Is this the correct default behavior? */
|
||||
scope = 14;
|
||||
}
|
||||
else
|
||||
scope = in6->sin6_addr.s6_addr[1] & 0xf;
|
||||
}
|
||||
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] == 16)
|
||||
|| (addr[0] == 192 && addr[1] == 168))
|
||||
scope = 5;
|
||||
else
|
||||
scope = 14;
|
||||
}
|
||||
else
|
||||
/* XXX What is a good default? */
|
||||
scope = 15;
|
||||
|
||||
return scope;
|
||||
}
|
||||
|
||||
|
||||
/* XXX The system administrator should be able to install other
|
||||
tables. We need to make this configurable. The problem is that
|
||||
the kernel is also involved since it needs the same table. */
|
||||
static const struct prefixlist
|
||||
{
|
||||
struct in6_addr prefix;
|
||||
unsigned int bits;
|
||||
int val;
|
||||
} default_labels[] =
|
||||
{
|
||||
/* See RFC 3484 for the details. */
|
||||
{ { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0001 } } },
|
||||
128, 0 },
|
||||
{ { .in6_u = { .u6_addr16 = { 0x2002, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000 } } },
|
||||
16, 2 },
|
||||
{ { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000 } } },
|
||||
96, 3 },
|
||||
{ { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0xffff, 0x0000, 0x0000 } } },
|
||||
96, 4 },
|
||||
{ { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000 } } },
|
||||
0, 1 }
|
||||
};
|
||||
|
||||
|
||||
static const struct prefixlist default_precedence[] =
|
||||
{
|
||||
/* See RFC 3484 for the details. */
|
||||
{ { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0001 } } },
|
||||
128, 50 },
|
||||
{ { .in6_u = { .u6_addr16 = { 0x2002, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000 } } },
|
||||
16, 30 },
|
||||
{ { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000 } } },
|
||||
96, 20 },
|
||||
{ { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0xffff, 0x0000, 0x0000 } } },
|
||||
96, 10 },
|
||||
{ { .in6_u = { .u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000 } } },
|
||||
0, 40 }
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
match_prefix (const struct sockaddr_storage *ss, const struct prefixlist *list,
|
||||
int default_val)
|
||||
{
|
||||
int idx;
|
||||
struct sockaddr_in6 in6_mem;
|
||||
const struct sockaddr_in6 *in6;
|
||||
|
||||
if (ss->ss_family == PF_INET6)
|
||||
in6 = (const struct sockaddr_in6 *) ss;
|
||||
else if (ss->ss_family == PF_INET)
|
||||
{
|
||||
const struct sockaddr_in *in = (const struct sockaddr_in *) ss;
|
||||
|
||||
/* Convert to IPv6 address. */
|
||||
in6_mem.sin6_family = PF_INET6;
|
||||
in6_mem.sin6_port = in->sin_port;
|
||||
in6_mem.sin6_flowinfo = 0;
|
||||
if (in->sin_addr.s_addr == htonl (0x7f000001))
|
||||
in6_mem.sin6_addr = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
|
||||
else
|
||||
{
|
||||
/* Construct a V4-to-6 mapped address. */
|
||||
memset (&in6_mem.sin6_addr, '\0', sizeof (in6_mem.sin6_addr));
|
||||
in6_mem.sin6_addr.s6_addr16[5] = 0xffff;
|
||||
in6_mem.sin6_addr.s6_addr32[3] = in->sin_addr.s_addr;
|
||||
in6_mem.sin6_scope_id = 0;
|
||||
}
|
||||
|
||||
in6 = &in6_mem;
|
||||
}
|
||||
else
|
||||
return default_val;
|
||||
|
||||
for (idx = 0; ; ++idx)
|
||||
{
|
||||
unsigned int bits = list[idx].bits;
|
||||
uint8_t *mask = list[idx].prefix.s6_addr;
|
||||
uint8_t *val = in6->sin6_addr.s6_addr;
|
||||
|
||||
while (bits > 8)
|
||||
{
|
||||
if (*mask != *val)
|
||||
break;
|
||||
|
||||
++mask;
|
||||
++val;
|
||||
bits -= 8;
|
||||
}
|
||||
|
||||
if (bits < 8)
|
||||
{
|
||||
if ((*mask & (0xff >> bits)) == (*val & (0xff >> bits)))
|
||||
/* Match! */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return list[idx].val;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
get_label (const struct sockaddr_storage *ss)
|
||||
{
|
||||
/* XXX What is a good default value? */
|
||||
return match_prefix (ss, default_labels, INT_MAX);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
get_precedence (const struct sockaddr_storage *ss)
|
||||
{
|
||||
/* XXX What is a good default value? */
|
||||
return match_prefix (ss, default_precedence, 0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rfc3484_sort (const void *p1, const void *p2)
|
||||
{
|
||||
const struct sort_result *a1 = (const struct sort_result *) p1;
|
||||
const struct sort_result *a2 = (const struct sort_result *) p2;
|
||||
|
||||
/* Rule 1: Avoid unusable destinations.
|
||||
We have the got_source_addr flag set if the destination is reachable. */
|
||||
if (a1->got_source_addr && ! a2->got_source_addr)
|
||||
return -1;
|
||||
if (! a1->got_source_addr && a2->got_source_addr)
|
||||
return 1;
|
||||
|
||||
|
||||
/* Rule 2: Prefer matching scope. Only interesting if both
|
||||
destination addresses are IPv6. */
|
||||
int a1_dst_scope
|
||||
= get_scope ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
|
||||
|
||||
int a2_dst_scope
|
||||
= get_scope ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
|
||||
|
||||
if (a1->got_source_addr)
|
||||
{
|
||||
int a1_src_scope = get_scope (&a1->source_addr);
|
||||
int a2_src_scope = get_scope (&a2->source_addr);
|
||||
|
||||
if (a1_dst_scope == a1_src_scope && a2_dst_scope != a2_src_scope)
|
||||
return -1;
|
||||
if (a1_dst_scope != a1_src_scope && a2_dst_scope == a2_src_scope)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Rule 3: Avoid deprecated addresses.
|
||||
That's something only the kernel could decide. */
|
||||
|
||||
/* Rule 4: Prefer home addresses.
|
||||
Another thing only the kernel can decide. */
|
||||
|
||||
/* Rule 5: Prefer matching label. */
|
||||
if (a1->got_source_addr)
|
||||
{
|
||||
int a1_dst_label
|
||||
= get_label ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
|
||||
int a1_src_label = get_label (&a1->source_addr);
|
||||
|
||||
int a2_dst_label
|
||||
= get_label ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
|
||||
int a2_src_label = get_label (&a2->source_addr);
|
||||
|
||||
if (a1_dst_label == a1_src_label && a2_dst_label != a2_src_label)
|
||||
return -1;
|
||||
if (a1_dst_label != a1_src_label && a2_dst_label == a2_src_label)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Rule 6: Prefer higher precedence. */
|
||||
int a1_prec
|
||||
= get_precedence ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
|
||||
int a2_prec
|
||||
= get_precedence ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
|
||||
|
||||
if (a1_prec > a2_prec)
|
||||
return -1;
|
||||
if (a1_prec < a2_prec)
|
||||
return 1;
|
||||
|
||||
|
||||
/* Rule 7: Prefer native transport.
|
||||
XXX How to recognize tunnels? */
|
||||
|
||||
|
||||
/* Rule 8: Prefer smaller scope. */
|
||||
if (a1_dst_scope < a2_dst_scope)
|
||||
return -1;
|
||||
if (a1_dst_scope > a2_dst_scope)
|
||||
return 1;
|
||||
|
||||
|
||||
/* Rule 9: Use longest matching prefix. */
|
||||
if (a1->got_source_addr
|
||||
&& a1->dest_addr->ai_family == a2->dest_addr->ai_family)
|
||||
{
|
||||
int bit1 = 0;
|
||||
int bit2 = 0;
|
||||
|
||||
if (a1->dest_addr->ai_family == PF_INET)
|
||||
{
|
||||
assert (a1->source_addr.ss_family == PF_INET);
|
||||
assert (a2->source_addr.ss_family == PF_INET);
|
||||
|
||||
struct sockaddr_in *in1_dst;
|
||||
struct sockaddr_in *in1_src;
|
||||
struct sockaddr_in *in2_dst;
|
||||
struct sockaddr_in *in2_src;
|
||||
|
||||
in1_dst = (struct sockaddr_in *) a1->dest_addr->ai_addr;
|
||||
in1_src = (struct sockaddr_in *) &a1->source_addr;
|
||||
in2_dst = (struct sockaddr_in *) a2->dest_addr->ai_addr;
|
||||
in2_src = (struct sockaddr_in *) &a2->source_addr;
|
||||
|
||||
bit1 = ffs (in1_dst->sin_addr.s_addr ^ in1_src->sin_addr.s_addr);
|
||||
bit2 = ffs (in2_dst->sin_addr.s_addr ^ in2_src->sin_addr.s_addr);
|
||||
}
|
||||
else if (a1->dest_addr->ai_family == PF_INET6)
|
||||
{
|
||||
assert (a1->source_addr.ss_family == PF_INET6);
|
||||
assert (a2->source_addr.ss_family == PF_INET6);
|
||||
|
||||
struct sockaddr_in6 *in1_dst;
|
||||
struct sockaddr_in6 *in1_src;
|
||||
struct sockaddr_in6 *in2_dst;
|
||||
struct sockaddr_in6 *in2_src;
|
||||
|
||||
in1_dst = (struct sockaddr_in6 *) a1->dest_addr->ai_addr;
|
||||
in1_src = (struct sockaddr_in6 *) &a1->source_addr;
|
||||
in2_dst = (struct sockaddr_in6 *) a2->dest_addr->ai_addr;
|
||||
in2_src = (struct sockaddr_in6 *) &a2->source_addr;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
if (in1_dst->sin6_addr.s6_addr32[i]
|
||||
!= in1_src->sin6_addr.s6_addr32[i]
|
||||
|| (in2_dst->sin6_addr.s6_addr32[i]
|
||||
!= in2_src->sin6_addr.s6_addr32[i]))
|
||||
break;
|
||||
|
||||
if (i < 4)
|
||||
{
|
||||
bit1 = ffs (in1_dst->sin6_addr.s6_addr32[i]
|
||||
^ in1_src->sin6_addr.s6_addr32[i]);
|
||||
bit2 = ffs (in2_dst->sin6_addr.s6_addr32[i]
|
||||
^ in2_src->sin6_addr.s6_addr32[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (bit1 > bit2)
|
||||
return -1;
|
||||
if (bit1 < bit2)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Rule 10: Otherwise, leave the order unchanged. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
getaddrinfo (const char *name, const char *service,
|
||||
const struct addrinfo *hints, struct addrinfo **pai)
|
||||
{
|
||||
int i = 0, j = 0, last_i = 0;
|
||||
int nresults = 0;
|
||||
struct addrinfo *p = NULL, **end;
|
||||
struct gaih *g = gaih, *pg = NULL;
|
||||
struct gaih_service gaih_service, *pservice;
|
||||
@ -1000,7 +1332,11 @@ getaddrinfo (const char *name, const char *service,
|
||||
return -(i & GAIH_EAI);
|
||||
}
|
||||
if (end)
|
||||
while(*end) end = &((*end)->ai_next);
|
||||
while (*end)
|
||||
{
|
||||
end = &((*end)->ai_next);
|
||||
++nresults;
|
||||
}
|
||||
}
|
||||
}
|
||||
++g;
|
||||
@ -1009,6 +1345,46 @@ getaddrinfo (const char *name, const char *service,
|
||||
if (j == 0)
|
||||
return EAI_FAMILY;
|
||||
|
||||
if (nresults > 1)
|
||||
{
|
||||
/* Sort results according to RFC 3484. */
|
||||
struct sort_result results[nresults];
|
||||
struct addrinfo *q;
|
||||
|
||||
for (i = 0, q = p; q != NULL; ++i, q = q->ai_next)
|
||||
{
|
||||
results[i].dest_addr = q;
|
||||
results[i].got_source_addr = false;
|
||||
|
||||
/* We overwrite the type with SOCK_DGRAM since we do not
|
||||
want connect() to connect to the other side. If we
|
||||
cannot determine the source address remember this
|
||||
fact. */
|
||||
int fd = __socket (q->ai_family, SOCK_DGRAM, IPPROTO_IP);
|
||||
if (fd != -1)
|
||||
{
|
||||
socklen_t sl = sizeof (results[i].source_addr);
|
||||
if (__connect (fd, q->ai_addr, q->ai_addrlen) == 0
|
||||
&& __getsockname (fd,
|
||||
(struct sockaddr *) &results[i].source_addr,
|
||||
&sl) == 0)
|
||||
results[i].got_source_addr = true;
|
||||
|
||||
close_not_cancel_no_status (fd);
|
||||
}
|
||||
}
|
||||
|
||||
/* We got all the source addresses we can get, now sort using
|
||||
the information. */
|
||||
qsort (results, nresults, sizeof (results[0]), rfc3484_sort);
|
||||
|
||||
/* Queue the results up as they come out of sorting. */
|
||||
q = p = results[0].dest_addr;
|
||||
for (i = 1; i < nresults; ++i)
|
||||
q = q->ai_next = results[i].dest_addr;
|
||||
q->ai_next = NULL;
|
||||
}
|
||||
|
||||
if (p)
|
||||
{
|
||||
*pai = p;
|
||||
|
Loading…
Reference in New Issue
Block a user