Allow specifying port numbers for http and tftp paths and allow ipv6 addresses to be recognized with brackets around them, which is required to specify a port number.
Co-authored-by: Aaron Miller <aaronmil...@fb.com> Signed-off-by: Aaron Miller <aaronmil...@fb.com> Co-authored-by: Peter Jones <pjo...@redhat.com> Signed-off-by: Peter Jones <pjo...@redhat.com> Signed-off-by: Robbie Harwood <rharw...@redhat.com> --- docs/grub.texi | 12 +++++++ grub-core/net/http.c | 18 ++++++++--- grub-core/net/net.c | 77 +++++++++++++++++++++++++++++++++++++++++--- grub-core/net/tftp.c | 6 +++- include/grub/net.h | 1 + 5 files changed, 104 insertions(+), 10 deletions(-) diff --git a/docs/grub.texi b/docs/grub.texi index 73f4d8c017..bca1407bf3 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -3057,6 +3057,18 @@ environment variable @samp{net_default_server} is used. Before using the network drive, you must initialize the network. @xref{Network}, for more information. +When using @samp{http} or @samp{tftp}, ports other than @samp{80} can be +specified using a colon (@samp{:}) after the address. To avoid parsing +conflicts, when using IPv6 addresses with custom ports, the addresses +must be enclosed with square brackets (@samp{[]}), as is standard +practice. + +@example +(http,example.com:31337) +(http,127.0.0.1:339) +(http,[::1]:11235) +@end example + If you boot GRUB from a CD-ROM, @samp{(cd)} is available. @xref{Making a GRUB bootable CD-ROM}, for details. diff --git a/grub-core/net/http.c b/grub-core/net/http.c index d67cad4829..df690acf67 100644 --- a/grub-core/net/http.c +++ b/grub-core/net/http.c @@ -318,12 +318,14 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) int i; struct grub_net_buff *nb; grub_err_t err; + char *server = file->device->net->server; + int port = file->device->net->port; nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE + sizeof ("GET ") - 1 + grub_strlen (data->filename) + sizeof (" HTTP/1.1\r\nHost: ") - 1 - + grub_strlen (file->device->net->server) + + grub_strlen (server) + sizeof (":XXXXXXXXXX") + sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n") - 1 + sizeof ("Range: bytes=XXXXXXXXXXXXXXXXXXXX" @@ -362,7 +364,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) sizeof (" HTTP/1.1\r\nHost: ") - 1); ptr = nb->tail; - err = grub_netbuff_put (nb, grub_strlen (file->device->net->server)); + err = grub_netbuff_put (nb, grub_strlen (server)); if (err) { grub_netbuff_free (nb); @@ -371,6 +373,12 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) grub_memcpy (ptr, file->device->net->server, grub_strlen (file->device->net->server)); + if (port) + { + ptr = nb->tail; + grub_snprintf ((char *) ptr, sizeof (":XXXXXXXXXX"), ":%d", port); + } + ptr = nb->tail; err = grub_netbuff_put (nb, sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n") @@ -396,8 +404,10 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) grub_netbuff_put (nb, 2); grub_memcpy (ptr, "\r\n", 2); - data->sock = grub_net_tcp_open (file->device->net->server, - HTTP_PORT, http_receive, + grub_dprintf ("http", "opening path %s on host %s TCP port %d\n", + data->filename, server, port ? port : HTTP_PORT); + data->sock = grub_net_tcp_open (server, + port ? port : HTTP_PORT, http_receive, http_err, NULL, file); if (!data->sock) diff --git a/grub-core/net/net.c b/grub-core/net/net.c index 7046dc5789..03a3063ca2 100644 --- a/grub-core/net/net.c +++ b/grub-core/net/net.c @@ -443,6 +443,13 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) grub_uint16_t newip[8]; const char *ptr = val; int word, quaddot = -1; + bool bracketed = false; + + if (ptr[0] == '[') + { + bracketed = true; + ptr++; + } if (ptr[0] == ':' && ptr[1] != ':') return 0; @@ -481,6 +488,8 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); } grub_memcpy (ip, newip, 16); + if (bracketed && *ptr == ']') + ptr++; if (rest) *rest = ptr; return 1; @@ -1319,8 +1328,10 @@ grub_net_open_real (const char *name) { grub_net_app_level_t proto; const char *protname, *server; + char *host, *port_start; grub_size_t protnamelen; int try; + int port = 0; if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) { @@ -1358,6 +1369,62 @@ grub_net_open_real (const char *name) return NULL; } + /* ipv6 or port specified? */ + if ((port_start = grub_strchr (server, ':'))) + { + char *ipv6_begin; + if ((ipv6_begin = grub_strchr (server, '['))) + { + char *ipv6_end = grub_strchr (server, ']'); + if (!ipv6_end) + { + grub_error (GRUB_ERR_NET_BAD_ADDRESS, N_("mismatched [ in address")); + return NULL; + } + /* port number after bracketed ipv6 addr */ + if (ipv6_end[1] == ':') + { + port = grub_strtoul (ipv6_end + 2, NULL, 10); + if (port == 0 || port > 65535) + { + grub_error (GRUB_ERR_NET_BAD_ADDRESS, N_("bad port number")); + return NULL; + } + } + host = grub_strndup (ipv6_begin, (ipv6_end - ipv6_begin) + 1); + } + else + { + if (grub_strchr (port_start + 1, ':')) + { + int iplen = grub_strlen (server); + /* bracket bare ipv6 addrs */ + host = grub_malloc (iplen + 3); + if (!host) + return NULL; + host[0] = '['; + grub_memcpy (host + 1, server, iplen); + host[iplen + 1] = ']'; + host[iplen + 2] = '\0'; + } + else + { + /* hostname:port or ipv4:port */ + port = grub_strtol (port_start + 1, NULL, 10); + if (port == 0 || port > 65535) + { + grub_error (GRUB_ERR_NET_BAD_ADDRESS, N_("bad port number")); + return NULL; + } + host = grub_strndup (server, port_start - server); + } + } + } + else + host = grub_strdup (server); + if (!host) + return NULL; + for (try = 0; try < 2; try++) { FOR_NET_APP_LEVEL (proto) @@ -1367,14 +1434,13 @@ grub_net_open_real (const char *name) { grub_net_t ret = grub_zalloc (sizeof (*ret)); if (!ret) - return NULL; - ret->protocol = proto; - ret->server = grub_strdup (server); - if (!ret->server) { - grub_free (ret); + grub_free (host); return NULL; } + ret->protocol = proto; + ret->port = port; + ret->server = host; ret->fs = &grub_net_fs; return ret; } @@ -1449,6 +1515,7 @@ grub_net_open_real (const char *name) grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"), name); + grub_free (host); return NULL; } diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c index 7dbd3056d6..409b1d09bc 100644 --- a/grub-core/net/tftp.c +++ b/grub-core/net/tftp.c @@ -295,6 +295,7 @@ tftp_open (struct grub_file *file, const char *filename) grub_err_t err; grub_uint8_t *nbd; grub_net_network_level_address_t addr; + int port = file->device->net->port; data = grub_zalloc (sizeof (*data)); if (!data) @@ -361,12 +362,15 @@ tftp_open (struct grub_file *file, const char *filename) err = grub_net_resolve_address (file->device->net->server, &addr); if (err) { + grub_dprintf ("tftp", "Address resolution failed: %d\n", err); + grub_dprintf ("tftp", "file_size is %" PRIuGRUB_UINT64_T ", block_size is %" PRIuGRUB_UINT32_T "\n", + data->file_size, data->block_size); grub_free (data); return err; } data->sock = grub_net_udp_open (addr, - TFTP_SERVER_PORT, tftp_receive, + port ? port : TFTP_SERVER_PORT, tftp_receive, file); if (!data->sock) { diff --git a/include/grub/net.h b/include/grub/net.h index 79cba357ae..844e501c12 100644 --- a/include/grub/net.h +++ b/include/grub/net.h @@ -271,6 +271,7 @@ typedef struct grub_net { char *server; char *name; + grub_uint16_t port; grub_net_app_level_t protocol; grub_net_packets_t packs; grub_off_t offset; -- 2.40.0 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel