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-666-ga1c4eb8


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  a1c4eb8794e789b5055d7ceb13b2b3231abf5e26 (commit)
      from  3f853f22c87f0b671c0366eb290919719fa56c0e (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=a1c4eb8794e789b5055d7ceb13b2b3231abf5e26

commit a1c4eb8794e789b5055d7ceb13b2b3231abf5e26
Author: Florian Weimer <fweimer@redhat.com>
Date:   Fri Jun 30 20:19:10 2017 +0200

    resolv: Mirror the entire resolver configuration in struct resolv_conf
    
    This commit adds the remaining unchanging members (which are loaded
    from /etc/resolv.conf) to struct resolv_conf.
    
    The extended name server list is currently not used by the stub
    resolver.  The switch depends on a cleanup: The _u._ext.nssocks
    array stores just a single socket, and needs to be replaced with
    a single socket value.
    
    (The compatibility gethostname implementation does not use the
    extended addres sort list, either.  Updating the compat code is
    not worthwhile.)

diff --git a/ChangeLog b/ChangeLog
index 0061126..6478aed 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,41 @@
 2017-06-30  Florian Weimer  <fweimer@redhat.com>
 
+	Mirror the entire resolver configuration in struct resolv_conf.
+	* resolv/resolv_context.h (__resolv_context_nameserver_count)
+	(__resolv_context_nameserver): New functions.
+	(__resolv_context_sort_count, __resolv_context_sort_entry):
+	Likewise.
+	* resolv/nss_dns/dns-host.c (getanswer_r): Add struct
+	resolv_context parameter.
+	(gethostbyname3_context, _nss_dns_gethostbyaddr2_r): Adjust.
+	(addrsort): Switch to struct resolv_context.
+	* resolv/resolv_conf.h (struct resolv_sortlist_entry): Define.
+	(struct resolv_conf): Add nameserver_list, nameserver_list_size,
+	sort_list, sort_list_size, options, retrans, retry, ndots members.
+	* resolv/resolv_conf.c (same_address_v4, same_address_v6)
+	(same_address): New functions.
+	(resolv_conf_matches): Compare the new array members.
+	(__resolv_conf_allocate): Allocate and copy the new array members.
+	(update_from_conf): Copy the entire configuration.
+	* resolv/res_init.c (struct nameserver_list, struct sort_list):
+	Define using dynarray.
+	(struct resolv_conf_parser): Add nameserver_list, sort_list,
+	template members.
+	(resolv_conf_parser_init): Add preinit argument.  Initialize the
+	new members.
+	(resolv_conf_parser_free): Deallocate the new arrays.
+	(allocate_address_v4): New function.
+	(res_setoptions): Switch to struct resolv_conf_parser * parameter.
+	(res_vinit_1): Drop res_state parameter.  Write all parsed date to
+	the parser object instead.  Use allocate_address_v4 to allocate
+	IPv4 addresses.
+	(__res_vinit): Adjust.
+	* resolv/tst-resolv-res_init-skeleton.c (print_resp): Print the
+	extended name server list.
+	(test_cases): Adjust.
+
+2017-06-30  Florian Weimer  <fweimer@redhat.com>
+
 	[BZ #19569]
 	[BZ #21475]
 	Support an arbitrary number of search domains.
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
index 9d7ceb1..7cd54ab 100644
--- a/resolv/nss_dns/dns-host.c
+++ b/resolv/nss_dns/dns-host.c
@@ -108,7 +108,8 @@ typedef union querybuf
   u_char buf[MAXPACKET];
 } querybuf;
 
-static enum nss_status getanswer_r (const querybuf *answer, int anslen,
+static enum nss_status getanswer_r (struct resolv_context *ctx,
+				    const querybuf *answer, int anslen,
 				    const char *qname, int qtype,
 				    struct hostent *result, char *buffer,
 				    size_t buflen, int *errnop, int *h_errnop,
@@ -264,8 +265,9 @@ gethostbyname3_context (struct resolv_context *ctx,
       result->h_length = INADDRSZ;
     }
 
-  status = getanswer_r (host_buffer.buf, n, name, type, result, buffer, buflen,
-			errnop, h_errnop, map, ttlp, canonp);
+  status = getanswer_r
+    (ctx, host_buffer.buf, n, name, type, result, buffer, buflen,
+     errnop, h_errnop, map, ttlp, canonp);
   if (host_buffer.buf != orig_host_buffer)
     free (host_buffer.buf);
   return status;
@@ -522,8 +524,9 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
       return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
     }
 
-  status = getanswer_r (host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen,
-			errnop, h_errnop, 0 /* XXX */, ttlp, NULL);
+  status = getanswer_r
+    (ctx, host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen,
+     errnop, h_errnop, 0 /* XXX */, ttlp, NULL);
   if (host_buffer.buf != orig_host_buffer)
     free (host_buffer.buf);
   if (status != NSS_STATUS_SUCCESS)
@@ -553,25 +556,27 @@ _nss_dns_gethostbyaddr_r (const void *addr, socklen_t len, int af,
 				    errnop, h_errnop, NULL);
 }
 
-static void addrsort (char **ap, int num);
-
 static void
-addrsort (char **ap, int num)
+addrsort (struct resolv_context *ctx, char **ap, int num)
 {
   int i, j;
   char **p;
   short aval[MAX_NR_ADDRS];
   int needsort = 0;
+  size_t nsort = __resolv_context_sort_count (ctx);
 
   p = ap;
   if (num > MAX_NR_ADDRS)
     num = MAX_NR_ADDRS;
   for (i = 0; i < num; i++, p++)
     {
-      for (j = 0 ; (unsigned)j < _res.nsort; j++)
-	if (_res.sort_list[j].addr.s_addr ==
-	    (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
-	  break;
+      for (j = 0 ; (unsigned)j < nsort; j++)
+	{
+	  struct resolv_sortlist_entry e
+	    = __resolv_context_sort_entry (ctx, j);
+	  if (e.addr.s_addr == (((struct in_addr *)(*p))->s_addr & e.mask))
+	    break;
+	}
       aval[i] = j;
       if (needsort == 0 && i > 0 && j < aval[i-1])
 	needsort = i;
@@ -598,7 +603,8 @@ addrsort (char **ap, int num)
 }
 
 static enum nss_status
-getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
+getanswer_r (struct resolv_context *ctx,
+	     const querybuf *answer, int anslen, const char *qname, int qtype,
 	     struct hostent *result, char *buffer, size_t buflen,
 	     int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp)
 {
@@ -961,8 +967,9 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
        * in its return structures - should give it the "best"
        * address in that case, not some random one
        */
-      if (_res.nsort && haveanswer > 1 && qtype == T_A)
-	addrsort (host_data->h_addr_ptrs, haveanswer);
+      if (haveanswer > 1 && qtype == T_A
+	  && __resolv_context_sort_count (ctx) > 0)
+	addrsort (ctx, host_data->h_addr_ptrs, haveanswer);
 
       if (result->h_name == NULL)
 	{
diff --git a/resolv/res_init.c b/resolv/res_init.c
index 5941d37..80a21fb 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -104,7 +104,6 @@
 #include <errno.h>
 #include <resolv_conf.h>
 
-static void res_setoptions (res_state, const char *);
 static uint32_t net_mask (struct in_addr);
 
 unsigned long long int __res_initstamp;
@@ -124,28 +123,70 @@ is_sort_mask (char ch)
   return ch == '/' || ch == '&';
 }
 
+/* Array of name server addresses.  */
+#define DYNARRAY_STRUCT nameserver_list
+#define DYNARRAY_ELEMENT const struct sockaddr *
+#define DYNARRAY_ELEMENT_FREE(e) free ((struct sockaddr *) *(e))
+#define DYNARRAY_INITIAL_SIZE 3
+#define DYNARRAY_PREFIX nameserver_list_
+#include <malloc/dynarray-skeleton.c>
+
 /* 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_INITIAL_SIZE 6
 #define DYNARRAY_PREFIX search_list_
 #include <malloc/dynarray-skeleton.c>
 
+/* Array of name server addresses.  */
+#define DYNARRAY_STRUCT sort_list
+#define DYNARRAY_ELEMENT struct resolv_sortlist_entry
+#define DYNARRAY_INITIAL_SIZE 0
+#define DYNARRAY_PREFIX sort_list_
+#include <malloc/dynarray-skeleton.c>
+
 /* resolv.conf parser state and results.  */
 struct resolv_conf_parser
 {
   char *buffer;            /* Temporary buffer for reading lines.  */
+
+  struct nameserver_list nameserver_list; /* Nameserver addresses.  */
+
   char *search_list_store; /* Backing storage for search list entries.  */
   struct search_list search_list; /* Points into search_list_store.  */
+
+  struct sort_list sort_list;   /* Address preference sorting list.  */
+
+  /* Configuration template.  The non-array elements are filled in
+     directly.  The array elements are updated prior to the call to
+     __resolv_conf_attach.  */
+  struct resolv_conf template;
 };
 
 static void
-resolv_conf_parser_init (struct resolv_conf_parser *parser)
+resolv_conf_parser_init (struct resolv_conf_parser *parser,
+                         const struct __res_state *preinit)
 {
   parser->buffer = NULL;
   parser->search_list_store = NULL;
+  nameserver_list_init (&parser->nameserver_list);
   search_list_init (&parser->search_list);
+  sort_list_init (&parser->sort_list);
+
+  if (preinit != NULL)
+    {
+      parser->template.retrans = preinit->retrans;
+      parser->template.retry = preinit->retry;
+      parser->template.options = preinit->options | RES_INIT;
+    }
+  else
+    {
+      parser->template.retrans = RES_TIMEOUT;
+      parser->template.retry = RES_DFLRETRY;
+      parser->template.options = RES_DEFAULT | RES_INIT;
+    }
+  parser->template.ndots = 1;
 }
 
 static void
@@ -153,7 +194,23 @@ resolv_conf_parser_free (struct resolv_conf_parser *parser)
 {
   free (parser->buffer);
   free (parser->search_list_store);
+  nameserver_list_free (&parser->nameserver_list);
   search_list_free (&parser->search_list);
+  sort_list_free (&parser->sort_list);
+}
+
+/* Allocate a struct sockaddr_in object on the heap, with the
+   specified address and port.  */
+static struct sockaddr *
+allocate_address_v4 (struct in_addr a, uint16_t port)
+{
+  struct sockaddr_in *sa4 = malloc (sizeof (*sa4));
+  if (sa4 == NULL)
+    return NULL;
+  sa4->sin_family = AF_INET;
+  sa4->sin_addr = a;
+  sa4->sin_port = htons (port);
+  return (struct sockaddr *) sa4;
 }
 
 /* Try to obtain the domain name from the host name and store it in
@@ -181,40 +238,17 @@ domain_from_hostname (char **result)
   return true;
 }
 
+static void res_setoptions (struct resolv_conf_parser *, const char *options);
+
 /* 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,
-             struct resolv_conf_parser *parser)
+res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser)
 {
   char *cp;
   size_t buffer_size = 0;
-  int nserv = 0;    /* Number of nameservers read from file.  */
-  bool have_serv6 = false;
   bool haveenv = false;
-  int nsort = 0;
-  char *net;
-
-  if (!preinit)
-    {
-      statp->retrans = RES_TIMEOUT;
-      statp->retry = RES_DFLRETRY;
-      statp->options = RES_DEFAULT;
-      statp->id = res_randomid ();
-    }
-
-  statp->nscount = 0;
-  statp->defdname[0] = '\0';
-  statp->ndots = 1;
-  statp->pfcode = 0;
-  statp->_vcsock = -1;
-  statp->_flags = 0;
-  statp->__glibc_unused_qhook = NULL;
-  statp->__glibc_unused_rhook = NULL;
-  statp->_u._ext.nscount = 0;
-  for (int n = 0; n < MAXNS; n++)
-    statp->_u._ext.nsaddrs[n] = NULL;
 
   /* Allow user to override the local domain definition.  */
   if ((cp = getenv ("LOCALDOMAIN")) != NULL)
@@ -350,19 +384,19 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp,
               continue;
             }
           /* Read nameservers to query.  */
-          if (MATCH (parser->buffer, "nameserver") && nserv < MAXNS)
+          if (MATCH (parser->buffer, "nameserver"))
             {
               struct in_addr a;
 
               cp = parser->buffer + sizeof ("nameserver") - 1;
               while (*cp == ' ' || *cp == '\t')
                 cp++;
+              struct sockaddr *sa;
               if ((*cp != '\0') && (*cp != '\n') && __inet_aton (cp, &a))
                 {
-                  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++;
+                  sa = allocate_address_v4 (a, NAMESERVER_PORT);
+                  if (sa == NULL)
+                    return false;
                 }
               else
                 {
@@ -392,13 +426,18 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp,
                            compatibility.  */
                         __inet6_scopeid_pton
                           (&a6, el + 1, &sa6->sin6_scope_id);
-
-                      statp->nsaddr_list[nserv].sin_family = 0;
-                      statp->_u._ext.nsaddrs[nserv] = sa6;
-                      statp->_u._ext.nssocks[nserv] = -1;
-                      have_serv6 = true;
-                      nserv++;
+                      sa = (struct sockaddr *) sa6;
                     }
+                  else
+                    /* IPv6 address parse failure.  */
+                    sa = NULL;
+                }
+              if (sa != NULL)
+                {
+                  const struct sockaddr **p = nameserver_list_emplace
+                    (&parser->nameserver_list);
+                  if (p != NULL)
+                    *p = sa;
                 }
               continue;
             }
@@ -407,21 +446,22 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp,
               struct in_addr a;
 
               cp = parser->buffer + sizeof ("sortlist") - 1;
-              while (nsort < MAXRESOLVSORT)
+              while (true)
                 {
                   while (*cp == ' ' || *cp == '\t')
                     cp++;
                   if (*cp == '\0' || *cp == '\n' || *cp == ';')
                     break;
-                  net = cp;
+                  char *net = cp;
                   while (*cp && !is_sort_mask (*cp) && *cp != ';'
                          && isascii (*cp) && !isspace (*cp))
                     cp++;
                   char separator = *cp;
                   *cp = 0;
+                  struct resolv_sortlist_entry e;
                   if (__inet_aton (net, &a))
                     {
-                      statp->sort_list[nsort].addr = a;
+                      e.addr = a;
                       if (is_sort_mask (separator))
                         {
                           *cp++ = separator;
@@ -432,15 +472,13 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp,
                           separator = *cp;
                           *cp = 0;
                           if (__inet_aton (net, &a))
-                            statp->sort_list[nsort].mask = a.s_addr;
+                            e.mask = a.s_addr;
                           else
-                            statp->sort_list[nsort].mask
-                              = net_mask (statp->sort_list[nsort].addr);
+                            e.mask = net_mask (e.addr);
                         }
                       else
-                        statp->sort_list[nsort].mask
-                          = net_mask (statp->sort_list[nsort].addr);
-                      nsort++;
+                        e.mask = net_mask (e.addr);
+                      sort_list_add (&parser->sort_list, e);
                     }
                   *cp = separator;
                 }
@@ -448,23 +486,22 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp,
             }
           if (MATCH (parser->buffer, "options"))
             {
-              res_setoptions (statp, parser->buffer + sizeof ("options") - 1);
+              res_setoptions (parser, parser->buffer + sizeof ("options") - 1);
               continue;
             }
         }
-      statp->nscount = nserv;
-      if (have_serv6)
-        /* We try IPv6 servers again.  */
-        statp->ipv6_unavail = false;
-      statp->nsort = nsort;
       fclose (fp);
     }
-  if (__glibc_unlikely (statp->nscount == 0))
+  if (__glibc_unlikely (nameserver_list_size (&parser->nameserver_list) == 0))
     {
-      statp->nsaddr.sin_addr = __inet_makeaddr (IN_LOOPBACKNET, 1);
-      statp->nsaddr.sin_family = AF_INET;
-      statp->nsaddr.sin_port = htons (NAMESERVER_PORT);
-      statp->nscount = 1;
+      const struct sockaddr **p
+        = nameserver_list_emplace (&parser->nameserver_list);
+      if (p == NULL)
+        return false;
+      *p = allocate_address_v4 (__inet_makeaddr (IN_LOOPBACKNET, 1),
+                                NAMESERVER_PORT);
+      if (*p == NULL)
+        return false;
     }
 
   if (search_list_size (&parser->search_list) == 0)
@@ -481,15 +518,16 @@ res_vinit_1 (res_state statp, bool preinit, FILE *fp,
     }
 
   if ((cp = getenv ("RES_OPTIONS")) != NULL)
-    res_setoptions (statp, cp);
+    res_setoptions (parser, cp);
 
-  if (search_list_has_failed (&parser->search_list))
+  if (nameserver_list_has_failed (&parser->nameserver_list)
+      || search_list_has_failed (&parser->search_list)
+      || sort_list_has_failed (&parser->sort_list))
     {
       __set_errno (ENOMEM);
       return false;
     }
 
-  statp->options |= RES_INIT;
   return true;
 }
 
