15a2072
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
15a2072
From: Aaron Miller <aaronmiller@fb.com>
15a2072
Date: Fri, 29 Jul 2016 17:41:38 +0800
15a2072
Subject: [PATCH] net: read bracketed ipv6 addrs and port numbers
15a2072
15a2072
Allow specifying port numbers for http and tftp paths, and allow ipv6 addresses
15a2072
to be recognized with brackets around them, which is required to specify a port
15a2072
number
7e98da0
7e98da0
Signed-off-by: Aaron Miller <aaronmiller@fb.com>
7e98da0
[pjones: various bug fixes]
7e98da0
Signed-off-by: Peter Jones <pjones@redhat.com>
15a2072
---
46968b6
 grub-core/net/http.c | 25 ++++++++++++---
7e98da0
 grub-core/net/net.c  | 87 +++++++++++++++++++++++++++++++++++++++++++++++++---
7e98da0
 grub-core/net/tftp.c |  8 +++--
15a2072
 include/grub/net.h   |  1 +
46968b6
 4 files changed, 109 insertions(+), 12 deletions(-)
15a2072
15a2072
diff --git a/grub-core/net/http.c b/grub-core/net/http.c
46968b6
index b616cf40b1e..12a2632ea55 100644
15a2072
--- a/grub-core/net/http.c
15a2072
+++ b/grub-core/net/http.c
7e98da0
@@ -289,7 +289,9 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)),
7e98da0
 	  nb2 = grub_netbuff_alloc (data->chunk_rem);
7e98da0
 	  if (!nb2)
7e98da0
 	    return grub_errno;
7e98da0
-	  grub_netbuff_put (nb2, data->chunk_rem);
7e98da0
+	  err = grub_netbuff_put (nb2, data->chunk_rem);
7e98da0
+	  if (err)
7e98da0
+	    return grub_errno;
7e98da0
 	  grub_memcpy (nb2->data, nb->data, data->chunk_rem);
7e98da0
 	  if (file->device->net->packs.count >= 20)
