]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
issue separate DNS queries for ipv4 and ipv6
authorGustavo Luiz Duarte <gustavold@linux.vnet.ibm.com>
Tue, 5 Nov 2013 19:30:20 +0000 (17:30 -0200)
committerPaulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
Tue, 5 Nov 2013 19:41:16 +0000 (17:41 -0200)
Adding multiple questions on a single DNS query is not supportted by
most DNS servers. This patch issues two separate DNS queries
sequentially for ipv4 and then for ipv6.

Fixes: https://savannah.gnu.org/bugs/?39710
 * grub-core/net/bootp.c (parse_dhcp_vendor): Add DNS option.
 * grub-core/net/dns.c (grub_dns_qtype_id): New enum.
 * (grub_net_dns_lookup): Now using separated dns packages.
 * (grub_cmd_nslookup): Add error condition.
 * (grub_cmd_list_dns): Print DNS option.
 * (grub_cmd_add_dns): Add four parameters: --only-ipv4,
 * --only-ipv6, --prefer-ipv4, and --prefer-ipv6.
 * include/grub/net.h (grub_dns_option_t): New enum.
 * (grub_net_network_level_address): option added.

Also-by: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
Signed-off-by: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
ChangeLog
grub-core/net/bootp.c
grub-core/net/dns.c
include/grub/net.h

index 1cc746068495edc488ea9a044a953d3ec05709f7..236b1018ee646bb412a7cc0797d7ad2c2eb9e85e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2013-11-05  Gustavo Luiz Duarte  <gustavold@linux.vnet.ibm.com>
+2013-11-05  Paulo Flabiano Smorigo  <pfsmorigo@br.ibm.com>
+
+       Issue separate DNS queries for ipv4 and ipv6
+
+       Adding multiple questions on a single DNS query is not supportted by
+       most DNS servers. This patch issues two separate DNS queries
+       sequentially for ipv4 and then for ipv6.
+
+       Fixes: https://savannah.gnu.org/bugs/?39710
+
+       * grub-core/net/bootp.c (parse_dhcp_vendor): Add DNS option.
+       * grub-core/net/dns.c (grub_dns_qtype_id): New enum.
+       * (grub_net_dns_lookup): Now using separated dns packages.
+       * (grub_cmd_nslookup): Add error condition.
+       * (grub_cmd_list_dns): Print DNS option.
+       * (grub_cmd_add_dns): Add four parameters: --only-ipv4, --only-ipv6,
+       --prefer-ipv4, and --prefer-ipv6.
+       * include/grub/net.h (grub_dns_option_t): New enum.
+       * (grub_net_network_level_address): option added.
+
 2013-11-05  Vladimir Testov  <vladimir.testov@rosalab.ru>
 
        * grub-core/video/fb/video_fb.c: Merge two blit functions
index 2c5a35b6c333c35b008ec5af8437fa2d00a656f2..dad76d03f783fc8e1814b2a40da4a28af1cc8a13 100644 (file)
@@ -123,6 +123,7 @@ parse_dhcp_vendor (const char *name, void *vend, int limit, int *mask)
                struct grub_net_network_level_address s;
                s.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
                s.ipv4 = grub_get_unaligned32 (ptr);
+               s.option = DNS_OPTION_PREFER_IPV4;
                grub_net_add_dns_server (&s);
                ptr += 4;
              }
index de649cfba2631da84f3bf48dff3b1c1d490782db..5524af9369909913ff17ce53f4378f07e87f25eb 100644 (file)
@@ -34,6 +34,12 @@ struct dns_cache_element
 #define DNS_CACHE_SIZE 1021
 #define DNS_HASH_BASE 423
 
+typedef enum grub_dns_qtype_id
+  {
+    GRUB_DNS_QTYPE_A = 1,
+    GRUB_DNS_QTYPE_AAAA = 28
+  } grub_dns_qtype_id_t;
+
 static struct dns_cache_element dns_cache[DNS_CACHE_SIZE];
 static struct grub_net_network_level_address *dns_servers;
 static grub_size_t dns_nservers, dns_servers_alloc;
