This is the mail archive of the glibc-cvs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GNU C Library master sources branch master updated. glibc-2.25-665-g3f853f2


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, master has been updated
       via  3f853f22c87f0b671c0366eb290919719fa56c0e (commit)
      from  f30a54b21b83f254533c59ca72ad17af5249c6be (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=3f853f22c87f0b671c0366eb290919719fa56c0e

commit 3f853f22c87f0b671c0366eb290919719fa56c0e
Author: Florian Weimer <fweimer@redhat.com>
Date:   Sat Jul 1 00:53:05 2017 +0200

    resolv: Lift domain search list limits [BZ #19569] [BZ #21475]
    
    This change uses the extended resolver state in struct resolv_conf to
    store the search list.  If applications have not patched the _res
    object directly, this extended search list will be used by the stub
    resolver during name resolution.

diff --git a/ChangeLog b/ChangeLog
index db53433..0061126 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,31 @@
 2017-06-30  Florian Weimer  <fweimer@redhat.com>
 
+	[BZ #19569]
+	[BZ #21475]
+	Support an arbitrary number of search domains.
+	* resolv/resolv_context.h (__resolv_context_search_list): New.
+	* resolv/resolv_conf.h (struct resolv_conf): Add search_list,
+	search_list_size members.
+	* resolv/resolv_conf.c (resolv_conf_matches): Compare search list.
+	(__resolv_conf_allocate): Allocate and and copy search list.
+	(update_from_conf): Copy the search list.
+	* resolv/res_init.c (struct search_list): Define using dynarray.
+	(struct resolv_conf_parser): Define.
+	(resolv_conf_parser_init, resolv_conf_parser_free)
+	(domain_from_hostname): New functions.
+	(res_vinit_1): Add struct resolv_conf_parser * parameter.  Use
+	struct search_list to collect search list entries.  Call
+	domain_from_hostname to obtain the fallback domain name.
+	(__res_vinit): Create and destroy parser object.  Pass search list
+	to __resolv_conf_allocate.
+	* resolv/res_query.c (__res_context_search): Use
+	__resolv_context_search_list to obtain search list entries.
+	* resolv/tst-resolv-res_init-skeleton.c (print_resp): Print data
+	from extended resolver context.
+	(test_cases): Update.
+
+2017-06-30  Florian Weimer  <fweimer@redhat.com>
+
 	Add extended resolver state/configuration (struct resolv_conf).
 	* resolv/resolv_conf.h, resolv/resolv_conf.c: New files.
 	* resolv/res-close.c (__res_iclose): Call __resolv_conf_detach.
diff --git a/NEWS b/NEWS
index df6f394..bf2b5df 100644
--- a/NEWS
+++ b/NEWS
@@ -237,6 +237,14 @@ Version 2.26
 * The _res_opcodes variable has been removed from libresolv.  It had been
   exported by accident.
 
+* The glibc DNS stub resolver now supports an arbitary number of search
+  domains (configured using the â??searchâ?? directive in /etc/resolv.conf).
+  Most applications will automatically benefit from this change, but for
+  backwards compatibility reasons, applications which directly modify _res
+  objects (which contain the resolver state, including the search list
+  array, which is limited to six entries) will only use the first six search
+  domains, as before.
+
 Security related changes:
 
 * The DNS stub resolver limits the advertised UDP buffer size to 1200 bytes,
diff --git a/resolv/res_init.c b/resolv/res_init.c
index 659d3ea..5941d37 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -124,18 +124,75 @@ is_sort_mask (char ch)
   return ch == '/' || ch == '&';
 }
 
+/* Array of strings for the search array.  The backing store is
+   managed separately.  */
+#define DYNARRAY_STRUCT search_list
+#define DYNARRAY_ELEMENT const char *
+#define DYNARRAY_INITIAL_SIZE 4
+#define DYNARRAY_PREFIX search_list_
+#include <malloc/dynarray-skeleton.c>
+
+/* resolv.conf parser state and results.  */
+struct resolv_conf_parser
+{
+  char *buffer;            /* Temporary buffer for reading lines.  */
+  char *search_list_store; /* Backing storage for search list entries.  */
+  struct search_list search_list; /* Points into search_list_store.  */
+};
+
+static void
+resolv_conf_parser_init (struct resolv_conf_parser *parser)
+{
+  parser->buffer = NULL;
+  parser->search_list_store = NULL;
+  search_list_init (&parser->search_list);
+}
+
+static void
+resolv_conf_parser_free (struct resolv_conf_parser *parser)
+{
+  free (parser->buffer);
+  free (parser->search_list_store);
+  search_list_free (&parser->search_list);
+}
+
+/* Try to obtain the domain name from the host name and store it in
+   *RESULT.  Return false on memory allocation failure.  If the domain
+   name cannot be determined for any other reason, write NULL to
+   *RESULT and return true.  */
+static bool
+domain_from_hostname (char **result)
+{
+  char buf[256];
+  /* gethostbyname may not terminate the buffer.  */
+  buf[sizeof (buf) - 1] = '\0';
+  if (__gethostname (buf, sizeof (buf) - 1) == 0)
+    {
+      char *dot = strchr (buf, '.');
+      if (dot != NULL)
+        {
+          *result = __strdup (dot + 1);
+          if (*result == NULL)
+            return false;
+          return true;
+        }
+    }
+  *result = NULL;
+  return true;
+}
+
 /* Internal helper function for __res_vinit, to aid with resource
    deallocation and error handling.  Return true on success, false on
    failure.  */
 static bool
-res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
+res_vinit_1 (res_state statp, bool preinit, FILE *fp,
+             struct resolv_conf_parser *parser)
 {
-  char *cp, **pp;
+  char *cp;
   size_t buffer_size = 0;
   int nserv = 0;    /* Number of nameservers read from file.  */
   bool have_serv6 = false;
   bool haveenv = false;
-  bool havesearch = false;
   int nsort = 0;
   char *net;
 
@@ -162,39 +219,40 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
   /* Allow user to override the local domain definition.  */
   if ((cp = getenv ("LOCALDOMAIN")) != NULL)
     {
-      strncpy (statp->defdname, cp, sizeof (statp->defdname) - 1);
-      statp->defdname[sizeof (statp->defdname) - 1] = '\0';
+      /* The code below splits the string in place.  */
+      cp = __strdup (cp);
+      if (cp == NULL)
+        return false;
+      free (parser->search_list_store);
+      parser->search_list_store = cp;
       haveenv = true;
 
+      /* The string will be truncated as needed below.  */
+      search_list_add (&parser->search_list, cp);
+
       /* Set search list to be blank-separated strings from rest of
          env value.  Permits users of LOCALDOMAIN to still have a
          search list, and anyone to set the one that they want to use
          as an individual (even more important now that the rfc1535
          stuff restricts searches).  */
-      cp = statp->defdname;
-      pp = statp->dnsrch;
-      *pp++ = cp;
-      for (int n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++)
+      for (bool in_name = true; *cp != '\0'; cp++)
         {
           if (*cp == '\n')
-            break;
+            {
+              *cp = '\0';
+              break;
+            }
           else if (*cp == ' ' || *cp == '\t')
             {
-              *cp = 0;
-              n = 1;
+              *cp = '\0';
+              in_name = false;
             }
-          else if (n > 0)
+          else if (!in_name)
             {
-              *pp++ = cp;
-              n = 0;
-              havesearch = true;
+              search_list_add (&parser->search_list, cp);
+              in_name = true;
             }
         }
-      /* Null terminate last domain if there are excess.  */
-      while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
-        cp++;
-      *cp = '\0';
-      *pp++ = 0;
     }
 
 #define MATCH(line, name)                       \
@@ -210,7 +268,7 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
       while (true)
         {
           {
-            ssize_t ret = __getline (buffer, &buffer_size, fp);
+            ssize_t ret = __getline (&parser->buffer, &buffer_size, fp);
             if (ret <= 0)
               {
                 if (_IO_ferror_unlocked (fp))
@@ -221,73 +279,82 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
           }
 
           /* Skip comments.  */
-          if (**buffer == ';' || **buffer == '#')
+          if (*parser->buffer == ';' || *parser->buffer == '#')
             continue;
           /* Read default domain name.  */
-          if (MATCH (*buffer, "domain"))
+          if (MATCH (parser->buffer, "domain"))
             {
               if (haveenv)
                 /* LOCALDOMAIN overrides the configuration file.  */
                 continue;
-              cp = *buffer + sizeof ("domain") - 1;
+              cp = parser->buffer + sizeof ("domain") - 1;
               while (*cp == ' ' || *cp == '\t')
                 cp++;
               if ((*cp == '\0') || (*cp == '\n'))
                 continue;
-              strncpy (statp->defdname, cp, sizeof (statp->defdname) - 1);
-              statp->defdname[sizeof (statp->defdname) - 1] = '\0';
-              if ((cp = strpbrk (statp->defdname, " \t\n")) != NULL)
+
+              cp = __strdup (cp);
+              if (cp == NULL)
+                return false;
+              free (parser->search_list_store);
+              parser->search_list_store = cp;
+              search_list_clear (&parser->search_list);
+              search_list_add (&parser->search_list, cp);
+              /* Replace trailing whitespace.  */
+              if ((cp = strpbrk (cp, " \t\n")) != NULL)
                 *cp = '\0';
-              havesearch = false;
               continue;
             }
           /* Set search list.  */
-          if (MATCH (*buffer, "search"))
+          if (MATCH (parser->buffer, "search"))
             {
               if (haveenv)
                 /* LOCALDOMAIN overrides the configuration file.  */
                 continue;
-              cp = *buffer + sizeof ("search") - 1;
+              cp = parser->buffer + sizeof ("search") - 1;
               while (*cp == ' ' || *cp == '\t')
                 cp++;
               if ((*cp == '\0') || (*cp == '\n'))
                 continue;
-              strncpy (statp->defdname, cp, sizeof (statp->defdname) - 1);
-              statp->defdname[sizeof (statp->defdname) - 1] = '\0';
-              if ((cp = strchr (statp->defdname, '\n')) != NULL)
-                *cp = '\0';
+
+              {
+                char *p = strchr (cp, '\n');
+                if (p != NULL)
+                  *p = '\0';
+              }
+              cp = __strdup (cp);
+              if (cp == NULL)
+                return false;
+              free (parser->search_list_store);
+              parser->search_list_store = cp;
+
+              /* The string is truncated below.  */
+              search_list_clear (&parser->search_list);
+              search_list_add (&parser->search_list, cp);
+
               /* Set search list to be blank-separated strings on rest
                  of line.  */
-              cp = statp->defdname;
-              pp = statp->dnsrch;
-              *pp++ = cp;
-              for (int n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++)
+              for (bool in_name = true; *cp != '\0'; cp++)
                 {
                   if (*cp == ' ' || *cp == '\t')
                     {
-                      *cp = 0;
-                      n = 1;
+                      *cp = '\0';
+                      in_name = false;
                     }
-                  else if (n)
+                  else if (!in_name)
                     {
-                      *pp++ = cp;
-                      n = 0;
+                      search_list_add (&parser->search_list, cp);
+                      in_name = true;
                     }
                 }
-              /* Null terminate last domain if there are excess.  */
-              while (*cp != '\0' && *cp != ' ' && *cp != '\t')
-                cp++;
-              *cp = '\0';
-              *pp++ = 0;
-              havesearch = true;
               continue;
             }
           /* Read nameservers to query.  */
-          if (MATCH (*buffer, "nameserver") && nserv < MAXNS)
+          if (MATCH (parser->buffer, "nameserver") && nserv < MAXNS)
             {
               struct in_addr a;
 
-              cp = *buffer + sizeof ("nameserver") - 1;
+              cp = parser->buffer + sizeof ("nameserver") - 1;
               while (*cp == ' ' || *cp == '\t')
                 cp++;
               if ((*cp != '\0') && (*cp != '\n') && __inet_aton (cp, &a))
@@ -335,11 +402,11 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
                 }
               continue;
             }
-          if (MATCH (*buffer, "sortlist"))
+          if (MATCH (parser->buffer, "sortlist"))
             {
               struct in_addr a;
 
-              cp = *buffer + sizeof ("sortlist") - 1;
+              cp = parser->buffer + sizeof ("sortlist") - 1;
               while (nsort < MAXRESOLVSORT)
                 {
                   while (*cp == ' ' || *cp == '\t')
@@ -379,9 +446,9 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
                 }
               continue;
             }
-          if (MATCH (*buffer, "options"))
+          if (MATCH (parser->buffer, "options"))
             {
-              res_setoptions (statp, *buffer + sizeof ("options") - 1);
+              res_setoptions (statp, parser->buffer + sizeof ("options") - 1);
               continue;
             }
         }
@@ -399,25 +466,29 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp, char **buffer)
       statp->nsaddr.sin_port = htons (NAMESERVER_PORT);
       statp->nscount = 1;
     }
-  if (statp->defdname[0] == 0)
-    {
-      char buf[sizeof (statp->defdname)];
-      if (__gethostname (buf, sizeof (statp->defdname) - 1) == 0
-          && (cp = strchr (buf, '.')) != NULL)
-        strcpy (statp->defdname, cp + 1);
-    }
 
-  /* Find components of local domain that might be searched.  */
-  if (!havesearch)
+  if (search_list_size (&parser->search_list) == 0)
     {
-      pp = statp->dnsrch;
-      *pp++ = statp->defdname;
-      *pp = NULL;
-
+      char *domain;
+      if (!domain_from_hostname (&domain))
+        return false;
+      if (domain != NULL)
+        {
+          free (parser->search_list_store);
+          parser->search_list_store = domain;
+          search_list_add (&parser->search_list, domain);
+        }
     }
 
   if ((cp = getenv ("RES_OPTIONS")) != NULL)
     res_setoptions (statp, cp);
+
+  if (search_list_has_failed (&parser->search_list))
+    {
+      __set_errno (ENOMEM);
+      return false;
+    }
+
   statp->options |= RES_INIT;
   return true;
 }
@@ -453,13 +524,17 @@ __res_vinit (res_state statp, int preinit)
         return -1;
       }
 
