summary refs log tree commit diff
path: root/resolv/res_query.c
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2017-06-30 21:10:23 +0200
committerFlorian Weimer <fweimer@redhat.com>2017-07-03 20:52:59 +0200
commit352f4ff9a268b81ef5d4b2413f582565806e4790 (patch)
treefb27056dfdeafe43c021f6127c9544c016e78019 /resolv/res_query.c
parent4e45d83c92dbb5b8dc20654f32395108d18cf739 (diff)
downloadglibc-352f4ff9a268b81ef5d4b2413f582565806e4790.tar.gz
glibc-352f4ff9a268b81ef5d4b2413f582565806e4790.tar.xz
glibc-352f4ff9a268b81ef5d4b2413f582565806e4790.zip
resolv: Introduce struct resolv_context [BZ #21668]
struct resolv_context objects provide a temporary resolver context
which does not change during a name lookup operation.  Only when the
outmost context is created, the stub resolver configuration is
verified to be current (at present, only against previous res_init
calls).  Subsequent attempts to obtain the context will reuse the
result of the initial verification operation.

struct resolv_context can also be extended in the future to store
data which needs to be deallocated during thread cancellation.
Diffstat (limited to 'resolv/res_query.c')
-rw-r--r--resolv/res_query.c298
1 files changed, 172 insertions, 126 deletions
diff --git a/resolv/res_query.c b/resolv/res_query.c
index 760bf324e8..33249e36f5 100644
--- a/resolv/res_query.c
+++ b/resolv/res_query.c
@@ -75,6 +75,7 @@
 #include <netdb.h>
 #include <resolv.h>
 #include <resolv/resolv-internal.h>
+#include <resolv/resolv_context.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -89,33 +90,28 @@
 #define QUERYSIZE	(HFIXEDSZ + QFIXEDSZ + MAXCDNAME + 1)
 
 static int
-__libc_res_nquerydomain(res_state statp, const char *name, const char *domain,
-			int class, int type, u_char *answer, int anslen,
-			u_char **answerp, u_char **answerp2, int *nanswerp2,
-			int *resplen2, int *answerp2_malloced);
-
-/*
- * Formulate a normal query, send, and await answer.
- * Returned answer is placed in supplied buffer "answer".
- * Perform preliminary check of answer, returning success only
- * if no error is indicated and the answer count is nonzero.
- * Return the size of the response on success, -1 on error.
- * Error number is left in H_ERRNO.
- *
- * Caller must parse answer and determine whether it answers the question.
- */
+__res_context_querydomain (struct resolv_context *,
+			   const char *name, const char *domain,
+			   int class, int type, unsigned char *answer, int anslen,
+			   unsigned char **answerp, unsigned char **answerp2, int *nanswerp2,
+			   int *resplen2, int *answerp2_malloced);
+
+/* Formulate a normal query, send, and await answer.  Returned answer
+   is placed in supplied buffer ANSWER.  Perform preliminary check of
+   answer, returning success only if no error is indicated and the
+   answer count is nonzero.  Return the size of the response on
+   success, -1 on error.  Error number is left in h_errno.
+
+   Caller must parse answer and determine whether it answers the
+   question.  */
 int
-__libc_res_nquery(res_state statp,
-		  const char *name,	/* domain name */
-		  int class, int type,	/* class and type of query */
-		  u_char *answer,	/* buffer to put answer */
-		  int anslen,		/* size of answer buffer */
-		  u_char **answerp,	/* if buffer needs to be enlarged */
-		  u_char **answerp2,
-		  int *nanswerp2,
-		  int *resplen2,
-		  int *answerp2_malloced)
+__res_context_query (struct resolv_context *ctx, const char *name,
+		     int class, int type,
+		     unsigned char *answer, int anslen,
+		     unsigned char **answerp, unsigned char **answerp2,
+		     int *nanswerp2, int *resplen2, int *answerp2_malloced)
 {
+	struct __res_state *statp = ctx->resp;
 	HEADER *hp = (HEADER *) answer;
 	HEADER *hp2;
 	int n, use_malloc = 0;
@@ -132,15 +128,15 @@ __libc_res_nquery(res_state statp,
 
 	if (type == T_QUERY_A_AND_AAAA)
 	  {
-	    n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL,
-			     query1, bufsize);
+	    n = __res_context_mkquery (ctx, QUERY, name, class, T_A, NULL,
+				       query1, bufsize);
 	    if (n > 0)
 	      {
 		if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
 		  {
 		    /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
 		       buffer can be reallocated.  */
-		    n = __res_nopt (statp, n, query1, bufsize,
+		    n = __res_nopt (ctx, n, query1, bufsize,
 				    RESOLV_EDNS_BUFFER_SIZE);
 		    if (n < 0)
 		      goto unspec_nomem;
@@ -157,13 +153,13 @@ __libc_res_nquery(res_state statp,
 		  }
 		int nused = n + npad;
 		query2 = buf + nused;
-		n = res_nmkquery(statp, QUERY, name, class, T_AAAA, NULL, 0,
-				 NULL, query2, bufsize - nused);
+		n = __res_context_mkquery (ctx, QUERY, name, class, T_AAAA,
+					   NULL, query2, bufsize - nused);
 		if (n > 0
 		    && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
 		  /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
 		     buffer can be reallocated.  */
-		  n = __res_nopt (statp, n, query2, bufsize,
+		  n = __res_nopt (ctx, n, query2, bufsize,
 				  RESOLV_EDNS_BUFFER_SIZE);
 		nquery2 = n;
 	      }
@@ -172,8 +168,8 @@ __libc_res_nquery(res_state statp,
 	  }
 	else
 	  {
-	    n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
-			     query1, bufsize);
+	    n = __res_context_mkquery (ctx, QUERY, name, class, type, NULL,
+				       query1, bufsize);
 
 	    if (n > 0
 		&& (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
@@ -185,7 +181,7 @@ __libc_res_nquery(res_state statp,
 		  advertise = anslen;
 		else
 		  advertise = RESOLV_EDNS_BUFFER_SIZE;
-		n = __res_nopt (statp, n, query1, bufsize, advertise);
+		n = __res_nopt (ctx, n, query1, bufsize, advertise);
 	      }
 
 	    nquery1 = n;
@@ -209,9 +205,9 @@ __libc_res_nquery(res_state statp,
 		return (n);
 	}
 	assert (answerp == NULL || (void *) *answerp == (void *) answer);
-	n = __libc_res_nsend(statp, query1, nquery1, query2, nquery2, answer,
-			     anslen, answerp, answerp2, nanswerp2, resplen2,
-			     answerp2_malloced);
+	n = __res_context_send (ctx, query1, nquery1, query2, nquery2, answer,
+				anslen, answerp, answerp2, nanswerp2, resplen2,
+				answerp2_malloced);
 	if (use_malloc)
 		free (buf);
 	if (n < 0) {
@@ -220,7 +216,7 @@ __libc_res_nquery(res_state statp,
 	}
 
 	if (answerp != NULL)
-	  /* __libc_res_nsend might have reallocated the buffer.  */
+	  /* __res_context_send might have reallocated the buffer.  */
 	  hp = (HEADER *) *answerp;
 
 	/* We simplify the following tests by assigning HP to HP2 or
@@ -280,7 +276,24 @@ __libc_res_nquery(res_state statp,
  success:
 	return (n);
 }
-libresolv_hidden_def (__libc_res_nquery)
+libresolv_hidden_def (__res_context_query)
+
+/* Common part of res_nquery and res_query.  */
+static int
+context_query_common (struct resolv_context *ctx,
+		      const char *name, int class, int type,
+		      unsigned char *answer, int anslen)
+{
+  if (ctx == NULL)
+    {
+      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+      return -1;
+    }
+  int result = __res_context_query (ctx, name, class, type, answer, anslen,
+				    NULL, NULL, NULL, NULL, NULL);
+  __resolv_context_put (ctx);
+  return result;
+}
 
 int
 res_nquery(res_state statp,
@@ -289,41 +302,30 @@ res_nquery(res_state statp,
 	   u_char *answer,	/* buffer to put answer */
 	   int anslen)		/* size of answer buffer */
 {
-	return __libc_res_nquery(statp, name, class, type, answer, anslen,
-				 NULL, NULL, NULL, NULL, NULL);
+  return context_query_common
+    (__resolv_context_get_override (statp), name, class, type, answer, anslen);
 }
-libresolv_hidden_def (res_nquery)
 
 int
 res_query (const char *name, int class, int type,
 	   unsigned char *answer, int anslen)
 {
-  if (__res_maybe_init (&_res, 1) == -1)
-    {
-      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
-      return -1;
-    }
-  return res_nquery (&_res, name, class, type, answer, anslen);
+  return context_query_common
+    (__resolv_context_get (), name, class, type, answer, anslen);
 }
 
-/*
- * Formulate a normal query, send, and retrieve answer in supplied buffer.
- * Return the size of the response on success, -1 on error.
- * If enabled, implement search rules until answer or unrecoverable failure
- * is detected.  Error code, if any, is left in H_ERRNO.
- */
+/* Formulate a normal query, send, and retrieve answer in supplied
+   buffer.  Return the size of the response on success, -1 on error.
+   If enabled, implement search rules until answer or unrecoverable
+   failure is detected.  Error code, if any, is left in h_errno.  */
 int
-__libc_res_nsearch(res_state statp,
-		   const char *name,	/* domain name */
-		   int class, int type,	/* class and type of query */
-		   u_char *answer,	/* buffer to put answer */
-		   int anslen,		/* size of answer */
-		   u_char **answerp,
-		   u_char **answerp2,
-		   int *nanswerp2,
-		   int *resplen2,
-		   int *answerp2_malloced)
+__res_context_search (struct resolv_context *ctx,
+		      const char *name, int class, int type,
+		      unsigned char *answer, int anslen,
+		      unsigned char **answerp, unsigned char **answerp2,
+		      int *nanswerp2, int *resplen2, int *answerp2_malloced)
 {
+	struct __res_state *statp = ctx->resp;
 	const char *cp, * const *domain;
 	HEADER *hp = (HEADER *) answer;
 	char tmp[NS_MAXDNAME];
@@ -344,10 +346,11 @@ __libc_res_nsearch(res_state statp,
 		trailing_dot++;
 
 	/* If there aren't any dots, it could be a user-level alias. */
-	if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
-		return (__libc_res_nquery(statp, cp, class, type, answer,
-					  anslen, answerp, answerp2,
-					  nanswerp2, resplen2, answerp2_malloced));
+	if (!dots && (cp = __res_context_hostalias
+		      (ctx, name, tmp, sizeof tmp))!= NULL)
+	  return __res_context_query (ctx, cp, class, type, answer,
+				      anslen, answerp, answerp2,
+				      nanswerp2, resplen2, answerp2_malloced);
 
 	/*
 	 * If there are enough dots in the name, let's just give it a
@@ -356,10 +359,10 @@ __libc_res_nsearch(res_state statp,
 	 */
 	saved_herrno = -1;
 	if (dots >= statp->ndots || trailing_dot) {
-		ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
-					      answer, anslen, answerp,
-					      answerp2, nanswerp2, resplen2,
-					      answerp2_malloced);
+		ret = __res_context_querydomain (ctx, name, NULL, class, type,
+						 answer, anslen, answerp,
+						 answerp2, nanswerp2, resplen2,
+						 answerp2_malloced);
 		if (ret > 0 || trailing_dot
 		    /* If the second response is valid then we use that.  */
 		    || (ret == 0 && resplen2 != NULL && *resplen2 > 0))
@@ -395,7 +398,7 @@ __libc_res_nsearch(res_state statp,
 			const char *dname = domain[0];
 			searched = 1;
 
-			/* __libc_res_nquerydoman concatenates name
+			/* __res_context_querydoman concatenates name
 			   with dname with a "." in between.  If we
 			   pass it in dname the "." we got from the
 			   configured default search path, we'll end
@@ -409,11 +412,10 @@ __libc_res_nsearch(res_state statp,
 			if (dname[0] == '\0')
 				root_on_list++;
 
-			ret = __libc_res_nquerydomain(statp, name, dname,
-						      class, type,
-						      answer, anslen, answerp,
-						      answerp2, nanswerp2,
-						      resplen2, answerp2_malloced);
+			ret = __res_context_querydomain
+			  (ctx, name, dname, class, type,
+			   answer, anslen, answerp, answerp2, nanswerp2,
+			   resplen2, answerp2_malloced);
 			if (ret > 0 || (ret == 0 && resplen2 != NULL
 					&& *resplen2 > 0))
 				return (ret);
@@ -481,10 +483,10 @@ __libc_res_nsearch(res_state statp,
 	 */
 	if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0)
 	    && !(tried_as_is || root_on_list)) {
-		ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
-					      answer, anslen, answerp,
-					      answerp2, nanswerp2, resplen2,
-					      answerp2_malloced);
+		ret = __res_context_querydomain
+		  (ctx, name, NULL, class, type,
+		   answer, anslen, answerp, answerp2, nanswerp2,
+		   resplen2, answerp2_malloced);
 		if (ret > 0 || (ret == 0 && resplen2 != NULL
 				&& *resplen2 > 0))
 			return (ret);
@@ -512,7 +514,24 @@ __libc_res_nsearch(res_state statp,
 		RES_SET_H_ERRNO(statp, TRY_AGAIN);
 	return (-1);
 }
-libresolv_hidden_def (__libc_res_nsearch)
+libresolv_hidden_def (__res_context_search)
+
+/* Common part of res_nsearch and res_search.  */
+static int
+context_search_common (struct resolv_context *ctx,
+		       const char *name, int class, int type,
+		       unsigned char *answer, int anslen)
+{
+  if (ctx == NULL)
+    {
+      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+      return -1;
+    }
+  int result = __res_context_search (ctx, name, class, type, answer, anslen,
+				     NULL, NULL, NULL, NULL, NULL);
+  __resolv_context_put (ctx);
+  return result;
+}
 
 int
 res_nsearch(res_state statp,
@@ -521,40 +540,30 @@ res_nsearch(res_state statp,
 	    u_char *answer,	/* buffer to put answer */
 	    int anslen)		/* size of answer */
 {
-	return __libc_res_nsearch(statp, name, class, type, answer,
-				  anslen, NULL, NULL, NULL, NULL, NULL);
+  return context_search_common
+    (__resolv_context_get_override (statp), name, class, type, answer, anslen);
 }
-libresolv_hidden_def (res_nsearch)
 
 int
 res_search (const char *name, int class, int type,
 	    unsigned char *answer, int anslen)
 {
-  if (__res_maybe_init (&_res, 1) == -1)
-    {
-      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
-      return -1;
-    }
-
-  return res_nsearch (&_res, name, class, type, answer, anslen);
+  return context_search_common
+    (__resolv_context_get (), name, class, type, answer, anslen);
 }
 
-/*
- * Perform a call on res_query on the concatenation of name and domain.
- */
+/*  Perform a call on res_query on the concatenation of name and
+    domain.  */
 static int
-__libc_res_nquerydomain(res_state statp,
-			const char *name,
-			const char *domain,
-			int class, int type,	/* class and type of query */
-			u_char *answer,		/* buffer to put answer */
-			int anslen,			/* size of answer */
-			u_char **answerp,
-			u_char **answerp2,
-			int *nanswerp2,
-			int *resplen2,
-			int *answerp2_malloced)
+__res_context_querydomain (struct resolv_context *ctx,
+			   const char *name, const char *domain,
+			   int class, int type,
+			   unsigned char *answer, int anslen,
+			   unsigned char **answerp, unsigned char **answerp2,
+			   int *nanswerp2, int *resplen2,
+			   int *answerp2_malloced)
 {
+	struct __res_state *statp = ctx->resp;
 	char nbuf[MAXDNAME];
 	const char *longname = nbuf;
 	size_t n, d;
@@ -580,9 +589,28 @@ __libc_res_nquerydomain(res_state statp,
 		}
 		sprintf(nbuf, "%s.%s", name, domain);
 	}
-	return (__libc_res_nquery(statp, longname, class, type, answer,
-				  anslen, answerp, answerp2, nanswerp2,
-				  resplen2, answerp2_malloced));
+	return __res_context_query (ctx, longname, class, type, answer,
+				    anslen, answerp, answerp2, nanswerp2,
+				    resplen2, answerp2_malloced);
+}
+
+/* Common part of res_nquerydomain and res_querydomain.  */
+static int
+context_querydomain_common (struct resolv_context *ctx,
+			    const char *name, const char *domain,
+			    int class, int type,
+			    unsigned char *answer, int anslen)
+{
+  if (ctx == NULL)
+    {
+      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+      return -1;
+    }
+  int result = __res_context_querydomain (ctx, name, domain, class, type,
+					  answer, anslen,
+					  NULL, NULL, NULL, NULL, NULL);
+  __resolv_context_put (ctx);
+  return result;
 }
 
 int
@@ -593,32 +621,28 @@ res_nquerydomain(res_state statp,
 	    u_char *answer,		/* buffer to put answer */
 	    int anslen)		/* size of answer */
 {
-	return __libc_res_nquerydomain(statp, name, domain, class, type,
-				       answer, anslen, NULL, NULL, NULL, NULL,
-				       NULL);
+  return context_querydomain_common
+    (__resolv_context_get_override (statp),
+     name, domain, class, type, answer, anslen);
 }
-libresolv_hidden_def (res_nquerydomain)
 
 int
 res_querydomain (const char *name, const char *domain, int class, int type,
 		 unsigned char *answer, int anslen)
 {
-  if (__res_maybe_init (&_res, 1) == -1)
-    {
-      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
-      return -1;
-    }
-
-  return res_nquerydomain (&_res, name, domain, class, type, answer, anslen);
+  return context_querydomain_common
+    (__resolv_context_get (), name, domain, class, type, answer, anslen);
 }
 
 const char *
-res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
+__res_context_hostalias (struct resolv_context *ctx,
+			 const char *name, char *dst, size_t siz)
+{
 	char *file, *cp1, *cp2;
 	char buf[BUFSIZ];
 	FILE *fp;
 
-	if (statp->options & RES_NOALIASES)
+	if (ctx->resp->options & RES_NOALIASES)
 		return (NULL);
 	file = getenv("HOSTALIASES");
 	if (file == NULL || (fp = fopen(file, "rce")) == NULL)
@@ -648,15 +672,37 @@ res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
 	fclose(fp);
 	return (NULL);
 }
-libresolv_hidden_def (res_hostalias)
+libresolv_hidden_def (__res_context_hostalias)
+
+/* Common part of res_hostalias and hostalias.  */
+static const char *
+context_hostalias_common (struct resolv_context *ctx,
+			  const char *name, char *dst, size_t siz)
+{
+  if (ctx == NULL)
+    {
+      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+      return NULL;
+    }
+  const char *result = __res_context_hostalias (ctx, name, dst, siz);
+  __resolv_context_put (ctx);
+  return result;
+}
+
+const char *
+res_hostalias (res_state statp, const char *name, char *dst, size_t siz)
+{
+  return context_hostalias_common
+    (__resolv_context_get_override (statp), name, dst, siz);
+}
 
 const char *
 hostalias (const char *name)
 {
   static char abuf[MAXDNAME];
-  return res_hostalias (&_res, name, abuf, sizeof abuf);
+  return context_hostalias_common
+    (__resolv_context_get (), name, abuf, sizeof (abuf));
 }
-libresolv_hidden_def (hostalias)
 
 #if SHLIB_COMPAT (libresolv, GLIBC_2_0, GLIBC_2_2)
 # undef res_query