@@ -426,6 +432,7 @@ grub_net_dns_lookup (const char *name,
   const char *iptr;
   struct dns_header *head;
   static grub_uint16_t id = 1;
+  grub_uint8_t *qtypeptr;
   grub_err_t err = GRUB_ERR_NONE;
   struct recv_data data = {naddresses, addresses, cache,
                           grub_cpu_to_be16 (id++), 0, 0, name, 0};
@@ -478,8 +485,7 @@ grub_net_dns_lookup (const char *name,
                           + GRUB_NET_MAX_LINK_HEADER_SIZE
                           + GRUB_NET_UDP_HEADER_SIZE
                           + sizeof (struct dns_header)
-                          + grub_strlen (name) + 2 + 4
-                          + 2 + 4);
+                          + grub_strlen (name) + 2 + 4);
   if (!nb)
     {
       grub_free (sockets);
@@ -490,7 +496,7 @@ grub_net_dns_lookup (const char *name,
                        + GRUB_NET_MAX_LINK_HEADER_SIZE
                        + GRUB_NET_UDP_HEADER_SIZE);
   grub_netbuff_put (nb, sizeof (struct dns_header)
-                   + grub_strlen (name) + 2 + 4 + 2 + 4);
+                   + grub_strlen (name) + 2 + 4);
   head = (struct dns_header *) nb->data;
   optr = (grub_uint8_t *) (head + 1);
   for (iptr = name; *iptr; )
@@ -516,20 +522,9 @@ grub_net_dns_lookup (const char *name,
     }
   *optr++ = 0;
 
-  /* Type: A.  */
+  /* Type.  */
   *optr++ = 0;
-  *optr++ = 1;
-
-  /* Class.  */
-  *optr++ = 0;
-  *optr++ = 1;
-
-  /* Compressed name.  */
-  *optr++ = 0xc0;
-  *optr++ = 0x0c;
-  /* Type: AAAA.  */
-  *optr++ = 0;
-  *optr++ = 28;
+  qtypeptr = optr++;
 
   /* Class.  */
   *optr++ = 0;
@@ -538,7 +533,7 @@ grub_net_dns_lookup (const char *name,
   head->id = data.id;
   head->flags = FLAGS_RD;
   head->ra_z_r_code = 0;
-  head->qdcount = grub_cpu_to_be16_compile_time (2);
+  head->qdcount = grub_cpu_to_be16_compile_time (1);
   head->ancount = grub_cpu_to_be16_compile_time (0);
   head->nscount = grub_cpu_to_be16_compile_time (0);
   head->arcount = grub_cpu_to_be16_compile_time (0);
@@ -572,18 +567,33 @@ grub_net_dns_lookup (const char *name,
        goto out;
       for (j = 0; j < send_servers; j++)
        {
-         grub_err_t err2;
-         if (!sockets[j])
-           continue;
-         nb->data = nbd;
-         err2 = grub_net_send_udp_packet (sockets[j], nb);
-         if (err2)
-           {
-             grub_errno = GRUB_ERR_NONE;
-             err = err2;
-           }
-         if (*data.naddresses)
-           goto out;
+          grub_err_t err2;
+          if (!sockets[j])
+            continue;
+          nb->data = nbd;
+
+          grub_size_t t = 0;
+          do
+            {
+              if (servers[j].option == DNS_OPTION_IPV4 ||
+                 ((servers[j].option == DNS_OPTION_PREFER_IPV4) && (t++ == 0)) ||
+                 ((servers[j].option == DNS_OPTION_PREFER_IPV6) && (t++ == 1)))
+                *qtypeptr = GRUB_DNS_QTYPE_A;
+              else
+                *qtypeptr = GRUB_DNS_QTYPE_AAAA;
+
+              grub_dprintf ("dns", "QTYPE: %u QNAME: %s\n", *qtypeptr, name);
+
+              err2 = grub_net_send_udp_packet (sockets[j], nb);
+              if (err2)
+                {
+                  grub_errno = GRUB_ERR_NONE;
+                  err = err2;
+                }
+              if (*data.naddresses)
+                goto out;
+            }
+          while (t == 1);
        }
       grub_net_poll_cards (200, &data.stop);
     }
@@ -615,22 +625,28 @@ grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)),
                   int argc, char **args)
 {
   grub_err_t err;
-  grub_size_t naddresses, i;
+  struct grub_net_network_level_address cmd_server;
+  struct grub_net_network_level_address *servers;
+  grub_size_t nservers, i, naddresses = 0;
   struct grub_net_network_level_address *addresses = 0;
   if (argc != 2 && argc != 1)
     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
   if (argc == 2)
     {
-      struct grub_net_network_level_address server;
-      err = grub_net_resolve_address (args[1], &server);
+      err = grub_net_resolve_address (args[1], &cmd_server);
       if (err)
        return err;
-      err = grub_net_dns_lookup (args[0], &server, 1, &naddresses,
-                                &addresses, 0);
+      servers = &cmd_server;
+      nservers = 1;
     }
   else
-    err = grub_net_dns_lookup (args[0], dns_servers, dns_nservers, &naddresses,
-                              &addresses, 0);
+    {
+      servers = dns_servers;
+      nservers = dns_nservers;
+    }
+
+  grub_net_dns_lookup (args[0], servers, nservers, &naddresses,
+                       &addresses, 0);
 
   for (i = 0; i < naddresses; i++)
     {
@@ -639,7 +655,9 @@ grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)),
       grub_printf ("%s\n", buf);
     }
   grub_free (addresses);
