Blame SOURCES/0250-net-read-bracketed-ipv6-addrs-and-port-numbers.patch

a85e8e
From fc71f52ca2ea207a692b79819502bb1738c5d148 Mon Sep 17 00:00:00 2001
a85e8e
From: Aaron Miller <aaronmiller@fb.com>
a85e8e
Date: Fri, 29 Jul 2016 17:41:38 +0800
a85e8e
Subject: [PATCH 250/260] net: read bracketed ipv6 addrs and port numbers
a85e8e
a85e8e
Allow specifying port numbers for http and tftp paths, and allow ipv6 addresses
a85e8e
to be recognized with brackets around them, which is required to specify a port
a85e8e
number
a85e8e
---
a85e8e
 grub-core/net/http.c | 25 +++++++++++---
a85e8e
 grub-core/net/net.c  | 94 ++++++++++++++++++++++++++++++++++++++++++++++------
a85e8e
 grub-core/net/tftp.c | 25 +++++++++++---
a85e8e
 include/grub/net.h   |  1 +
a85e8e
 4 files changed, 125 insertions(+), 20 deletions(-)
a85e8e
a85e8e
diff --git a/grub-core/net/http.c b/grub-core/net/http.c
a85e8e
index ef9538c53..e8accbe68 100644
a85e8e
--- a/grub-core/net/http.c
a85e8e
+++ b/grub-core/net/http.c
a85e8e
@@ -289,7 +289,9 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)),
a85e8e
 	  nb2 = grub_netbuff_alloc (data->chunk_rem);
a85e8e
 	  if (!nb2)
a85e8e
 	    return grub_errno;
a85e8e
-	  grub_netbuff_put (nb2, data->chunk_rem);
a85e8e
+	  err = grub_netbuff_put (nb2, data->chunk_rem);
a85e8e
+	  if (err)
a85e8e
+	    return grub_errno;
a85e8e
 	  grub_memcpy (nb2->data, nb->data, data->chunk_rem);
a85e8e
 	  if (file->device->net->packs.count >= 20)