@@ -525,17 +563,27 @@ __res_vinit (res_state statp, int preinit)
       }
 
   struct resolv_conf_parser parser;
-  resolv_conf_parser_init (&parser);
-  bool ok = res_vinit_1 (statp, preinit, fp, &parser);
+  if (preinit)
+    {
+      resolv_conf_parser_init (&parser, statp);
+      statp->id = res_randomid ();
+    }
+  else
+    resolv_conf_parser_init (&parser, NULL);
 
+  bool ok = res_vinit_1 (fp, &parser);
   if (ok)
     {
-      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);
+      parser.template.nameserver_list
+        = nameserver_list_begin (&parser.nameserver_list);
+      parser.template.nameserver_list_size
+        = nameserver_list_size (&parser.nameserver_list);
+      parser.template.search_list = search_list_begin (&parser.search_list);
+      parser.template.search_list_size
+        = search_list_size (&parser.search_list);
+      parser.template.sort_list = sort_list_begin (&parser.sort_list);
+      parser.template.sort_list_size = sort_list_size (&parser.sort_list);
+      struct resolv_conf *conf = __resolv_conf_allocate (&parser.template);
       if (conf == NULL)
         ok = false;
       else
@@ -547,18 +595,13 @@ __res_vinit (res_state statp, int preinit)
   resolv_conf_parser_free (&parser);
 
   if (!ok)