-  char *buffer = NULL;
-  bool ok = res_vinit_1 (statp, preinit, fp, &buffer);
-  free (buffer);
+  struct resolv_conf_parser parser;
+  resolv_conf_parser_init (&parser);
+  bool ok = res_vinit_1 (statp, preinit, fp, &parser);
 
   if (ok)
     {
-      struct resolv_conf init = { 0 }; /* No data yet.  */
+      struct resolv_conf init =
+        {
+          .search_list = search_list_begin (&parser.search_list),
+          .search_list_size = search_list_size (&parser.search_list),
+        };
       struct resolv_conf *conf = __resolv_conf_allocate (&init);
       if (conf == NULL)
         ok = false;
@@ -469,6 +544,7 @@ __res_vinit (res_state statp, int preinit)
           __resolv_conf_put (conf);
         }
     }
+  resolv_conf_parser_free (&parser);
 
   if (!ok)
     {
diff --git a/resolv/res_query.c b/resolv/res_query.c
index 33249e3..ebbe5a6 100644
--- a/resolv/res_query.c
+++ b/resolv/res_query.c
@@ -326,7 +326,7 @@ __res_context_search (struct resolv_context *ctx,
 		      int *nanswerp2, int *resplen2, int *answerp2_malloced)
 {
 	struct __res_state *statp = ctx->resp;
-	const char *cp, * const *domain;
+	const char *cp;
 	HEADER *hp = (HEADER *) answer;
 	char tmp[NS_MAXDNAME];
 	u_int dots;
@@ -392,10 +392,11 @@ __res_context_search (struct resolv_context *ctx,
 	    (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) {
 		int done = 0;
 
-		for (domain = (const char * const *)statp->dnsrch;
-		     *domain && !done;
-		     domain++) {
-			const char *dname = domain[0];
+		for (size_t domain_index = 0; !done; ++domain_index) {
+			const char *dname = __resolv_context_search_list
+			  (ctx, domain_index);
+			if (dname == NULL)
+			  break;
 			searched = 1;
 
 			/* __res_context_querydoman concatenates name
diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c
index cabe69c..76d55fc 100644
--- a/resolv/resolv_conf.c
+++ b/resolv/resolv_conf.c
@@ -133,6 +133,34 @@ static bool
 resolv_conf_matches (const struct __res_state *resp,
                      const struct resolv_conf *conf)
 {
+  /* Check that the search list in *RESP has not been modified by the
+     application.  */
+  {
+    if (!(resp->dnsrch[0] == resp->defdname
+          && resp->dnsrch[MAXDNSRCH] == NULL))
+      return false;
+    size_t search_list_size = 0;
+    for (size_t i = 0; i < conf->search_list_size; ++i)
+      {
+        if (resp->dnsrch[i] != NULL)
+          {
+            search_list_size += strlen (resp->dnsrch[i]) + 1;
+            if (strcmp (resp->dnsrch[i], conf->search_list[i]) != 0)
+              return false;
+          }
+        else
+          {
+            /* resp->dnsrch is truncated if the number of elements
+               exceeds MAXDNSRCH, or if the combined storage space for
+               the search list exceeds what can be stored in
+               resp->defdname.  */
+            if (i == MAXDNSRCH || search_list_size > sizeof (resp->dnsrch))
+              break;
+            /* Otherwise, a mismatch indicates a match failure.  */
+            return false;
+          }
+      }
+  }
   return true;
 }
 
@@ -162,10 +190,17 @@ __resolv_conf_put (struct resolv_conf *conf)
 struct resolv_conf *
 __resolv_conf_allocate (const struct resolv_conf *init)
 {
+  /* Space needed by the strings.  */
+  size_t string_space = 0;
+  for (size_t i = 0; i < init->search_list_size; ++i)
+    string_space += strlen (init->search_list[i]) + 1;
+
   /* Allocate the buffer.  */
   void *ptr;
   struct alloc_buffer buffer = alloc_buffer_allocate
-    (sizeof (struct resolv_conf),
+    (sizeof (struct resolv_conf)
+     + init->search_list_size * sizeof (init->search_list[0])
+     + string_space,
      &ptr);
   struct resolv_conf *conf
     = alloc_buffer_alloc (&buffer, struct resolv_conf);
@@ -178,6 +213,16 @@ __resolv_conf_allocate (const struct resolv_conf *init)
   conf->__refcount = 1;
   conf->initstamp = __res_initstamp;
 
+  /* Allocate and fill the search list array.  */
+  {
+    conf->search_list_size = init->search_list_size;
+    const char **array = alloc_buffer_alloc_array
+      (&buffer, const char *, init->search_list_size);
+    conf->search_list = array;
+    for (size_t i = 0; i < init->search_list_size; ++i)
+      array[i] = alloc_buffer_copy_string (&buffer, init->search_list[i]);
+  }
+
   assert (!alloc_buffer_has_failed (&buffer));
   return conf;
 }
@@ -186,6 +231,24 @@ __resolv_conf_allocate (const struct resolv_conf *init)
 static __attribute__ ((nonnull (1, 2), warn_unused_result)) bool
 update_from_conf (struct __res_state *resp, const struct resolv_conf *conf)
 {
+  /* Fill in the prefix of the search list.  It is truncated either at
+     MAXDNSRCH, or if reps->defdname has insufficient space.  */
+  {
+    struct alloc_buffer buffer
+      = alloc_buffer_create (resp->defdname, sizeof (resp->defdname));
+    size_t size = conf->search_list_size;
+    size_t i;
+    for (i = 0; i < size && i < MAXDNSRCH; ++i)
+      {
+        resp->dnsrch[i] = alloc_buffer_copy_string
+          (&buffer, conf->search_list[i]);
+        if (resp->dnsrch[i] == NULL)
+          /* No more space in resp->defdname.  Truncate.  */
+          break;
+      }
+    resp->dnsrch[i] = NULL;
+  }
+
   /* The overlapping parts of both configurations should agree after
      initialization.  */
   assert (resolv_conf_matches (resp, conf));
diff --git a/resolv/resolv_conf.h b/resolv/resolv_conf.h
index 48f92d6..80a0b93 100644
--- a/resolv/resolv_conf.h
+++ b/resolv/resolv_conf.h
@@ -35,6 +35,10 @@ struct resolv_conf
   /* Reference counter.  The object is deallocated once it reaches
      zero.  For internal use within resolv_conf only.  */
   size_t __refcount;
+
+  /* The domain names forming the search list.  */
+  const char *const *search_list;
+  size_t search_list_size;
 };
 
 /* The functions below are for use by the res_init resolv.conf parser
diff --git a/resolv/resolv_context.h b/resolv/resolv_context.h
index ff9ef2c..0f4d47d 100644
--- a/resolv/resolv_context.h
+++ b/resolv/resolv_context.h
@@ -93,6 +93,25 @@ struct resolv_context *__resolv_context_get_override (struct __res_state *)
   __attribute__ ((nonnull (1), warn_unused_result));
 libc_hidden_proto (__resolv_context_get_override)
 
+/* Return the search path entry at INDEX, or NULL if there are fewer
+   than INDEX entries.  */
+static __attribute__ ((nonnull (1), unused)) const char *
+__resolv_context_search_list (const struct resolv_context *ctx, size_t index)
+{
+  if (ctx->conf != NULL)
+    {
+      if (index < ctx->conf->search_list_size)
+        return ctx->conf->search_list[index];
+      else
+        return NULL;
+    }
+  /* Fallback.  ctx->resp->dnsrch is a NULL-terminated array.  */
+  for (size_t i = 0; ctx->resp->dnsrch[i] != NULL && i < MAXDNSRCH; ++i)
+    if (i == index)
+      return ctx->resp->dnsrch[i];
+  return NULL;
+}
+
 /* Called during thread shutdown to free the associated resolver
    context (mostly in response to cancellation, otherwise the
    __resolv_context_get/__resolv_context_put pairing will already have
diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c
index ce206f5..cea1456 100644
--- a/resolv/tst-resolv-res_init-skeleton.c
+++ b/resolv/tst-resolv-res_init-skeleton.c
@@ -25,6 +25,7 @@
 #include <gnu/lib-names.h>
 #include <netdb.h>
 #include <resolv/resolv-internal.h> /* For DEPRECATED_RES_USE_INET6.  */
+#include <resolv/resolv_context.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <support/capture_subprocess.h>
@@ -116,6 +117,11 @@ print_option_flag (FILE *fp, int *options, int flag, const char *name)
 static void
 print_resp (FILE *fp, res_state resp)
 {
+  struct resolv_context *ctx = __resolv_context_get_override (resp);
+  TEST_VERIFY_EXIT (ctx != NULL);
+  if (ctx->conf == NULL)
+    fprintf (fp, "; extended resolver state missing\n");
+
   /* The options directive.  */
   {
     /* RES_INIT is used internally for tracking initialization.  */
@@ -165,6 +171,19 @@ print_resp (FILE *fp, res_state resp)
   else if (resp->defdname[0] != '\0')
     fprintf (fp, "domain %s\n", resp->defdname);
 
+  /* The extended search path.  */
+  {
+    size_t i = 0;
+    while (true)
+      {
+        const char *name = __resolv_context_search_list (ctx, i);
+        if (name == NULL)
+          break;
+        fprintf (fp, "; search[%zu]: %s\n", i, name);
+        ++i;
+      }
+  }
+
   /* The sortlist directive.  */
   if (resp->nsort > 0)
     {
@@ -224,6 +243,8 @@ print_resp (FILE *fp, res_state resp)
     }
 
   TEST_VERIFY (!ferror (fp));
+
+  __resolv_context_put (ctx);
 }
 
 /* Parameters of one test case.  */
@@ -368,11 +389,13 @@ struct test_case test_cases[] =
     {.name = "empty file",
      .conf = "",
      .expected = "search example.com\n"
+     "; search[0]: example.com\n"
      "nameserver 127.0.0.1\n"
     },
     {.name = "empty file with LOCALDOMAIN",
      .conf = "",
      .expected = "search example.net\n"
+     "; search[0]: example.net\n"
      "nameserver 127.0.0.1\n",
      .localdomain = "example.net",
     },
@@ -380,6 +403,7 @@ struct test_case test_cases[] =
      .conf = "",
      .expected = "options attempts:5 edns0\n"
      "search example.com\n"
+     "; search[0]: example.com\n"
      "nameserver 127.0.0.1\n",
      .res_options = "edns0 attempts:5",
     },
@@ -387,6 +411,7 @@ struct test_case test_cases[] =
      .conf = "",
      .expected = "options attempts:5 edns0\n"
      "search example.org\n"
+     "; search[0]: example.org\n"
      "nameserver 127.0.0.1\n",
      .localdomain = "example.org",
      .res_options = "edns0 attempts:5",
@@ -396,6 +421,8 @@ struct test_case test_cases[] =
      "search corp.example.com example.com\n"
      "nameserver 192.0.2.1\n",
      .expected = "search corp.example.com example.com\n"
+     "; search[0]: corp.example.com\n"
+     "; search[1]: example.com\n"
      "nameserver 192.0.2.1\n"
     },
     {.name = "whitespace",
@@ -403,16 +430,46 @@ struct test_case test_cases[] =
      " (trailing whitespace,\n"
      "# missing newline at end of file).\n"
      "\n"
-     "domain  example.net\n"
      ";search commented out\n"
-     "search corp.example.com\texample.com\n"
+     "search corp.example.com\texample.com \n"
      "#nameserver 192.0.2.3\n"
      "nameserver 192.0.2.1 \n"
      "nameserver 192.0.2.2",    /* No \n at end of file.  */
      .expected = "search corp.example.com example.com\n"
+     "; search[0]: corp.example.com\n"
+     "; search[1]: example.com\n"
      "nameserver 192.0.2.1\n"
      "nameserver 192.0.2.2\n"
     },
+    {.name = "domain",
+     .conf = "domain example.net\n"
+     "nameserver 192.0.2.1\n",
+     .expected = "search example.net\n"
+     "; search[0]: example.net\n"
+     "nameserver 192.0.2.1\n"
+    },
+    {.name = "domain space",
+     .conf = "domain example.net \n"
+     "nameserver 192.0.2.1\n",
+     .expected = "search example.net\n"
+     "; search[0]: example.net\n"
+     "nameserver 192.0.2.1\n"
+    },
+    {.name = "domain tab",
+     .conf = "domain example.net\t\n"
+     "nameserver 192.0.2.1\n",
+     .expected = "search example.net\n"
+     "; search[0]: example.net\n"
+     "nameserver 192.0.2.1\n"
+    },
+    {.name = "domain override",
+     .conf = "search example.com example.org\n"
+     "nameserver 192.0.2.1\n"
+     "domain example.net",      /* No \n at end of file.  */
+     .expected = "search example.net\n"
+     "; search[0]: example.net\n"
+     "nameserver 192.0.2.1\n"
+    },
     {.name = "option values, multiple servers",
      .conf = "options\tinet6\tndots:3 edns0\tattempts:5\ttimeout:19\n"
      "domain  example.net\n"
@@ -423,6 +480,8 @@ struct test_case test_cases[] =
      "nameserver 192.0.2.2\n",
      .expected = "options ndots:3 timeout:19 attempts:5 inet6 edns0\n"
      "search corp.example.com example.com\n"
+     "; search[0]: corp.example.com\n"
+     "; search[1]: example.com\n"
      "nameserver 192.0.2.1\n"
      "nameserver ::1\n"
      "nameserver 192.0.2.2\n"
@@ -432,6 +491,7 @@ struct test_case test_cases[] =
      "search example.com\n",
      .expected = "options ndots:15 timeout:30 attempts:5 use-vc\n"
      "search example.com\n"
+     "; search[0]: example.com\n"
      "nameserver 127.0.0.1\n"
     },
     {.name = "repeated directives",
@@ -443,6 +503,7 @@ struct test_case test_cases[] =
      "search\n",
      .expected = "options ndots:2 use-vc edns0\n"
      "search example.org\n"
+     "; search[0]: example.org\n"
      "nameserver 127.0.0.1\n"
     },
     {.name = "many name servers, sortlist",
@@ -459,6 +520,10 @@ struct test_case test_cases[] =
      "nameserver 192.0.2.8\n",
      .expected = "options single-request\n"
      "search example.org example.com example.net corp.example.com\n"
+     "; search[0]: example.org\n"
+     "; search[1]: example.com\n"
+     "; search[2]: example.net\n"
+     "; search[3]: corp.example.com\n"
      "sortlist 192.0.2.0/255.255.255.0\n"
      "nameserver 192.0.2.1\n"
      "nameserver 192.0.2.2\n"
@@ -480,6 +545,11 @@ struct test_case test_cases[] =
      .expected = "options single-request\n"
      "search example.org example.com example.net corp.example.com"
      " legacy.example.com\n"
+     "; search[0]: example.org\n"
+     "; search[1]: example.com\n"
+     "; search[2]: example.net\n"
+     "; search[3]: corp.example.com\n"
+     "; search[4]: legacy.example.com\n"
      "sortlist 192.0.2.0/255.255.255.0\n"
      "nameserver 192.0.2.1\n"
      "nameserver 2001:db8::2\n"
@@ -490,6 +560,7 @@ struct test_case test_cases[] =
      "nameserver 192.0.2.2:5353\n"
      "nameserver 192.0.2.3 5353\n",
      .expected = "search example.com\n"
+     "; search[0]: example.com\n"
      "nameserver 192.0.2.1\n"
      "nameserver 192.0.2.3\n"
     },
@@ -498,9 +569,42 @@ struct test_case test_cases[] =
      "nameserver 192.0.2.1\n",
      .expected = "options ndots:3 timeout:7 attempts:5 use-vc edns0\n"
      "search example.com\n"
+     "; search[0]: example.com\n"
      "nameserver 192.0.2.1\n",
      .res_options = "attempts:5 ndots:3 edns0 ",
     },
+    {.name = "many search list entries (bug 19569)",
+     .conf = "nameserver 192.0.2.1\n"
+     "search corp.example.com support.example.com"
+     " community.example.org wan.example.net vpn.example.net"
+     " example.com example.org example.net\n",
+     .expected = "search corp.example.com support.example.com"
+     " community.example.org wan.example.net vpn.example.net example.com\n"
+     "; search[0]: corp.example.com\n"
+     "; search[1]: support.example.com\n"
+     "; search[2]: community.example.org\n"
+     "; search[3]: wan.example.net\n"
+     "; search[4]: vpn.example.net\n"
+     "; search[5]: example.com\n"
+     "; search[6]: example.org\n"
+     "; search[7]: example.net\n"
+     "nameserver 192.0.2.1\n",
+    },
+    {.name = "very long search list entries (bug 21475)",
+     .conf = "nameserver 192.0.2.1\n"
+     "search example.com "
+#define H63 "this-host-name-is-longer-than-yours-yes-I-really-really-mean-it"
+#define D63 "this-domain-name-is-as-long-as-the-previous-name--63-characters"
+     " " H63 "." D63 ".example.org"
+     " " H63 "." D63 ".example.net\n",
+     .expected = "search example.com " H63 "." D63 ".example.org\n"
+     "; search[0]: example.com\n"
+     "; search[1]: " H63 "." D63 ".example.org\n"
+     "; search[2]: " H63 "." D63 ".example.net\n"
+#undef H63
+#undef D63
+     "nameserver 192.0.2.1\n",
+    },
     { NULL }
   };
 

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                             |   26 ++++
 NEWS                                  |    8 ++
 resolv/res_init.c                     |  222 ++++++++++++++++++++++-----------
 resolv/res_query.c                    |   11 +-
 resolv/resolv_conf.c                  |   65 ++++++++++-
 resolv/resolv_conf.h                  |    4 +
 resolv/resolv_context.h               |   19 +++
 resolv/tst-resolv-res_init-skeleton.c |  108 ++++++++++++++++-
 8 files changed, 382 insertions(+), 81 deletions(-)


hooks/post-receive
-- 
GNU C Library master sources


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]