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
15a2072
---
15a2072
 grub-core/net/http.c | 21 +++++++++++---
15a2072
 grub-core/net/net.c  | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++
15a2072
 grub-core/net/tftp.c |  8 ++++--
15a2072
 include/grub/net.h   |  1 +
15a2072
 4 files changed, 101 insertions(+), 6 deletions(-)
15a2072
15a2072
diff --git a/grub-core/net/http.c b/grub-core/net/http.c
15a2072
index 5aa4ad3befc..f182d7b871d 100644
15a2072
--- a/grub-core/net/http.c
15a2072
+++ b/grub-core/net/http.c
15a2072
@@ -312,12 +312,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"
15a2072
@@ -356,7 +358,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);
15a2072
@@ -365,6 +367,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")
15a2072
@@ -390,8 +401,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,
15a2072
 				  http_err, http_err,
15a2072
 				  file);
15a2072
   if (!data->sock)
15a2072
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
15a2072
index 9b8944292c7..1f887d44b32 100644
15a2072
--- a/grub-core/net/net.c
15a2072
+++ b/grub-core/net/net.c
15a2072
@@ -439,6 +439,12 @@ 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
+
15a2072
+  if (ptr[0] == '[') {
15a2072
+    bracketed = 1;
15a2072
+    ptr++;
15a2072
+  }
15a2072
 
15a2072
   if (ptr[0] == ':' && ptr[1] != ':')
15a2072
     return 0;
15a2072
@@ -477,6 +483,9 @@ 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);
15a2072
+  if (bracketed && *ptr == ']') {
15a2072
+    ptr++;
15a2072
+  }
15a2072
   if (rest)
15a2072
     *rest = ptr;
15a2072
   return 1;
15a2072
@@ -1336,8 +1345,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
     {
15a2072
@@ -1375,6 +1386,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, ':')))
15a2072
+  {
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)
15a2072
diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
15a2072
index f90071353ad..e267af354f4 100644
15a2072
--- a/grub-core/net/tftp.c
15a2072
+++ b/grub-core/net/tftp.c
15a2072
@@ -333,6 +333,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)
15a2072
@@ -405,7 +406,10 @@ 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
       destroy_pq (data);
15a2072
       grub_free (data);
15a2072
       return err;
15a2072
@@ -413,7 +417,7 @@ tftp_open (struct grub_file *file, const char *filename)
15a2072
 
15a2072
   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
15a2072
index e9ebc6a1b4f..f4cd86e582f 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;