-    {
-      /* Deallocate the name server addresses which have been
-         allocated.  */
-      for (int n = 0; n < MAXNS; n++)
-        free (statp->_u._ext.nsaddrs[n]);
-      return -1;
-    }
-  return 0;
+    return -1;
+  else
+    return 0;
 }
 
 static void
-res_setoptions (res_state statp, const char *options)
+res_setoptions (struct resolv_conf_parser *parser, const char *options)
 {
   const char *cp = options;
 
@@ -572,25 +615,25 @@ res_setoptions (res_state statp, const char *options)
         {
           int i = atoi (cp + sizeof ("ndots:") - 1);
           if (i <= RES_MAXNDOTS)
-            statp->ndots = i;
+            parser->template.ndots = i;
           else
-            statp->ndots = RES_MAXNDOTS;
+            parser->template.ndots = RES_MAXNDOTS;
         }
       else if (!strncmp (cp, "timeout:", sizeof ("timeout:") - 1))
         {
           int i = atoi (cp + sizeof ("timeout:") - 1);
           if (i <= RES_MAXRETRANS)
-            statp->retrans = i;
+            parser->template.retrans = i;
           else
-            statp->retrans = RES_MAXRETRANS;
+            parser->template.retrans = RES_MAXRETRANS;
         }
       else if (!strncmp (cp, "attempts:", sizeof ("attempts:") - 1))
         {
           int i = atoi (cp + sizeof ("attempts:") - 1);
           if (i <= RES_MAXRETRY)
-            statp->retry = i;
+            parser->template.retry = i;
           else
-            statp->retry = RES_MAXRETRY;
+            parser->template.retry = RES_MAXRETRY;
         }
       else
         {
@@ -616,9 +659,9 @@ res_setoptions (res_state statp, const char *options)
             if (strncmp (cp, options[i].str, options[i].len) == 0)
               {
                 if (options[i].clear)
-                  statp->options &= options[i].flag;
+                  parser->template.options &= options[i].flag;
                 else
-                  statp->options |= options[i].flag;
+                  parser->template.options |= options[i].flag;
                 break;
               }
         }
diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c
index 76d55fc..dd66523 100644
--- a/resolv/resolv_conf.c
+++ b/resolv/resolv_conf.c
@@ -128,11 +128,80 @@ resolv_conf_get_1 (const struct __res_state *resp)
   return conf;
 }
 
+/* Return true if both IPv4 addresses are equal.  */
+static bool
+same_address_v4 (const struct sockaddr_in *left,
+                 const struct sockaddr_in *right)
+{
+  return left->sin_addr.s_addr == right->sin_addr.s_addr
+    && left->sin_port == right->sin_port;
+}
+
+/* Return true if both IPv6 addresses are equal.  This ignores the
+   flow label.  */
+static bool
+same_address_v6 (const struct sockaddr_in6 *left,
+                 const struct sockaddr_in6 *right)
+{
+  return memcmp (&left->sin6_addr, &right->sin6_addr,
+                 sizeof (left->sin6_addr)) == 0
+    && left->sin6_port == right->sin6_port
+    && left->sin6_scope_id == right->sin6_scope_id;
+}
+
+static bool
+same_address (const struct sockaddr *left, const struct sockaddr *right)
+{
+  if (left->sa_family != right->sa_family)
+    return false;
+  switch (left->sa_family)
+    {
+    case AF_INET:
+      return same_address_v4 ((const struct sockaddr_in *) left,
+                              (const struct sockaddr_in *) right);
+    case AF_INET6:
+      return same_address_v6 ((const struct sockaddr_in6 *) left,
+                              (const struct sockaddr_in6 *) right);
+    }
+  return false;
+}
+
 /* Check that *RESP and CONF match.  Used by __resolv_conf_get.  */
 static bool
 resolv_conf_matches (const struct __res_state *resp,
                      const struct resolv_conf *conf)
 {
+  /* NB: Do not compare the options, retrans, retry, ndots.  These can
+     be changed by applicaiton.  */
+
+  /* Check that the name servers in *RESP have not been modified by
+     the application.  */
+  {
+    size_t nserv = conf->nameserver_list_size;
+    if (nserv > MAXNS)
+      nserv = MAXNS;
+    /* _ext.nscount is 0 until initialized by res_send.c.  */
+    if (resp->nscount != nserv
+        && (resp->_u._ext.nscount != 0 && resp->_u._ext.nscount != nserv))
+      return false;
+    for (size_t i = 0; i < nserv; ++i)
+      {
+        if (resp->nsaddr_list[i].sin_family == 0)
+          {
+            if (resp->_u._ext.nsaddrs[i]->sin6_family != AF_INET6)
+              return false;
+            if (!same_address ((struct sockaddr *) resp->_u._ext.nsaddrs[i],
+                               conf->nameserver_list[i]))
+              return false;
+          }
+        else if (resp->nsaddr_list[i].sin_family != AF_INET)
+          return false;
+        else if (!same_address ((struct sockaddr *) &resp->nsaddr_list[i],
+                                conf->nameserver_list[i]))
+          return false;
+      }
+  }
+
   /* Check that the search list in *RESP has not been modified by the
      application.  */
   {
@@ -161,6 +230,18 @@ resolv_conf_matches (const struct __res_state *resp,
           }
       }
   }
