From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=MAILING_LIST_MULTI, RCVD_IN_MSPIKE_H2,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 756 invoked from network); 24 Aug 2022 23:32:43 -0000 Received: from second.openwall.net (193.110.157.125) by inbox.vuxu.org with ESMTPUTF8; 24 Aug 2022 23:32:43 -0000 Received: (qmail 27910 invoked by uid 550); 24 Aug 2022 23:32:41 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Reply-To: musl@lists.openwall.com Received: (qmail 27878 invoked from network); 24 Aug 2022 23:32:40 -0000 Date: Wed, 24 Aug 2022 19:32:28 -0400 From: Rich Felker To: Markus Wichmann Cc: musl@lists.openwall.com Message-ID: <20220824233228.GM7074@brightrain.aerifal.cx> References: <20220824190349.GB1923@voyager> <20220824232657.GL7074@brightrain.aerifal.cx> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20220824232657.GL7074@brightrain.aerifal.cx> User-Agent: Mutt/1.5.21 (2010-09-15) Subject: Re: [musl] IPv4 fallback in __res_msend_rc not functional On Wed, Aug 24, 2022 at 07:26:58PM -0400, Rich Felker wrote: > On Wed, Aug 24, 2022 at 09:03:49PM +0200, Markus Wichmann wrote: > > Hi all, > > > > I noticed something while reading some code: There is a fallback in > > __res_msend_rc(), in case an IPv6 socket is requested but cannot be > > allocated. In that case, the function tries to create an IPv4 socket > > instead. However, I do not think this code can work that way. For > > reference, this is the code: > > > > /* Get local address and open/bind a socket */ > > sa.sin.sin_family = family; > > fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); > > > > /* Handle case where system lacks IPv6 support */ > > if (fd < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) { > > fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); > > family = AF_INET; > > } > > if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) { > > if (fd >= 0) close(fd); > > pthread_setcancelstate(cs, 0); > > return -1; > > } > > > > The problem is, if the fallback is triggered, the local address is still > > set to be an IPv6 address, and so the bind() must necessarily fail with > > EINVAL. > > > > The fix depends on whether the fallback is still intended functionality > > or not. If not, then the easiest would be to just get rid of the entire > > fallback block. If the fallback is still intended to work, then the > > fallback block must reset sl to the length of an IPv4 socket, and the > > setting of sa.sin.sin_family must be delayed until after that block. > > > > There is also the issue of the sendto() loop further down in the > > function. If it is intended that the socket can be an IPv4 socket but > > there can be IPv6 addresses in the list, then it might be prudent to > > prevent sendto() from sending to the wrong address family. Or not, I > > mean, you do not test for errors from sendto(), and the sends to the > > wrong address family are just going to fail. So they would only waste > > time and change errno, but not much of a visible side effect. > > Thanks for reporting this! It's intended to be functional, but it's > probably of little consequence whether it works since the issue seems > to arise only when resolv.conf requested IPv6 nameservers but the > system doesn't support IPv6. I'll look at what it'll take to fix it... > hopefully it won't be too bad. Does this work? diff --git a/src/network/res_msend.c b/src/network/res_msend.c index 3e018009..105bf598 100644 --- a/src/network/res_msend.c +++ b/src/network/res_msend.c @@ -68,14 +68,15 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries, } /* Get local address and open/bind a socket */ - sa.sin.sin_family = family; fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); /* Handle case where system lacks IPv6 support */ if (fd < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) { fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); family = AF_INET; + sl = sizeof sa.sin; } + sa.sin.sin_family = family; if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) { if (fd >= 0) close(fd); pthread_setcancelstate(cs, 0);