diff options
author | Alexey Izbyshev <izbyshev@ispras.ru> | 2023-02-25 01:07:33 +0300 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2023-02-27 10:03:56 -0500 |
commit | d0b7f9768df133428b6587a5273551c56c46d6a6 (patch) | |
tree | df653ccc3e63dec0ec704bb658880b7362bf72aa /src/network | |
parent | bec42ef393c0ad64e699a901ab0746d16bfde251 (diff) | |
download | musl-d0b7f9768df133428b6587a5273551c56c46d6a6.tar.gz |
dns: fix workaround for systems defaulting to ipv6-only sockets
When IPv6 nameservers are present, __res_msend_rc attempts to disable
IPV6_V6ONLY socket option to ensure that it can communicate with IPv4
nameservers (if they are present too) via IPv4-mapped IPv6 addresses.
However, this option can't be disabled on bound sockets, so setsockopt
always fails.
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/res_msend.c | 31 |
1 files changed, 16 insertions, 15 deletions
diff --git a/src/network/res_msend.c b/src/network/res_msend.c index 2643be22..86c2fcf4 100644 --- a/src/network/res_msend.c +++ b/src/network/res_msend.c @@ -133,6 +133,22 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries, family = AF_INET; sl = sizeof sa.sin; } + + /* Convert any IPv4 addresses in a mixed environment to v4-mapped */ + if (fd >= 0 && family == AF_INET6) { + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0); + for (i=0; i<nns; i++) { + if (ns[i].sin.sin_family != AF_INET) continue; + memcpy(ns[i].sin6.sin6_addr.s6_addr+12, + &ns[i].sin.sin_addr, 4); + memcpy(ns[i].sin6.sin6_addr.s6_addr, + "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + ns[i].sin6.sin6_family = AF_INET6; + ns[i].sin6.sin6_flowinfo = 0; + ns[i].sin6.sin6_scope_id = 0; + } + } + sa.sin.sin_family = family; if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) { if (fd >= 0) close(fd); @@ -152,21 +168,6 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries, pthread_cleanup_push(cleanup, pfd); pthread_setcancelstate(cs, 0); - /* Convert any IPv4 addresses in a mixed environment to v4-mapped */ - if (family == AF_INET6) { - setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0); - for (i=0; i<nns; i++) { - if (ns[i].sin.sin_family != AF_INET) continue; - memcpy(ns[i].sin6.sin6_addr.s6_addr+12, - &ns[i].sin.sin_addr, 4); - memcpy(ns[i].sin6.sin6_addr.s6_addr, - "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); - ns[i].sin6.sin6_family = AF_INET6; - ns[i].sin6.sin6_flowinfo = 0; - ns[i].sin6.sin6_scope_id = 0; - } - } - memset(alens, 0, sizeof *alens * nqueries); retry_interval = timeout / attempts; |