+
+  /* Check that the sort list has not been modified.  */
+  {
+    size_t nsort = conf->sort_list_size;
+    if (nsort > MAXRESOLVSORT)
+      nsort = MAXRESOLVSORT;
+    for (size_t i = 0; i < nsort; ++i)
+      if (resp->sort_list[i].addr.s_addr != conf->sort_list[i].addr.s_addr
+          || resp->sort_list[i].mask != conf->sort_list[i].mask)
+        return false;
+  }
+
   return true;
 }
 
@@ -190,7 +271,28 @@ __resolv_conf_put (struct resolv_conf *conf)
 struct resolv_conf *
 __resolv_conf_allocate (const struct resolv_conf *init)
 {
-  /* Space needed by the strings.  */
+  /* Allocate in decreasing order of alignment.  */
+  _Static_assert (__alignof__ (const char *const *)
+                  <= __alignof__ (struct resolv_conf), "alignment");
+  _Static_assert (__alignof__ (struct sockaddr_in6)
+                  <= __alignof__ (const char *const *), "alignment");
+  _Static_assert (__alignof__ (struct sockaddr_in)
+                  ==  __alignof__ (struct sockaddr_in6), "alignment");
+  _Static_assert (__alignof__ (struct resolv_sortlist_entry)
+                  <= __alignof__ (struct sockaddr_in), "alignment");
+
+  /* Space needed by the nameserver addresses.  */
+  size_t address_space = 0;
+  for (size_t i = 0; i < init->nameserver_list_size; ++i)
+    if (init->nameserver_list[i]->sa_family == AF_INET)
+      address_space += sizeof (struct sockaddr_in);
+    else
+      {
+        assert (init->nameserver_list[i]->sa_family == AF_INET6);
+        address_space += sizeof (struct sockaddr_in6);
+      }
+
+  /* Space needed by the search list 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;
@@ -199,7 +301,10 @@ __resolv_conf_allocate (const struct resolv_conf *init)
   void *ptr;
   struct alloc_buffer buffer = alloc_buffer_allocate
     (sizeof (struct resolv_conf)
+     + init->nameserver_list_size * sizeof (init->nameserver_list[0])
+     + address_space
      + init->search_list_size * sizeof (init->search_list[0])
+     + init->sort_list_size * sizeof (init->sort_list[0])
      + string_space,
      &ptr);
   struct resolv_conf *conf
@@ -211,16 +316,57 @@ __resolv_conf_allocate (const struct resolv_conf *init)
 
   /* Initialize the contents.  */
   conf->__refcount = 1;
+  conf->retrans = init->retrans;
+  conf->retry = init->retry;
+  conf->options = init->options;
+  conf->ndots = init->ndots;
   conf->initstamp = __res_initstamp;
 
-  /* Allocate and fill the search list array.  */
+  /* Allocate the arrays with pointers.  These must come first because
+     they have the highets alignment.  */
+  conf->nameserver_list_size = init->nameserver_list_size;
+  const struct sockaddr **nameserver_array = alloc_buffer_alloc_array
+    (&buffer, const struct sockaddr *, init->nameserver_list_size);
+  conf->nameserver_list = nameserver_array;
+
+  conf->search_list_size = init->search_list_size;
+  const char **search_array = alloc_buffer_alloc_array
+    (&buffer, const char *, init->search_list_size);
+  conf->search_list = search_array;
+
+  /* Fill the name server list array.  */
+  for (size_t i = 0; i < init->nameserver_list_size; ++i)
+    if (init->nameserver_list[i]->sa_family == AF_INET)
+      {
+        struct sockaddr_in *sa = alloc_buffer_alloc
+          (&buffer, struct sockaddr_in);
+        *sa = *(struct sockaddr_in *) init->nameserver_list[i];
+        nameserver_array[i] = (struct sockaddr *) sa;
+      }
+    else
+      {
+        struct sockaddr_in6 *sa = alloc_buffer_alloc
+          (&buffer, struct sockaddr_in6);
+        *sa = *(struct sockaddr_in6 *) init->nameserver_list[i];
+        nameserver_array[i] = (struct sockaddr *) sa;
+      }
+
+  /* Allocate and fill the sort list array.  */
+  {
+    conf->sort_list_size = init->sort_list_size;
+    struct resolv_sortlist_entry *array = alloc_buffer_alloc_array
+      (&buffer, struct resolv_sortlist_entry, init->sort_list_size);
+    conf->sort_list = array;
+    for (size_t i = 0; i < init->sort_list_size; ++i)
+      array[i] = init->sort_list[i];
+  }
+
+  /* Fill the search list array.  This must come last because the
+     strings are the least aligned part of the allocation.  */
   {
-    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]);
+      search_array[i] = alloc_buffer_copy_string
+        (&buffer, init->search_list[i]);
   }
 
   assert (!alloc_buffer_has_failed (&buffer));
