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 <aaronmiller@fb.com>
Signed-off-by: Aaron Miller <aaronmiller@fb.com>
Co-authored-by: Peter Jones <pjones@redhat.com>
Signed-off-by: Peter Jones <pjones@redhat.com>
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
This commit is contained in:
authored and Daniel Kiper committed 2023-05-16 17:26:28 +02:00
1 parent 52061b2cf4
commit 26cfaa8a90
5 files changed
+111 -10

No files matched your search

+12
View File
@@ -3057,6 +3057,18 @@ environment variable @samp{net_default_server} is used.
Before using the network drive, you must initialize the network. Before using the network drive, you must initialize the network.
@xref{Network}, for more information. @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 If you boot GRUB from a CD-ROM, @samp{(cd)} is available. @xref{Making
a GRUB bootable CD-ROM}, for details. a GRUB bootable CD-ROM}, for details.
+14 -4
View File
@@ -318,12 +318,14 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
int i; int i;
struct grub_net_buff *nb; struct grub_net_buff *nb;
grub_err_t err; 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 nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE
+ sizeof ("GET ") - 1 + sizeof ("GET ") - 1
+ grub_strlen (data->filename) + grub_strlen (data->filename)
+ sizeof (" HTTP/1.1\r\nHost: ") - 1 + sizeof (" HTTP/1.1\r\nHost: ") - 1
+ grub_strlen (file->device->net->server) + grub_strlen (server) + sizeof (":XXXXXXXXXX")
+ sizeof ("\r\nUser-Agent: " PACKAGE_STRING + sizeof ("\r\nUser-Agent: " PACKAGE_STRING
"\r\n") - 1 "\r\n") - 1
+ sizeof ("Range: bytes=XXXXXXXXXXXXXXXXXXXX" + 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); sizeof (" HTTP/1.1\r\nHost: ") - 1);
ptr = nb->tail; ptr = nb->tail;
err = grub_netbuff_put (nb, grub_strlen (file->device->net->server)); err = grub_netbuff_put (nb, grub_strlen (server));
if (err) if (err)
{ {
grub_netbuff_free (nb); 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_memcpy (ptr, file->device->net->server,
grub_strlen (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; ptr = nb->tail;
err = grub_netbuff_put (nb, err = grub_netbuff_put (nb,
sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n") 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_netbuff_put (nb, 2);
grub_memcpy (ptr, "\r\n", 2); grub_memcpy (ptr, "\r\n", 2);
data->sock = grub_net_tcp_open (file->device->net->server, grub_dprintf ("http", "opening path %s on host %s TCP port %d\n",
HTTP_PORT, http_receive, data->filename, server, port ? port : HTTP_PORT);
data->sock = grub_net_tcp_open (server,
port ? port : HTTP_PORT, http_receive,
http_err, NULL, http_err, NULL,
file); file);
if (!data->sock) if (!data->sock)
+79 -5
View File
@@ -443,6 +443,13 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
grub_uint16_t newip[8]; grub_uint16_t newip[8];
const char *ptr = val; const char *ptr = val;
int word, quaddot = -1; int word, quaddot = -1;
bool bracketed = false;
if (ptr[0] == '[')
{
bracketed = true;
ptr++;
}
if (ptr[0] == ':' && ptr[1] != ':') if (ptr[0] == ':' && ptr[1] != ':')
return 0; 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_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
} }
grub_memcpy (ip, newip, 16); grub_memcpy (ip, newip, 16);
if (bracketed && *ptr == ']')
ptr++;
if (rest) if (rest)
*rest = ptr; *rest = ptr;
return 1; return 1;
@@ -1319,8 +1328,10 @@ grub_net_open_real (const char *name)
{ {
grub_net_app_level_t proto; grub_net_app_level_t proto;
const char *protname, *server; const char *protname, *server;
char *host, *port_start;
grub_size_t protnamelen; grub_size_t protnamelen;
int try; int try;
int port = 0;
if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
{ {
@@ -1358,6 +1369,69 @@ grub_net_open_real (const char *name)
return NULL; 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 (try = 0; try < 2; try++)
{ {
FOR_NET_APP_LEVEL (proto) FOR_NET_APP_LEVEL (proto)
@@ -1367,14 +1441,13 @@ grub_net_open_real (const char *name)
{ {
grub_net_t ret = grub_zalloc (sizeof (*ret)); grub_net_t ret = grub_zalloc (sizeof (*ret));
if (!ret) if (!ret)
return NULL;
ret->protocol = proto;
ret->server = grub_strdup (server);
if (!ret->server)
{ {
grub_free (ret); grub_free (host);
return NULL; return NULL;
} }
ret->protocol = proto;
ret->port = port;
ret->server = host;
ret->fs = &grub_net_fs; ret->fs = &grub_net_fs;
return ret; return ret;
} }
@@ -1449,6 +1522,7 @@ grub_net_open_real (const char *name)
grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"), grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"),
name); name);
grub_free (host);
return NULL; return NULL;
} }
+5 -1
View File
@@ -295,6 +295,7 @@ tftp_open (struct grub_file *file, const char *filename)
grub_err_t err; grub_err_t err;
grub_uint8_t *nbd; grub_uint8_t *nbd;
grub_net_network_level_address_t addr; grub_net_network_level_address_t addr;
int port = file->device->net->port;
data = grub_zalloc (sizeof (*data)); data = grub_zalloc (sizeof (*data));
if (!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); err = grub_net_resolve_address (file->device->net->server, &addr);
if (err) 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); grub_free (data);
return err; return err;
} }
data->sock = grub_net_udp_open (addr, data->sock = grub_net_udp_open (addr,
TFTP_SERVER_PORT, tftp_receive, port ? port : TFTP_SERVER_PORT, tftp_receive,
file); file);
if (!data->sock) if (!data->sock)
{ {
+1
View File
@@ -271,6 +271,7 @@ typedef struct grub_net
{ {
char *server; char *server;
char *name; char *name;
grub_uint16_t port;
grub_net_app_level_t protocol; grub_net_app_level_t protocol;
grub_net_packets_t packs; grub_net_packets_t packs;
grub_off_t offset; grub_off_t offset;