[dhcp6relay] Fix option parsing and add dhcpv6 client messages (#10819)

(cherry picked from commit 2ead3aaefc)
This commit is contained in:
kellyyeh 2022-05-24 14:37:16 -07:00 committed by Guohan Lu
parent 13ba0639dd
commit 81ce8b1010
2 changed files with 19 additions and 10 deletions

View File

@ -60,6 +60,8 @@ std::map<int, std::string> counterMap = {{DHCPv6_MESSAGE_TYPE_UNKNOWN, "Unknown"
{DHCPv6_MESSAGE_TYPE_REPLY, "Reply"}, {DHCPv6_MESSAGE_TYPE_REPLY, "Reply"},
{DHCPv6_MESSAGE_TYPE_RELEASE, "Release"}, {DHCPv6_MESSAGE_TYPE_RELEASE, "Release"},
{DHCPv6_MESSAGE_TYPE_DECLINE, "Decline"}, {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_FORW, "Relay-Forward"},
{DHCPv6_MESSAGE_TYPE_RELAY_REPL, "Relay-Reply"}, {DHCPv6_MESSAGE_TYPE_RELAY_REPL, "Relay-Reply"},
{DHCPv6_MESSAGE_TYPE_MALFORMED, "Malformed"}}; {DHCPv6_MESSAGE_TYPE_MALFORMED, "Malformed"}};
@ -84,6 +86,8 @@ void initialize_counter(std::string counterVlan) {
m_stateDbRedisClient.hset(counterVlan, "Reply", toString(counters[DHCPv6_MESSAGE_TYPE_REPLY])); m_stateDbRedisClient.hset(counterVlan, "Reply", toString(counters[DHCPv6_MESSAGE_TYPE_REPLY]));
m_stateDbRedisClient.hset(counterVlan, "Release", toString(counters[DHCPv6_MESSAGE_TYPE_RELEASE])); m_stateDbRedisClient.hset(counterVlan, "Release", toString(counters[DHCPv6_MESSAGE_TYPE_RELEASE]));
m_stateDbRedisClient.hset(counterVlan, "Decline", toString(counters[DHCPv6_MESSAGE_TYPE_DECLINE])); m_stateDbRedisClient.hset(counterVlan, "Decline", toString(counters[DHCPv6_MESSAGE_TYPE_DECLINE]));
m_stateDbRedisClient.hset(counterVlan, "Reconfigure", toString(counters[DHCPv6_MESSAGE_TYPE_RECONFIGURE]));
m_stateDbRedisClient.hset(counterVlan, "Information-Request", toString(counters[DHCPv6_MESSAGE_TYPE_INFORMATION_REQUEST]));
m_stateDbRedisClient.hset(counterVlan, "Relay-Forward", toString(counters[DHCPv6_MESSAGE_TYPE_RELAY_FORW])); m_stateDbRedisClient.hset(counterVlan, "Relay-Forward", toString(counters[DHCPv6_MESSAGE_TYPE_RELAY_FORW]));
m_stateDbRedisClient.hset(counterVlan, "Relay-Reply", toString(counters[DHCPv6_MESSAGE_TYPE_RELAY_REPL])); m_stateDbRedisClient.hset(counterVlan, "Relay-Reply", toString(counters[DHCPv6_MESSAGE_TYPE_RELAY_REPL]));
m_stateDbRedisClient.hset(counterVlan, "Malformed", toString(counters[DHCPv6_MESSAGE_TYPE_MALFORMED])); m_stateDbRedisClient.hset(counterVlan, "Malformed", toString(counters[DHCPv6_MESSAGE_TYPE_MALFORMED]));
@ -203,11 +207,12 @@ const struct dhcpv6_relay_msg *parse_dhcpv6_relay(const uint8_t *buffer) {
* @return dhcpv6_option end of dhcpv6 message option * @return dhcpv6_option end of dhcpv6 message option
*/ */
const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_t **out_end) { const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_t **out_end) {
uint32_t size = 4; // option-code + option-len auto option = (const struct dhcpv6_option *)buffer;
size += ntohs(*(uint16_t *)(buffer + 2)); uint8_t size = 4; // option-code + option-len
(*out_end) = buffer + size; size += *(uint16_t *)(buffer);
(*out_end) = buffer + size + ntohs(option->option_length);
return (const struct dhcpv6_option *)buffer; return option;
} }
/** /**
@ -588,6 +593,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) { void callback(evutil_socket_t fd, short event, void *arg) {
struct relay_config *config = (struct relay_config *)(arg); struct relay_config *config = (struct relay_config *)(arg);
static uint8_t message_buffer[4096]; static uint8_t message_buffer[4096];
std::string counterVlan = counter_table;
int32_t len = recv(config->filter, message_buffer, 4096, 0); int32_t len = recv(config->filter, message_buffer, 4096, 0);
if (len <= 0) { if (len <= 0) {
syslog(LOG_WARNING, "recv: Failed to receive data at filter socket: %s\n", strerror(errno)); syslog(LOG_WARNING, "recv: Failed to receive data at filter socket: %s\n", strerror(errno));
@ -625,10 +631,6 @@ void callback(evutil_socket_t fd, short event, void *arg) {
auto msg = parse_dhcpv6_hdr(current_position); auto msg = parse_dhcpv6_hdr(current_position);
auto option_position = current_position + sizeof(struct dhcpv6_msg); auto option_position = current_position + sizeof(struct dhcpv6_msg);
counters[msg->msg_type]++;
std::string counterVlan = counter_table;
update_counter(counterVlan.append(config->interface), msg->msg_type);
switch (msg->msg_type) { switch (msg->msg_type) {
case DHCPv6_MESSAGE_TYPE_RELAY_FORW: case DHCPv6_MESSAGE_TYPE_RELAY_FORW:
{ {
@ -637,21 +639,25 @@ void callback(evutil_socket_t fd, short event, void *arg) {
} }
case DHCPv6_MESSAGE_TYPE_SOLICIT: case DHCPv6_MESSAGE_TYPE_SOLICIT:
case DHCPv6_MESSAGE_TYPE_REQUEST: case DHCPv6_MESSAGE_TYPE_REQUEST:
case DHCPv6_MESSAGE_TYPE_CONFIRM:
case DHCPv6_MESSAGE_TYPE_RENEW: case DHCPv6_MESSAGE_TYPE_RENEW:
case DHCPv6_MESSAGE_TYPE_REBIND: case DHCPv6_MESSAGE_TYPE_REBIND:
case DHCPv6_MESSAGE_TYPE_RELEASE: case DHCPv6_MESSAGE_TYPE_RELEASE:
case DHCPv6_MESSAGE_TYPE_DECLINE: case DHCPv6_MESSAGE_TYPE_DECLINE:
case DHCPv6_MESSAGE_TYPE_INFORMATION_REQUEST:
{ {
while (option_position - message_buffer < len) { while (option_position - message_buffer < len) {
auto option = parse_dhcpv6_opt(option_position, &tmp); auto option = parse_dhcpv6_opt(option_position, &tmp);
option_position = tmp; option_position = tmp;
if(ntohs(option->option_code) > DHCPv6_OPTION_LIMIT) { if (ntohs(option->option_code) > DHCPv6_OPTION_LIMIT) {
counters[DHCPv6_MESSAGE_TYPE_MALFORMED]++; counters[DHCPv6_MESSAGE_TYPE_MALFORMED]++;
update_counter(config->db, counterVlan.append(config->interface), DHCPv6_MESSAGE_TYPE_MALFORMED); update_counter(counterVlan.append(config->interface), DHCPv6_MESSAGE_TYPE_MALFORMED);
syslog(LOG_WARNING, "DHCPv6 option is invalid or contains malformed payload\n"); syslog(LOG_WARNING, "DHCPv6 option is invalid or contains malformed payload\n");
return; return;
} }
} }
counters[msg->msg_type]++;
update_counter(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); relay_client(config->local_sock, current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, ether_header, config);
break; break;
} }

View File

@ -36,6 +36,8 @@ typedef enum
DHCPv6_MESSAGE_TYPE_REPLY = 7, DHCPv6_MESSAGE_TYPE_REPLY = 7,
DHCPv6_MESSAGE_TYPE_RELEASE = 8, DHCPv6_MESSAGE_TYPE_RELEASE = 8,
DHCPv6_MESSAGE_TYPE_DECLINE = 9, 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_FORW = 12,
DHCPv6_MESSAGE_TYPE_RELAY_REPL = 13, DHCPv6_MESSAGE_TYPE_RELAY_REPL = 13,
DHCPv6_MESSAGE_TYPE_MALFORMED = 14, DHCPv6_MESSAGE_TYPE_MALFORMED = 14,
@ -59,6 +61,7 @@ struct relay_config {
struct dhcpv6_msg { struct dhcpv6_msg {
uint8_t msg_type; uint8_t msg_type;
uint8_t xid[3];
}; };
struct PACKED dhcpv6_relay_msg { struct PACKED dhcpv6_relay_msg {