From 79555c894aa5c5718e3481d3fc30948bcd75f27a Mon Sep 17 00:00:00 2001 From: kellyyeh <42761586+kellyyeh@users.noreply.github.com> Date: Wed, 1 Jun 2022 14:20:26 -0700 Subject: [PATCH] [dhcp6relay] Add dhcpv6 option check (#10486) (#10808) --- src/dhcp6relay/src/relay.cpp | 70 +++++++++++++++++++++++++----------- src/dhcp6relay/src/relay.h | 5 +++ 2 files changed, 55 insertions(+), 20 deletions(-) diff --git a/src/dhcp6relay/src/relay.cpp b/src/dhcp6relay/src/relay.cpp index 951b31f90a..8387584f6a 100644 --- a/src/dhcp6relay/src/relay.cpp +++ b/src/dhcp6relay/src/relay.cpp @@ -49,18 +49,21 @@ const struct sock_fprog ether_relay_fprog = { /* DHCPv6 Counter */ uint64_t counters[DHCPv6_MESSAGE_TYPE_COUNT]; -std::map counterMap = {{0, "Unknown"}, - {1, "Solicit"}, - {2, "Advertise"}, - {3, "Request"}, - {4, "Confirm"}, - {5, "Renew"}, - {6, "Rebind"}, - {7, "Reply"}, - {8, "Release"}, - {9, "Decline"}, - {12, "Relay-Forward"}, - {13, "Relay-Reply"}}; +std::map counterMap = {{DHCPv6_MESSAGE_TYPE_UNKNOWN, "Unknown"}, + {DHCPv6_MESSAGE_TYPE_SOLICIT, "Solicit"}, + {DHCPv6_MESSAGE_TYPE_ADVERTISE, "Advertise"}, + {DHCPv6_MESSAGE_TYPE_REQUEST, "Request"}, + {DHCPv6_MESSAGE_TYPE_CONFIRM, "Confirm"}, + {DHCPv6_MESSAGE_TYPE_RENEW, "Renew"}, + {DHCPv6_MESSAGE_TYPE_REBIND, "Rebind"}, + {DHCPv6_MESSAGE_TYPE_REPLY, "Reply"}, + {DHCPv6_MESSAGE_TYPE_RELEASE, "Release"}, + {DHCPv6_MESSAGE_TYPE_DECLINE, "Decline"}, + {DHCPv6_MESSAGE_TYPE_RECONFIGURE, "Reconfigure"}, + {DHCPv6_MESSAGE_TYPE_INFORMATION_REQUEST, "Information-Request"}, + {DHCPv6_MESSAGE_TYPE_RELAY_FORW, "Relay-Forward"}, + {DHCPv6_MESSAGE_TYPE_RELAY_REPL, "Relay-Reply"}, + {DHCPv6_MESSAGE_TYPE_MALFORMED, "Malformed"}}; /** * @code void initialize_counter(swss::DBConnector *db, std::string counterVlan); @@ -83,8 +86,11 @@ void initialize_counter(swss::DBConnector *db, std::string counterVlan) { db->hset(counterVlan, "Reply", toString(counters[DHCPv6_MESSAGE_TYPE_REPLY])); db->hset(counterVlan, "Release", toString(counters[DHCPv6_MESSAGE_TYPE_RELEASE])); db->hset(counterVlan, "Decline", toString(counters[DHCPv6_MESSAGE_TYPE_DECLINE])); + db->hset(counterVlan, "Reconfigure", toString(counters[DHCPv6_MESSAGE_TYPE_RECONFIGURE])); + db->hset(counterVlan, "Information-Request", toString(counters[DHCPv6_MESSAGE_TYPE_INFORMATION_REQUEST])); db->hset(counterVlan, "Relay-Forward", toString(counters[DHCPv6_MESSAGE_TYPE_RELAY_FORW])); db->hset(counterVlan, "Relay-Reply", toString(counters[DHCPv6_MESSAGE_TYPE_RELAY_REPL])); + db->hset(counterVlan, "Malformed", toString(counters[DHCPv6_MESSAGE_TYPE_MALFORMED])); } /** @@ -202,11 +208,12 @@ const struct dhcpv6_relay_msg *parse_dhcpv6_relay(const uint8_t *buffer) { * @return dhcpv6_option end of dhcpv6 message option */ const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_t **out_end) { - uint32_t size = 4; // option-code + option-len - size += ntohs(*(uint16_t *)(buffer + 2)); - (*out_end) = buffer + size; + auto option = (const struct dhcpv6_option *)buffer; + uint8_t size = 4; // option-code + option-len + size += *(uint16_t *)(buffer); + (*out_end) = buffer + size + ntohs(option->option_length); - return (const struct dhcpv6_option *)buffer; + return option; } /** @@ -587,6 +594,7 @@ void relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr * void callback(evutil_socket_t fd, short event, void *arg) { struct relay_config *config = (struct relay_config *)arg; static uint8_t message_buffer[4096]; + std::string counterVlan = counter_table; int32_t len = recv(config->filter, message_buffer, 4096, 0); if (len <= 0) { syslog(LOG_WARNING, "recv: Failed to receive data at filter socket: %s\n", strerror(errno)); @@ -622,9 +630,7 @@ void callback(evutil_socket_t fd, short event, void *arg) { current_position = tmp; auto msg = parse_dhcpv6_hdr(current_position); - counters[msg->msg_type]++; - std::string counterVlan = counter_table; - update_counter(config->db, counterVlan.append(config->interface), msg->msg_type); + auto option_position = current_position + sizeof(struct dhcpv6_msg); switch (msg->msg_type) { case DHCPv6_MESSAGE_TYPE_RELAY_FORW: @@ -632,9 +638,33 @@ void callback(evutil_socket_t fd, short event, void *arg) { relay_relay_forw(config->local_sock, current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, config); break; } + case DHCPv6_MESSAGE_TYPE_SOLICIT: + case DHCPv6_MESSAGE_TYPE_REQUEST: + case DHCPv6_MESSAGE_TYPE_CONFIRM: + case DHCPv6_MESSAGE_TYPE_RENEW: + case DHCPv6_MESSAGE_TYPE_REBIND: + case DHCPv6_MESSAGE_TYPE_RELEASE: + case DHCPv6_MESSAGE_TYPE_DECLINE: + case DHCPv6_MESSAGE_TYPE_INFORMATION_REQUEST: + { + while (option_position - message_buffer < len) { + auto option = parse_dhcpv6_opt(option_position, &tmp); + option_position = tmp; + if (ntohs(option->option_code) > DHCPv6_OPTION_LIMIT) { + counters[DHCPv6_MESSAGE_TYPE_MALFORMED]++; + update_counter(config->db, counterVlan.append(config->interface), DHCPv6_MESSAGE_TYPE_MALFORMED); + syslog(LOG_WARNING, "DHCPv6 option is invalid or contains malformed payload\n"); + return; + } + } + counters[msg->msg_type]++; + update_counter(config->db, counterVlan.append(config->interface), msg->msg_type); + relay_client(config->local_sock, current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, ether_header, config); + break; + } default: { - relay_client(config->local_sock, current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, ether_header, config); + syslog(LOG_WARNING, "DHCPv6 client message received was not relayed\n"); break; } } diff --git a/src/dhcp6relay/src/relay.h b/src/dhcp6relay/src/relay.h index c224a9b286..c5b0732542 100644 --- a/src/dhcp6relay/src/relay.h +++ b/src/dhcp6relay/src/relay.h @@ -16,6 +16,7 @@ #define RELAY_PORT 547 #define CLIENT_PORT 546 #define HOP_LIMIT 8 //HOP_LIMIT reduced from 32 to 8 as stated in RFC8415 +#define DHCPv6_OPTION_LIMIT 56 // DHCPv6 option code greater than 56 are currently unassigned #define lengthof(A) (sizeof (A) / sizeof (A)[0]) @@ -35,8 +36,11 @@ typedef enum DHCPv6_MESSAGE_TYPE_REPLY = 7, DHCPv6_MESSAGE_TYPE_RELEASE = 8, DHCPv6_MESSAGE_TYPE_DECLINE = 9, + DHCPv6_MESSAGE_TYPE_RECONFIGURE = 10, + DHCPv6_MESSAGE_TYPE_INFORMATION_REQUEST = 11, DHCPv6_MESSAGE_TYPE_RELAY_FORW = 12, DHCPv6_MESSAGE_TYPE_RELAY_REPL = 13, + DHCPv6_MESSAGE_TYPE_MALFORMED = 14, DHCPv6_MESSAGE_TYPE_COUNT } dhcp_message_type_t; @@ -58,6 +62,7 @@ struct relay_config { struct dhcpv6_msg { uint8_t msg_type; + uint8_t xid[3]; }; struct PACKED dhcpv6_relay_msg {