summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2018-07-11 15:03:34 -0400
committerRich Felker <dalias@aerifal.cx>2018-07-11 15:03:34 -0400
commit4f35eb7591031a1e5ef9828f9304361f282f28b9 (patch)
tree87631061e55eb527b03c66b921119038fa426c80 /src
parentb0d2b3a1e5820271c0f81d4c1fb8972a2f1141f5 (diff)
downloadmusl-4f35eb7591031a1e5ef9828f9304361f282f28b9.tar.gz
resolver: don't depend on v4mapped ipv6 to probe routability of v4 addrs
to produce sorted results roughly corresponding to RFC 3484/6724, __lookup_name computes routability and choice of source address via dummy UDP connect operations (which do not produce any packets). since at the logical level, the properties fed into the sort key are computed on ipv6 addresses, the code was written to use the v4mapped ipv6 form of ipv4 addresses and share a common code path for them all. however, on kernels where ipv6 support has been completely omitted, this causes ipv4 to appear equally unroutable as ipv6, thereby putting unreachable ipv6 addresses before ipv4 addresses in the results. instead, use only ipv4 sockets to compute routability for ipv4 addresses. some gratuitous conversion back and forth is left so that the logic is not affected by these changes. it may be possible to simplify the ipv4 case considerably, thereby reducing code size and complexity.
Diffstat (limited to 'src')
-rw-r--r--src/network/lookup_name.c47
1 files changed, 32 insertions, 15 deletions
diff --git a/src/network/lookup_name.c b/src/network/lookup_name.c
index a1851f1f..0e6db9ef 100644
--- a/src/network/lookup_name.c
+++ b/src/network/lookup_name.c
@@ -355,36 +355,53 @@ int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], c
* excessive runtime and code size cost and dubious benefit.
* So far the label/precedence table cannot be customized. */
for (i=0; i<cnt; i++) {
+ int family = buf[i].family;
int key = 0;
- struct sockaddr_in6 sa, da = {
+ struct sockaddr_in6 sa6 = { 0 }, da6 = {
.sin6_family = AF_INET6,
.sin6_scope_id = buf[i].scopeid,
.sin6_port = 65535
};
- if (buf[i].family == AF_INET6) {
- memcpy(da.sin6_addr.s6_addr, buf[i].addr, 16);
+ struct sockaddr_in sa4 = { 0 }, da4 = {
+ .sin_family = AF_INET,
+ .sin_port = 65535
+ };
+ void *sa, *da;
+ socklen_t salen, dalen;
+ if (family == AF_INET6) {
+ memcpy(da6.sin6_addr.s6_addr, buf[i].addr, 16);
+ da = &da6; dalen = sizeof da6;
+ sa = &sa6; salen = sizeof sa6;
} else {
- memcpy(da.sin6_addr.s6_addr,
+ memcpy(sa6.sin6_addr.s6_addr,
+ "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
+ memcpy(da6.sin6_addr.s6_addr+12, buf[i].addr, 4);
+ memcpy(da6.sin6_addr.s6_addr,
"\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
- memcpy(da.sin6_addr.s6_addr+12, buf[i].addr, 4);
+ memcpy(da6.sin6_addr.s6_addr+12, buf[i].addr, 4);
+ memcpy(&da4.sin_addr, buf[i].addr, 4);
+ da = &da4; dalen = sizeof da4;
+ sa = &sa4; salen = sizeof sa4;
}
- const struct policy *dpolicy = policyof(&da.sin6_addr);
- int dscope = scopeof(&da.sin6_addr);
+ const struct policy *dpolicy = policyof(&da6.sin6_addr);
+ int dscope = scopeof(&da6.sin6_addr);
int dlabel = dpolicy->label;
int dprec = dpolicy->prec;
int prefixlen = 0;
- int fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_UDP);
+ int fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_UDP);
if (fd >= 0) {
- if (!connect(fd, (void *)&da, sizeof da)) {
+ if (!connect(fd, da, dalen)) {
key |= DAS_USABLE;
- if (!getsockname(fd, (void *)&sa,
- &(socklen_t){sizeof sa})) {
- if (dscope == scopeof(&sa.sin6_addr))
+ if (!getsockname(fd, sa, &salen)) {
+ if (family == AF_INET) memcpy(
+ &sa6.sin6_addr.s6_addr+12,
+ &sa4.sin_addr, 4);
+ if (dscope == scopeof(&sa6.sin6_addr))
key |= DAS_MATCHINGSCOPE;
- if (dlabel == labelof(&sa.sin6_addr))
+ if (dlabel == labelof(&sa6.sin6_addr))
key |= DAS_MATCHINGLABEL;
- prefixlen = prefixmatch(&sa.sin6_addr,
- &da.sin6_addr);
+ prefixlen = prefixmatch(&sa6.sin6_addr,
+ &da6.sin6_addr);
}
}
close(fd);