@@ -231,6 +377,56 @@ __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)
 {
+  resp->defdname[0] = '\0';
+  resp->pfcode = 0;
+  resp->_vcsock = -1;
+  resp->_flags = 0;
+  resp->ipv6_unavail = false;
+  resp->__glibc_unused_qhook = NULL;
+  resp->__glibc_unused_rhook = NULL;
+
+  resp->retrans = conf->retrans;
+  resp->retry = conf->retry;
+  resp->options = conf->options;
+  resp->ndots = conf->ndots;
+
+  /* Copy the name server addresses.  */
+  {
+    resp->nscount = 0;
+    resp->_u._ext.nscount = 0;
+    size_t nserv = conf->nameserver_list_size;
+    if (nserv > MAXNS)
+      nserv = MAXNS;
+    for (size_t i = 0; i < nserv; i++)
+      {
+        if (conf->nameserver_list[i]->sa_family == AF_INET)
+          {
+            resp->nsaddr_list[i]
+              = *(struct sockaddr_in *)conf->nameserver_list[i];
+            resp->_u._ext.nsaddrs[i] = NULL;
+          }
+        else
+          {
+            assert (conf->nameserver_list[i]->sa_family == AF_INET6);
+            resp->nsaddr_list[i].sin_family = 0;
+            /* Make a defensive copy of the name server address, in
+               case the application overwrites it.  */
+            struct sockaddr_in6 *sa = malloc (sizeof (*sa));
+            if (sa == NULL)
+              {
+                for (size_t j = 0; j < i; ++j)
+                  free (resp->_u._ext.nsaddrs[j]);
+                return false;
+              }
+            *sa = *(struct sockaddr_in6 *)conf->nameserver_list[i];
+            resp->_u._ext.nsaddrs[i] = sa;
+          }
+        resp->_u._ext.nssocks[i] = -1;
+      }
+    resp->nscount = nserv;
+    /* Leave resp->_u._ext.nscount at 0.  res_send.c handles this.  */
+  }
+
   /* Fill in the prefix of the search list.  It is truncated either at
      MAXDNSRCH, or if reps->defdname has insufficient space.  */
   {
@@ -249,6 +445,19 @@ update_from_conf (struct __res_state *resp, const struct resolv_conf *conf)
     resp->dnsrch[i] = NULL;
   }
 
+  /* Copy the sort list.  */
+  {
+    size_t nsort = conf->sort_list_size;
+    if (nsort > MAXRESOLVSORT)
+      nsort = MAXRESOLVSORT;
+    for (size_t i = 0; i < nsort; ++i)
+      {
+        resp->sort_list[i].addr = conf->sort_list[i].addr;
+        resp->sort_list[i].mask = conf->sort_list[i].mask;
+      }
+    resp->nsort = nsort;
+  }
+
   /* 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 80a0b93..7ca80cd 100644
--- a/resolv/resolv_conf.h
+++ b/resolv/resolv_conf.h
@@ -19,9 +19,17 @@
 #ifndef RESOLV_STATE_H
 #define RESOLV_STATE_H
 
+#include <netinet/in.h>
 #include <stdbool.h>
 #include <stddef.h>
 
+/* This type corresponds to members of the _res.sort_list array.  */
+struct resolv_sortlist_entry
+{
+  struct in_addr addr;
+  uint32_t mask;
+};
+
 /* Extended resolver state associated with res_state objects.  Client
    code can reach this state through a struct resolv_context
    object.  */
@@ -36,9 +44,24 @@ struct resolv_conf
      zero.  For internal use within resolv_conf only.  */
   size_t __refcount;
 
+  /* List of IPv4 and IPv6 name server addresses.  */
+  const struct sockaddr **nameserver_list;
+  size_t nameserver_list_size;
+
   /* The domain names forming the search list.  */
   const char *const *search_list;
   size_t search_list_size;
+
+  /* IPv4 address preference rules.  */
+  const struct resolv_sortlist_entry *sort_list;
+  size_t sort_list_size;
+
+  /* _res.options has type unsigned long, but we can only use 32 bits
+     for portability across all architectures.  */
+  unsigned int options;
+  unsigned int retrans;         /* Timeout.  */
+  unsigned int retry;           /* Number of times to retry.  */
+  unsigned int ndots; /* Dots needed for initial non-search query.  */
 };
 
 /* 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 0f4d47d..e2f7ad6 100644
--- a/resolv/resolv_context.h
+++ b/resolv/resolv_context.h
@@ -112,6 +112,67 @@ __resolv_context_search_list (const struct resolv_context *ctx, size_t index)
   return NULL;
 }
 
+/* Return the number of name servers.  */
+static __attribute__ ((nonnull (1), unused)) size_t
+__resolv_context_nameserver_count (const struct resolv_context *ctx)
+{
+  if (ctx->conf != NULL)
+    return ctx->conf->nameserver_list_size;
+  else
+    return ctx->resp->nscount;
+}
+
+/* Return a pointer to the socket address of the name server INDEX, or
+   NULL if the index is out of bounds.  */
+static __attribute__ ((nonnull (1), unused)) const struct sockaddr *
+__resolv_context_nameserver (const struct resolv_context *ctx, size_t index)
+{
+  if (ctx->conf != NULL)
+    {
+      if (index < ctx->conf->nameserver_list_size)
+        return ctx->conf->nameserver_list[index];
+    }
+  else
+    if (index < ctx->resp->nscount)
+      {
+        if (ctx->resp->nsaddr_list[index].sin_family != 0)
+          return (const struct sockaddr *) &ctx->resp->nsaddr_list[index];
+        else
+          return (const struct sockaddr *) &ctx->resp->_u._ext.nsaddrs[index];
+      }
+  return NULL;
+}
+
+/* Return the number of sort list entries.  */
+static __attribute__ ((nonnull (1), unused)) size_t
+__resolv_context_sort_count (const struct resolv_context *ctx)
+{
+  if (ctx->conf != NULL)
+    return ctx->conf->sort_list_size;
+  else
+    return ctx->resp->nsort;
+}
+
+/* Return the sort list entry at INDEX.  */
+static __attribute__ ((nonnull (1), unused)) struct resolv_sortlist_entry
+__resolv_context_sort_entry (const struct resolv_context *ctx, size_t index)
+{
+  if (ctx->conf != NULL)
+    {
+      if (index < ctx->conf->sort_list_size)
+        return ctx->conf->sort_list[index];
+      /* Fall through.  */
+    }
+  else if (index < ctx->resp->nsort)
+    return (struct resolv_sortlist_entry)
+      {
+        .addr = ctx->resp->sort_list[index].addr,
+        .mask = ctx->resp->sort_list[index].mask,
+      };
+
+  return (struct resolv_sortlist_entry) { .mask = 0, };
+}
+
 /* 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 cea1456..f98e9f4 100644
--- a/resolv/tst-resolv-res_init-skeleton.c
+++ b/resolv/tst-resolv-res_init-skeleton.c
@@ -242,6 +242,46 @@ print_resp (FILE *fp, res_state resp)
         }
     }
 
+  /* The extended name server list.  */
+  {
+    size_t i = 0;
+    while (true)
+      {
+        const struct sockaddr *addr = __resolv_context_nameserver (ctx, i);
+        if (addr == NULL)
+          break;
+        size_t addrlen;
+        switch (addr->sa_family)
+          {
+          case AF_INET:
+            addrlen = sizeof (struct sockaddr_in);
+            break;
+          case AF_INET6:
+            addrlen = sizeof (struct sockaddr_in6);
+            break;
+          default:
+            FAIL_EXIT1 ("invalid address family %d", addr->sa_family);
+          }
+
+        char host[NI_MAXHOST];
+        char service[NI_MAXSERV];
+        int ret = getnameinfo (addr, addrlen,
+                               host, sizeof (host), service, sizeof (service),
+                               NI_NUMERICHOST | NI_NUMERICSERV);
+
+        if (ret != 0)
+          {
+            if (ret == EAI_SYSTEM)
+              fprintf (fp, "; error: getnameinfo: %m\n");
+            else
+              fprintf (fp, "; error: getnameinfo: %s\n", gai_strerror (ret));
+          }
+        else
+          fprintf (fp, "; nameserver[%zu]: [%s]:%s\n", i, host, service);
+        ++i;
+      }
+  }
+
   TEST_VERIFY (!ferror (fp));
 
   __resolv_context_put (ctx);
