From 723c3174e4b3ab02f3dbc771c43d7486915e3fd9 Mon Sep 17 00:00:00 2001 From: Andrei Borzenkov Date: Thu, 7 Mar 2019 15:14:15 +0000 Subject: [PATCH] net/dhcp: Actually send out DHCPv4 DISCOVER and REQUEST messages Even though we were parsing some DHCP options sent by the server, so far we are only using the BOOTP 2-way handshake, even when talking to a DHCP server. Change this by actually sending out DHCP DISCOVER packets instead of the generic (mostly empty) BOOTP BOOTREQUEST packets. A pure BOOTP server would ignore the extra DHCP options in the DISCOVER packet and would just reply with a BOOTREPLY packet, which we also handle in the code. Signed-off-by: Andre Przywara Reviewed-by: Daniel Kiper --- grub-core/net/bootp.c | 139 ++++++++++++++++++++++++++++++++++++------ include/grub/net.h | 2 + 2 files changed, 123 insertions(+), 18 deletions(-) diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c index d6b28576a..7e0b2b1f2 100644 --- a/grub-core/net/bootp.c +++ b/grub-core/net/bootp.c @@ -35,14 +35,52 @@ #error "unknown bootp architecture" #endif -static grub_uint8_t dhcp_option_header[] = {GRUB_NET_BOOTP_RFC1048_MAGIC_0, - GRUB_NET_BOOTP_RFC1048_MAGIC_1, - GRUB_NET_BOOTP_RFC1048_MAGIC_2, - GRUB_NET_BOOTP_RFC1048_MAGIC_3}; static grub_uint8_t grub_userclass[] = {0x4D, 0x06, 0x05, 'G', 'R', 'U', 'B', '2'}; static grub_uint8_t grub_dhcpdiscover[] = {0x35, 0x01, 0x01}; static grub_uint8_t grub_dhcptime[] = {0x33, 0x04, 0x00, 0x00, 0x0e, 0x10}; +struct grub_dhcp_discover_options +{ + grub_uint8_t magic[4]; + struct + { + grub_uint8_t code; + grub_uint8_t len; + grub_uint8_t data; + } GRUB_PACKED message_type; + grub_uint8_t end; +} GRUB_PACKED; + +struct grub_dhcp_request_options +{ + grub_uint8_t magic[4]; + struct + { + grub_uint8_t code; + grub_uint8_t len; + grub_uint8_t data; + } GRUB_PACKED message_type; + struct + { + grub_uint8_t type; + grub_uint8_t len; + grub_uint32_t data; + } GRUB_PACKED server_identifier; + struct + { + grub_uint8_t type; + grub_uint8_t len; + grub_uint32_t data; + } GRUB_PACKED requested_ip; + struct + { + grub_uint8_t type; + grub_uint8_t len; + grub_uint8_t data[7]; + } GRUB_PACKED parameter_request; + grub_uint8_t end; +} GRUB_PACKED; + enum { GRUB_DHCP_OPT_OVERLOAD_FILE = 1, @@ -61,9 +99,6 @@ enum GRUB_DHCP_MESSAGE_INFORM, }; -/* Max timeout when waiting for BOOTP/DHCP reply */ -#define GRUB_DHCP_MAX_PACKET_TIMEOUT 32 - #define GRUB_BOOTP_MAX_OPTIONS_SIZE 64 /* Max timeout when waiting for BOOTP/DHCP reply */ @@ -405,35 +440,102 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) grub_net_link_level_address_t ll_target; grub_uint8_t *offset; - nb = grub_netbuff_alloc (sizeof (*pack) + sizeof(dhcp_option_header) - + sizeof(grub_userclass) + static struct grub_dhcp_discover_options discover_options = + { + { + GRUB_NET_BOOTP_RFC1048_MAGIC_0, + GRUB_NET_BOOTP_RFC1048_MAGIC_1, + GRUB_NET_BOOTP_RFC1048_MAGIC_2, + GRUB_NET_BOOTP_RFC1048_MAGIC_3, + }, + { + GRUB_NET_DHCP_MESSAGE_TYPE, + sizeof (discover_options.message_type.data), + GRUB_DHCP_MESSAGE_DISCOVER, + }, + GRUB_NET_BOOTP_END, + }; + + static struct grub_dhcp_request_options request_options = + { + { + GRUB_NET_BOOTP_RFC1048_MAGIC_0, + GRUB_NET_BOOTP_RFC1048_MAGIC_1, + GRUB_NET_BOOTP_RFC1048_MAGIC_2, + GRUB_NET_BOOTP_RFC1048_MAGIC_3, + }, + { + GRUB_NET_DHCP_MESSAGE_TYPE, + sizeof (request_options.message_type.data), + GRUB_DHCP_MESSAGE_REQUEST, + }, + { + GRUB_NET_DHCP_SERVER_IDENTIFIER, + sizeof (request_options.server_identifier.data), + 0, + }, + { + GRUB_NET_DHCP_REQUESTED_IP_ADDRESS, + sizeof (request_options.requested_ip.data), + 0, + }, + { + GRUB_NET_DHCP_PARAMETER_REQUEST_LIST, + sizeof (request_options.parameter_request.data), + { + GRUB_NET_BOOTP_NETMASK, + GRUB_NET_BOOTP_ROUTER, + GRUB_NET_BOOTP_DNS, + GRUB_NET_BOOTP_DOMAIN, + GRUB_NET_BOOTP_HOSTNAME, + GRUB_NET_BOOTP_ROOT_PATH, + GRUB_NET_BOOTP_EXTENSIONS_PATH, + }, + }, + GRUB_NET_BOOTP_END, + }; + + COMPILE_TIME_ASSERT (sizeof (discover_options) <= GRUB_BOOTP_MAX_OPTIONS_SIZE); + COMPILE_TIME_ASSERT (sizeof (request_options) <= GRUB_BOOTP_MAX_OPTIONS_SIZE); + + nb = grub_netbuff_alloc (sizeof (*pack) + sizeof(grub_userclass) + sizeof(grub_dhcpdiscover) + sizeof(grub_dhcptime) + GRUB_BOOTP_MAX_OPTIONS_SIZE + 128); if (!nb) return grub_errno; - err = grub_netbuff_reserve (nb, sizeof (*pack) + sizeof(dhcp_option_header) - + sizeof(grub_userclass) + err = grub_netbuff_reserve (nb, sizeof (*pack) + sizeof(grub_userclass) + sizeof(grub_dhcpdiscover) + sizeof(grub_dhcptime) + GRUB_BOOTP_MAX_OPTIONS_SIZE + 128); if (err) goto out; - err = grub_netbuff_push (nb, sizeof(dhcp_option_header) - + sizeof(grub_userclass) + err = grub_netbuff_push (nb, sizeof(grub_userclass) + sizeof(grub_dhcpdiscover) + sizeof(grub_dhcptime) + GRUB_BOOTP_MAX_OPTIONS_SIZE); if (err) goto out; - grub_memset (nb->data, 0, sizeof(dhcp_option_header) - + sizeof(grub_userclass) + grub_memset (nb->data, 0, sizeof(grub_userclass) + sizeof(grub_dhcpdiscover) + sizeof(grub_dhcptime) + GRUB_BOOTP_MAX_OPTIONS_SIZE); + if (!iface->srv_id) + { + grub_memcpy (nb->data, &discover_options, sizeof (discover_options)); + } + else + { + struct grub_dhcp_request_options *ro = (struct grub_dhcp_request_options *) nb->data; + + grub_memcpy (nb->data, &request_options, sizeof (request_options)); + /* my_ip and srv_id are stored in network order so do not need conversion. */ + grub_set_unaligned32 (&ro->server_identifier.data, iface->srv_id); + grub_set_unaligned32 (&ro->requested_ip.data, iface->my_ip); + } err = grub_netbuff_push (nb, sizeof (*pack)); if (err) @@ -451,12 +553,13 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) t = 0; } pack->seconds = grub_cpu_to_be16 (t); - pack->ident = grub_cpu_to_be32 (t); + if (!iface->srv_id) + iface->xid = pack->ident = grub_cpu_to_be32 (t); + else + pack->ident = iface->xid; grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, 6); offset = (grub_uint8_t *)&pack->vendor; - grub_memcpy (offset, dhcp_option_header, sizeof(dhcp_option_header)); - offset += sizeof(dhcp_option_header); grub_memcpy (offset, grub_dhcpdiscover, sizeof(grub_dhcpdiscover)); offset += sizeof(grub_dhcpdiscover); grub_memcpy (offset, grub_userclass, sizeof(grub_userclass)); diff --git a/include/grub/net.h b/include/grub/net.h index 85964a0ab..65d442537 100644 --- a/include/grub/net.h +++ b/include/grub/net.h @@ -463,9 +463,11 @@ enum GRUB_NET_BOOTP_DOMAIN = 0x0f, GRUB_NET_BOOTP_ROOT_PATH = 0x11, GRUB_NET_BOOTP_EXTENSIONS_PATH = 0x12, + GRUB_NET_DHCP_REQUESTED_IP_ADDRESS = 50, GRUB_NET_DHCP_OVERLOAD = 52, GRUB_NET_DHCP_MESSAGE_TYPE = 53, GRUB_NET_DHCP_SERVER_IDENTIFIER = 54, + GRUB_NET_DHCP_PARAMETER_REQUEST_LIST = 55, GRUB_NET_DHCP_TFTP_SERVER_NAME = 66, GRUB_NET_DHCP_BOOTFILE_NAME = 67, GRUB_NET_BOOTP_END = 0xff