diff options
Diffstat (limited to 'libdhcp')
-rw-r--r-- | libdhcp/dhcp_client.c | 63 |
1 files changed, 36 insertions, 27 deletions
diff --git a/libdhcp/dhcp_client.c b/libdhcp/dhcp_client.c index 4c4ece3..1b4bf61 100644 --- a/libdhcp/dhcp_client.c +++ b/libdhcp/dhcp_client.c @@ -64,32 +64,24 @@ * SPDX-License-Identifier: MIT */ -/* IPv4: +/* Implemented: * - DHCPv4: https://datatracker.ietf.org/doc/html/rfc2131 - * - Auto-IP: https://datatracker.ietf.org/doc/html/rfc3927 - * - DNAv4: https://datatracker.ietf.org/doc/html/rfc4436 - * - * This implmementation does NOT support RFC 4361 and thus cannot - * support RFC 6842. - * - * - DHCPv4 node-specific client identifiers: https://datatracker.ietf.org/doc/html/rfc4361 + * - DHCPv4 long options: https://datatracker.ietf.org/doc/html/rfc3396 * - DHCPv4 client identifiers in replies: https://datatracker.ietf.org/doc/html/rfc6842 * - * This implementation does NOT support split options (originally RFC - * 2131, but clarified in RFC 3396). + * TODO: + * - AutoIPv4: https://datatracker.ietf.org/doc/html/rfc3927 + * - mDNS responder: https://datatracker.ietf.org/doc/html/rfc6762 * - * - DHCPv4 long options: https://datatracker.ietf.org/doc/html/rfc3396 + * Not implemented: + * - DHCPv4 node-specific client identifiers: https://datatracker.ietf.org/doc/html/rfc4361 + * - DNAv4: https://datatracker.ietf.org/doc/html/rfc4436 + * - LLMNR responder: https://datatracker.ietf.org/doc/html/rfc4795 * - - * IPv6: + * Not implemented, because the W5500 doesn't support IPv6: * - SLAAC: https://datatracker.ietf.org/doc/html/rfc2462 * - DNAv6: https://datatracker.ietf.org/doc/html/rfc6059 - * - * Common: - * - NetBIOS name resolution: https://datatracker.ietf.org/doc/html/rfc1001 - * https://datatracker.ietf.org/doc/html/rfc1002 - * - LLMNR: https://datatracker.ietf.org/doc/html/rfc4795 - * - mDNS: https://datatracker.ietf.org/doc/html/rfc6762 + * - DHCPv6: https://datatracker.ietf.org/doc/html/rfc8415 */ #include <string.h> /* for strlen(), memcpy(), memset() */ @@ -141,6 +133,8 @@ struct dhcp_client { implements_net_packet_conn *sock; struct net_eth_addr self_eth_addr; char self_hostname[63]; + size_t self_id_len; + uint8_t *self_id_dat; /* Mutable. */ enum { @@ -331,7 +325,7 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, char *e [DHCP_OPT_ADDRESS_TIME] = { 1, { MAY, MUST_NOT, MAY, MUST_NOT, MUST_NOT }, NONE }, [DHCP_OPT_OVERLOAD] = { 1, { MAY, MAY, MAY, MAY, MAY }, NONE }, [DHCP_OPT_DHCP_MSG_TYPE] = { 1, { MUST, MUST, MUST, MUST, MUST }, V(msgtyp) }, - [DHCP_OPT_CLIENT_ID] = { 1, { MAY, MAY, MAY, MAY, MAY }, NONE }, + [DHCP_OPT_CLIENT_ID] = { 1, { MAY, MAY, MAY, MAY, MAY }, client->self_id_len, client->self_id_dat }, [DHCP_OPT_CLASS_ID] = { 1, { MAY, MAY, MAY, MUST_NOT, MUST_NOT }, NONE }, [DHCP_OPT_DHCP_SERVER_ID] = { 1, { MUST_NOT, MUST_NOT, INC_SERVER, MUST, MUST }, V(client->lease_server_id) }, [DHCP_OPT_PARAMETER_LIST] = { 1, { MAY, MAY, MAY, MUST_NOT, MUST_NOT }, V(parameter_request_list) }, @@ -369,11 +363,17 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, char *e case SHOULD_NOT: case MAY: if (options[opt].val_len) { - assert(options[opt].val_len <= UINT8_MAX); - msg.options[optlen++] = opt; - msg.options[optlen++] = options[opt].val_len; - memcpy(&msg.options[optlen], options[opt].val_ptr, options[opt].val_len); - optlen += options[opt].val_len; + assert(options[opt].val_len <= UINT16_MAX); + for (size_t done = 0; done < options[opt].val_len;) { + uint8_t len = options[opt].val_len - done > UINT8_MAX + ? UINT8_MAX + : options[opt].val_len - done; + msg.options[optlen++] = opt; + msg.options[optlen++] = len; + memcpy(&msg.options[optlen], &((char*)options[opt].val_ptr)[done], len); + optlen += len; + done += len; + } } break; case _SHOULD_NOT_HAPPEN: @@ -562,7 +562,8 @@ static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg enum requirement cols[3]; } option_req[0x100] = { /* Enocde the table from - * https://datatracker.ietf.org/doc/html/rfc2131#page-29 */ + * https://datatracker.ietf.org/doc/html/rfc2131#page-29, with modifications from + * https://datatracker.ietf.org/doc/html/rfc6842#page-4 */ #define REQ_TIME client->last_sent_msgtyp == DHCP_MSGTYP_REQUEST ? MUST : MUST_NOT /* Option DHCPOFFER DHCPACK DHCPNAK */ /* ------ -------- ---------- -------- */ @@ -572,7 +573,7 @@ static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg [DHCP_OPT_DHCP_MSG_TYPE] = { 1, { MUST, MUST, MUST } }, [DHCP_OPT_PARAMETER_LIST] = { 1, { MUST_NOT, MUST_NOT, MUST_NOT } }, [DHCP_OPT_DHCP_MESSAGE] = { 1, { SHOULD, SHOULD, SHOULD } }, - [DHCP_OPT_CLIENT_ID] = { 1, { MUST_NOT, MUST_NOT, MAY } }, + [DHCP_OPT_CLIENT_ID] = { 1, { MAY, MAY, MAY } }, /* MUST_NOTs changed to MAY, per RFC 6842 */ [DHCP_OPT_CLASS_ID] = { 1, { MAY, MAY, MAY } }, [DHCP_OPT_DHCP_SERVER_ID] = { 1, { MUST, MUST, MUST } }, [DHCP_OPT_DHCP_MAX_MSG_SIZE] = { 1, { MUST_NOT, MUST_NOT, MUST_NOT } }, @@ -609,6 +610,14 @@ static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg assert_notreached("bad table"); } } + /* Validate values of options. */ + if (ret->options[DHCP_OPT_CLASS_ID].len) { + /* https://datatracker.ietf.org/doc/html/rfc6842#page-4 */ + if (ret->options[DHCP_OPT_CLASS_ID].len != client->self_id_len) + goto ignore; + if (memcmp(ret->options[DHCP_OPT_CLASS_ID].dat, client->self_id_dat, client->self_id_len)) + goto ignore; + } return 0; } |