From cfdb8431df86105698eabe9e5e1ee112c06fd7db Mon Sep 17 00:00:00 2001 From: kellyyeh <42761586+kellyyeh@users.noreply.github.com> Date: Thu, 5 May 2022 18:04:14 -0700 Subject: [PATCH] [dhcp6relay] Add dhcpv6 option check (#10486) --- .../test_show_dhcp6relay_counters.py | 1 + .../cli/show/plugins/show_dhcp_relay.py | 2 +- src/dhcp6relay/src/relay.cpp | 50 ++++++++++++++----- src/dhcp6relay/src/relay.h | 2 + 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/dockers/docker-dhcp-relay/cli-plugin-tests/test_show_dhcp6relay_counters.py b/dockers/docker-dhcp-relay/cli-plugin-tests/test_show_dhcp6relay_counters.py index 501309ddd4..d818fa9c69 100644 --- a/dockers/docker-dhcp-relay/cli-plugin-tests/test_show_dhcp6relay_counters.py +++ b/dockers/docker-dhcp-relay/cli-plugin-tests/test_show_dhcp6relay_counters.py @@ -32,6 +32,7 @@ expected_counts = """\ Decline Relay-Forward Relay-Reply + Malformed """ diff --git a/dockers/docker-dhcp-relay/cli/show/plugins/show_dhcp_relay.py b/dockers/docker-dhcp-relay/cli/show/plugins/show_dhcp_relay.py index 2e641c4c42..91d5082e8f 100644 --- a/dockers/docker-dhcp-relay/cli/show/plugins/show_dhcp_relay.py +++ b/dockers/docker-dhcp-relay/cli/show/plugins/show_dhcp_relay.py @@ -12,7 +12,7 @@ from swsscommon.swsscommon import SonicV2Connector DHCPv6_COUNTER_TABLE = 'DHCPv6_COUNTER_TABLE' # DHCPv6 Counter Messages -messages = ["Unknown", "Solicit", "Advertise", "Request", "Confirm", "Renew", "Rebind", "Reply", "Release", "Decline", "Relay-Forward", "Relay-Reply"] +messages = ["Unknown", "Solicit", "Advertise", "Request", "Confirm", "Renew", "Rebind", "Reply", "Release", "Decline", "Relay-Forward", "Relay-Reply", "Malformed"] # DHCP_RELAY Config Table DHCP_RELAY = 'DHCP_RELAY' diff --git a/src/dhcp6relay/src/relay.cpp b/src/dhcp6relay/src/relay.cpp index 951b31f90a..f9c7900c26 100644 --- a/src/dhcp6relay/src/relay.cpp +++ b/src/dhcp6relay/src/relay.cpp @@ -49,18 +49,19 @@ 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_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); @@ -85,6 +86,7 @@ void initialize_counter(swss::DBConnector *db, std::string counterVlan) { db->hset(counterVlan, "Decline", toString(counters[DHCPv6_MESSAGE_TYPE_DECLINE])); 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])); } /** @@ -622,6 +624,8 @@ void callback(evutil_socket_t fd, short event, void *arg) { current_position = tmp; auto msg = parse_dhcpv6_hdr(current_position); + auto option_position = current_position + sizeof(struct dhcpv6_msg); + counters[msg->msg_type]++; std::string counterVlan = counter_table; update_counter(config->db, counterVlan.append(config->interface), msg->msg_type); @@ -632,9 +636,29 @@ 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_RENEW: + case DHCPv6_MESSAGE_TYPE_REBIND: + case DHCPv6_MESSAGE_TYPE_RELEASE: + case DHCPv6_MESSAGE_TYPE_DECLINE: + { + 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; + } + } + 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..29e365bb5d 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]) @@ -37,6 +38,7 @@ typedef enum DHCPv6_MESSAGE_TYPE_DECLINE = 9, 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;