-  return GRUB_ERR_NONE;
+  if (naddresses)
+    return GRUB_ERR_NONE;
+  return grub_error (GRUB_ERR_NET_NO_DOMAIN, N_("no DNS record found"));
 }
 
 static grub_err_t
@@ -648,11 +666,32 @@ grub_cmd_list_dns (struct grub_command *cmd __attribute__ ((unused)),
                   char **args __attribute__ ((unused)))
 {
   grub_size_t i;
+  const char *strtype = "";
+
   for (i = 0; i < dns_nservers; i++)
     {
+      switch (dns_servers[i].option)
+        {
+        case DNS_OPTION_IPV4:
+          strtype = "only ipv4";
+          break;
+
+        case DNS_OPTION_IPV6:
+          strtype = "only ipv6";
+          break;
+
+        case DNS_OPTION_PREFER_IPV4:
+          strtype = "prefer ipv4";
+          break;
+
+        case DNS_OPTION_PREFER_IPV6:
+          strtype = "prefer ipv6";
+          break;
+        }
+
       char buf[GRUB_NET_MAX_STR_ADDR_LEN];
       grub_net_addr_to_str (&dns_servers[i], buf);
-      grub_printf ("%s\n", buf);
+      grub_printf ("%s (%s)\n", buf, strtype);
     }
   return GRUB_ERR_NONE;
 }
@@ -664,8 +703,24 @@ grub_cmd_add_dns (struct grub_command *cmd __attribute__ ((unused)),
   grub_err_t err;
   struct grub_net_network_level_address server;
 
-  if (argc != 1)
+  if ((argc < 1) || (argc > 2))
     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+  else if (argc == 1)
+    server.option = DNS_OPTION_PREFER_IPV4;
+  else
+    {
+      if (grub_strcmp (args[1], "--only-ipv4") == 0)
+          server.option = DNS_OPTION_IPV4;
+      else if (grub_strcmp (args[1], "--only-ipv6") == 0)
+          server.option = DNS_OPTION_IPV6;
+      else if (grub_strcmp (args[1], "--prefer-ipv4") == 0)
+          server.option = DNS_OPTION_PREFER_IPV4;
+      else if (grub_strcmp (args[1], "--prefer-ipv6") == 0)
+          server.option = DNS_OPTION_PREFER_IPV6;
+      else
+        return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid argument"));
+    }
+
   err = grub_net_resolve_address (args[0], &server);
   if (err)
     return err;
index 1bd7af2f6d4ef5d7fe03d707e5e1b4ffb7eda50d..788516a2d25bcf9e907454007098cad984a403b6 100644 (file)
@@ -156,6 +156,14 @@ typedef enum grub_network_level_protocol_id
   GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
 } grub_network_level_protocol_id_t;
 
+typedef enum
+{
+  DNS_OPTION_IPV4,
+  DNS_OPTION_IPV6,
+  DNS_OPTION_PREFER_IPV4,
+  DNS_OPTION_PREFER_IPV6
+} grub_dns_option_t;
+
 typedef struct grub_net_network_level_address
 {
   grub_network_level_protocol_id_t type;
@@ -164,6 +172,7 @@ typedef struct grub_net_network_level_address
     grub_uint32_t ipv4;
     grub_uint64_t ipv6[2];
   };
+  grub_dns_option_t option;
 } grub_net_network_level_address_t;
 
 typedef struct grub_net_network_level_netaddress