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

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