From: Robbie Harwood Date: Tue, 25 Apr 2023 15:05:13 +0000 (-0400) Subject: net: Read bracketed IPv6 addrs and port numbers X-Git-Tag: grub-2.12-rc1~90 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=26cfaa8a90f5a0294bedd53c9d856b8bca4af0e9;p=thirdparty%2Fgrub.git net: Read bracketed IPv6 addrs and port numbers 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 Signed-off-by: Aaron Miller Co-authored-by: Peter Jones Signed-off-by: Peter Jones Signed-off-by: Robbie Harwood Reviewed-by: Daniel Kiper --- diff --git a/docs/grub.texi b/docs/grub.texi index 73f4d8c01..36f8d0a96 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,grub.example.com:31337) +(http,192.0.2.1:339) +(http,[2001:db8::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 d67cad482..df690acf6 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 7046dc578..8cad4fb6d 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,69 @@ 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 addr. */ + 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 +1441,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 +1522,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 7dbd3056d..409b1d09b 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 79cba357a..844e501c1 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;