@@ -391,12 +431,14 @@ struct test_case test_cases[] =
      .expected = "search example.com\n"
      "; search[0]: example.com\n"
      "nameserver 127.0.0.1\n"
+     "; nameserver[0]: [127.0.0.1]:53\n"
     },
     {.name = "empty file with LOCALDOMAIN",
      .conf = "",
      .expected = "search example.net\n"
      "; search[0]: example.net\n"
-     "nameserver 127.0.0.1\n",
+     "nameserver 127.0.0.1\n"
+     "; nameserver[0]: [127.0.0.1]:53\n",
      .localdomain = "example.net",
     },
     {.name = "empty file with RES_OPTIONS",
@@ -404,7 +446,8 @@ struct test_case test_cases[] =
      .expected = "options attempts:5 edns0\n"
      "search example.com\n"
      "; search[0]: example.com\n"
-     "nameserver 127.0.0.1\n",
+     "nameserver 127.0.0.1\n"
+     "; nameserver[0]: [127.0.0.1]:53\n",
      .res_options = "edns0 attempts:5",
     },
     {.name = "empty file with RES_OPTIONS and LOCALDOMAIN",
@@ -412,7 +455,8 @@ struct test_case test_cases[] =
      .expected = "options attempts:5 edns0\n"
      "search example.org\n"
      "; search[0]: example.org\n"
-     "nameserver 127.0.0.1\n",
+     "nameserver 127.0.0.1\n"
+     "; nameserver[0]: [127.0.0.1]:53\n",
      .localdomain = "example.org",
      .res_options = "edns0 attempts:5",
     },
@@ -424,6 +468,7 @@ struct test_case test_cases[] =
      "; search[0]: corp.example.com\n"
      "; search[1]: example.com\n"
      "nameserver 192.0.2.1\n"
+     "; nameserver[0]: [192.0.2.1]:53\n"
     },
     {.name = "whitespace",
      .conf = "# This test covers comment and whitespace processing "
@@ -440,6 +485,8 @@ struct test_case test_cases[] =
      "; search[1]: example.com\n"
      "nameserver 192.0.2.1\n"
      "nameserver 192.0.2.2\n"
+     "; nameserver[0]: [192.0.2.1]:53\n"
+     "; nameserver[1]: [192.0.2.2]:53\n"
     },
     {.name = "domain",
      .conf = "domain example.net\n"
@@ -447,6 +494,7 @@ struct test_case test_cases[] =
      .expected = "search example.net\n"
      "; search[0]: example.net\n"
      "nameserver 192.0.2.1\n"
+     "; nameserver[0]: [192.0.2.1]:53\n"
     },
     {.name = "domain space",
      .conf = "domain example.net \n"
@@ -454,6 +502,7 @@ struct test_case test_cases[] =
      .expected = "search example.net\n"
      "; search[0]: example.net\n"
      "nameserver 192.0.2.1\n"
+     "; nameserver[0]: [192.0.2.1]:53\n"
     },
     {.name = "domain tab",
      .conf = "domain example.net\t\n"
@@ -461,6 +510,7 @@ struct test_case test_cases[] =
      .expected = "search example.net\n"
      "; search[0]: example.net\n"
      "nameserver 192.0.2.1\n"
+     "; nameserver[0]: [192.0.2.1]:53\n"
     },
     {.name = "domain override",
      .conf = "search example.com example.org\n"
@@ -469,6 +519,7 @@ struct test_case test_cases[] =
      .expected = "search example.net\n"
      "; search[0]: example.net\n"
      "nameserver 192.0.2.1\n"
+     "; nameserver[0]: [192.0.2.1]:53\n"
     },
     {.name = "option values, multiple servers",
      .conf = "options\tinet6\tndots:3 edns0\tattempts:5\ttimeout:19\n"
@@ -485,6 +536,9 @@ struct test_case test_cases[] =
      "nameserver 192.0.2.1\n"
      "nameserver ::1\n"
      "nameserver 192.0.2.2\n"
+     "; nameserver[0]: [192.0.2.1]:53\n"
+     "; nameserver[1]: [::1]:53\n"
+     "; nameserver[2]: [192.0.2.2]:53\n"
     },
     {.name = "out-of-range option vales",
      .conf = "options use-vc timeout:999 attempts:999 ndots:99\n"
@@ -493,6 +547,7 @@ struct test_case test_cases[] =
      "search example.com\n"
      "; search[0]: example.com\n"
      "nameserver 127.0.0.1\n"
+     "; nameserver[0]: [127.0.0.1]:53\n"
     },
     {.name = "repeated directives",
      .conf = "options ndots:3 use-vc\n"
@@ -505,6 +560,7 @@ struct test_case test_cases[] =
      "search example.org\n"
      "; search[0]: example.org\n"
      "nameserver 127.0.0.1\n"
+     "; nameserver[0]: [127.0.0.1]:53\n"
     },
     {.name = "many name servers, sortlist",
      .conf = "options single-request\n"
@@ -528,6 +584,14 @@ struct test_case test_cases[] =
      "nameserver 192.0.2.1\n"
      "nameserver 192.0.2.2\n"
      "nameserver 192.0.2.3\n"
+     "; nameserver[0]: [192.0.2.1]:53\n"
+     "; nameserver[1]: [192.0.2.2]:53\n"
+     "; nameserver[2]: [192.0.2.3]:53\n"
+     "; nameserver[3]: [192.0.2.4]:53\n"
+     "; nameserver[4]: [192.0.2.5]:53\n"
+     "; nameserver[5]: [192.0.2.6]:53\n"
+     "; nameserver[6]: [192.0.2.7]:53\n"
+     "; nameserver[7]: [192.0.2.8]:53\n"
     },
     {.name = "IPv4 and IPv6 nameservers",
      .conf = "options single-request\n"
@@ -554,6 +618,14 @@ struct test_case test_cases[] =
      "nameserver 192.0.2.1\n"
      "nameserver 2001:db8::2\n"
      "nameserver 192.0.2.3\n"
+     "; nameserver[0]: [192.0.2.1]:53\n"
+     "; nameserver[1]: [2001:db8::2]:53\n"
+     "; nameserver[2]: [192.0.2.3]:53\n"
+     "; nameserver[3]: [2001:db8::4]:53\n"
+     "; nameserver[4]: [192.0.2.5]:53\n"
+     "; nameserver[5]: [2001:db8::6]:53\n"
+     "; nameserver[6]: [192.0.2.7]:53\n"
+     "; nameserver[7]: [2001:db8::8]:53\n",
     },
     {.name = "garbage after nameserver",
      .conf = "nameserver 192.0.2.1 garbage\n"
@@ -563,6 +635,8 @@ struct test_case test_cases[] =
      "; search[0]: example.com\n"
      "nameserver 192.0.2.1\n"
      "nameserver 192.0.2.3\n"
+     "; nameserver[0]: [192.0.2.1]:53\n"
+     "; nameserver[1]: [192.0.2.3]:53\n"
     },
     {.name = "RES_OPTIONS is cummulative",
      .conf = "options timeout:7 ndots:2 use-vc\n"
@@ -570,7 +644,8 @@ struct test_case test_cases[] =
      .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",
+     "nameserver 192.0.2.1\n"
+     "; nameserver[0]: [192.0.2.1]:53\n",
      .res_options = "attempts:5 ndots:3 edns0 ",
     },
     {.name = "many search list entries (bug 19569)",
@@ -588,7 +663,8 @@ struct test_case test_cases[] =
      "; search[5]: example.com\n"
      "; search[6]: example.org\n"
      "; search[7]: example.net\n"
-     "nameserver 192.0.2.1\n",
+     "nameserver 192.0.2.1\n"
+     "; nameserver[0]: [192.0.2.1]:53\n"
     },
     {.name = "very long search list entries (bug 21475)",
      .conf = "nameserver 192.0.2.1\n"
@@ -603,7 +679,8 @@ struct test_case test_cases[] =
      "; search[2]: " H63 "." D63 ".example.net\n"
 #undef H63
 #undef D63
-     "nameserver 192.0.2.1\n",
+     "nameserver 192.0.2.1\n"
+     "; nameserver[0]: [192.0.2.1]:53\n"
     },
     { NULL }
   };

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

Summary of changes:
 ChangeLog                             |   36 ++++++
 resolv/nss_dns/dns-host.c             |   37 ++++---
 resolv/res_init.c                     |  219 +++++++++++++++++++-------------
 resolv/resolv_conf.c                  |  223 +++++++++++++++++++++++++++++++-
 resolv/resolv_conf.h                  |   23 ++++
 resolv/resolv_context.h               |   61 +++++++++
 resolv/tst-resolv-res_init-skeleton.c |   89 ++++++++++++-
 7 files changed, 572 insertions(+), 116 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]