7e98da0
 	    {
7e98da0
@@ -312,12 +314,14 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
15a2072
   int i;
15a2072
   struct grub_net_buff *nb;
15a2072
   grub_err_t err;
15a2072
+  char* server = file->device->net->server;
15a2072
+  int port = file->device->net->port;
15a2072
 
15a2072
   nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE
15a2072
 			   + sizeof ("GET ") - 1
15a2072
 			   + grub_strlen (data->filename)
15a2072
 			   + sizeof (" HTTP/1.1\r\nHost: ") - 1
15a2072
-			   + grub_strlen (file->device->net->server)
15a2072
+			   + grub_strlen (server) + sizeof (":XXXXXXXXXX")
15a2072
 			   + sizeof ("\r\nUser-Agent: " PACKAGE_STRING
15a2072
 				     "\r\n") - 1
15a2072
 			   + sizeof ("Range: bytes=XXXXXXXXXXXXXXXXXXXX"
7e98da0
@@ -356,7 +360,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
15a2072
 	       sizeof (" HTTP/1.1\r\nHost: ") - 1);
15a2072
 
15a2072
   ptr = nb->tail;
15a2072
-  err = grub_netbuff_put (nb, grub_strlen (file->device->net->server));
15a2072
+  err = grub_netbuff_put (nb, grub_strlen (server));
15a2072
   if (err)
15a2072
     {
15a2072
       grub_netbuff_free (nb);
7e98da0
@@ -365,6 +369,15 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
15a2072
   grub_memcpy (ptr, file->device->net->server,
15a2072
 	       grub_strlen (file->device->net->server));
15a2072
 
15a2072
+  if (port)
15a2072
+    {
15a2072
+      ptr = nb->tail;
15a2072
+      grub_snprintf ((char *) ptr,
15a2072
+	  sizeof (":XXXXXXXXXX"),
15a2072
+	  ":%d",
15a2072
+	  port);
15a2072
+    }
15a2072
+
15a2072
   ptr = nb->tail;
15a2072
   err = grub_netbuff_put (nb, 
15a2072
 			  sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n")
46968b6
@@ -390,8 +403,10 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
15a2072
   grub_netbuff_put (nb, 2);
15a2072
   grub_memcpy (ptr, "\r\n", 2);
15a2072
 
15a2072
-  data->sock = grub_net_tcp_open (file->device->net->server,
15a2072
-				  HTTP_PORT, http_receive,
15a2072
+  grub_dprintf ("http", "opening path %s on host %s TCP port %d\n",
15a2072
+		data->filename, server, port ? port : HTTP_PORT);
15a2072
+  data->sock = grub_net_tcp_open (server,
15a2072
+				  port ? port : HTTP_PORT, http_receive,
46968b6
 				  http_err, NULL,
15a2072
 				  file);
15a2072
   if (!data->sock)
15a2072
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
46968b6
index a46f82362ed..0ce5e675ed7 100644
15a2072
--- a/grub-core/net/net.c
15a2072
+++ b/grub-core/net/net.c
46968b6
@@ -444,6 +444,13 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
15a2072
   grub_uint16_t newip[8];
15a2072
   const char *ptr = val;
15a2072
   int word, quaddot = -1;
15a2072
+  int bracketed = 0;
15a2072
+
7e98da0
+  if (ptr[0] == '[')
7e98da0
+    {
7e98da0
+      bracketed = 1;
7e98da0
+      ptr++;
7e98da0
+    }
15a2072
 
15a2072
   if (ptr[0] == ':' && ptr[1] != ':')
15a2072
     return 0;
46968b6
@@ -482,6 +489,8 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
15a2072
       grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
15a2072
     }
15a2072
   grub_memcpy (ip, newip, 16);
7e98da0
+  if (bracketed && *ptr == ']')
15a2072
+    ptr++;
15a2072
   if (rest)
15a2072
     *rest = ptr;
15a2072
   return 1;
46968b6
@@ -1343,8 +1352,10 @@ grub_net_open_real (const char *name)
15a2072
 {
15a2072
   grub_net_app_level_t proto;
15a2072
   const char *protname, *server;
15a2072
+  char *host;
15a2072
   grub_size_t protnamelen;
15a2072
   int try;
15a2072
+  int port = 0;
15a2072
 
15a2072
   if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
15a2072
     {
46968b6
@@ -1382,6 +1393,72 @@ grub_net_open_real (const char *name)
15a2072
       return NULL;
15a2072
     }  
15a2072
 
15a2072
+  char* port_start;
15a2072
+  /* ipv6 or port specified? */
15a2072
+  if ((port_start = grub_strchr (server, ':')))
7e98da0
+    {
15a2072
+      char* ipv6_begin;
15a2072
+      if((ipv6_begin = grub_strchr (server, '[')))
15a2072
+	{
15a2072
+	  char* ipv6_end = grub_strchr (server, ']');
15a2072
+	  if(!ipv6_end)
15a2072
+	    {
15a2072
+	      grub_error (GRUB_ERR_NET_BAD_ADDRESS,
15a2072
+		      N_("mismatched [ in address"));
15a2072
+	      return NULL;
15a2072
+	    }
15a2072
+	  /* port number after bracketed ipv6 addr */
15a2072
+	  if(ipv6_end[1] == ':')
15a2072
+	    {
15a2072
+	      port = grub_strtoul (ipv6_end + 2, NULL, 10);
15a2072
+	      if(port > 65535)
15a2072
+		{
15a2072
+		  grub_error (GRUB_ERR_NET_BAD_ADDRESS,
15a2072
+			  N_("bad port number"));
15a2072
+		  return NULL;
15a2072
+		}
15a2072
+	    }
15a2072
+	  host = grub_strndup (ipv6_begin, (ipv6_end - ipv6_begin) + 1);
15a2072
+	}
15a2072
+      else
15a2072
+	{
15a2072
+	  if (grub_strchr (port_start + 1, ':'))
15a2072
+	    {
15a2072
+	      int iplen = grub_strlen (server);
15a2072
+	      /* bracket bare ipv6 addrs */
15a2072
+	      host = grub_malloc (iplen + 3);
15a2072
+	      if(!host)
15a2072
+		{
15a2072
+		  return NULL;
15a2072
+		}
15a2072
+	      host[0] = '[';
15a2072
+	      grub_memcpy (host + 1, server, iplen);
15a2072
+	      host[iplen + 1] = ']';
15a2072
+	      host[iplen + 2] = '\0';
15a2072
+	    }
15a2072
+	  else
15a2072
+	    {
15a2072
+	      /* hostname:port or ipv4:port */
15a2072
+	      port = grub_strtol (port_start + 1, NULL, 10);
15a2072
+	      if(port > 65535)
15a2072
+		{
15a2072
+		  grub_error (GRUB_ERR_NET_BAD_ADDRESS,
15a2072
+			  N_("bad port number"));
15a2072
+		  return NULL;
15a2072
+		}
15a2072
+	      host = grub_strndup (server, port_start - server);
15a2072
+	    }
15a2072
+	}
15a2072
+    }
15a2072
+  else
15a2072
+    {
15a2072
+      host = grub_strdup (server);
15a2072
+    }
15a2072
+  if (!host)
15a2072
+    {
15a2072
+      return NULL;
15a2072
+    }
15a2072
+
15a2072
   for (try = 0; try < 2; try++)
15a2072
     {
15a2072
       FOR_NET_APP_LEVEL (proto)
46968b6
@@ -1391,14 +1468,13 @@ grub_net_open_real (const char *name)
7e98da0
 	  {
7e98da0
 	    grub_net_t ret = grub_zalloc (sizeof (*ret));
7e98da0
 	    if (!ret)
7e98da0
-	      return NULL;
7e98da0
-	    ret->protocol = proto;
7e98da0
-	    ret->server = grub_strdup (server);
7e98da0
-	    if (!ret->server)
7e98da0
 	      {
7e98da0
-		grub_free (ret);
7e98da0
+		grub_free (host);
7e98da0
 		return NULL;
7e98da0
 	      }
7e98da0
+	    ret->protocol = proto;
7e98da0
+	    ret->port = port;
7e98da0
+	    ret->server = host;
7e98da0
 	    ret->fs = &grub_net_fs;
7e98da0
 	    return ret;
7e98da0
 	  }
46968b6
@@ -1473,6 +1549,7 @@ grub_net_open_real (const char *name)
7e98da0
   grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"),
7e98da0
 	      name);
7e98da0
 
7e98da0
+  grub_free (host);
7e98da0
   return NULL;
7e98da0
 }
7e98da0
 
15a2072
diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
46968b6
index 4ab2f5c7357..d54b13f09ff 100644
15a2072
--- a/grub-core/net/tftp.c
15a2072
+++ b/grub-core/net/tftp.c
46968b6
@@ -295,6 +295,7 @@ tftp_open (struct grub_file *file, const char *filename)
15a2072
   grub_err_t err;
15a2072
   grub_uint8_t *nbd;
15a2072
   grub_net_network_level_address_t addr;
15a2072
+  int port = file->device->net->port;
15a2072
 
15a2072
   data = grub_zalloc (sizeof (*data));
15a2072
   if (!data)
46968b6
@@ -362,14 +363,17 @@ tftp_open (struct grub_file *file, const char *filename)
15a2072
   err = grub_net_resolve_address (file->device->net->server, &addr);
15a2072
   if (err)
15a2072
     {
15a2072
-      grub_dprintf("tftp", "Address resolution failed: %d\n", err);
15a2072
+      grub_dprintf ("tftp", "Address resolution failed: %d\n", err);
15a2072
+      grub_dprintf ("tftp", "file_size is %llu, block_size is %llu\n",
15a2072
+		    (unsigned long long)data->file_size,
15a2072
+		    (unsigned long long)data->block_size);
15a2072
       grub_free (data);
15a2072
       return err;
46968b6
     }
15a2072
 
46968b6
   grub_dprintf("tftp", "opening connection\n");
15a2072
   data->sock = grub_net_udp_open (addr,
15a2072
-				  TFTP_SERVER_PORT, tftp_receive,
15a2072
+				  port ? port : TFTP_SERVER_PORT, tftp_receive,
15a2072
 				  file);
15a2072
   if (!data->sock)
15a2072
     {
15a2072
diff --git a/include/grub/net.h b/include/grub/net.h
46968b6
index af0404db7e3..d55d505a03a 100644
15a2072
--- a/include/grub/net.h
15a2072
+++ b/include/grub/net.h
15a2072
@@ -273,6 +273,7 @@ typedef struct grub_net
15a2072
 {
15a2072
   char *server;
15a2072
   char *name;
15a2072
+  int port;
15a2072
   grub_net_app_level_t protocol;
15a2072
   grub_net_packets_t packs;
15a2072
   grub_off_t offset;