diff mbox

Rewrite handling of nameserver configuration in resolver

Message ID mvmvbirworv.fsf@hawking.suse.de
State New
Headers show

Commit Message

Andreas Schwab Feb. 24, 2015, 11:08 a.m. UTC
The handing of nameservers in the resolver is overly complex and
completely unmaintainable, all the recent attempts at fixing it made it
only worse.  This patch rewrites most of it to make it clear and simple.
I have tested it with all possible mixes of IPv4 and IPv6 nameserver
addresses, including RES_ROTATE handling and fallback on unreachable
nameservers.

Andreas.

	[BZ #13028]
	[BZ #17053]
	* resolv/res_private.h: New file.
	* resolv/resolv.h (struct __res_state): Add pointer to struct
	__res_state_ext member, rename ext.nsmap, ext.nscount6,
	ext.nsinit, ext.nsaddrs members to __glibc_reserved*.
	* resolv/res_init.c (__res_vinit): Rewrite handling of nameserver
	addresses.
	(__res_iclose): Deallocate __res_state_ext memory if free_addr.
	* resolv/res_send.c (__libc_res_nsend): Rewrite nameserver setup.
	(get_nsaddr): New function.
	(res_ourserver_p, send_vc, reopen): Use it instead of accessing
	statp directly.
---
 resolv/res_init.c    | 125 +++++++++++++++---------------------
 resolv/res_private.h |  29 +++++++++
 resolv/res_send.c    | 176 ++++++++++++++++++++++-----------------------------
 resolv/resolv.h      |   9 +--
 4 files changed, 160 insertions(+), 179 deletions(-)
 create mode 100644 resolv/res_private.h
diff mbox

Patch

diff --git a/resolv/res_init.c b/resolv/res_init.c
index 553ba12..567afaa 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -89,6 +89,8 @@  static const char rcsid[] = "$BINDId: res_init.c,v 8.16 2000/05/09 07:10:12 vixi
 
 #include <not-cancel.h>
 
+#include "res_private.h"
+
 /* Options.  Should all be left alone. */
 #define RESOLVSORT
 #define RFC1535
@@ -153,10 +155,8 @@  __res_vinit(res_state statp, int preinit) {
 	char *cp, **pp;
 	int n;
 	char buf[BUFSIZ];
-	int nserv = 0;    /* number of IPv4 nameservers read from file */
-#ifdef _LIBC
-	int nservall = 0; /* number of (IPv4 + IPV6) nameservers read from file */
-#endif
+	int nserv = 0;    /* number of nameservers read from file */
+	int have_serv6 = 0;
 	int haveenv = 0;
 	int havesearch = 0;
 #ifdef RESOLVSORT
@@ -184,15 +184,12 @@  __res_vinit(res_state statp, int preinit) {
 	statp->_flags = 0;
 	statp->qhook = NULL;
 	statp->rhook = NULL;
-	statp->_u._ext.nsinit = 0;
 	statp->_u._ext.nscount = 0;
-#ifdef _LIBC
-	statp->_u._ext.nscount6 = 0;
-	for (n = 0; n < MAXNS; n++) {
-		statp->_u._ext.nsaddrs[n] = NULL;
-		statp->_u._ext.nsmap[n] = MAXNS;
+	if (statp->_u._ext.ext == NULL) {
+	    statp->_u._ext.ext = malloc (sizeof (*statp->_u._ext.ext));
+	    if (statp->_u._ext.ext != NULL)
+		memset (statp->_u._ext.ext, 0, sizeof (*statp->_u._ext.ext));
 	}
-#endif
 
 	/* Allow user to override the local domain definition */
 	if ((cp = getenv("LOCALDOMAIN")) != NULL) {
@@ -296,11 +293,7 @@  __res_vinit(res_state statp, int preinit) {
 		    continue;
 		}
 		/* read nameservers to query */
-#ifdef _LIBC
-		if (MATCH(buf, "nameserver") && nservall < MAXNS) {
-#else
 		if (MATCH(buf, "nameserver") && nserv < MAXNS) {
-#endif
 		    struct in_addr a;
 
 		    cp = buf + sizeof("nameserver") - 1;
@@ -308,13 +301,11 @@  __res_vinit(res_state statp, int preinit) {
 			cp++;
 		    if ((*cp != '\0') && (*cp != '\n')
 			&& __inet_aton(cp, &a)) {
-			statp->nsaddr_list[nservall].sin_addr = a;
-			statp->nsaddr_list[nservall].sin_family = AF_INET;
-			statp->nsaddr_list[nservall].sin_port =
+			statp->nsaddr_list[nserv].sin_addr = a;
+			statp->nsaddr_list[nserv].sin_family = AF_INET;
+			statp->nsaddr_list[nserv].sin_port =
 				htons(NAMESERVER_PORT);
 			nserv++;
-#ifdef _LIBC
-			nservall++;
 		    } else {
 			struct in6_addr a6;
 			char *el;
@@ -324,45 +315,40 @@  __res_vinit(res_state statp, int preinit) {
 			if ((el = strchr(cp, SCOPE_DELIMITER)) != NULL)
 			    *el = '\0';
 			if ((*cp != '\0') &&
-			    (__inet_pton(AF_INET6, cp, &a6) > 0)) {
-			    struct sockaddr_in6 *sa6;
-
-			    sa6 = malloc(sizeof(*sa6));
-			    if (sa6 != NULL) {
-				sa6->sin6_family = AF_INET6;
-				sa6->sin6_port = htons(NAMESERVER_PORT);
-				sa6->sin6_flowinfo = 0;
-				sa6->sin6_addr = a6;
-
-				if (__glibc_likely (el == NULL))
-				    sa6->sin6_scope_id = 0;
-				else {
-				    int try_numericscope = 1;
-				    if (IN6_IS_ADDR_LINKLOCAL (&a6)
-					|| IN6_IS_ADDR_MC_LINKLOCAL (&a6)) {
-					sa6->sin6_scope_id
-					  = __if_nametoindex (el + 1);
-					if (sa6->sin6_scope_id != 0)
-					    try_numericscope = 0;
-				    }
-
-				    if (try_numericscope) {
-					char *end;
-					sa6->sin6_scope_id
-					  = (uint32_t) strtoul (el + 1, &end,
-								10);
-					if (*end != '\0')
-					    sa6->sin6_scope_id = 0;
-				    }
+			    (__inet_pton(AF_INET6, cp, &a6) > 0)
+			    && statp->_u._ext.ext != NULL) {
+			    struct sockaddr_in6 *sa6
+			      = &statp->_u._ext.ext->nsaddrs[nserv].sin6;
+
+			    sa6->sin6_family = AF_INET6;
+			    sa6->sin6_port = htons(NAMESERVER_PORT);
+			    sa6->sin6_flowinfo = 0;
+			    sa6->sin6_addr = a6;
+
+			    if (__glibc_likely (el == NULL))
+			        sa6->sin6_scope_id = 0;
+			    else {
+				int try_numericscope = 1;
+				if (IN6_IS_ADDR_LINKLOCAL (&a6)
+				    || IN6_IS_ADDR_MC_LINKLOCAL (&a6)) {
+				    sa6->sin6_scope_id
+				      = __if_nametoindex (el + 1);
+				    if (sa6->sin6_scope_id != 0)
+					try_numericscope = 0;
 				}
 
-				statp->_u._ext.nsaddrs[nservall] = sa6;
-				statp->_u._ext.nssocks[nservall] = -1;
-				statp->_u._ext.nsmap[nservall] = MAXNS + 1;
-				nservall++;
+				if (try_numericscope) {
+				    char *end;
+				    sa6->sin6_scope_id
+				      = (uint32_t) strtoul (el + 1, &end, 10);
+				    if (*end != '\0')
+					sa6->sin6_scope_id = 0;
+				}
 			    }
+			    statp->nsaddr_list[nserv].sin_family = 0;
+			    have_serv6 = 1;
+			    nserv++;
 			}
-#endif
 		    }
 		    continue;
 		}
@@ -414,10 +400,9 @@  __res_vinit(res_state statp, int preinit) {
 		    continue;
 		}
 	    }
-	    statp->nscount = nservall;
+	    statp->nscount = nserv;
 #ifdef _LIBC
-	    if (nservall - nserv > 0) {
-		statp->_u._ext.nscount6 = nservall - nserv;
+	    if (have_serv6) {
 		/* We try IPv6 servers again.  */
 		statp->ipv6_unavail = false;
 	    }
@@ -606,23 +591,15 @@  __res_iclose(res_state statp, bool free_addr) {
 		statp->_vcsock = -1;
 		statp->_flags &= ~(RES_F_VC | RES_F_CONN);
 	}
-#ifdef _LIBC
-	for (ns = 0; ns < MAXNS; ns++)
-#else
-	for (ns = 0; ns < statp->_u._ext.nscount; ns++)
-#endif
-		if (statp->_u._ext.nsaddrs[ns]) {
-			if (statp->_u._ext.nssocks[ns] != -1) {
-				close_not_cancel_no_status(statp->_u._ext.nssocks[ns]);
-				statp->_u._ext.nssocks[ns] = -1;
-			}
-			if (free_addr) {
-				free (statp->_u._ext.nsaddrs[ns]);
-				statp->_u._ext.nsaddrs[ns] = NULL;
-			}
+	for (ns = 0; ns < statp->nscount; ns++)
+		if (statp->_u._ext.nssocks[ns] != -1) {
+			close_not_cancel_no_status(statp->_u._ext.nssocks[ns]);
+			statp->_u._ext.nssocks[ns] = -1;
 		}
-	if (free_addr)
-		statp->_u._ext.nsinit = 0;
+	if (free_addr) {
+		free (statp->_u._ext.ext);
+		statp->_u._ext.ext = NULL;
+	}
 }
 libc_hidden_def (__res_iclose)
 
diff --git a/resolv/res_private.h b/resolv/res_private.h
new file mode 100644
index 0000000..deb495b
--- /dev/null
+++ b/resolv/res_private.h
@@ -0,0 +1,29 @@ 
+/* Private definitions for the stub resolver.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+union res_sockaddr_union
+{
+  struct sockaddr s;
+  struct sockaddr_in sin;
+  struct sockaddr_in6 sin6;
+};
+
+struct __res_state_ext
+{
+  union res_sockaddr_union nsaddrs[MAXNS];
+};
diff --git a/resolv/res_send.c b/resolv/res_send.c
index c35fb66..1e6d217 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -179,11 +179,13 @@  evNowTime(struct timespec *res) {
 /* Options.  Leave them on. */
 /* #undef DEBUG */
 #include "res_debug.h"
+#include "res_private.h"
 
 #define EXT(res) ((res)->_u._ext)
 
 /* Forward. */
 
+static struct sockaddr *get_nsaddr (res_state, int);
 static int		send_vc(res_state, const u_char *, int,
 				const u_char *, int,
 				u_char **, int *, int *, int, u_char **,
@@ -221,20 +223,21 @@  res_ourserver_p(const res_state statp, const struct sockaddr_in6 *inp)
 	    in_port_t port = in4p->sin_port;
 	    in_addr_t addr = in4p->sin_addr.s_addr;
 
-	    for (ns = 0;  ns < MAXNS;  ns++) {
+	    for (ns = 0;  ns < statp->nscount;  ns++) {
 		const struct sockaddr_in *srv =
-		    (struct sockaddr_in *)EXT(statp).nsaddrs[ns];
+		    (struct sockaddr_in *) get_nsaddr (statp, ns);
 
-		if ((srv != NULL) && (srv->sin_family == AF_INET) &&
+		if ((srv->sin_family == AF_INET) &&
 		    (srv->sin_port == port) &&
 		    (srv->sin_addr.s_addr == INADDR_ANY ||
 		     srv->sin_addr.s_addr == addr))
 		    return (1);
 	    }
 	} else if (inp->sin6_family == AF_INET6) {
-	    for (ns = 0;  ns < MAXNS;  ns++) {
-		const struct sockaddr_in6 *srv = EXT(statp).nsaddrs[ns];
-		if ((srv != NULL) && (srv->sin6_family == AF_INET6) &&
+	    for (ns = 0;  ns < statp->nscount;  ns++) {
+		const struct sockaddr_in6 *srv
+		  = (struct sockaddr_in6 *) get_nsaddr (statp, ns);
+		if ((srv->sin6_family == AF_INET6) &&
 		    (srv->sin6_port == inp->sin6_port) &&
 		    !(memcmp(&srv->sin6_addr, &in6addr_any,
 			     sizeof (struct in6_addr)) &&
@@ -384,80 +387,40 @@  __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
 	 * If the ns_addr_list in the resolver context has changed, then
 	 * invalidate our cached copy and the associated timing data.
 	 */
-	if (EXT(statp).nsinit) {
+	if (EXT(statp).nscount != 0) {
 		int needclose = 0;
 
 		if (EXT(statp).nscount != statp->nscount)
 			needclose++;
 		else
-			for (ns = 0; ns < MAXNS; ns++) {
-				unsigned int map = EXT(statp).nsmap[ns];
-				if (map < MAXNS
+			for (ns = 0; ns < statp->nscount; ns++) {
+				if (statp->nsaddr_list[ns].sin_family != 0
 				    && !sock_eq((struct sockaddr_in6 *)
-						&statp->nsaddr_list[map],
-						EXT(statp).nsaddrs[ns]))
+						&statp->nsaddr_list[ns],
+						&EXT(statp).ext->nsaddrs[ns].sin6))
 				{
 					needclose++;
 					break;
 				}
 			}
-		if (needclose)
+		if (needclose) {
 			__res_iclose(statp, false);
+			EXT(statp).nscount = 0;
+		}
 	}
 
 	/*
 	 * Maybe initialize our private copy of the ns_addr_list.
 	 */
-	if (EXT(statp).nsinit == 0) {
-		unsigned char map[MAXNS];
-
-		memset (map, MAXNS, sizeof (map));
-		for (n = 0; n < MAXNS; n++) {
-			ns = EXT(statp).nsmap[n];
-			if (ns < statp->nscount)
-				map[ns] = n;
-			else if (ns < MAXNS) {
-				free(EXT(statp).nsaddrs[n]);
-				EXT(statp).nsaddrs[n] = NULL;
-				EXT(statp).nsmap[n] = MAXNS;
-			}
+	if (EXT(statp).nscount == 0) {
+		for (ns = 0; ns < statp->nscount; ns++) {
+			EXT(statp).nssocks[ns] = -1;
+			if (statp->nsaddr_list[ns].sin_family != 0
+			    && EXT(statp).ext != NULL)
+				EXT(statp).ext->nsaddrs[ns].sin
+				  = statp->nsaddr_list[ns];
 		}
-		n = statp->nscount;
-		if (statp->nscount > EXT(statp).nscount)
-			for (n = EXT(statp).nscount, ns = 0;
-			     n < statp->nscount; n++) {
-				while (ns < MAXNS
-				       && EXT(statp).nsmap[ns] != MAXNS)
-					ns++;
-				if (ns == MAXNS)
-					break;
-				/* NS never exceeds MAXNS, but gcc 4.9 somehow
-				   does not see this.  */
-				DIAG_PUSH_NEEDS_COMMENT;
-				DIAG_IGNORE_NEEDS_COMMENT (4.9,
-							   "-Warray-bounds");
-				EXT(statp).nsmap[ns] = n;
-				DIAG_POP_NEEDS_COMMENT;
-				map[n] = ns++;
-			}
-		EXT(statp).nscount = n;
-		for (ns = 0; ns < EXT(statp).nscount; ns++) {
-			n = map[ns];
-			if (EXT(statp).nsaddrs[n] == NULL)
-				EXT(statp).nsaddrs[n] =
-				    malloc(sizeof (struct sockaddr_in6));
-			if (EXT(statp).nsaddrs[n] != NULL) {
-				memset (mempcpy(EXT(statp).nsaddrs[n],
-						&statp->nsaddr_list[ns],
-						sizeof (struct sockaddr_in)),
-					'\0',
-					sizeof (struct sockaddr_in6)
-					- sizeof (struct sockaddr_in));
-				EXT(statp).nssocks[n] = -1;
-				n++;
-			}
-		}
-		EXT(statp).nsinit = 1;
+		EXT(statp).nscount = statp->nscount;
 	}
 
 	/*
@@ -466,44 +429,41 @@  __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
 	 */
 	if (__builtin_expect ((statp->options & RES_ROTATE) != 0, 0) &&
 	    (statp->options & RES_BLAST) == 0) {
-		struct sockaddr_in6 *ina;
-		unsigned int map;
-
-		n = 0;
-		while (n < MAXNS && EXT(statp).nsmap[n] == MAXNS)
-			n++;
-		if (n < MAXNS) {
-			ina = EXT(statp).nsaddrs[n];
-			map = EXT(statp).nsmap[n];
-			for (;;) {
-				ns = n + 1;
-				while (ns < MAXNS
-				       && EXT(statp).nsmap[ns] == MAXNS)
-					ns++;
-				if (ns == MAXNS)
-					break;
-				EXT(statp).nsaddrs[n] = EXT(statp).nsaddrs[ns];
-				EXT(statp).nsmap[n] = EXT(statp).nsmap[ns];
-				n = ns;
-			}
-			EXT(statp).nsaddrs[n] = ina;
-			EXT(statp).nsmap[n] = map;
+		union res_sockaddr_union inu;
+		struct sockaddr_in ina;
+		int lastns = statp->nscount - 1;
+		int fd;
+
+		if (EXT(statp).ext != NULL)
+		    inu = EXT(statp).ext->nsaddrs[0];
+		ina = statp->nsaddr_list[0];
+		fd = EXT(statp).nssocks[0];
+		for (ns = 0; ns < lastns; ns++) {
+		    if (EXT(statp).ext != NULL)
+		        EXT(statp).ext->nsaddrs[ns]
+			  = EXT(statp).ext->nsaddrs[ns + 1];
+		    statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
+		    EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
 		}
+		if (EXT(statp).ext != NULL)
+		    EXT(statp).ext->nsaddrs[lastns] = inu;
+		statp->nsaddr_list[lastns] = ina;
+		EXT(statp).nssocks[lastns] = fd;
 	}
 
 	/*
 	 * Send request, RETRY times, or until successful.
 	 */
 	for (try = 0; try < statp->retry; try++) {
-	    for (ns = 0; ns < MAXNS; ns++)
+	    for (ns = 0; ns < statp->nscount; ns++)
 	    {
 #ifdef DEBUG
 		char tmpbuf[40];
 #endif
-		struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
+#if defined USE_HOOKS || defined DEBUG
+		struct sockaddr *nsap = get_nsaddr (statp, ns);
+#endif
 
-		if (nsap == NULL)
-			goto next_ns;
 	    same_ns:
 #ifdef USE_HOOKS
 		if (__glibc_unlikely (statp->qhook != NULL))       {
@@ -542,9 +502,9 @@  __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
 
 		Dprint(statp->options & RES_DEBUG,
 		       (stdout, ";; Querying server (# %d) address = %s\n",
-			ns + 1, inet_ntop(nsap->sin6_family,
-					  (nsap->sin6_family == AF_INET6
-					   ? &nsap->sin6_addr
+			ns + 1, inet_ntop(nsap->sa_family,
+					  (nsap->sa_family == AF_INET6
+					   ? &((struct sockaddr_in6 *) nsap)->sin6_addr
 					   : &((struct sockaddr_in *) nsap)->sin_addr),
 					  tmpbuf, sizeof (tmpbuf))));
 
@@ -660,6 +620,22 @@  libresolv_hidden_def (res_nsend)
 
 /* Private */
 
+static struct sockaddr *
+get_nsaddr (res_state statp, int n)
+{
+
+  if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext)
+    /* - EXT(statp).ext->nsaddrs[n] holds an address that is larger
+         than struct sockaddr, and
+       - user code did not update statp->nsaddr_list[n].  */
+    return &EXT(statp).ext->nsaddrs[n].s;
+  else
+    /* - user code updated statp->nsaddr_list[n], or
+       - statp->nsaddr_list[n] has the same content as
+         EXT(statp).ext->nsaddrs[n].  */
+    return (struct sockaddr *) (void *) &statp->nsaddr_list[n];
+}
+
 static int
 send_vc(res_state statp,
 	const u_char *buf, int buflen, const u_char *buf2, int buflen2,
@@ -674,7 +650,7 @@  send_vc(res_state statp,
 	// XXX REMOVE
 	// int anssiz = *anssizp;
 	HEADER *anhp = (HEADER *) ans;
-	struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
+	struct sockaddr *nsap = get_nsaddr (statp, ns);
 	int truncating, connreset, n;
 	/* On some architectures compiler might emit a warning indicating
 	   'resplen' may be used uninitialized.  However if buf2 == NULL
@@ -711,8 +687,8 @@  send_vc(res_state statp,
 
 		if (getpeername(statp->_vcsock,
 				(struct sockaddr *)&peer, &size) < 0 ||
-		    !sock_eq(&peer, nsap)) {
-		  __res_iclose(statp, false);
+		    !sock_eq(&peer, (struct sockaddr_in6 *) nsap)) {
+			__res_iclose(statp, false);
 			statp->_flags &= ~RES_F_VC;
 		}
 	}
@@ -721,20 +697,19 @@  send_vc(res_state statp,
 		if (statp->_vcsock >= 0)
 		  __res_iclose(statp, false);
 
-		statp->_vcsock = socket(nsap->sin6_family, SOCK_STREAM, 0);
+		statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0);
 		if (statp->_vcsock < 0) {
 			*terrno = errno;
 			Perror(statp, stderr, "socket(vc)", errno);
 			return (-1);
 		}
 		__set_errno (0);
-		if (connect(statp->_vcsock, (struct sockaddr *)nsap,
-			    nsap->sin6_family == AF_INET
+		if (connect(statp->_vcsock, nsap,
+			    nsap->sa_family == AF_INET
 			    ? sizeof (struct sockaddr_in)
 			    : sizeof (struct sockaddr_in6)) < 0) {
 			*terrno = errno;
-			Aerror(statp, stderr, "connect/vc", errno,
-			       (struct sockaddr *) nsap);
+			Aerror(statp, stderr, "connect/vc", errno, nsap);
 			__res_iclose(statp, false);
 			return (0);
 		}
@@ -945,8 +920,7 @@  static int
 reopen (res_state statp, int *terrno, int ns)
 {
 	if (EXT(statp).nssocks[ns] == -1) {
-		struct sockaddr *nsap
-		  = (struct sockaddr *) EXT(statp).nsaddrs[ns];
+		struct sockaddr *nsap = get_nsaddr (statp, ns);
 		socklen_t slen;
 
 		/* only try IPv6 if IPv6 NS and if not failed before */
diff --git a/resolv/resolv.h b/resolv/resolv.h
index 53c3bba..dffd1db 100644
--- a/resolv/resolv.h
+++ b/resolv/resolv.h
@@ -100,6 +100,7 @@  typedef res_sendhookact (*res_send_rhook) (const struct sockaddr_in *__ns,
 # define RES_MAXRETRY		5	/* only for resolv.conf/RES_OPTIONS */
 # define RES_DFLRETRY		2	/* Default #/tries. */
 # define RES_MAXTIME		65535	/* Infinity, in milliseconds. */
+struct __res_state_ext;
 
 struct __res_state {
 	int	retrans;		/* retransmition time interval */
@@ -133,11 +134,11 @@  struct __res_state {
 		char	pad[52];	/* On an i386 this means 512b total. */
 		struct {
 			u_int16_t		nscount;
-			u_int16_t		nsmap[MAXNS];
+			u_int16_t __glibc_reserved1[MAXNS];
 			int			nssocks[MAXNS];
-			u_int16_t		nscount6;
-			u_int16_t		nsinit;
-			struct sockaddr_in6	*nsaddrs[MAXNS];
+			u_int16_t __glibc_reserved2[2];
+			struct __res_state_ext *ext;	/* extension for IPv6 */
+			void *__glibc_reserved3[MAXNS-1];
 #ifdef _LIBC
 			unsigned long long int	initstamp
 			  __attribute__((packed));