[3/4] resolv: fix issues when using IPv6 name servers only

Message ID 1402673533-13243-4-git-send-email-aurelien@aurel32.net
State Changes Requested, archived
Headers

Commit Message

Aurelien Jarno June 13, 2014, 3:32 p.m. UTC
  statp->nscount contains the number of servers in the statp->nsaddr_list
array, which only contains IPv4 name servers.

When resolv.conf only contains IPv6 name servers, statp->nscount equals
to 0, which causes the existing code to add a 127.0.0.1 entry. Change
that by checking nservall, contains the number of IPv4 + IPv6 servers
instead.

The same way __libc_res_nsend exits almost immediately when
statp->nscount considering that no name servers are available, while
IPv6 name servers are actually available. Change that by checking
(statp->nscount + EXT(statp).nscount6) instead.

Finally in send_dg, the seconds variable is wrongly computed in case of
IPv6 only name servers. Use (statp->nscount + EXT(statp).nscount6)
instead of statp->nscount.

2014-06-13  Aurelien Jarno  <aurelien@aurel32.net>

	* resolv/res_init.c (__res_vinit): Check for both IPv4 and IPv6
	name servers before adding a localhost name server entry.
	* resolv/res_send.c (__libc_res_nsend): Check for both IPv4 and
	IPv6 name servers before ignoring the request.
	(send_dg): Check for both IPv4 and IPv6 name servers to compute
	time for the total operation.
  

Comments

Siddhesh Poyarekar June 20, 2014, 3:02 a.m. UTC | #1
On Fri, Jun 13, 2014 at 05:32:12PM +0200, Aurelien Jarno wrote:
> statp->nscount contains the number of servers in the statp->nsaddr_list
> array, which only contains IPv4 name servers.
> 
> When resolv.conf only contains IPv6 name servers, statp->nscount equals
> to 0, which causes the existing code to add a 127.0.0.1 entry. Change
> that by checking nservall, contains the number of IPv4 + IPv6 servers
> instead.
> 
> The same way __libc_res_nsend exits almost immediately when
> statp->nscount considering that no name servers are available, while
> IPv6 name servers are actually available. Change that by checking
> (statp->nscount + EXT(statp).nscount6) instead.
> 
> Finally in send_dg, the seconds variable is wrongly computed in case of
> IPv6 only name servers. Use (statp->nscount + EXT(statp).nscount6)
> instead of statp->nscount.
> 
> 2014-06-13  Aurelien Jarno  <aurelien@aurel32.net>
> 
> 	* resolv/res_init.c (__res_vinit): Check for both IPv4 and IPv6
> 	name servers before adding a localhost name server entry.
> 	* resolv/res_send.c (__libc_res_nsend): Check for both IPv4 and
> 	IPv6 name servers before ignoring the request.
> 	(send_dg): Check for both IPv4 and IPv6 name servers to compute
> 	time for the total operation.

You may also have to fix this bit to also account for ipv6
nameservers:

...
static void __attribute__ ((section ("__libc_thread_freeres_fn")))
res_thread_freeres (void)
{
  if (_res.nscount == 0)
    /* Never called res_ninit.  */
    return;
...

Likewise for any other checks in the resolver that may be using only
nscount.

Siddhesh

>  
> diff --git a/resolv/res_init.c b/resolv/res_init.c
> index 37004ab..95564af 100644
> --- a/resolv/res_init.c
> +++ b/resolv/res_init.c
> @@ -427,7 +427,7 @@ __res_vinit(res_state statp, int preinit) {
>  #endif
>  	    (void) fclose(fp);
>  	}
> -	if (__builtin_expect(statp->nscount == 0, 0)) {
> +	if (__builtin_expect(nservall == 0, 0)) {
>  	    statp->nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
>  	    statp->nsaddr.sin_family = AF_INET;
>  	    statp->nsaddr.sin_port = htons(NAMESERVER_PORT);
> diff --git a/resolv/res_send.c b/resolv/res_send.c
> index af42b8a..82242bd 100644
> --- a/resolv/res_send.c
> +++ b/resolv/res_send.c
> @@ -347,7 +347,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
>  {
>    int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
>  
> -	if (statp->nscount == 0) {
> +	if ((statp->nscount + EXT(statp).nscount6) == 0) {
>  		__set_errno (ESRCH);
>  		return (-1);
>  	}
> @@ -1013,7 +1013,7 @@ send_dg(res_state statp,
>  	 */
>  	int seconds = (statp->retrans << ns);
>  	if (ns > 0)
> -		seconds /= statp->nscount;
> +		seconds /= (statp->nscount + EXT(statp).nscount6);
>  	if (seconds <= 0)
>  		seconds = 1;
>  	bool single_request_reopen = (statp->options & RES_SNGLKUPREOP) != 0;
> -- 
> 2.0.0
>
  

Patch

diff --git a/resolv/res_init.c b/resolv/res_init.c
index 37004ab..95564af 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -427,7 +427,7 @@  __res_vinit(res_state statp, int preinit) {
 #endif
 	    (void) fclose(fp);
 	}
-	if (__builtin_expect(statp->nscount == 0, 0)) {
+	if (__builtin_expect(nservall == 0, 0)) {
 	    statp->nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
 	    statp->nsaddr.sin_family = AF_INET;
 	    statp->nsaddr.sin_port = htons(NAMESERVER_PORT);
diff --git a/resolv/res_send.c b/resolv/res_send.c
index af42b8a..82242bd 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -347,7 +347,7 @@  __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
 {
   int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
 
-	if (statp->nscount == 0) {
+	if ((statp->nscount + EXT(statp).nscount6) == 0) {
 		__set_errno (ESRCH);
 		return (-1);
 	}
@@ -1013,7 +1013,7 @@  send_dg(res_state statp,
 	 */
 	int seconds = (statp->retrans << ns);
 	if (ns > 0)
-		seconds /= statp->nscount;
+		seconds /= (statp->nscount + EXT(statp).nscount6);
 	if (seconds <= 0)
 		seconds = 1;
 	bool single_request_reopen = (statp->options & RES_SNGLKUPREOP) != 0;