a85e8e
 	    {
a85e8e
@@ -312,12 +314,14 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
a85e8e
   int i;
a85e8e
   struct grub_net_buff *nb;
a85e8e
   grub_err_t err;
a85e8e
+  char* server = file->device->net->server;
a85e8e
+  int port = file->device->net->port;
a85e8e
 
a85e8e
   nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE
a85e8e
 			   + sizeof ("GET ") - 1
a85e8e
 			   + grub_strlen (data->filename)
a85e8e
 			   + sizeof (" HTTP/1.1\r\nHost: ") - 1
a85e8e
-			   + grub_strlen (file->device->net->server)
a85e8e
+			   + grub_strlen (server) + sizeof (":XXXXXXXXXX")
a85e8e
 			   + sizeof ("\r\nUser-Agent: " PACKAGE_STRING
a85e8e
 				     "\r\n") - 1
a85e8e
 			   + sizeof ("Range: bytes=XXXXXXXXXXXXXXXXXXXX"
a85e8e
@@ -356,7 +360,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
a85e8e
 	       sizeof (" HTTP/1.1\r\nHost: ") - 1);
a85e8e
 
a85e8e
   ptr = nb->tail;
a85e8e
-  err = grub_netbuff_put (nb, grub_strlen (file->device->net->server));
a85e8e
+  err = grub_netbuff_put (nb, grub_strlen (server));
a85e8e
   if (err)
a85e8e
     {
a85e8e
       grub_netbuff_free (nb);
a85e8e
@@ -365,6 +369,15 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
a85e8e
   grub_memcpy (ptr, file->device->net->server,
a85e8e
 	       grub_strlen (file->device->net->server));
a85e8e
 
a85e8e
+  if (port)
a85e8e
+    {
a85e8e
+      ptr = nb->tail;
a85e8e
+      grub_snprintf ((char *) ptr,
a85e8e
+	  sizeof (":xxxxxxxxxx"),
a85e8e
+	  ":%d",
a85e8e
+	  port);
a85e8e
+    }
a85e8e
+
a85e8e
   ptr = nb->tail;
a85e8e
   err = grub_netbuff_put (nb, 
a85e8e
 			  sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n")
a85e8e
@@ -391,8 +404,10 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
a85e8e
   grub_netbuff_put (nb, 2);
a85e8e
   grub_memcpy (ptr, "\r\n", 2);
a85e8e
 
a85e8e
-  data->sock = grub_net_tcp_open (file->device->net->server,
a85e8e
-				  HTTP_PORT, http_receive,
a85e8e
+  grub_dprintf ("http", "opening path %s on host %s TCP port %d\n",
a85e8e
+		data->filename, server, port ? port : HTTP_PORT);
a85e8e
+  data->sock = grub_net_tcp_open (server,
a85e8e
+				  port ? port : HTTP_PORT, http_receive,
a85e8e
 				  http_err, NULL,
a85e8e
 				  file);
a85e8e
   if (!data->sock)
a85e8e
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
a85e8e
index b3a80ba29..6b4b10ba4 100644
a85e8e
--- a/grub-core/net/net.c
a85e8e
+++ b/grub-core/net/net.c
a85e8e
@@ -462,6 +462,13 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
a85e8e
   grub_uint16_t newip[8];
a85e8e
   const char *ptr = val;
a85e8e
   int word, quaddot = -1;
a85e8e
+  int bracketed = 0;
a85e8e
+
a85e8e
+  if (ptr[0] == '[')
a85e8e
+    {
a85e8e
+      bracketed = 1;
a85e8e
+      ptr++;
a85e8e
+    }
a85e8e
 
a85e8e
   if (ptr[0] == ':' && ptr[1] != ':')
a85e8e
     return 0;
a85e8e
@@ -500,6 +507,8 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
a85e8e
       grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
a85e8e
     }
a85e8e
   grub_memcpy (ip, newip, 16);
a85e8e
+  if (bracketed && *ptr == ']')
a85e8e
+    ptr++;
a85e8e
   if (rest)
a85e8e
     *rest = ptr;
a85e8e
   return 1;
a85e8e
@@ -1348,8 +1357,10 @@ grub_net_open_real (const char *name)
a85e8e
 {
a85e8e
   grub_net_app_level_t proto;
a85e8e
   const char *protname, *server;
a85e8e
+  char *host;
a85e8e
   grub_size_t protnamelen;
a85e8e
   int try;
a85e8e
+  int port = 0;
a85e8e
 
a85e8e
   if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
a85e8e
     {
a85e8e
@@ -1387,6 +1398,72 @@ grub_net_open_real (const char *name)
a85e8e
       return NULL;
a85e8e
     }  
a85e8e
 
a85e8e
+  char* port_start;
a85e8e
+  /* ipv6 or port specified? */
a85e8e
+  if ((port_start = grub_strchr (server, ':')))
a85e8e
+    {
a85e8e
+      char* ipv6_begin;
a85e8e
+      if((ipv6_begin = grub_strchr (server, '[')))
a85e8e
+	{
a85e8e
+	  char* ipv6_end = grub_strchr (server, ']');
a85e8e
+	  if(!ipv6_end)
a85e8e
+	    {
a85e8e
+	      grub_error (GRUB_ERR_NET_BAD_ADDRESS,
a85e8e
+		      N_("mismatched [ in address"));
a85e8e
+	      return NULL;
a85e8e
+	    }
a85e8e
+	  /* port number after bracketed ipv6 addr */
a85e8e
+	  if(ipv6_end[1] == ':')
a85e8e
+	    {
a85e8e
+	      port = grub_strtoul (ipv6_end + 2, NULL, 10);
a85e8e
+	      if(port > 65535)
a85e8e
+		{
a85e8e
+		  grub_error (GRUB_ERR_NET_BAD_ADDRESS,
a85e8e
+			  N_("bad port number"));
a85e8e
+		  return NULL;
a85e8e
+		}
a85e8e
+	    }
a85e8e
+	  host = grub_strndup (ipv6_begin, (ipv6_end - ipv6_begin) + 1);
a85e8e
+	}
a85e8e
+      else
a85e8e
+	{
a85e8e
+	  if (grub_strchr (port_start + 1, ':'))
a85e8e
+	    {
a85e8e
+	      int iplen = grub_strlen (server);
a85e8e
+	      /* bracket bare ipv6 addrs */
a85e8e
+	      host = grub_malloc (iplen + 3);
a85e8e
+	      if(!host)
a85e8e
+		{
a85e8e
+		  return NULL;
a85e8e
+		}
a85e8e
+	      host[0] = '[';
a85e8e
+	      grub_memcpy (host + 1, server, iplen);
a85e8e
+	      host[iplen + 1] = ']';
a85e8e
+	      host[iplen + 2] = '\0';
a85e8e
+	    }
a85e8e
+	  else
a85e8e
+	    {
a85e8e
+	      /* hostname:port or ipv4:port */
a85e8e
+	      port = grub_strtol (port_start + 1, NULL, 10);
a85e8e
+	      if(port > 65535)
a85e8e
+		{
a85e8e
+		  grub_error (GRUB_ERR_NET_BAD_ADDRESS,
a85e8e
+			  N_("bad port number"));
a85e8e
+		  return NULL;
a85e8e
+		}
a85e8e
+	      host = grub_strndup (server, port_start - server);
a85e8e
+	    }
a85e8e
+	}
a85e8e
+    }
a85e8e
+  else
a85e8e
+    {
a85e8e
+      host = grub_strdup (server);
a85e8e
+    }
a85e8e
+  if (!host)
a85e8e
+    {
a85e8e
+      return NULL;
a85e8e
+    }
a85e8e
+
a85e8e
   for (try = 0; try < 2; try++)
a85e8e
     {
a85e8e
       FOR_NET_APP_LEVEL (proto)
a85e8e
@@ -1396,19 +1473,13 @@ grub_net_open_real (const char *name)
a85e8e
 	  {
a85e8e
 	    grub_net_t ret = grub_zalloc (sizeof (*ret));
a85e8e
 	    if (!ret)
a85e8e
-	      return NULL;
a85e8e
-	    ret->protocol = proto;
a85e8e
-	    if (server)
a85e8e
 	      {
a85e8e
-		ret->server = grub_strdup (server);
a85e8e
-		if (!ret->server)
a85e8e
-		  {
a85e8e
-		    grub_free (ret);
a85e8e
-		    return NULL;
a85e8e
-		  }
a85e8e
+		grub_free (host);
a85e8e
+		return NULL;
a85e8e
 	      }
a85e8e
-	    else
a85e8e
-	      ret->server = NULL;
a85e8e
+	    ret->protocol = proto;
a85e8e
+	    ret->port = port;
a85e8e
+	    ret->server = host;
a85e8e
 	    ret->fs = &grub_net_fs;
a85e8e
 	    ret->offset = 0;
a85e8e
 	    ret->eof = 0;
a85e8e
@@ -1439,6 +1510,7 @@ grub_net_open_real (const char *name)
a85e8e
   grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"),
a85e8e
 	      name);
a85e8e
 
a85e8e
+  grub_free (host);
a85e8e
   return NULL;
a85e8e
 }
a85e8e
 
a85e8e
diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
a85e8e
index 3931884c6..ed12e610f 100644
a85e8e
--- a/grub-core/net/tftp.c
a85e8e
+++ b/grub-core/net/tftp.c
a85e8e
@@ -333,6 +333,7 @@ tftp_open (struct grub_file *file, const char *filename)
a85e8e
   grub_err_t err;
a85e8e
   grub_uint8_t *nbd;
a85e8e
   grub_net_network_level_address_t addr;
a85e8e
+  int port = file->device->net->port;
a85e8e
 
a85e8e
   data = grub_zalloc (sizeof (*data));
a85e8e
   if (!data)
a85e8e
@@ -345,7 +346,10 @@ tftp_open (struct grub_file *file, const char *filename)
a85e8e
   grub_netbuff_reserve (&nb, 1500);
a85e8e
   err = grub_netbuff_push (&nb, sizeof (*tftph));
a85e8e
   if (err)
a85e8e
-    return err;
a85e8e
+    {
a85e8e
+      grub_free (data);
a85e8e
+      return err;
a85e8e
+    }
a85e8e
 
a85e8e
   tftph = (struct tftphdr *) nb.data;
a85e8e
 
a85e8e
@@ -383,32 +387,43 @@ tftp_open (struct grub_file *file, const char *filename)
a85e8e
 
a85e8e
   err = grub_netbuff_unput (&nb, nb.tail - (nb.data + hdrlen));
a85e8e
   if (err)
a85e8e
-    return err;
a85e8e
+    {
a85e8e
+      grub_free (data);
a85e8e
+      return err;
a85e8e
+    }
a85e8e
 
a85e8e
   file->not_easily_seekable = 1;
a85e8e
   file->data = data;
a85e8e
 
a85e8e
   data->pq = grub_priority_queue_new (sizeof (struct grub_net_buff *), cmp);
a85e8e
   if (!data->pq)
a85e8e
-    return grub_errno;
a85e8e
+    {
a85e8e
+      grub_free (data);
a85e8e
+      return grub_errno;
a85e8e
+    }
a85e8e
 
a85e8e
   grub_dprintf("tftp", "resolving address for %s\n", file->device->net->server);
a85e8e
   err = grub_net_resolve_address (file->device->net->server, &addr);
a85e8e
   if (err)
a85e8e
     {
a85e8e
       grub_dprintf("tftp", "Address resolution failed: %d\n", err);
a85e8e
+      grub_dprintf ("tftp", "file_size is %llu, block_size is %llu\n",
a85e8e
+		    (unsigned long long)data->file_size,
a85e8e
+		    (unsigned long long)data->block_size);
a85e8e
       destroy_pq (data);
a85e8e
+      grub_free (data);
a85e8e
       return err;
a85e8e
     }
a85e8e
 
a85e8e
   grub_dprintf("tftp", "opening connection\n");
a85e8e
   data->sock = grub_net_udp_open (addr,
a85e8e
-				  TFTP_SERVER_PORT, tftp_receive,
a85e8e
+				  port ? port : TFTP_SERVER_PORT, tftp_receive,
a85e8e
 				  file);
a85e8e
   if (!data->sock)
a85e8e
     {
a85e8e
       grub_dprintf("tftp", "connection failed\n");
a85e8e
       destroy_pq (data);
a85e8e
+      grub_free (data);
a85e8e
       return grub_errno;
a85e8e
     }
a85e8e
 
a85e8e
@@ -422,6 +437,7 @@ tftp_open (struct grub_file *file, const char *filename)
a85e8e
 	{
a85e8e
 	  grub_net_udp_close (data->sock);
a85e8e
 	  destroy_pq (data);
a85e8e
+	  grub_free (data);
a85e8e
 	  return err;
a85e8e
 	}
a85e8e
       grub_net_poll_cards (GRUB_NET_INTERVAL + (i * GRUB_NET_INTERVAL_ADDITION),
a85e8e
@@ -438,6 +454,7 @@ tftp_open (struct grub_file *file, const char *filename)
a85e8e
     {
a85e8e
       grub_net_udp_close (data->sock);
a85e8e
       destroy_pq (data);
a85e8e
+      grub_free (data);
a85e8e
       return grub_errno;
a85e8e
     }
a85e8e
 
a85e8e
diff --git a/include/grub/net.h b/include/grub/net.h
a85e8e
index 0d9213d67..20e699bb0 100644
a85e8e
--- a/include/grub/net.h
a85e8e
+++ b/include/grub/net.h
a85e8e
@@ -261,6 +261,7 @@ typedef struct grub_net
a85e8e
 {
a85e8e
   char *server;
a85e8e
   char *name;
a85e8e
+  int port;
a85e8e
   grub_net_app_level_t protocol;
a85e8e
   grub_net_packets_t packs;
a85e8e
   grub_off_t offset;
a85e8e
-- 
a85e8e
2.13.0
a85e8e