From b6495892c44204f4b12f7e8429896c7167a3e3f2 Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Wed, 7 Jun 2023 13:56:52 +0000 Subject: [PATCH 01/19] 202012 dualtor dhcpv6 relay issue fix --- src/main.cpp | 15 ++- src/relay.cpp | 334 +++++++++++++++++++++++++++++++++++++++----------- src/relay.h | 24 ++-- 3 files changed, 286 insertions(+), 87 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 9da3cb8..09613ef 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,19 +4,28 @@ #include "configInterface.h" bool dual_tor_sock = false; +char loopback[IF_NAMESIZE] = "Loopback0"; static void usage() { - printf("Usage: ./dhcp6relay {-d}\n"); - printf("\t-d: enable dual tor option\n"); + printf("Usage: ./dhcp6relay [-u ]\n"); + printf("\tloopback interface: is the loopback interface for dual tor setup\n"); } int main(int argc, char *argv[]) { if (argc > 1) { switch (argv[1][1]) { - case 'd': + case 'u': + if (strlen(argv[i + 1]) < IF_NAMESIZE) { + std::memset(loopback, 0, IF_NAMESIZE); + std::memcpy(loopback, argv[i + 1], strlen(argv[i + 1])); + } else { + syslog(LOG_ERR, "loopback interface name over length %d.\n", IF_NAMESIZE); + return 1; + } dual_tor_sock = true; + i += 2; break; default: fprintf(stderr, "%s: Unknown option\n", basename(argv[0])); diff --git a/src/relay.cpp b/src/relay.cpp index 64390a9..e98e791 100644 --- a/src/relay.cpp +++ b/src/relay.cpp @@ -14,8 +14,6 @@ #define BUFFER_SIZE 9200 -struct event *listen_event; -struct event *server_listen_event; struct event_base *base; struct event *ev_sigint; struct event *ev_sigterm; @@ -71,6 +69,9 @@ std::map counterMap = {{DHCPv6_MESSAGE_TYPE_UNKNOWN, "Unknown" /* interface to vlan mapping */ std::unordered_map vlan_map; +/* ipv6 address to vlan name mapping */ +std::unordered_map addr_vlan_map; + /** * @code initialize_counter(std::shared_ptr state_db, std::string counterVlan); * @@ -269,6 +270,9 @@ int sock_open(const struct sock_fprog *fprog) return -1; } + evutil_make_listen_socket_reuseable(s); + evutil_make_socket_nonblocking(s); + struct sockaddr_ll sll = { .sll_family = AF_PACKET, .sll_protocol = htons(ETH_P_ALL), @@ -306,22 +310,22 @@ int sock_open(const struct sock_fprog *fprog) } /** - * @code prepare_relay_config(relay_config &interface_config, int local_sock, int filter); + * @code prepare_relay_config(relay_config &interface_config, int gua_sock, int filter); * * @brief prepare for specified relay interface config: server and link address * * @param interface_config pointer to relay config to be prepared - * @param local_sock L3 socket used for relaying messages + * @param gua_sock L3 socket used for relaying messages * @param filter socket attached with filter * * @return none */ -void prepare_relay_config(relay_config &interface_config, int local_sock, int filter) { +void prepare_relay_config(relay_config &interface_config, int gua_sock, int filter) { struct ifaddrs *ifa, *ifa_tmp; sockaddr_in6 non_link_local; sockaddr_in6 link_local; - interface_config.local_sock = local_sock; + interface_config.gua_sock = gua_sock; interface_config.filter = filter; for(auto server: interface_config.servers) { @@ -360,38 +364,91 @@ void prepare_relay_config(relay_config &interface_config, int local_sock, int fi if(!IN6_IS_ADDR_LINKLOCAL(&non_link_local.sin6_addr)) { interface_config.link_address = non_link_local; + addr_vlan_map[non_link_local] = interface_config.interface; } else { interface_config.link_address = link_local; + addr_vlan_map[link_local] = interface_config.interface; } } +int prepare_lo_socket(const char *lo) { + struct ifaddrs *ifa, *ifa_tmp; + sockaddr_in6 gua = {0}; + int lo_sock = -1; + + if ((lo_sock = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) { + syslog(LOG_ERR, "socket: Failed to create gua socket on interface %s\n", lo); + return -1; + } + + evutil_make_listen_socket_reuseable(lo_sock); + evutil_make_socket_nonblocking(lo_sock); + + if (getifaddrs(&ifa) == -1) { + syslog(LOG_WARNING, "getifaddrs: Unable to get network interfaces with %s\n", strerror(errno)); + } + bool bind_gua = false; + ifa_tmp = ifa; + while (ifa_tmp) { + if (ifa_tmp->ifa_addr && (ifa_tmp->ifa_addr->sa_family == AF_INET6)) { + if (strcmp(ifa_tmp->ifa_name, lo) == 0)) { + struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa_tmp->ifa_addr; + if (!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { + bind_gua = true; + gua = *in6; + gua->sin6_family = AF_INET6; + gua->sin6_port = htons(RELAY_PORT); + break; + } + } + } + ifa_tmp = ifa_tmp->ifa_next; + } + freeifaddrs(ifa); + + if (!bind_gua || bind(lo_sock, (sockaddr *)&gua, sizeof(gua)) == -1) { + syslog(LOG_ERR, "bind: Failed to bind socket on interface %s with %s\n", lo, strerror(errno)); + (void) close(lo_sock); + return -1; + } + + return lo_sock; +} + /** - * @code prepare_socket(int &local_sock, int &server_sock, relay_config &config); + * @code prepare_vlan_sockets(int &gua_sock, int &lla_sock, relay_config &config); * - * @brief prepare L3 socket for sending + * @brief prepare vlan l3 socket for sending * - * @param local_sock pointer to socket binded to global address for relaying client message to server and listening for server message - * @param server_sock pointer to socket binded to link_local address for relaying server message to client + * @param gua_sock socket binded to global address for relaying client message to server and listening for server message + * @param lla_sock socket binded to link_local address for relaying server message to client * - * @return none + * @return int */ -void prepare_socket(int &local_sock, int &server_sock, relay_config &config) { +int prepare_vlan_sockets(int &gua_sock, int &lla_sock, relay_config &config) { struct ifaddrs *ifa, *ifa_tmp; - sockaddr_in6 addr = {0}; - sockaddr_in6 ll_addr = {0}; + sockaddr_in6 gua = {0}, lla = {0}; - if ((local_sock = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) { - syslog(LOG_ERR, "socket: Failed to create socket on interface %s\n", config.interface.c_str()); + if ((gua_sock = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) { + syslog(LOG_ERR, "socket: Failed to create gua socket on interface %s\n", config.interface.c_str()); + return -1; } - if ((server_sock = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) { - syslog(LOG_ERR, "socket: Failed to create socket on interface %s\n", config.interface.c_str()); + if ((lla_sock = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) { + syslog(LOG_ERR, "socket: Failed to create lla socket on interface %s\n", config.interface.c_str()); + close(gua_sock); + return -1; } + evutil_make_listen_socket_reuseable(gua_sock); + evutil_make_socket_nonblocking(gua_sock); + evutil_make_listen_socket_reuseable(lla_sock); + evutil_make_socket_nonblocking(lla_sock); + int retry = 0; - bool bind_addr = false; - bool bind_ll_addr = false; + bool bind_gua = false; + bool bind_lla = false; do { if (getifaddrs(&ifa) == -1) { syslog(LOG_WARNING, "getifaddrs: Unable to get network interfaces with %s\n", strerror(errno)); @@ -399,19 +456,20 @@ void prepare_socket(int &local_sock, int &server_sock, relay_config &config) { else { ifa_tmp = ifa; while (ifa_tmp) { - if (ifa_tmp->ifa_addr && (ifa_tmp->ifa_addr->sa_family == AF_INET6) && (strcmp(ifa_tmp->ifa_name, config.interface.c_str()) == 0)) { - struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa_tmp->ifa_addr; - if(!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { - bind_addr = true; - in6->sin6_family = AF_INET6; - in6->sin6_port = htons(RELAY_PORT); - addr = *in6; - } - if(IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { - bind_ll_addr = true; - in6->sin6_family = AF_INET6; - in6->sin6_port = htons(RELAY_PORT); - ll_addr = *in6; + if (ifa_tmp->ifa_addr && (ifa_tmp->ifa_addr->sa_family == AF_INET6)) { + if (strcmp(ifa_tmp->ifa_name, config.interface.c_str()) == 0)) { + struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa_tmp->ifa_addr; + if (!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { + bind_gua = true; + gua = *in6; + gua->sin6_family = AF_INET6; + gua->sin6_port = htons(RELAY_PORT); + } else { + bind_lla = true; + lla = *in6; + lla->sin6_family = AF_INET6; + lla->sin6_port = htons(RELAY_PORT); + } } } ifa_tmp = ifa_tmp->ifa_next; @@ -419,7 +477,7 @@ void prepare_socket(int &local_sock, int &server_sock, relay_config &config) { freeifaddrs(ifa); } - if (bind_addr && bind_ll_addr) { + if (bind_gua && bind_lla) { break; } @@ -427,13 +485,22 @@ void prepare_socket(int &local_sock, int &server_sock, relay_config &config) { sleep(5); } while (retry < 6); - if ((!bind_addr) || (bind(local_sock, (sockaddr *)&addr, sizeof(addr)) == -1)) { - syslog(LOG_ERR, "bind: Failed to bind socket to global ipv6 address on interface %s after %d retries with %s\n", config.interface.c_str(), retry, strerror(errno)); + if ((!bind_gua) || (bind(gua_sock, (sockaddr *)&gua, sizeof(gua)) == -1)) { + syslog(LOG_ERR, "bind: Failed to bind socket to global ipv6 address on interface %s after %d retries with %s\n", + config.interface.c_str(), retry, strerror(errno)); + close(gua_sock); + close(lla_sock); + return -1; } - if ((!bind_ll_addr) || (bind(server_sock, (sockaddr *)&ll_addr, sizeof(addr)) == -1)) { - syslog(LOG_ERR, "bind: Failed to bind socket to link local ipv6 address on interface %s after %d retries with %s\n", config.interface.c_str(), retry, strerror(errno)); + if ((!bind_lla) || (bind(lla_sock, (sockaddr *)&lla, sizeof(lla)) == -1)) { + syslog(LOG_ERR, "bind: Failed to bind socket to link local ipv6 address on interface %s after %d retries with %s\n", + config.interface.c_str(), retry, strerror(errno)); + close(gua_sock); + close(lla_sock); + return -1; } + return 0; } @@ -738,11 +805,15 @@ void client_packet_handler(uint8_t *buffer, ssize_t length, struct relay_config } auto option_position = current_position + sizeof(struct dhcpv6_msg); + auto relay_socket = config->gua_sock; + if (dual_tor_sock) { + relay_socket = config->lo_sock; + } switch (msg->msg_type) { case DHCPv6_MESSAGE_TYPE_RELAY_FORW: { - relay_relay_forw(config->local_sock, current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, config); + relay_relay_forw(relay_socket, current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, config); break; } case DHCPv6_MESSAGE_TYPE_SOLICIT: @@ -766,7 +837,7 @@ void client_packet_handler(uint8_t *buffer, ssize_t length, struct relay_config } counters[msg->msg_type]++; update_counter(config->state_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); + relay_client(relay_socket, current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, ether_header, config); break; } default: @@ -777,6 +848,103 @@ void client_packet_handler(uint8_t *buffer, ssize_t length, struct relay_config } } +/** + * @code bool inline isIPv6Zero(struct in6_addr *addr) + * + * @brief check if ipv6 address is zero + * + * @param addr ipv6 address + * + * @return bool + */ +bool inline isIPv6Zero(struct in6_addr *addr) { + return (memcmp(&addr, &in6addr_any, sizeof(in6addr_any)) == 0); +} + +struct relay_config * +get_relay_int_from_packet(uint8_t *packet, int32_t len, std::unordered_map &vlans) { + auto current_position = packet; + auto dhcp_relay_header = parse_dhcpv6_relay(packet); + + // multi-level relay agents + if (isIPv6Zero(&dhcp_relay_header->link_address)) { + // This is temp solution for multi-level relay + // In this case, we need add + // 1. Add option82 in Relay Relay-Forward packets + // 2. Decode option82 in Relay-Reply to find out source vlan config + return NULL; + } + + if (addr_vlan_map.find(dhcp_relay_header->link_address) == addr_vlan_map.end()) { + char link_addr_str[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &dhcp_relay_header->link_address, link_addr_str, INET6_ADDRSTRLEN); + syslog(LOG_WARNING, "DHCPv6 type %d can't find vlan info from link address %s\n", + dhcp_relay_header->msg_type, link_addr_str); + return NULL; + } + auto vlan_name = addr_vlan_map[dhcp_relay_header->link_address]; + + if (vlans.find(vlan_name) == vlans.end()) { + syslog(LOG_WARNING, "DHCPv6 can't find vlan %s config\n", vlan_name); + return NULL; + } + return &vlans[vlan_name]; +} + +/** + * @code void server_callback_dualtor(evutil_socket_t fd, short event, void *arg); + * + * @brief callback for libevent that is called everytime data is received at the loopback socket + * + * @param fd loopback socket + * @param event libevent triggered event + * @param arg callback argument provided by user + * + * @return none + */ +void server_callback_dualtor(evutil_socket_t fd, short event, void *arg) { + auto vlans = reinterpret_cast *>(arg); + sockaddr_in6 from; + socklen_t len = sizeof(from); + int32_t pkts_num = 0; + static uint8_t message_buffer[BUFFER_SIZE]; + + while (pkts_num++ < BATCH_SIZE) { + std::string counterVlan = counter_table; + auto buffer_sz = recvfrom(fd, message_buffer, BUFFER_SIZE, 0, (sockaddr *)&from, &len); + if (buffer_sz <= 0) { + if (errno != EAGAIN) { + syslog(LOG_ERR, "recv: Failed to receive data from server: %s\n", strerror(errno)); + } + return; + } + + if (buffer_sz < (int32_t)sizeof(struct dhcpv6_msg)) { + syslog(LOG_WARNING, "Invalid DHCPv6 packet length %ld, no space for dhcpv6 msg header\n", buffer_sz); + continue; + } + + auto config = get_relay_int_from_packet(message_buffer, buffer_sz, vlans)) { + syslog(LOG_WARNING, "Invalid DHCPv6 header content, packet will be dropped\n"); + continue; + } + auto msg = parse_dhcpv6_hdr(message_buffer); + // RFC3315 only + if (msg->msg_type < DHCPv6_MESSAGE_TYPE_SOLICIT || msg->msg_type > DHCPv6_MESSAGE_TYPE_RELAY_REPL) { + update_counter(config->state_db, counterVlan.append(config->interface), DHCPv6_MESSAGE_TYPE_UNKNOWN); + syslog(LOG_WARNING, "Unknown DHCPv6 message type %d\n", msg->msg_type); + continue; + } else { + counters[msg->msg_type]++; + } + + update_counter(config->state_db, counterVlan.append(config->interface), msg->msg_type); + if (msg->msg_type == DHCPv6_MESSAGE_TYPE_RELAY_REPL) { + relay_relay_reply(config->lla_sock, message_buffer, buffer_sz, config); + } + } +} + /** * @code void server_callback(evutil_socket_t fd, short event, void *arg); @@ -795,10 +963,10 @@ void server_callback(evutil_socket_t fd, short event, void *arg) { socklen_t len = sizeof(from); int32_t pkts_num = 0; static uint8_t message_buffer[BUFFER_SIZE]; - std::string counterVlan = counter_table; while (pkts_num++ < BATCH_SIZE) { - auto buffer_sz = recvfrom(config->local_sock, message_buffer, BUFFER_SIZE, 0, (sockaddr *)&from, &len); + std::string counterVlan = counter_table; + auto buffer_sz = recvfrom(config->gua_sock, message_buffer, BUFFER_SIZE, 0, (sockaddr *)&from, &len); if (buffer_sz <= 0) { if (errno != EAGAIN) { syslog(LOG_ERR, "recv: Failed to receive data from server: %s\n", strerror(errno)); @@ -823,7 +991,7 @@ void server_callback(evutil_socket_t fd, short event, void *arg) { update_counter(config->state_db, counterVlan.append(config->interface), msg->msg_type); if (msg->msg_type == DHCPv6_MESSAGE_TYPE_RELAY_REPL) { - relay_relay_reply(config->server_sock, message_buffer, buffer_sz, config); + relay_relay_reply(config->lla_sock, message_buffer, buffer_sz, config); } } } @@ -922,7 +1090,7 @@ void loop_relay(std::unordered_map &vlans) { std::vector sockets; base = event_base_new(); if(base == NULL) { - syslog(LOG_ERR, "libevent: Failed to create base\n"); + syslog(LOG_ERR, "libevent: Failed to create event base\n"); } std::shared_ptr state_db = std::make_shared ("STATE_DB", 0); @@ -934,21 +1102,41 @@ void loop_relay(std::unordered_map &vlans) { auto filter = sock_open(ðer_relay_fprog); if (filter != -1) { sockets.push_back(filter); - listen_event = event_new(base, filter, EV_READ|EV_PERSIST, client_callback, - reinterpret_cast(&vlans)); - if (listen_event == NULL) { - syslog(LOG_ERR, "libevent: Failed to create client listen libevent\n"); + auto event = event_new(base, filter, EV_READ|EV_PERSIST, client_callback, + reinterpret_cast(&vlans)); + if (event == NULL) { + syslog(LOG_ERR, "libevent: Failed to create client listen event\n"); + exit(EXIT_FAILURE); } - event_add(listen_event, NULL); - syslog(LOG_INFO, "libevent: add filter socket event\n"); + event_add(event, NULL); + syslog(LOG_INFO, "libevent: Add client listen socket event\n"); } else { - syslog(LOG_ALERT, "Failed to create relay filter socket"); + syslog(LOG_ERR, "Failed to create client listen socket"); exit(EXIT_FAILURE); } + int lo_sock = -1; + if (dual_tor_sock) { + lo_sock = prepare_lo_socket(loopback); + if (lo_sock != -1) { + sockets.push_back(lo_sock); + auto event = event_new(base, lo_sock, EV_READ|EV_PERSIST, server_callback_dualtor, + reinterpret_cast(&vlans)); + if (event == NULL) { + syslog(LOG_ERR, "libevent: Failed to create dualtor loopback listen event\n"); + exit(EXIT_FAILURE); + } + event_add(event, NULL); + syslog(LOG_INFO, "libevent: Add dualtor loopback socket event\n"); + } else{ + syslog(LOG_ERR, "Failed to create dualtor loopback listen socket"); + exit(EXIT_FAILURE); + } + } + for(auto &vlan : vlans) { - int local_sock = 0; - int server_sock = 0; + int gua_sock = 0; + int lla_sock = 0; vlan.second.config_db = config_db; vlan.second.mux_table = mStateDbMuxTablePtr; vlan.second.state_db = state_db; @@ -958,28 +1146,28 @@ void loop_relay(std::unordered_map &vlans) { std::string counterVlan = counter_table; initialize_counter(vlan.second.state_db, counterVlan.append(vlan.second.interface)); - prepare_socket(local_sock, server_sock, vlan.second); - - vlan.second.local_sock = local_sock; - vlan.second.server_sock = server_sock; - - sockets.push_back(local_sock); - sockets.push_back(server_sock); - prepare_relay_config(vlan.second, local_sock, filter); - - evutil_make_listen_socket_reuseable(filter); - evutil_make_socket_nonblocking(filter); - - evutil_make_listen_socket_reuseable(local_sock); - evutil_make_socket_nonblocking(local_sock); + if (prepare_vlan_sockets(gua_sock, lla_sock, vlan.second) != -1) { + vlan.second.gua_sock = gua_sock; + vlan.second.lla_sock = lla_sock; + vlan.second.lo_sock = lo_sock; + + sockets.push_back(gua_sock); + sockets.push_back(lla_sock); + prepare_relay_config(vlan.second, gua_sock, filter); - server_listen_event = event_new(base, local_sock, EV_READ|EV_PERSIST, server_callback, &(vlan.second)); - - if (server_listen_event == NULL) { - syslog(LOG_ERR, "libevent: Failed to create server listen libevent\n"); + if (!dual_tor_sock) { + auto event = event_new(base, gua_sock, EV_READ|EV_PERSIST, + server_callback, &(vlan.second)); + if (event == NULL) { + syslog(LOG_ERR, "libevent: Failed to create server listen libevent\n"); + } + event_add(event, NULL); + syslog(LOG_INFO, "libevent: add server listen socket for %s\n", vlan.first.c_str()); + } + } else { + syslog(LOG_ERR, "Failed to create dualtor loopback listen socket"); + exit(EXIT_FAILURE); } - event_add(server_listen_event, NULL); - syslog(LOG_INFO, "libevent: add server listen socket for %s\n", vlan.first.c_str()); } if((signal_init() == 0) && signal_start() == 0) { diff --git a/src/relay.h b/src/relay.h index 240db54..668f8df 100644 --- a/src/relay.h +++ b/src/relay.h @@ -58,8 +58,9 @@ typedef enum } dhcp_message_type_t; struct relay_config { - int local_sock; - int server_sock; + int gua_sock; + int lla_sock; + int lo_sock; int filter; sockaddr_in6 link_address; std::shared_ptr state_db; @@ -116,30 +117,31 @@ struct interface_id_option { */ int sock_open(const struct sock_fprog *fprog); + /** - * @code prepare_socket(int *local_sock, int *server_sock, relay_config *config); + * @code prepare_vlan_sockets(int &gua_sock, int &lla_sock, relay_config &config); * - * @brief prepare L3 socket for sending + * @brief prepare vlan l3 socket for sending * - * @param local_sock pointer to socket binded to global address for relaying client message to server and listening for server message - * @param server_sock pointer to socket binded to link_local address for relaying server message to client + * @param gua_sock socket binded to global address for relaying client message to server and listening for server message + * @param lla_sock socket binded to link_local address for relaying server message to client * - * @return none + * @return none */ -void prepare_socket(int *local_sock, int *server_sock, relay_config *config); +void prepare_vlan_sockets(int &gua_sock, int &lla_sock, relay_config &config); /** - * @code prepare_relay_config(relay_config &interface_config, int local_sock, int filter); + * @code prepare_relay_config(relay_config &interface_config, int gua_sock, int filter); * * @brief prepare for specified relay interface config: server and link address * * @param interface_config pointer to relay config to be prepared - * @param local_sock L3 socket used for relaying messages + * @param gua_sock L3 socket used for relaying messages * @param filter socket attached with filter * * @return none */ -void prepare_relay_config(relay_config &interface_config, int local_sock, int filter); +void prepare_relay_config(relay_config &interface_config, int gua_sock, int filter); /** * @code relay_forward(uint8_t *buffer, const struct dhcpv6_msg *msg, uint16_t msg_length); From 7b84d91c63a843e8e82529ab8a6b5b7616b2d4ef Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Sat, 10 Jun 2023 14:06:55 +0000 Subject: [PATCH 02/19] fix multi-relay agent case --- src/relay.cpp | 124 +++++++++++++++++++++++++++++++++++--------------- src/relay.h | 9 ++-- 2 files changed, 91 insertions(+), 42 deletions(-) diff --git a/src/relay.cpp b/src/relay.cpp index e98e791..b0e6a56 100644 --- a/src/relay.cpp +++ b/src/relay.cpp @@ -112,6 +112,7 @@ void initialize_counter(std::shared_ptr state_db, std::string * @return none */ void update_counter(std::shared_ptr state_db, std::string counterVlan, uint8_t msg_type) { + counters[msg_type]++; state_db->hset(counterVlan, counterMap.find(msg_type)->second, toString(counters[msg_type])); } @@ -226,7 +227,6 @@ const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_ void process_sent_msg(relay_config *config, uint8_t msg_type) { std::string counterVlan = counter_table; if (counterMap.find(msg_type) != counterMap.end()) { - counters[msg_type]++; update_counter(config->state_db, counterVlan.append(config->interface), msg_type); } else { syslog(LOG_WARNING, "unexpected message type %d(0x%x)\n", msg_type, msg_type); @@ -518,7 +518,7 @@ int prepare_vlan_sockets(int &gua_sock, int &lla_sock, relay_config &config) { * * @return none */ -void relay_client(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config) { +void relay_client(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config) { static uint8_t buffer[BUFFER_SIZE]; auto current_buffer_position = buffer; dhcpv6_relay_msg new_message; @@ -563,6 +563,10 @@ void relay_client(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_h relay_forward(current_buffer_position, parse_dhcpv6_hdr(msg), dhcp_message_length); current_buffer_position += dhcp_message_length + sizeof(dhcpv6_option); + auto sock = config->gua_sock; + if (dual_tor_sock) { + sock = config->lo_sock; + } for(auto server: config->servers_sock) { if(send_udp(sock, buffer, server, current_buffer_position - buffer)) { process_sent_msg(config, new_message.msg_type); @@ -583,7 +587,7 @@ void relay_client(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_h * * @return none */ -void relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config) { +void relay_relay_forw(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config) { static uint8_t buffer[BUFFER_SIZE]; dhcpv6_relay_msg new_message; auto current_buffer_position = buffer; @@ -601,10 +605,28 @@ void relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr * memcpy(current_buffer_position, &new_message, sizeof(dhcpv6_relay_msg)); current_buffer_position += sizeof(dhcpv6_relay_msg); + // insert option82 for new relay-forward packet, we need this information + // to get original relay-forward source interface for accurate counting in dualtor env + if (dual_tor_sock) { + interface_id_option intf_id; + intf_id.option_code = htons(OPTION_INTERFACE_ID); + intf_id.option_length = htons(sizeof(in6_addr)); + intf_id.interface_id = config->link_address.sin6_addr; + if ((unsigned)(current_buffer_position + sizeof(linklayer_addr_option) - buffer) > sizeof(buffer)) { + return; + } + memcpy(current_buffer_position, &intf_id, sizeof(interface_id_option)); + current_buffer_position += sizeof(interface_id_option); + } + auto dhcp_message_length = len; relay_forward(current_buffer_position, parse_dhcpv6_hdr(msg), dhcp_message_length); current_buffer_position += dhcp_message_length + sizeof(dhcpv6_option); + auto sock = config->gua_sock; + if (dual_tor_sock) { + sock = config->lo_sock; + } for(auto server: config->servers_sock) { if(send_udp(sock, buffer, server, current_buffer_position - buffer)) { process_sent_msg(config, new_message.msg_type); @@ -658,6 +680,11 @@ void relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr * target_addr.sin6_flowinfo = 0; target_addr.sin6_port = htons(CLIENT_PORT); target_addr.sin6_scope_id = if_nametoindex(config->interface.c_str()); + auto sock = config->lla_sock; + if (isIPv6Zero(dhcp_relay_header->link_address)) { + // In this case, it's multi-level relay + sock = config->gua_sock; + } if(send_udp(sock, buffer, target_addr, current_buffer_position - buffer)) { process_sent_msg(config, type); @@ -805,15 +832,10 @@ void client_packet_handler(uint8_t *buffer, ssize_t length, struct relay_config } auto option_position = current_position + sizeof(struct dhcpv6_msg); - auto relay_socket = config->gua_sock; - if (dual_tor_sock) { - relay_socket = config->lo_sock; - } - switch (msg->msg_type) { case DHCPv6_MESSAGE_TYPE_RELAY_FORW: { - relay_relay_forw(relay_socket, current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, config); + relay_relay_forw(current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, config); break; } case DHCPv6_MESSAGE_TYPE_SOLICIT: @@ -829,15 +851,13 @@ void client_packet_handler(uint8_t *buffer, ssize_t length, struct relay_config 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->state_db, counterVlan.append(config->interface), DHCPv6_MESSAGE_TYPE_MALFORMED); syslog(LOG_WARNING, "DHCPv6 option is invalid or contains malformed payload from %s\n", ifname.c_str()); return; } } - counters[msg->msg_type]++; update_counter(config->state_db, counterVlan.append(config->interface), msg->msg_type); - relay_client(relay_socket, current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, ether_header, config); + relay_client(current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, ether_header, config); break; } default: @@ -861,28 +881,62 @@ bool inline isIPv6Zero(struct in6_addr *addr) { return (memcmp(&addr, &in6addr_any, sizeof(in6addr_any)) == 0); } +/** + * @code struct relay_config * + * get_relay_int_from_relay_msg(uint8_t *packet, int32_t len, + * std::unordered_map &vlans) + * + * @brief get relay interface info from relay message + * + * @param addr ipv6 address + * + * @return bool + */ struct relay_config * -get_relay_int_from_packet(uint8_t *packet, int32_t len, std::unordered_map &vlans) { +get_relay_int_from_relay_msg(uint8_t *packet, int32_t len, std::unordered_map &vlans) { auto current_position = packet; auto dhcp_relay_header = parse_dhcpv6_relay(packet); + interface_id_option intf_id; + current_position += sizeof(struct dhcpv6_relay_msg); + while ((current_position - packet) < len) { + const uint8_t *tmp = NULL; + auto option = parse_dhcpv6_opt(current_position, &tmp); + current_position = tmp; + if (current_position - msg > len) { + break; + } + switch (ntohs(option->option_code)) { + case OPTION_INTERFACE_ID: { + intf_id.option_code = OPTION_INTERFACE_ID; + intf_id.option_length = ntohs(option->option_length); + memcpy(&intf_id.interface_id, ((uint8_t *)option) + sizeof(struct dhcpv6_option), intf_id.option_length); + break; + } + default: + break; + } + } + + struct in6_addr *addr = NULL; + if (!isIPv6Zero(&intf_id.interface_id)) { + addr = &intf_id.interface_id; + } else if (isIPv6Zero(&dhcp_relay_header->link_address)) { + addr = &dhcp_relay_header->link_address; + } // multi-level relay agents - if (isIPv6Zero(&dhcp_relay_header->link_address)) { - // This is temp solution for multi-level relay - // In this case, we need add - // 1. Add option82 in Relay Relay-Forward packets - // 2. Decode option82 in Relay-Reply to find out source vlan config + if (!addr) { return NULL; } - if (addr_vlan_map.find(dhcp_relay_header->link_address) == addr_vlan_map.end()) { + if (addr_vlan_map.find(*addr) == addr_vlan_map.end()) { char link_addr_str[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &dhcp_relay_header->link_address, link_addr_str, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, addr, link_addr_str, INET6_ADDRSTRLEN); syslog(LOG_WARNING, "DHCPv6 type %d can't find vlan info from link address %s\n", dhcp_relay_header->msg_type, link_addr_str); return NULL; } - auto vlan_name = addr_vlan_map[dhcp_relay_header->link_address]; + auto vlan_name = addr_vlan_map[*addr]; if (vlans.find(vlan_name) == vlans.end()) { syslog(LOG_WARNING, "DHCPv6 can't find vlan %s config\n", vlan_name); @@ -924,24 +978,22 @@ void server_callback_dualtor(evutil_socket_t fd, short event, void *arg) { continue; } - auto config = get_relay_int_from_packet(message_buffer, buffer_sz, vlans)) { - syslog(LOG_WARNING, "Invalid DHCPv6 header content, packet will be dropped\n"); + auto msg = parse_dhcpv6_hdr(message_buffer); + + if (msg->msg_type != DHCPv6_MESSAGE_TYPE_RELAY_REPL) { + syslog(LOG_WARNING, "Invalid DHCPv6 message type %d received on loopback interface\n", msg->msg_type); + update_counter(config->state_db, counterVlan.append(std::string(loopback)), msg->msg_type); continue; } - auto msg = parse_dhcpv6_hdr(message_buffer); - // RFC3315 only - if (msg->msg_type < DHCPv6_MESSAGE_TYPE_SOLICIT || msg->msg_type > DHCPv6_MESSAGE_TYPE_RELAY_REPL) { - update_counter(config->state_db, counterVlan.append(config->interface), DHCPv6_MESSAGE_TYPE_UNKNOWN); - syslog(LOG_WARNING, "Unknown DHCPv6 message type %d\n", msg->msg_type); + auto config = get_relay_int_from_relay_msg(message_buffer, buffer_sz, vlans); + if (!config) { + syslog(LOG_WARNING, "Invalid DHCPv6 header content on loopback socket, packet will be dropped\n"); + update_counter(config->state_db, counterVlan.append(std::string(loopback)), msg->msg_type); continue; - } else { - counters[msg->msg_type]++; } + update_counter(config->state_db, counterVlan.append(std::string(loopback)), msg->msg_type); - update_counter(config->state_db, counterVlan.append(config->interface), msg->msg_type); - if (msg->msg_type == DHCPv6_MESSAGE_TYPE_RELAY_REPL) { - relay_relay_reply(config->lla_sock, message_buffer, buffer_sz, config); - } + relay_relay_reply(message_buffer, buffer_sz, config); } } @@ -985,13 +1037,11 @@ void server_callback(evutil_socket_t fd, short event, void *arg) { update_counter(config->state_db, counterVlan.append(config->interface), DHCPv6_MESSAGE_TYPE_UNKNOWN); syslog(LOG_WARNING, "Unknown DHCPv6 message type %d\n", msg->msg_type); continue; - } else { - counters[msg->msg_type]++; } update_counter(config->state_db, counterVlan.append(config->interface), msg->msg_type); if (msg->msg_type == DHCPv6_MESSAGE_TYPE_RELAY_REPL) { - relay_relay_reply(config->lla_sock, message_buffer, buffer_sz, config); + relay_relay_reply(message_buffer, buffer_sz, config); } } } diff --git a/src/relay.h b/src/relay.h index 668f8df..ba2c49e 100644 --- a/src/relay.h +++ b/src/relay.h @@ -170,7 +170,7 @@ void relay_forward(uint8_t *buffer, const struct dhcpv6_msg *msg, uint16_t msg_l * * @return none */ -void relay_client(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config); +void relay_client(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config); /** * @code relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config) @@ -185,21 +185,20 @@ void relay_client(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_h * * @return none */ -void relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config); +void relay_relay_forw(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config); /** - * @code relay_relay_reply(int sock, const uint8_t *msg, int32_t len, relay_config *configs); + * @code relay_relay_reply(const uint8_t *msg, int32_t len, relay_config *configs); * * @brief relay and unwrap a relay-reply message * - * @param sock L3 socket for sending data to servers * @param msg pointer to dhcpv6 message header position * @param len size of data received * @param config relay interface config * * @return none */ -void relay_relay_reply(int sock, const uint8_t *msg, int32_t len, relay_config *configs); +void relay_relay_reply(const uint8_t *msg, int32_t len, relay_config *configs); /** * @code loop_relay(std::unordered_map &vlans); From 1c183075c45040c454839a874b8ca838c628e1dd Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Tue, 13 Jun 2023 12:31:16 +0000 Subject: [PATCH 03/19] fix input parameter issue --- src/main.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 09613ef..54fc75c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,23 +13,23 @@ static void usage() } int main(int argc, char *argv[]) { - if (argc > 1) { + if (argc > 2) { switch (argv[1][1]) { case 'u': - if (strlen(argv[i + 1]) < IF_NAMESIZE) { + if (strlen(argv[2]) != 0 && strlen(argv[2]) < IF_NAMESIZE) { std::memset(loopback, 0, IF_NAMESIZE); - std::memcpy(loopback, argv[i + 1], strlen(argv[i + 1])); + std::memcpy(loopback, argv[2], strlen(argv[2])); } else { syslog(LOG_ERR, "loopback interface name over length %d.\n", IF_NAMESIZE); return 1; } dual_tor_sock = true; - i += 2; break; default: fprintf(stderr, "%s: Unknown option\n", basename(argv[0])); usage(); + return 0; } } try { From fdeed08a8e898727ee049d1d0403a1be7cf430d3 Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Wed, 14 Jun 2023 13:09:14 +0000 Subject: [PATCH 04/19] fix build issue --- src/relay.cpp | 3 +-- src/relay.h | 6 ++---- test/MockRelay.cpp | 6 +++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/relay.cpp b/src/relay.cpp index b0e6a56..1136709 100644 --- a/src/relay.cpp +++ b/src/relay.cpp @@ -575,11 +575,10 @@ void relay_client(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, const } /** - * @code relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config) + * @code relay_relay_forw(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config) * * @brief construct a relay-forward message encapsulated relay-forward message * - * @param sock L3 socket for sending data to servers * @param msg pointer to dhcpv6 message header position * @param len size of data received * @param ip_hdr pointer to IPv6 header diff --git a/src/relay.h b/src/relay.h index ba2c49e..4a9f334 100644 --- a/src/relay.h +++ b/src/relay.h @@ -157,11 +157,10 @@ void prepare_relay_config(relay_config &interface_config, int gua_sock, int filt void relay_forward(uint8_t *buffer, const struct dhcpv6_msg *msg, uint16_t msg_length); /** - * @code relay_client(int sock, const uint8_t *msg, int32_t len, ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config); + * @code relay_client(const uint8_t *msg, int32_t len, ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config); * * @brief construct relay-forward message * - * @param sock L3 socket for sending data to servers * @param msg pointer to dhcpv6 message header position * @param len size of data received * @param ip_hdr pointer to IPv6 header @@ -173,11 +172,10 @@ void relay_forward(uint8_t *buffer, const struct dhcpv6_msg *msg, uint16_t msg_l void relay_client(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config); /** - * @code relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config) + * @code relay_relay_forw(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config) * * @brief construct a relay-forward message encapsulated relay-forward message * - * @param sock L3 socket for sending data to servers * @param msg pointer to dhcpv6 message header position * @param len size of data received * @param ip_hdr pointer to IPv6 header diff --git a/test/MockRelay.cpp b/test/MockRelay.cpp index 0d14de7..af0208d 100644 --- a/test/MockRelay.cpp +++ b/test/MockRelay.cpp @@ -357,7 +357,7 @@ TEST(relay, relay_client) ip6_hdr ip_hdr; std::string s_addr = "2000::3"; - relay_client(mock_sock, msg, msg_len, &ip_hdr, ðer_hdr, &config); + relay_client(msg, msg_len, &ip_hdr, ðer_hdr, &config); EXPECT_EQ(last_used_sock, 124); @@ -433,7 +433,7 @@ TEST(relay, relay_relay_forw) { std::string s_addr = "2000::3"; inet_pton(AF_INET6, s_addr.c_str(), &ip_hdr.ip6_src); - relay_relay_forw(mock_sock, msg, msg_len, &ip_hdr, &config); + relay_relay_forw(msg, msg_len, &ip_hdr, &config); EXPECT_EQ(last_used_sock, 125); @@ -497,7 +497,7 @@ TEST(relay, relay_relay_reply) prepare_relay_config(config, local_sock, filter); - relay_relay_reply(mock_sock, msg, msg_len, &config); + relay_relay_reply(msg, msg_len, &config); EXPECT_EQ(last_used_sock, 123); From ad0fa28228b6043fbbd012197a807bc68c54b3bb Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Wed, 14 Jun 2023 13:37:06 +0000 Subject: [PATCH 05/19] fix build issue, unordered_map --- src/relay.cpp | 6 +++--- src/relay.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/relay.cpp b/src/relay.cpp index 1136709..bddf870 100644 --- a/src/relay.cpp +++ b/src/relay.cpp @@ -70,7 +70,7 @@ std::map counterMap = {{DHCPv6_MESSAGE_TYPE_UNKNOWN, "Unknown" std::unordered_map vlan_map; /* ipv6 address to vlan name mapping */ -std::unordered_map addr_vlan_map; +std::unordered_map addr_vlan_map; /** * @code initialize_counter(std::shared_ptr state_db, std::string counterVlan); @@ -364,11 +364,11 @@ void prepare_relay_config(relay_config &interface_config, int gua_sock, int filt if(!IN6_IS_ADDR_LINKLOCAL(&non_link_local.sin6_addr)) { interface_config.link_address = non_link_local; - addr_vlan_map[non_link_local] = interface_config.interface; + addr_vlan_map[non_link_local.sin6_addr] = interface_config.interface; } else { interface_config.link_address = link_local; - addr_vlan_map[link_local] = interface_config.interface; + addr_vlan_map[link_local.sin6_addr] = interface_config.interface; } } diff --git a/src/relay.h b/src/relay.h index 4a9f334..fd23558 100644 --- a/src/relay.h +++ b/src/relay.h @@ -126,9 +126,9 @@ int sock_open(const struct sock_fprog *fprog); * @param gua_sock socket binded to global address for relaying client message to server and listening for server message * @param lla_sock socket binded to link_local address for relaying server message to client * - * @return none + * @return int */ -void prepare_vlan_sockets(int &gua_sock, int &lla_sock, relay_config &config); +int prepare_vlan_sockets(int &gua_sock, int &lla_sock, relay_config &config); /** * @code prepare_relay_config(relay_config &interface_config, int gua_sock, int filter); From 14105af4072491c83147fb0ca731e6da740cd475 Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Wed, 14 Jun 2023 14:54:43 +0000 Subject: [PATCH 06/19] fix build issue and multi-level relay target port issue --- src/relay.cpp | 61 +++++++++++++++++++++++----------------------- src/relay.h | 1 + test/MockRelay.cpp | 15 +++++++----- 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/src/relay.cpp b/src/relay.cpp index bddf870..0515f09 100644 --- a/src/relay.cpp +++ b/src/relay.cpp @@ -70,7 +70,7 @@ std::map counterMap = {{DHCPv6_MESSAGE_TYPE_UNKNOWN, "Unknown" std::unordered_map vlan_map; /* ipv6 address to vlan name mapping */ -std::unordered_map addr_vlan_map; +std::map addr_vlan_map; /** * @code initialize_counter(std::shared_ptr state_db, std::string counterVlan); @@ -132,6 +132,19 @@ std::string toString(uint64_t count) { return countValue; } +/** + * @code bool inline isIPv6Zero(const in6_addr *addr) + * + * @brief check if ipv6 address is zero + * + * @param addr ipv6 address + * + * @return bool + */ +bool inline isIPv6Zero(const in6_addr *addr) { + return (memcmp(&addr, &in6addr_any, sizeof(in6addr_any)) == 0); +} + /** * @code const struct ether_header *parse_ether_frame(const uint8_t *buffer, const uint8_t **out_end); * @@ -392,7 +405,7 @@ int prepare_lo_socket(const char *lo) { ifa_tmp = ifa; while (ifa_tmp) { if (ifa_tmp->ifa_addr && (ifa_tmp->ifa_addr->sa_family == AF_INET6)) { - if (strcmp(ifa_tmp->ifa_name, lo) == 0)) { + if (strcmp(ifa_tmp->ifa_name, lo) == 0) { struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa_tmp->ifa_addr; if (!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { bind_gua = true; @@ -457,7 +470,7 @@ int prepare_vlan_sockets(int &gua_sock, int &lla_sock, relay_config &config) { ifa_tmp = ifa; while (ifa_tmp) { if (ifa_tmp->ifa_addr && (ifa_tmp->ifa_addr->sa_family == AF_INET6)) { - if (strcmp(ifa_tmp->ifa_name, config.interface.c_str()) == 0)) { + if (strcmp(ifa_tmp->ifa_name, config.interface.c_str()) == 0) { struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa_tmp->ifa_addr; if (!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { bind_gua = true; @@ -563,7 +576,7 @@ void relay_client(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, const relay_forward(current_buffer_position, parse_dhcpv6_hdr(msg), dhcp_message_length); current_buffer_position += dhcp_message_length + sizeof(dhcpv6_option); - auto sock = config->gua_sock; + int sock = config->gua_sock; if (dual_tor_sock) { sock = config->lo_sock; } @@ -622,7 +635,7 @@ void relay_relay_forw(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, re relay_forward(current_buffer_position, parse_dhcpv6_hdr(msg), dhcp_message_length); current_buffer_position += dhcp_message_length + sizeof(dhcpv6_option); - auto sock = config->gua_sock; + int sock = config->gua_sock; if (dual_tor_sock) { sock = config->lo_sock; } @@ -679,10 +692,12 @@ void relay_relay_forw(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, re target_addr.sin6_flowinfo = 0; target_addr.sin6_port = htons(CLIENT_PORT); target_addr.sin6_scope_id = if_nametoindex(config->interface.c_str()); - auto sock = config->lla_sock; + int sock = config->lla_sock; if (isIPv6Zero(dhcp_relay_header->link_address)) { // In this case, it's multi-level relay - sock = config->gua_sock; + if (!IN6_IS_ADDR_LINKLOCAL(&dhcp_relay_header->peer_address)) + sock = config->gua_sock; + target_addr.sin6_port = htons(RELAY_PORT); } if(send_udp(sock, buffer, target_addr, current_buffer_position - buffer)) { @@ -867,23 +882,10 @@ void client_packet_handler(uint8_t *buffer, ssize_t length, struct relay_config } } -/** - * @code bool inline isIPv6Zero(struct in6_addr *addr) - * - * @brief check if ipv6 address is zero - * - * @param addr ipv6 address - * - * @return bool - */ -bool inline isIPv6Zero(struct in6_addr *addr) { - return (memcmp(&addr, &in6addr_any, sizeof(in6addr_any)) == 0); -} - /** * @code struct relay_config * - * get_relay_int_from_relay_msg(uint8_t *packet, int32_t len, - * std::unordered_map &vlans) + * get_relay_int_from_relay_msg(uint8_t *msg, int32_t len, + * std::unordered_map *vlans) * * @brief get relay interface info from relay message * @@ -892,14 +894,14 @@ bool inline isIPv6Zero(struct in6_addr *addr) { * @return bool */ struct relay_config * -get_relay_int_from_relay_msg(uint8_t *packet, int32_t len, std::unordered_map &vlans) { - auto current_position = packet; - auto dhcp_relay_header = parse_dhcpv6_relay(packet); +get_relay_int_from_relay_msg(uint8_t *msg, int32_t len, std::unordered_map *vlans) { + auto current_position = msg; + auto dhcp_relay_header = parse_dhcpv6_relay(msg); interface_id_option intf_id; current_position += sizeof(struct dhcpv6_relay_msg); - while ((current_position - packet) < len) { - const uint8_t *tmp = NULL; + while ((current_position - msg) < len) { + uint8_t *tmp = NULL; auto option = parse_dhcpv6_opt(current_position, &tmp); current_position = tmp; if (current_position - msg > len) { @@ -937,8 +939,8 @@ get_relay_int_from_relay_msg(uint8_t *packet, int32_t len, std::unordered_mapfind(vlan_name) == vlans->end()) { + syslog(LOG_WARNING, "DHCPv6 can't find vlan %s config\n", vlan_name.c_str()); return NULL; } return &vlans[vlan_name]; @@ -981,7 +983,6 @@ void server_callback_dualtor(evutil_socket_t fd, short event, void *arg) { if (msg->msg_type != DHCPv6_MESSAGE_TYPE_RELAY_REPL) { syslog(LOG_WARNING, "Invalid DHCPv6 message type %d received on loopback interface\n", msg->msg_type); - update_counter(config->state_db, counterVlan.append(std::string(loopback)), msg->msg_type); continue; } auto config = get_relay_int_from_relay_msg(message_buffer, buffer_sz, vlans); diff --git a/src/relay.h b/src/relay.h index fd23558..d2a45e2 100644 --- a/src/relay.h +++ b/src/relay.h @@ -34,6 +34,7 @@ #define BATCH_SIZE 64 extern bool dual_tor_sock; +extern char loopback[IF_NAMESIZE]; /* DHCPv6 message types */ typedef enum diff --git a/test/MockRelay.cpp b/test/MockRelay.cpp index af0208d..2e84081 100644 --- a/test/MockRelay.cpp +++ b/test/MockRelay.cpp @@ -316,8 +316,6 @@ TEST(counter, update_counter) TEST(relay, relay_client) { - int mock_sock = 124; - uint8_t msg[] = { 0x01, 0x2f, 0xf4, 0xc8, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x25, 0x3a, 0x37, 0xb9, @@ -345,6 +343,9 @@ TEST(relay, relay_client) } std::shared_ptr state_db = std::make_shared ("STATE_DB", 0); config.state_db = state_db; + config.gua_sock = 125; + config.lla_sock = 125; + config.lo_sock = 125; struct ether_header ether_hdr; ether_hdr.ether_shost[0] = 0x5a; @@ -394,8 +395,6 @@ TEST(relay, relay_client) } TEST(relay, relay_relay_forw) { - int mock_sock = 125; - uint8_t msg[] = { 0x0c, 0x00, 0x20, 0x01, 0x0d, 0xb8, 0x01, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -428,6 +427,9 @@ TEST(relay, relay_relay_forw) { } std::shared_ptr state_db = std::make_shared ("STATE_DB", 0); config.state_db = state_db; + config.gua_sock = 125; + config.lla_sock = 125; + config.lo_sock = 125; ip6_hdr ip_hdr; std::string s_addr = "2000::3"; @@ -453,8 +455,6 @@ TEST(relay, relay_relay_forw) { TEST(relay, relay_relay_reply) { - int mock_sock = 123; - uint8_t msg[] = { 0x0d, 0x00, 0x20, 0x01, 0x0d, 0xb8, 0x01, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -491,6 +491,9 @@ TEST(relay, relay_relay_reply) config.interface = "Vlan1000"; std::shared_ptr state_db = std::make_shared ("STATE_DB", 0); config.state_db = state_db; + config.gua_sock = 125; + config.lla_sock = 125; + config.lo_sock = 125; int local_sock = 1; int filter = 1; From 8b18980574e048ba4a7feacbd45dcc24414e291d Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Wed, 14 Jun 2023 15:16:56 +0000 Subject: [PATCH 07/19] fix build issue --- src/relay.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/relay.cpp b/src/relay.cpp index 0515f09..ae886c0 100644 --- a/src/relay.cpp +++ b/src/relay.cpp @@ -410,8 +410,8 @@ int prepare_lo_socket(const char *lo) { if (!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { bind_gua = true; gua = *in6; - gua->sin6_family = AF_INET6; - gua->sin6_port = htons(RELAY_PORT); + gua.sin6_family = AF_INET6; + gua.sin6_port = htons(RELAY_PORT); break; } } @@ -475,13 +475,13 @@ int prepare_vlan_sockets(int &gua_sock, int &lla_sock, relay_config &config) { if (!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { bind_gua = true; gua = *in6; - gua->sin6_family = AF_INET6; - gua->sin6_port = htons(RELAY_PORT); + gua.sin6_family = AF_INET6; + gua.sin6_port = htons(RELAY_PORT); } else { bind_lla = true; lla = *in6; - lla->sin6_family = AF_INET6; - lla->sin6_port = htons(RELAY_PORT); + lla.sin6_addr = AF_INET6; + lla.sin6_port = htons(RELAY_PORT); } } } @@ -647,18 +647,17 @@ void relay_relay_forw(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, re } /** - * @code relay_relay_reply(int sock, const uint8_t *msg, int32_t len, relay_config *configs); + * @code relay_relay_reply(const uint8_t *msg, int32_t len, relay_config *configs); * * @brief relay and unwrap a relay-reply message * - * @param sock L3 socket for sending data to servers * @param msg pointer to dhcpv6 message header position * @param len size of data received * @param config relay interface config * * @return none */ - void relay_relay_reply(int sock, const uint8_t *msg, int32_t len, relay_config *config) { + void relay_relay_reply(const uint8_t *msg, int32_t len, relay_config *config) { static uint8_t buffer[BUFFER_SIZE]; uint8_t type = 0; struct sockaddr_in6 target_addr; @@ -693,7 +692,7 @@ void relay_relay_forw(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, re target_addr.sin6_port = htons(CLIENT_PORT); target_addr.sin6_scope_id = if_nametoindex(config->interface.c_str()); int sock = config->lla_sock; - if (isIPv6Zero(dhcp_relay_header->link_address)) { + if (isIPv6Zero(&dhcp_relay_header->link_address)) { // In this case, it's multi-level relay if (!IN6_IS_ADDR_LINKLOCAL(&dhcp_relay_header->peer_address)) sock = config->gua_sock; @@ -901,7 +900,7 @@ get_relay_int_from_relay_msg(uint8_t *msg, int32_t len, std::unordered_map len) { @@ -919,7 +918,7 @@ get_relay_int_from_relay_msg(uint8_t *msg, int32_t len, std::unordered_maplink_address)) { @@ -943,7 +942,7 @@ get_relay_int_from_relay_msg(uint8_t *msg, int32_t len, std::unordered_mapfind(vlan_name)->second; } /** From 2cbaea84f6ced5b392e45393d8aa28b42e384818 Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Wed, 14 Jun 2023 15:57:55 +0000 Subject: [PATCH 08/19] fix hash map --- src/relay.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/relay.cpp b/src/relay.cpp index ae886c0..45eb2c8 100644 --- a/src/relay.cpp +++ b/src/relay.cpp @@ -70,7 +70,17 @@ std::map counterMap = {{DHCPv6_MESSAGE_TYPE_UNKNOWN, "Unknown" std::unordered_map vlan_map; /* ipv6 address to vlan name mapping */ -std::map addr_vlan_map; +struct in6_addrHash { + std::size_t operator()(const in6_addr& k) const { + std::size_t res = 17; + res = res * 31 + std::hash()(k.__in6_u.__u6_addr32[0]); + res = res * 31 + std::hash()(k.__in6_u.__u6_addr32[1]); + res = res * 31 + std::hash()(k.__in6_u.__u6_addr32[2]); + res = res * 31 + std::hash()(k.__in6_u.__u6_addr32[3]); + return res; + } +}; +std::unordered_map addr_vlan_map; /** * @code initialize_counter(std::shared_ptr state_db, std::string counterVlan); @@ -377,11 +387,11 @@ void prepare_relay_config(relay_config &interface_config, int gua_sock, int filt if(!IN6_IS_ADDR_LINKLOCAL(&non_link_local.sin6_addr)) { interface_config.link_address = non_link_local; - addr_vlan_map[non_link_local.sin6_addr] = interface_config.interface; + addr_vlan_map.insert({non_link_local.sin6_addr, interface_config.interface}); } else { interface_config.link_address = link_local; - addr_vlan_map[link_local.sin6_addr] = interface_config.interface; + addr_vlan_map.insert({link_local.sin6_addr, interface_config.interface}); } } @@ -480,7 +490,7 @@ int prepare_vlan_sockets(int &gua_sock, int &lla_sock, relay_config &config) { } else { bind_lla = true; lla = *in6; - lla.sin6_addr = AF_INET6; + lla.sin6_family = AF_INET6; lla.sin6_port = htons(RELAY_PORT); } } @@ -883,7 +893,7 @@ void client_packet_handler(uint8_t *buffer, ssize_t length, struct relay_config /** * @code struct relay_config * - * get_relay_int_from_relay_msg(uint8_t *msg, int32_t len, + * get_relay_int_from_relay_msg(const uint8_t *msg, int32_t len, * std::unordered_map *vlans) * * @brief get relay interface info from relay message @@ -893,7 +903,7 @@ void client_packet_handler(uint8_t *buffer, ssize_t length, struct relay_config * @return bool */ struct relay_config * -get_relay_int_from_relay_msg(uint8_t *msg, int32_t len, std::unordered_map *vlans) { +get_relay_int_from_relay_msg(const uint8_t *msg, int32_t len, std::unordered_map *vlans) { auto current_position = msg; auto dhcp_relay_header = parse_dhcpv6_relay(msg); interface_id_option intf_id; From 41e6bc948e0fc30532c521179fab99ab434d7118 Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Wed, 14 Jun 2023 16:19:34 +0000 Subject: [PATCH 09/19] fix map issue --- src/relay.cpp | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/relay.cpp b/src/relay.cpp index 45eb2c8..ac1d477 100644 --- a/src/relay.cpp +++ b/src/relay.cpp @@ -70,17 +70,7 @@ std::map counterMap = {{DHCPv6_MESSAGE_TYPE_UNKNOWN, "Unknown" std::unordered_map vlan_map; /* ipv6 address to vlan name mapping */ -struct in6_addrHash { - std::size_t operator()(const in6_addr& k) const { - std::size_t res = 17; - res = res * 31 + std::hash()(k.__in6_u.__u6_addr32[0]); - res = res * 31 + std::hash()(k.__in6_u.__u6_addr32[1]); - res = res * 31 + std::hash()(k.__in6_u.__u6_addr32[2]); - res = res * 31 + std::hash()(k.__in6_u.__u6_addr32[3]); - return res; - } -}; -std::unordered_map addr_vlan_map; +std::unordered_map addr_vlan_map; /** * @code initialize_counter(std::shared_ptr state_db, std::string counterVlan); @@ -385,13 +375,16 @@ void prepare_relay_config(relay_config &interface_config, int gua_sock, int filt } freeifaddrs(ifa); + char ipv6_str[INET6_ADDRSTRLEN] = {}; if(!IN6_IS_ADDR_LINKLOCAL(&non_link_local.sin6_addr)) { interface_config.link_address = non_link_local; - addr_vlan_map.insert({non_link_local.sin6_addr, interface_config.interface}); + inet_ntop(AF_INET6, &non_link_local.sin6_addr, ipv6_str, INET6_ADDRSTRLEN); + addr_vlan_map[std::string(ipv6_str)] = interface_config.interface; } else { interface_config.link_address = link_local; - addr_vlan_map.insert({link_local.sin6_addr, interface_config.interface}); + inet_ntop(AF_INET6, &link_local.sin6_addr, ipv6_str, INET6_ADDRSTRLEN); + addr_vlan_map[std::string(ipv6_str)] = interface_config.interface; } } @@ -939,14 +932,15 @@ get_relay_int_from_relay_msg(const uint8_t *msg, int32_t len, std::unordered_map return NULL; } - if (addr_vlan_map.find(*addr) == addr_vlan_map.end()) { - char link_addr_str[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, addr, link_addr_str, INET6_ADDRSTRLEN); + char ipv6_str[INET6_ADDRSTRLEN] = {}; + inet_ntop(AF_INET6, addr, ipv6_str, INET6_ADDRSTRLEN); + auto v6_string = std::string(ipv6_str); + if (addr_vlan_map.find(v6_string) == addr_vlan_map.end()) { syslog(LOG_WARNING, "DHCPv6 type %d can't find vlan info from link address %s\n", - dhcp_relay_header->msg_type, link_addr_str); + dhcp_relay_header->msg_type, ipv6_str); return NULL; } - auto vlan_name = addr_vlan_map[*addr]; + auto vlan_name = addr_vlan_map[v6_string]; if (vlans->find(vlan_name) == vlans->end()) { syslog(LOG_WARNING, "DHCPv6 can't find vlan %s config\n", vlan_name.c_str()); From 2c38694fd92ad5a3b15418675f5e97465a430f0c Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Wed, 14 Jun 2023 16:27:28 +0000 Subject: [PATCH 10/19] fix build issue --- src/configInterface.h | 3 +++ src/main.cpp | 1 - src/relay.h | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/configInterface.h b/src/configInterface.h index 94a0578..21b0669 100644 --- a/src/configInterface.h +++ b/src/configInterface.h @@ -11,6 +11,9 @@ struct swssNotification { std::unordered_map vlans; swss::SubscriberStateTable *ipHelpersTable; }; + +char loopback[IF_NAMESIZE] = "Loopback0"; + /** * @code void initialize_swss() * diff --git a/src/main.cpp b/src/main.cpp index 54fc75c..d952222 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,7 +4,6 @@ #include "configInterface.h" bool dual_tor_sock = false; -char loopback[IF_NAMESIZE] = "Loopback0"; static void usage() { diff --git a/src/relay.h b/src/relay.h index d2a45e2..fd23558 100644 --- a/src/relay.h +++ b/src/relay.h @@ -34,7 +34,6 @@ #define BATCH_SIZE 64 extern bool dual_tor_sock; -extern char loopback[IF_NAMESIZE]; /* DHCPv6 message types */ typedef enum From e8b2b9a1947cb0b884ea9edfd49577d6f5672233 Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Thu, 15 Jun 2023 06:15:09 +0000 Subject: [PATCH 11/19] fix build issue --- src/configInterface.h | 2 -- src/main.cpp | 1 + src/relay.cpp | 2 +- src/relay.h | 1 + test/main.cpp | 2 ++ 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/configInterface.h b/src/configInterface.h index 21b0669..38f3ee2 100644 --- a/src/configInterface.h +++ b/src/configInterface.h @@ -12,8 +12,6 @@ struct swssNotification { swss::SubscriberStateTable *ipHelpersTable; }; -char loopback[IF_NAMESIZE] = "Loopback0"; - /** * @code void initialize_swss() * diff --git a/src/main.cpp b/src/main.cpp index d952222..54fc75c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,7 @@ #include "configInterface.h" bool dual_tor_sock = false; +char loopback[IF_NAMESIZE] = "Loopback0"; static void usage() { diff --git a/src/relay.cpp b/src/relay.cpp index ac1d477..b9252ad 100644 --- a/src/relay.cpp +++ b/src/relay.cpp @@ -142,7 +142,7 @@ std::string toString(uint64_t count) { * @return bool */ bool inline isIPv6Zero(const in6_addr *addr) { - return (memcmp(&addr, &in6addr_any, sizeof(in6addr_any)) == 0); + return (memcmp(addr, &in6addr_any, sizeof(in6addr_any)) == 0); } /** diff --git a/src/relay.h b/src/relay.h index fd23558..d2a45e2 100644 --- a/src/relay.h +++ b/src/relay.h @@ -34,6 +34,7 @@ #define BATCH_SIZE 64 extern bool dual_tor_sock; +extern char loopback[IF_NAMESIZE]; /* DHCPv6 message types */ typedef enum diff --git a/test/main.cpp b/test/main.cpp index dfca267..8bbf55c 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -3,6 +3,8 @@ #include std::string database_config = "./test/database_config.json"; +bool dual_tor_sock = false; +char loopback[IF_NAMESIZE] = "Loopback0"; class DhcpRelayEnvironment : public ::testing::Environment { public: From 2bb0f3bae37791f42ac737f3bce7f482bf8722b8 Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Thu, 15 Jun 2023 06:26:37 +0000 Subject: [PATCH 12/19] fix test code build issue --- test/MockRelay.cpp | 1 + test/main.cpp | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/MockRelay.cpp b/test/MockRelay.cpp index 2e84081..dece937 100644 --- a/test/MockRelay.cpp +++ b/test/MockRelay.cpp @@ -11,6 +11,7 @@ #include "MockRelay.h" bool dual_tor_sock = false; +char loopback[IF_NAMESIZE] = "Loopback0"; extern struct event_base *base; extern struct event *ev_sigint; extern struct event *ev_sigterm; diff --git a/test/main.cpp b/test/main.cpp index 8bbf55c..6b3b209 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -1,10 +1,9 @@ #include "gtest/gtest.h" +#include #include #include std::string database_config = "./test/database_config.json"; -bool dual_tor_sock = false; -char loopback[IF_NAMESIZE] = "Loopback0"; class DhcpRelayEnvironment : public ::testing::Environment { public: From 6404aac2a74e970b4132e97b13f9e00fe904636b Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Wed, 21 Jun 2023 11:35:00 +0000 Subject: [PATCH 13/19] fix link-address get issue --- src/relay.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/relay.cpp b/src/relay.cpp index b9252ad..76eb4ef 100644 --- a/src/relay.cpp +++ b/src/relay.cpp @@ -921,27 +921,27 @@ get_relay_int_from_relay_msg(const uint8_t *msg, int32_t len, std::unordered_map } } - const in6_addr *addr = NULL; + in6_addr address = in6addr_any; if (!isIPv6Zero(&intf_id.interface_id)) { - addr = &intf_id.interface_id; + std::memcpy(&address, &intf_id.interface_id, sizeof(in6_addr)); } else if (isIPv6Zero(&dhcp_relay_header->link_address)) { - addr = &dhcp_relay_header->link_address; + std::memcpy(&address, &dhcp_relay_header->link_address, sizeof(in6_addr)); } // multi-level relay agents - if (!addr) { + if (!isIPv6Zero(&address)) { return NULL; } char ipv6_str[INET6_ADDRSTRLEN] = {}; - inet_ntop(AF_INET6, addr, ipv6_str, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, address, ipv6_str, INET6_ADDRSTRLEN); auto v6_string = std::string(ipv6_str); if (addr_vlan_map.find(v6_string) == addr_vlan_map.end()) { syslog(LOG_WARNING, "DHCPv6 type %d can't find vlan info from link address %s\n", dhcp_relay_header->msg_type, ipv6_str); return NULL; } - auto vlan_name = addr_vlan_map[v6_string]; + auto vlan_name = addr_vlan_map[v6_string]; if (vlans->find(vlan_name) == vlans->end()) { syslog(LOG_WARNING, "DHCPv6 can't find vlan %s config\n", vlan_name.c_str()); return NULL; @@ -991,7 +991,6 @@ void server_callback_dualtor(evutil_socket_t fd, short event, void *arg) { auto config = get_relay_int_from_relay_msg(message_buffer, buffer_sz, vlans); if (!config) { syslog(LOG_WARNING, "Invalid DHCPv6 header content on loopback socket, packet will be dropped\n"); - update_counter(config->state_db, counterVlan.append(std::string(loopback)), msg->msg_type); continue; } update_counter(config->state_db, counterVlan.append(std::string(loopback)), msg->msg_type); From 41827a733805d2d8cf92ef5b4b1240f2120328e7 Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Wed, 21 Jun 2023 12:24:21 +0000 Subject: [PATCH 14/19] fix issue --- src/relay.cpp | 6 +++--- src/relay.h | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/relay.cpp b/src/relay.cpp index 76eb4ef..4ae57bb 100644 --- a/src/relay.cpp +++ b/src/relay.cpp @@ -231,7 +231,6 @@ const struct dhcpv6_relay_msg *parse_dhcpv6_relay(const uint8_t *buffer) { const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_t **out_end) { 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 option; @@ -901,6 +900,7 @@ get_relay_int_from_relay_msg(const uint8_t *msg, int32_t len, std::unordered_map auto dhcp_relay_header = parse_dhcpv6_relay(msg); interface_id_option intf_id; + std::memset(&intf_id, 0, sizeof(interface_id_option)); current_position += sizeof(struct dhcpv6_relay_msg); while ((current_position - msg) < len) { const uint8_t *tmp = NULL; @@ -913,7 +913,7 @@ get_relay_int_from_relay_msg(const uint8_t *msg, int32_t len, std::unordered_map case OPTION_INTERFACE_ID: { intf_id.option_code = OPTION_INTERFACE_ID; intf_id.option_length = ntohs(option->option_length); - memcpy(&intf_id.interface_id, ((uint8_t *)option) + sizeof(struct dhcpv6_option), intf_id.option_length); + std::memcpy(&intf_id.interface_id, ((uint8_t *)option) + sizeof(struct dhcpv6_option), intf_id.option_length); break; } default: @@ -933,7 +933,7 @@ get_relay_int_from_relay_msg(const uint8_t *msg, int32_t len, std::unordered_map } char ipv6_str[INET6_ADDRSTRLEN] = {}; - inet_ntop(AF_INET6, address, ipv6_str, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, &address, ipv6_str, INET6_ADDRSTRLEN); auto v6_string = std::string(ipv6_str); if (addr_vlan_map.find(v6_string) == addr_vlan_map.end()) { syslog(LOG_WARNING, "DHCPv6 type %d can't find vlan info from link address %s\n", diff --git a/src/relay.h b/src/relay.h index d2a45e2..c43917e 100644 --- a/src/relay.h +++ b/src/relay.h @@ -89,7 +89,6 @@ struct PACKED dhcpv6_relay_msg { struct in6_addr peer_address; }; - struct dhcpv6_option { uint16_t option_code; uint16_t option_length; From c8b6915187e5d5f8be30be5fdea4d759d763b9dc Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Wed, 7 Jun 2023 13:56:52 +0000 Subject: [PATCH 15/19] 202012 dualtor dhcpv6 relay issue fix --- src/configInterface.h | 1 + src/main.cpp | 17 +- src/relay.cpp | 413 +++++++++++++++++++++++++++++++++--------- src/relay.h | 41 ++--- test/MockRelay.cpp | 22 ++- test/main.cpp | 1 + 6 files changed, 374 insertions(+), 121 deletions(-) diff --git a/src/configInterface.h b/src/configInterface.h index 94a0578..38f3ee2 100644 --- a/src/configInterface.h +++ b/src/configInterface.h @@ -11,6 +11,7 @@ struct swssNotification { std::unordered_map vlans; swss::SubscriberStateTable *ipHelpersTable; }; + /** * @code void initialize_swss() * diff --git a/src/main.cpp b/src/main.cpp index 9da3cb8..54fc75c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,23 +4,32 @@ #include "configInterface.h" bool dual_tor_sock = false; +char loopback[IF_NAMESIZE] = "Loopback0"; static void usage() { - printf("Usage: ./dhcp6relay {-d}\n"); - printf("\t-d: enable dual tor option\n"); + printf("Usage: ./dhcp6relay [-u ]\n"); + printf("\tloopback interface: is the loopback interface for dual tor setup\n"); } int main(int argc, char *argv[]) { - if (argc > 1) { + if (argc > 2) { switch (argv[1][1]) { - case 'd': + case 'u': + if (strlen(argv[2]) != 0 && strlen(argv[2]) < IF_NAMESIZE) { + std::memset(loopback, 0, IF_NAMESIZE); + std::memcpy(loopback, argv[2], strlen(argv[2])); + } else { + syslog(LOG_ERR, "loopback interface name over length %d.\n", IF_NAMESIZE); + return 1; + } dual_tor_sock = true; break; default: fprintf(stderr, "%s: Unknown option\n", basename(argv[0])); usage(); + return 0; } } try { diff --git a/src/relay.cpp b/src/relay.cpp index 64390a9..7b511db 100644 --- a/src/relay.cpp +++ b/src/relay.cpp @@ -14,8 +14,6 @@ #define BUFFER_SIZE 9200 -struct event *listen_event; -struct event *server_listen_event; struct event_base *base; struct event *ev_sigint; struct event *ev_sigterm; @@ -71,6 +69,9 @@ std::map counterMap = {{DHCPv6_MESSAGE_TYPE_UNKNOWN, "Unknown" /* interface to vlan mapping */ std::unordered_map vlan_map; +/* ipv6 address to vlan name mapping */ +std::unordered_map addr_vlan_map; + /** * @code initialize_counter(std::shared_ptr state_db, std::string counterVlan); * @@ -111,6 +112,7 @@ void initialize_counter(std::shared_ptr state_db, std::string * @return none */ void update_counter(std::shared_ptr state_db, std::string counterVlan, uint8_t msg_type) { + counters[msg_type]++; state_db->hset(counterVlan, counterMap.find(msg_type)->second, toString(counters[msg_type])); } @@ -130,6 +132,19 @@ std::string toString(uint64_t count) { return countValue; } +/** + * @code bool inline isIPv6Zero(const in6_addr *addr) + * + * @brief check if ipv6 address is zero + * + * @param addr ipv6 address + * + * @return bool + */ +bool inline isIPv6Zero(const in6_addr *addr) { + return (memcmp(addr, &in6addr_any, sizeof(in6addr_any)) == 0); +} + /** * @code const struct ether_header *parse_ether_frame(const uint8_t *buffer, const uint8_t **out_end); * @@ -216,7 +231,6 @@ const struct dhcpv6_relay_msg *parse_dhcpv6_relay(const uint8_t *buffer) { const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_t **out_end) { 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 option; @@ -225,7 +239,6 @@ const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_ void process_sent_msg(relay_config *config, uint8_t msg_type) { std::string counterVlan = counter_table; if (counterMap.find(msg_type) != counterMap.end()) { - counters[msg_type]++; update_counter(config->state_db, counterVlan.append(config->interface), msg_type); } else { syslog(LOG_WARNING, "unexpected message type %d(0x%x)\n", msg_type, msg_type); @@ -269,6 +282,9 @@ int sock_open(const struct sock_fprog *fprog) return -1; } + evutil_make_listen_socket_reuseable(s); + evutil_make_socket_nonblocking(s); + struct sockaddr_ll sll = { .sll_family = AF_PACKET, .sll_protocol = htons(ETH_P_ALL), @@ -306,22 +322,22 @@ int sock_open(const struct sock_fprog *fprog) } /** - * @code prepare_relay_config(relay_config &interface_config, int local_sock, int filter); + * @code prepare_relay_config(relay_config &interface_config, int gua_sock, int filter); * * @brief prepare for specified relay interface config: server and link address * * @param interface_config pointer to relay config to be prepared - * @param local_sock L3 socket used for relaying messages + * @param gua_sock L3 socket used for relaying messages * @param filter socket attached with filter * * @return none */ -void prepare_relay_config(relay_config &interface_config, int local_sock, int filter) { +void prepare_relay_config(relay_config &interface_config, int gua_sock, int filter) { struct ifaddrs *ifa, *ifa_tmp; sockaddr_in6 non_link_local; sockaddr_in6 link_local; - interface_config.local_sock = local_sock; + interface_config.gua_sock = gua_sock; interface_config.filter = filter; for(auto server: interface_config.servers) { @@ -358,40 +374,96 @@ void prepare_relay_config(relay_config &interface_config, int local_sock, int fi } freeifaddrs(ifa); + char ipv6_str[INET6_ADDRSTRLEN] = {}; if(!IN6_IS_ADDR_LINKLOCAL(&non_link_local.sin6_addr)) { interface_config.link_address = non_link_local; + inet_ntop(AF_INET6, &non_link_local.sin6_addr, ipv6_str, INET6_ADDRSTRLEN); + addr_vlan_map[std::string(ipv6_str)] = interface_config.interface; } else { interface_config.link_address = link_local; + inet_ntop(AF_INET6, &link_local.sin6_addr, ipv6_str, INET6_ADDRSTRLEN); + addr_vlan_map[std::string(ipv6_str)] = interface_config.interface; } } +int prepare_lo_socket(const char *lo) { + struct ifaddrs *ifa, *ifa_tmp; + sockaddr_in6 gua = {0}; + int lo_sock = -1; + + if ((lo_sock = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) { + syslog(LOG_ERR, "socket: Failed to create gua socket on interface %s\n", lo); + return -1; + } + + evutil_make_listen_socket_reuseable(lo_sock); + evutil_make_socket_nonblocking(lo_sock); + + if (getifaddrs(&ifa) == -1) { + syslog(LOG_WARNING, "getifaddrs: Unable to get network interfaces with %s\n", strerror(errno)); + } + bool bind_gua = false; + ifa_tmp = ifa; + while (ifa_tmp) { + if (ifa_tmp->ifa_addr && (ifa_tmp->ifa_addr->sa_family == AF_INET6)) { + if (strcmp(ifa_tmp->ifa_name, lo) == 0) { + struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa_tmp->ifa_addr; + if (!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { + bind_gua = true; + gua = *in6; + gua.sin6_family = AF_INET6; + gua.sin6_port = htons(RELAY_PORT); + break; + } + } + } + ifa_tmp = ifa_tmp->ifa_next; + } + freeifaddrs(ifa); + + if (!bind_gua || bind(lo_sock, (sockaddr *)&gua, sizeof(gua)) == -1) { + syslog(LOG_ERR, "bind: Failed to bind socket on interface %s with %s\n", lo, strerror(errno)); + (void) close(lo_sock); + return -1; + } + + return lo_sock; +} + /** - * @code prepare_socket(int &local_sock, int &server_sock, relay_config &config); + * @code prepare_vlan_sockets(int &gua_sock, int &lla_sock, relay_config &config); * - * @brief prepare L3 socket for sending + * @brief prepare vlan l3 socket for sending * - * @param local_sock pointer to socket binded to global address for relaying client message to server and listening for server message - * @param server_sock pointer to socket binded to link_local address for relaying server message to client + * @param gua_sock socket binded to global address for relaying client message to server and listening for server message + * @param lla_sock socket binded to link_local address for relaying server message to client * - * @return none + * @return int */ -void prepare_socket(int &local_sock, int &server_sock, relay_config &config) { +int prepare_vlan_sockets(int &gua_sock, int &lla_sock, relay_config &config) { struct ifaddrs *ifa, *ifa_tmp; - sockaddr_in6 addr = {0}; - sockaddr_in6 ll_addr = {0}; + sockaddr_in6 gua = {0}, lla = {0}; - if ((local_sock = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) { - syslog(LOG_ERR, "socket: Failed to create socket on interface %s\n", config.interface.c_str()); + if ((gua_sock = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) { + syslog(LOG_ERR, "socket: Failed to create gua socket on interface %s\n", config.interface.c_str()); + return -1; } - if ((server_sock = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) { - syslog(LOG_ERR, "socket: Failed to create socket on interface %s\n", config.interface.c_str()); + if ((lla_sock = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) { + syslog(LOG_ERR, "socket: Failed to create lla socket on interface %s\n", config.interface.c_str()); + close(gua_sock); + return -1; } + evutil_make_listen_socket_reuseable(gua_sock); + evutil_make_socket_nonblocking(gua_sock); + evutil_make_listen_socket_reuseable(lla_sock); + evutil_make_socket_nonblocking(lla_sock); + int retry = 0; - bool bind_addr = false; - bool bind_ll_addr = false; + bool bind_gua = false; + bool bind_lla = false; do { if (getifaddrs(&ifa) == -1) { syslog(LOG_WARNING, "getifaddrs: Unable to get network interfaces with %s\n", strerror(errno)); @@ -399,19 +471,20 @@ void prepare_socket(int &local_sock, int &server_sock, relay_config &config) { else { ifa_tmp = ifa; while (ifa_tmp) { - if (ifa_tmp->ifa_addr && (ifa_tmp->ifa_addr->sa_family == AF_INET6) && (strcmp(ifa_tmp->ifa_name, config.interface.c_str()) == 0)) { - struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa_tmp->ifa_addr; - if(!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { - bind_addr = true; - in6->sin6_family = AF_INET6; - in6->sin6_port = htons(RELAY_PORT); - addr = *in6; - } - if(IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { - bind_ll_addr = true; - in6->sin6_family = AF_INET6; - in6->sin6_port = htons(RELAY_PORT); - ll_addr = *in6; + if (ifa_tmp->ifa_addr && (ifa_tmp->ifa_addr->sa_family == AF_INET6)) { + if (strcmp(ifa_tmp->ifa_name, config.interface.c_str()) == 0) { + struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa_tmp->ifa_addr; + if (!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { + bind_gua = true; + gua = *in6; + gua.sin6_family = AF_INET6; + gua.sin6_port = htons(RELAY_PORT); + } else { + bind_lla = true; + lla = *in6; + lla.sin6_family = AF_INET6; + lla.sin6_port = htons(RELAY_PORT); + } } } ifa_tmp = ifa_tmp->ifa_next; @@ -419,7 +492,7 @@ void prepare_socket(int &local_sock, int &server_sock, relay_config &config) { freeifaddrs(ifa); } - if (bind_addr && bind_ll_addr) { + if (bind_gua && bind_lla) { break; } @@ -427,13 +500,22 @@ void prepare_socket(int &local_sock, int &server_sock, relay_config &config) { sleep(5); } while (retry < 6); - if ((!bind_addr) || (bind(local_sock, (sockaddr *)&addr, sizeof(addr)) == -1)) { - syslog(LOG_ERR, "bind: Failed to bind socket to global ipv6 address on interface %s after %d retries with %s\n", config.interface.c_str(), retry, strerror(errno)); + if ((!bind_gua) || (bind(gua_sock, (sockaddr *)&gua, sizeof(gua)) == -1)) { + syslog(LOG_ERR, "bind: Failed to bind socket to global ipv6 address on interface %s after %d retries with %s\n", + config.interface.c_str(), retry, strerror(errno)); + close(gua_sock); + close(lla_sock); + return -1; } - if ((!bind_ll_addr) || (bind(server_sock, (sockaddr *)&ll_addr, sizeof(addr)) == -1)) { - syslog(LOG_ERR, "bind: Failed to bind socket to link local ipv6 address on interface %s after %d retries with %s\n", config.interface.c_str(), retry, strerror(errno)); + if ((!bind_lla) || (bind(lla_sock, (sockaddr *)&lla, sizeof(lla)) == -1)) { + syslog(LOG_ERR, "bind: Failed to bind socket to link local ipv6 address on interface %s after %d retries with %s\n", + config.interface.c_str(), retry, strerror(errno)); + close(gua_sock); + close(lla_sock); + return -1; } + return 0; } @@ -451,7 +533,7 @@ void prepare_socket(int &local_sock, int &server_sock, relay_config &config) { * * @return none */ -void relay_client(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config) { +void relay_client(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config) { static uint8_t buffer[BUFFER_SIZE]; auto current_buffer_position = buffer; dhcpv6_relay_msg new_message; @@ -496,6 +578,10 @@ void relay_client(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_h relay_forward(current_buffer_position, parse_dhcpv6_hdr(msg), dhcp_message_length); current_buffer_position += dhcp_message_length + sizeof(dhcpv6_option); + int sock = config->gua_sock; + if (dual_tor_sock) { + sock = config->lo_sock; + } for(auto server: config->servers_sock) { if(send_udp(sock, buffer, server, current_buffer_position - buffer)) { process_sent_msg(config, new_message.msg_type); @@ -504,11 +590,10 @@ void relay_client(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_h } /** - * @code relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config) + * @code relay_relay_forw(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config) * * @brief construct a relay-forward message encapsulated relay-forward message * - * @param sock L3 socket for sending data to servers * @param msg pointer to dhcpv6 message header position * @param len size of data received * @param ip_hdr pointer to IPv6 header @@ -516,7 +601,7 @@ void relay_client(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_h * * @return none */ -void relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config) { +void relay_relay_forw(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config) { static uint8_t buffer[BUFFER_SIZE]; dhcpv6_relay_msg new_message; auto current_buffer_position = buffer; @@ -534,10 +619,28 @@ void relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr * memcpy(current_buffer_position, &new_message, sizeof(dhcpv6_relay_msg)); current_buffer_position += sizeof(dhcpv6_relay_msg); + // insert option82 for new relay-forward packet, we need this information + // to get original relay-forward source interface for accurate counting in dualtor env + if (dual_tor_sock) { + interface_id_option intf_id; + intf_id.option_code = htons(OPTION_INTERFACE_ID); + intf_id.option_length = htons(sizeof(in6_addr)); + intf_id.interface_id = config->link_address.sin6_addr; + if ((unsigned)(current_buffer_position + sizeof(linklayer_addr_option) - buffer) > sizeof(buffer)) { + return; + } + memcpy(current_buffer_position, &intf_id, sizeof(interface_id_option)); + current_buffer_position += sizeof(interface_id_option); + } + auto dhcp_message_length = len; relay_forward(current_buffer_position, parse_dhcpv6_hdr(msg), dhcp_message_length); current_buffer_position += dhcp_message_length + sizeof(dhcpv6_option); + int sock = config->gua_sock; + if (dual_tor_sock) { + sock = config->lo_sock; + } for(auto server: config->servers_sock) { if(send_udp(sock, buffer, server, current_buffer_position - buffer)) { process_sent_msg(config, new_message.msg_type); @@ -546,18 +649,17 @@ void relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr * } /** - * @code relay_relay_reply(int sock, const uint8_t *msg, int32_t len, relay_config *configs); + * @code relay_relay_reply(const uint8_t *msg, int32_t len, relay_config *configs); * * @brief relay and unwrap a relay-reply message * - * @param sock L3 socket for sending data to servers * @param msg pointer to dhcpv6 message header position * @param len size of data received * @param config relay interface config * * @return none */ - void relay_relay_reply(int sock, const uint8_t *msg, int32_t len, relay_config *config) { + void relay_relay_reply(const uint8_t *msg, int32_t len, relay_config *config) { static uint8_t buffer[BUFFER_SIZE]; uint8_t type = 0; struct sockaddr_in6 target_addr; @@ -591,6 +693,13 @@ void relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr * target_addr.sin6_flowinfo = 0; target_addr.sin6_port = htons(CLIENT_PORT); target_addr.sin6_scope_id = if_nametoindex(config->interface.c_str()); + int sock = config->lla_sock; + if (isIPv6Zero(&dhcp_relay_header->link_address)) { + // In this case, it's multi-level relay + if (!IN6_IS_ADDR_LINKLOCAL(&dhcp_relay_header->peer_address)) + sock = config->gua_sock; + target_addr.sin6_port = htons(RELAY_PORT); + } if(send_udp(sock, buffer, target_addr, current_buffer_position - buffer)) { process_sent_msg(config, type); @@ -738,11 +847,10 @@ void client_packet_handler(uint8_t *buffer, ssize_t length, struct relay_config } auto option_position = current_position + sizeof(struct dhcpv6_msg); - switch (msg->msg_type) { case DHCPv6_MESSAGE_TYPE_RELAY_FORW: { - relay_relay_forw(config->local_sock, current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, config); + relay_relay_forw(current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, config); break; } case DHCPv6_MESSAGE_TYPE_SOLICIT: @@ -758,15 +866,13 @@ void client_packet_handler(uint8_t *buffer, ssize_t length, struct relay_config 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->state_db, counterVlan.append(config->interface), DHCPv6_MESSAGE_TYPE_MALFORMED); syslog(LOG_WARNING, "DHCPv6 option is invalid or contains malformed payload from %s\n", ifname.c_str()); return; } } - counters[msg->msg_type]++; update_counter(config->state_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); + relay_client(current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, ether_header, config); break; } default: @@ -777,6 +883,121 @@ void client_packet_handler(uint8_t *buffer, ssize_t length, struct relay_config } } +/** + * @code struct relay_config * + * get_relay_int_from_relay_msg(const uint8_t *msg, int32_t len, + * std::unordered_map *vlans) + * + * @brief get relay interface info from relay message + * + * @param addr ipv6 address + * + * @return bool + */ +struct relay_config * +get_relay_int_from_relay_msg(const uint8_t *msg, int32_t len, std::unordered_map *vlans) { + auto current_position = msg; + auto dhcp_relay_header = parse_dhcpv6_relay(msg); + interface_id_option intf_id; + + std::memset(&intf_id, 0, sizeof(interface_id_option)); + current_position += sizeof(struct dhcpv6_relay_msg); + while ((current_position - msg) < len) { + const uint8_t *tmp = NULL; + auto option = parse_dhcpv6_opt(current_position, &tmp); + current_position = tmp; + if (current_position - msg > len) { + break; + } + switch (ntohs(option->option_code)) { + case OPTION_INTERFACE_ID: { + intf_id.option_code = OPTION_INTERFACE_ID; + intf_id.option_length = ntohs(option->option_length); + std::memcpy(&intf_id.interface_id, ((uint8_t *)option) + sizeof(struct dhcpv6_option), intf_id.option_length); + break; + } + default: + break; + } + } + + in6_addr address = in6addr_any; + if (!isIPv6Zero(&intf_id.interface_id)) { + std::memcpy(&address, &intf_id.interface_id, sizeof(in6_addr)); + } else { + std::memcpy(&address, &dhcp_relay_header->link_address, sizeof(in6_addr)); + } + if (isIPv6Zero(&address)) { + return NULL; + } + + char ipv6_str[INET6_ADDRSTRLEN] = {}; + inet_ntop(AF_INET6, &address, ipv6_str, INET6_ADDRSTRLEN); + auto v6_string = std::string(ipv6_str); + if (addr_vlan_map.find(v6_string) == addr_vlan_map.end()) { + syslog(LOG_WARNING, "DHCPv6 type %d can't find vlan info from link address %s\n", + dhcp_relay_header->msg_type, ipv6_str); + return NULL; + } + + auto vlan_name = addr_vlan_map[v6_string]; + if (vlans->find(vlan_name) == vlans->end()) { + syslog(LOG_WARNING, "DHCPv6 can't find vlan %s config\n", vlan_name.c_str()); + return NULL; + } + return &vlans->find(vlan_name)->second; +} + +/** + * @code void server_callback_dualtor(evutil_socket_t fd, short event, void *arg); + * + * @brief callback for libevent that is called everytime data is received at the loopback socket + * + * @param fd loopback socket + * @param event libevent triggered event + * @param arg callback argument provided by user + * + * @return none + */ +void server_callback_dualtor(evutil_socket_t fd, short event, void *arg) { + auto vlans = reinterpret_cast *>(arg); + sockaddr_in6 from; + socklen_t len = sizeof(from); + int32_t pkts_num = 0; + static uint8_t message_buffer[BUFFER_SIZE]; + + while (pkts_num++ < BATCH_SIZE) { + std::string counterVlan = counter_table; + auto buffer_sz = recvfrom(fd, message_buffer, BUFFER_SIZE, 0, (sockaddr *)&from, &len); + if (buffer_sz <= 0) { + if (errno != EAGAIN) { + syslog(LOG_ERR, "recv: Failed to receive data from server: %s\n", strerror(errno)); + } + return; + } + + if (buffer_sz < (int32_t)sizeof(struct dhcpv6_msg)) { + syslog(LOG_WARNING, "Invalid DHCPv6 packet length %ld, no space for dhcpv6 msg header\n", buffer_sz); + continue; + } + + auto msg = parse_dhcpv6_hdr(message_buffer); + + if (msg->msg_type != DHCPv6_MESSAGE_TYPE_RELAY_REPL) { + syslog(LOG_WARNING, "Invalid DHCPv6 message type %d received on loopback interface\n", msg->msg_type); + continue; + } + auto config = get_relay_int_from_relay_msg(message_buffer, buffer_sz, vlans); + if (!config) { + syslog(LOG_WARNING, "Invalid DHCPv6 header content on loopback socket, packet will be dropped\n"); + continue; + } + update_counter(config->state_db, counterVlan.append(std::string(loopback)), msg->msg_type); + + relay_relay_reply(message_buffer, buffer_sz, config); + } +} + /** * @code void server_callback(evutil_socket_t fd, short event, void *arg); @@ -795,10 +1016,10 @@ void server_callback(evutil_socket_t fd, short event, void *arg) { socklen_t len = sizeof(from); int32_t pkts_num = 0; static uint8_t message_buffer[BUFFER_SIZE]; - std::string counterVlan = counter_table; while (pkts_num++ < BATCH_SIZE) { - auto buffer_sz = recvfrom(config->local_sock, message_buffer, BUFFER_SIZE, 0, (sockaddr *)&from, &len); + std::string counterVlan = counter_table; + auto buffer_sz = recvfrom(config->gua_sock, message_buffer, BUFFER_SIZE, 0, (sockaddr *)&from, &len); if (buffer_sz <= 0) { if (errno != EAGAIN) { syslog(LOG_ERR, "recv: Failed to receive data from server: %s\n", strerror(errno)); @@ -817,13 +1038,11 @@ void server_callback(evutil_socket_t fd, short event, void *arg) { update_counter(config->state_db, counterVlan.append(config->interface), DHCPv6_MESSAGE_TYPE_UNKNOWN); syslog(LOG_WARNING, "Unknown DHCPv6 message type %d\n", msg->msg_type); continue; - } else { - counters[msg->msg_type]++; } update_counter(config->state_db, counterVlan.append(config->interface), msg->msg_type); if (msg->msg_type == DHCPv6_MESSAGE_TYPE_RELAY_REPL) { - relay_relay_reply(config->server_sock, message_buffer, buffer_sz, config); + relay_relay_reply(message_buffer, buffer_sz, config); } } } @@ -922,7 +1141,7 @@ void loop_relay(std::unordered_map &vlans) { std::vector sockets; base = event_base_new(); if(base == NULL) { - syslog(LOG_ERR, "libevent: Failed to create base\n"); + syslog(LOG_ERR, "libevent: Failed to create event base\n"); } std::shared_ptr state_db = std::make_shared ("STATE_DB", 0); @@ -934,21 +1153,41 @@ void loop_relay(std::unordered_map &vlans) { auto filter = sock_open(ðer_relay_fprog); if (filter != -1) { sockets.push_back(filter); - listen_event = event_new(base, filter, EV_READ|EV_PERSIST, client_callback, - reinterpret_cast(&vlans)); - if (listen_event == NULL) { - syslog(LOG_ERR, "libevent: Failed to create client listen libevent\n"); + auto event = event_new(base, filter, EV_READ|EV_PERSIST, client_callback, + reinterpret_cast(&vlans)); + if (event == NULL) { + syslog(LOG_ERR, "libevent: Failed to create client listen event\n"); + exit(EXIT_FAILURE); } - event_add(listen_event, NULL); - syslog(LOG_INFO, "libevent: add filter socket event\n"); + event_add(event, NULL); + syslog(LOG_INFO, "libevent: Add client listen socket event\n"); } else { - syslog(LOG_ALERT, "Failed to create relay filter socket"); + syslog(LOG_ERR, "Failed to create client listen socket"); exit(EXIT_FAILURE); } + int lo_sock = -1; + if (dual_tor_sock) { + lo_sock = prepare_lo_socket(loopback); + if (lo_sock != -1) { + sockets.push_back(lo_sock); + auto event = event_new(base, lo_sock, EV_READ|EV_PERSIST, server_callback_dualtor, + reinterpret_cast(&vlans)); + if (event == NULL) { + syslog(LOG_ERR, "libevent: Failed to create dualtor loopback listen event\n"); + exit(EXIT_FAILURE); + } + event_add(event, NULL); + syslog(LOG_INFO, "libevent: Add dualtor loopback socket event\n"); + } else{ + syslog(LOG_ERR, "Failed to create dualtor loopback listen socket"); + exit(EXIT_FAILURE); + } + } + for(auto &vlan : vlans) { - int local_sock = 0; - int server_sock = 0; + int gua_sock = 0; + int lla_sock = 0; vlan.second.config_db = config_db; vlan.second.mux_table = mStateDbMuxTablePtr; vlan.second.state_db = state_db; @@ -958,28 +1197,28 @@ void loop_relay(std::unordered_map &vlans) { std::string counterVlan = counter_table; initialize_counter(vlan.second.state_db, counterVlan.append(vlan.second.interface)); - prepare_socket(local_sock, server_sock, vlan.second); - - vlan.second.local_sock = local_sock; - vlan.second.server_sock = server_sock; - - sockets.push_back(local_sock); - sockets.push_back(server_sock); - prepare_relay_config(vlan.second, local_sock, filter); - - evutil_make_listen_socket_reuseable(filter); - evutil_make_socket_nonblocking(filter); - - evutil_make_listen_socket_reuseable(local_sock); - evutil_make_socket_nonblocking(local_sock); + if (prepare_vlan_sockets(gua_sock, lla_sock, vlan.second) != -1) { + vlan.second.gua_sock = gua_sock; + vlan.second.lla_sock = lla_sock; + vlan.second.lo_sock = lo_sock; + + sockets.push_back(gua_sock); + sockets.push_back(lla_sock); + prepare_relay_config(vlan.second, gua_sock, filter); - server_listen_event = event_new(base, local_sock, EV_READ|EV_PERSIST, server_callback, &(vlan.second)); - - if (server_listen_event == NULL) { - syslog(LOG_ERR, "libevent: Failed to create server listen libevent\n"); + if (!dual_tor_sock) { + auto event = event_new(base, gua_sock, EV_READ|EV_PERSIST, + server_callback, &(vlan.second)); + if (event == NULL) { + syslog(LOG_ERR, "libevent: Failed to create server listen libevent\n"); + } + event_add(event, NULL); + syslog(LOG_INFO, "libevent: add server listen socket for %s\n", vlan.first.c_str()); + } + } else { + syslog(LOG_ERR, "Failed to create dualtor loopback listen socket"); + exit(EXIT_FAILURE); } - event_add(server_listen_event, NULL); - syslog(LOG_INFO, "libevent: add server listen socket for %s\n", vlan.first.c_str()); } if((signal_init() == 0) && signal_start() == 0) { diff --git a/src/relay.h b/src/relay.h index 240db54..c43917e 100644 --- a/src/relay.h +++ b/src/relay.h @@ -34,6 +34,7 @@ #define BATCH_SIZE 64 extern bool dual_tor_sock; +extern char loopback[IF_NAMESIZE]; /* DHCPv6 message types */ typedef enum @@ -58,8 +59,9 @@ typedef enum } dhcp_message_type_t; struct relay_config { - int local_sock; - int server_sock; + int gua_sock; + int lla_sock; + int lo_sock; int filter; sockaddr_in6 link_address; std::shared_ptr state_db; @@ -87,7 +89,6 @@ struct PACKED dhcpv6_relay_msg { struct in6_addr peer_address; }; - struct dhcpv6_option { uint16_t option_code; uint16_t option_length; @@ -116,30 +117,31 @@ struct interface_id_option { */ int sock_open(const struct sock_fprog *fprog); + /** - * @code prepare_socket(int *local_sock, int *server_sock, relay_config *config); + * @code prepare_vlan_sockets(int &gua_sock, int &lla_sock, relay_config &config); * - * @brief prepare L3 socket for sending + * @brief prepare vlan l3 socket for sending * - * @param local_sock pointer to socket binded to global address for relaying client message to server and listening for server message - * @param server_sock pointer to socket binded to link_local address for relaying server message to client + * @param gua_sock socket binded to global address for relaying client message to server and listening for server message + * @param lla_sock socket binded to link_local address for relaying server message to client * - * @return none + * @return int */ -void prepare_socket(int *local_sock, int *server_sock, relay_config *config); +int prepare_vlan_sockets(int &gua_sock, int &lla_sock, relay_config &config); /** - * @code prepare_relay_config(relay_config &interface_config, int local_sock, int filter); + * @code prepare_relay_config(relay_config &interface_config, int gua_sock, int filter); * * @brief prepare for specified relay interface config: server and link address * * @param interface_config pointer to relay config to be prepared - * @param local_sock L3 socket used for relaying messages + * @param gua_sock L3 socket used for relaying messages * @param filter socket attached with filter * * @return none */ -void prepare_relay_config(relay_config &interface_config, int local_sock, int filter); +void prepare_relay_config(relay_config &interface_config, int gua_sock, int filter); /** * @code relay_forward(uint8_t *buffer, const struct dhcpv6_msg *msg, uint16_t msg_length); @@ -155,11 +157,10 @@ void prepare_relay_config(relay_config &interface_config, int local_sock, int fi void relay_forward(uint8_t *buffer, const struct dhcpv6_msg *msg, uint16_t msg_length); /** - * @code relay_client(int sock, const uint8_t *msg, int32_t len, ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config); + * @code relay_client(const uint8_t *msg, int32_t len, ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config); * * @brief construct relay-forward message * - * @param sock L3 socket for sending data to servers * @param msg pointer to dhcpv6 message header position * @param len size of data received * @param ip_hdr pointer to IPv6 header @@ -168,14 +169,13 @@ void relay_forward(uint8_t *buffer, const struct dhcpv6_msg *msg, uint16_t msg_l * * @return none */ -void relay_client(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config); +void relay_client(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config); /** - * @code relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config) + * @code relay_relay_forw(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config) * * @brief construct a relay-forward message encapsulated relay-forward message * - * @param sock L3 socket for sending data to servers * @param msg pointer to dhcpv6 message header position * @param len size of data received * @param ip_hdr pointer to IPv6 header @@ -183,21 +183,20 @@ void relay_client(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_h * * @return none */ -void relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config); +void relay_relay_forw(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config); /** - * @code relay_relay_reply(int sock, const uint8_t *msg, int32_t len, relay_config *configs); + * @code relay_relay_reply(const uint8_t *msg, int32_t len, relay_config *configs); * * @brief relay and unwrap a relay-reply message * - * @param sock L3 socket for sending data to servers * @param msg pointer to dhcpv6 message header position * @param len size of data received * @param config relay interface config * * @return none */ -void relay_relay_reply(int sock, const uint8_t *msg, int32_t len, relay_config *configs); +void relay_relay_reply(const uint8_t *msg, int32_t len, relay_config *configs); /** * @code loop_relay(std::unordered_map &vlans); diff --git a/test/MockRelay.cpp b/test/MockRelay.cpp index 0d14de7..dece937 100644 --- a/test/MockRelay.cpp +++ b/test/MockRelay.cpp @@ -11,6 +11,7 @@ #include "MockRelay.h" bool dual_tor_sock = false; +char loopback[IF_NAMESIZE] = "Loopback0"; extern struct event_base *base; extern struct event *ev_sigint; extern struct event *ev_sigterm; @@ -316,8 +317,6 @@ TEST(counter, update_counter) TEST(relay, relay_client) { - int mock_sock = 124; - uint8_t msg[] = { 0x01, 0x2f, 0xf4, 0xc8, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x25, 0x3a, 0x37, 0xb9, @@ -345,6 +344,9 @@ TEST(relay, relay_client) } std::shared_ptr state_db = std::make_shared ("STATE_DB", 0); config.state_db = state_db; + config.gua_sock = 125; + config.lla_sock = 125; + config.lo_sock = 125; struct ether_header ether_hdr; ether_hdr.ether_shost[0] = 0x5a; @@ -357,7 +359,7 @@ TEST(relay, relay_client) ip6_hdr ip_hdr; std::string s_addr = "2000::3"; - relay_client(mock_sock, msg, msg_len, &ip_hdr, ðer_hdr, &config); + relay_client(msg, msg_len, &ip_hdr, ðer_hdr, &config); EXPECT_EQ(last_used_sock, 124); @@ -394,8 +396,6 @@ TEST(relay, relay_client) } TEST(relay, relay_relay_forw) { - int mock_sock = 125; - uint8_t msg[] = { 0x0c, 0x00, 0x20, 0x01, 0x0d, 0xb8, 0x01, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -428,12 +428,15 @@ TEST(relay, relay_relay_forw) { } std::shared_ptr state_db = std::make_shared ("STATE_DB", 0); config.state_db = state_db; + config.gua_sock = 125; + config.lla_sock = 125; + config.lo_sock = 125; ip6_hdr ip_hdr; std::string s_addr = "2000::3"; inet_pton(AF_INET6, s_addr.c_str(), &ip_hdr.ip6_src); - relay_relay_forw(mock_sock, msg, msg_len, &ip_hdr, &config); + relay_relay_forw(msg, msg_len, &ip_hdr, &config); EXPECT_EQ(last_used_sock, 125); @@ -453,8 +456,6 @@ TEST(relay, relay_relay_forw) { TEST(relay, relay_relay_reply) { - int mock_sock = 123; - uint8_t msg[] = { 0x0d, 0x00, 0x20, 0x01, 0x0d, 0xb8, 0x01, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -491,13 +492,16 @@ TEST(relay, relay_relay_reply) config.interface = "Vlan1000"; std::shared_ptr state_db = std::make_shared ("STATE_DB", 0); config.state_db = state_db; + config.gua_sock = 125; + config.lla_sock = 125; + config.lo_sock = 125; int local_sock = 1; int filter = 1; prepare_relay_config(config, local_sock, filter); - relay_relay_reply(mock_sock, msg, msg_len, &config); + relay_relay_reply(msg, msg_len, &config); EXPECT_EQ(last_used_sock, 123); diff --git a/test/main.cpp b/test/main.cpp index dfca267..6b3b209 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -1,4 +1,5 @@ #include "gtest/gtest.h" +#include #include #include From 9e7eaacc4c4749d2d84e075b05e078c06e415996 Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Thu, 22 Jun 2023 03:04:06 +0000 Subject: [PATCH 16/19] cherry pick 5b3eea1 --- .azure-pipelines/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.azure-pipelines/build.yml b/.azure-pipelines/build.yml index 1702ef8..758e8a6 100644 --- a/.azure-pipelines/build.yml +++ b/.azure-pipelines/build.yml @@ -30,6 +30,8 @@ jobs: sudo apt-get install -y dotnet-sdk-6.0 displayName: install .Net - script: | + set -ex + sudo apt-get update sudo apt-get install -y \ libboost-system1.71-dev \ libboost-thread1.71-dev \ From 65615ea93fbed464a2a040c2583dd115de79a8d4 Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Thu, 22 Jun 2023 13:11:05 +0000 Subject: [PATCH 17/19] fix format issu --- src/relay.cpp | 3 +-- src/relay.h | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/relay.cpp b/src/relay.cpp index 7b511db..f36884b 100644 --- a/src/relay.cpp +++ b/src/relay.cpp @@ -230,8 +230,7 @@ const struct dhcpv6_relay_msg *parse_dhcpv6_relay(const uint8_t *buffer) { */ const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_t **out_end) { auto option = (const struct dhcpv6_option *)buffer; - uint8_t size = 4; // option-code + option-len - (*out_end) = buffer + size + ntohs(option->option_length); + (*out_end) = buffer + sizeof(struct dhcpv6_option) + ntohs(option->option_length); return option; } diff --git a/src/relay.h b/src/relay.h index c43917e..6ee7f5e 100644 --- a/src/relay.h +++ b/src/relay.h @@ -77,7 +77,7 @@ struct relay_config { /* DHCPv6 messages and options */ -struct dhcpv6_msg { +struct PACKED dhcpv6_msg { uint8_t msg_type; uint8_t xid[3]; }; @@ -89,18 +89,18 @@ struct PACKED dhcpv6_relay_msg { struct in6_addr peer_address; }; -struct dhcpv6_option { +struct PACKED dhcpv6_option { uint16_t option_code; uint16_t option_length; }; -struct linklayer_addr_option { +struct PACKED linklayer_addr_option { uint16_t option_code; uint16_t option_length; uint16_t link_layer_type; }; -struct interface_id_option { +struct PACKED interface_id_option { uint16_t option_code; uint16_t option_length; in6_addr interface_id; // to accomodate dual-tor, this opaque value is set to carry relay interface's global ipv6 address From 899f03eca60f8fc1f18fbbfc38e8c2ba1f4088aa Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Fri, 7 Jul 2023 13:33:02 +0000 Subject: [PATCH 18/19] fix comments --- src/configInterface.cpp | 12 ++++++++-- src/relay.cpp | 18 +++++++-------- src/relay.h | 14 ++++++++++++ test/MockRelay.cpp | 49 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 12 deletions(-) diff --git a/src/configInterface.cpp b/src/configInterface.cpp index d0801af..6ea9cc3 100644 --- a/src/configInterface.cpp +++ b/src/configInterface.cpp @@ -9,6 +9,8 @@ bool pollSwssNotifcation = true; std::shared_ptr mSwssThreadPtr; swss::Select swssSelect; +extern bool dual_tor_sock; + /** * @code void initialize_swss() * @@ -116,6 +118,12 @@ void handleRelayNotification(swss::SubscriberStateTable &ipHelpersTable, std::un void processRelayNotification(std::deque &entries, std::unordered_map &vlans) { std::vector servers; + bool option_79_default = true; + bool interface_id_default = false; + + if (dual_tor_sock) { + interface_id_default = true; + } for (auto &entry: entries) { std::string vlan = kfvKey(entry); @@ -123,8 +131,8 @@ void processRelayNotification(std::deque &entries, std::vector fieldValues = kfvFieldsValues(entry); relay_config intf; - intf.is_option_79 = true; - intf.is_interface_id = false; + intf.is_option_79 = option_79_default; + intf.is_interface_id = interface_id_default; intf.interface = vlan; intf.mux_key = ""; intf.state_db = nullptr; diff --git a/src/relay.cpp b/src/relay.cpp index 4ae57bb..cf2ae0c 100644 --- a/src/relay.cpp +++ b/src/relay.cpp @@ -377,14 +377,11 @@ void prepare_relay_config(relay_config &interface_config, int gua_sock, int filt char ipv6_str[INET6_ADDRSTRLEN] = {}; if(!IN6_IS_ADDR_LINKLOCAL(&non_link_local.sin6_addr)) { interface_config.link_address = non_link_local; - inet_ntop(AF_INET6, &non_link_local.sin6_addr, ipv6_str, INET6_ADDRSTRLEN); - addr_vlan_map[std::string(ipv6_str)] = interface_config.interface; - } - else { + } else { interface_config.link_address = link_local; - inet_ntop(AF_INET6, &link_local.sin6_addr, ipv6_str, INET6_ADDRSTRLEN); - addr_vlan_map[std::string(ipv6_str)] = interface_config.interface; } + inet_ntop(AF_INET6, &interface_config.link_address.sin6_addr, ipv6_str, INET6_ADDRSTRLEN); + addr_vlan_map[std::string(ipv6_str)] = interface_config.interface; } int prepare_lo_socket(const char *lo) { @@ -620,8 +617,9 @@ void relay_relay_forw(const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, re current_buffer_position += sizeof(dhcpv6_relay_msg); // insert option82 for new relay-forward packet, we need this information - // to get original relay-forward source interface for accurate counting in dualtor env - if (dual_tor_sock) { + // to get original relay-forward source interface for accurate counting in dualtor scenario + // is_interface_id is by-default enabled in dualtor scenario + if(config->is_interface_id) { interface_id_option intf_id; intf_id.option_code = htons(OPTION_INTERFACE_ID); intf_id.option_length = htons(sizeof(in6_addr)); @@ -924,11 +922,11 @@ get_relay_int_from_relay_msg(const uint8_t *msg, int32_t len, std::unordered_map in6_addr address = in6addr_any; if (!isIPv6Zero(&intf_id.interface_id)) { std::memcpy(&address, &intf_id.interface_id, sizeof(in6_addr)); - } else if (isIPv6Zero(&dhcp_relay_header->link_address)) { + } else { std::memcpy(&address, &dhcp_relay_header->link_address, sizeof(in6_addr)); } // multi-level relay agents - if (!isIPv6Zero(&address)) { + if (isIPv6Zero(&address)) { return NULL; } diff --git a/src/relay.h b/src/relay.h index c43917e..a45dd31 100644 --- a/src/relay.h +++ b/src/relay.h @@ -423,3 +423,17 @@ void server_callback(evutil_socket_t fd, short event, void *arg); * @return none */ void server_callback_dual_tor(evutil_socket_t fd, short event, void *arg); + +/** + * @code struct relay_config * + * get_relay_int_from_relay_msg(const uint8_t *msg, int32_t len, + * std::unordered_map *vlans) + * + * @brief get relay interface info from relay message + * + * @param addr ipv6 address + * + * @return bool + */ +struct relay_config * +get_relay_int_from_relay_msg(const uint8_t *msg, int32_t len, std::unordered_map *vlans); diff --git a/test/MockRelay.cpp b/test/MockRelay.cpp index dece937..2da9b3c 100644 --- a/test/MockRelay.cpp +++ b/test/MockRelay.cpp @@ -15,6 +15,7 @@ char loopback[IF_NAMESIZE] = "Loopback0"; extern struct event_base *base; extern struct event *ev_sigint; extern struct event *ev_sigterm; +extern std::unordered_map addr_vlan_map; static struct sock_filter ether_relay_filter[] = { @@ -563,3 +564,51 @@ TEST(relay, dhcp6relay_stop) { event_base_free(base); base = NULL; } + +TEST(relay, get_relay_int_from_relay_msg) { + struct relay_config config{}; + std::string lla_str = "fc02:1000::1"; + std::unordered_map vlans; + + config.is_option_79 = true; + config.is_interface_id = true; + inet_pton(AF_INET6, lla_str.c_str(), &config.link_address.sin6_addr); + config.servers.push_back("fc02:2000::1"); + config.servers.push_back("fc02:2000::2"); + config.interface = "Vlan1000"; + config.state_db = std::make_shared ("STATE_DB", 0); + + vlans["Vlan1000"] = config; + addr_vlan_map[lla_str] = "Vlan1000"; + + uint8_t relay_reply_with_opt18[] = { + 0x0d,0x00,0xfc,0x02,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x01,0xfe,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x70,0xfd,0xff,0xfe,0xcb, + 0x0c,0x06,0x00,0x09,0x00,0x04,0x07,0x00,0x30,0x39,0x00,0x12,0x00,0x0c,0x66,0x63, + 0x30,0x32,0x3a,0x31,0x30,0x30,0x30,0x3a,0x3a,0x31 + }; + + auto cfg = get_relay_int_from_relay_msg(relay_reply_with_opt18, sizeof(relay_reply_with_opt18), &vlans); + EXPECT_NE((uintptr_t)cfg, NULL); + EXPECT_EQ(cfg->interface, "Vlan1000"); + + uint8_t relay_reply_without_opt18[] = { + 0x0d,0x00,0xfc,0x02,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x01,0xfe,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x70,0xfd,0xff,0xfe,0xcb, + 0x0c,0x06,0x00,0x09,0x00,0x04,0x07,0x00,0x30,0x39 + }; + + cfg = get_relay_int_from_relay_msg(relay_reply_without_opt18, sizeof(relay_reply_without_opt18), &vlans); + EXPECT_NE((uintptr_t)cfg, NULL); + EXPECT_EQ(cfg->interface, "Vlan1000"); + + uint8_t relay_reply_without_opt18_linkaddr_zero[] = { + 0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xfe,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x70,0xfd,0xff,0xfe,0xcb, + 0x0c,0x06,0x00,0x09,0x00,0x04,0x07,0x00,0x30,0x39 + }; + + cfg = get_relay_int_from_relay_msg(relay_reply_without_opt18_linkaddr_zero, + sizeof(relay_reply_without_opt18_linkaddr_zero), &vlans); + EXPECT_EQ((uintptr_t)cfg, NULL); +} \ No newline at end of file From ffc6932d8812e90b428f209e37223df492432443 Mon Sep 17 00:00:00 2001 From: jcaiMR Date: Sat, 8 Jul 2023 15:40:18 +0000 Subject: [PATCH 19/19] fix test code issue --- test/MockRelay.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test/MockRelay.cpp b/test/MockRelay.cpp index 2da9b3c..cccf829 100644 --- a/test/MockRelay.cpp +++ b/test/MockRelay.cpp @@ -313,7 +313,7 @@ TEST(counter, update_counter) update_counter(state_db, "DHCPv6_COUNTER_TABLE|Vlan1000", 1); std::shared_ptr output = state_db->hget("DHCPv6_COUNTER_TABLE|Vlan1000", "Solicit"); std::string *ptr = output.get(); - EXPECT_EQ(*ptr, "0"); + EXPECT_EQ(*ptr, "1"); } TEST(relay, relay_client) @@ -362,7 +362,7 @@ TEST(relay, relay_client) relay_client(msg, msg_len, &ip_hdr, ðer_hdr, &config); - EXPECT_EQ(last_used_sock, 124); + EXPECT_EQ(last_used_sock, 125); auto sent_msg = parse_dhcpv6_relay(sender_buffer); @@ -504,7 +504,7 @@ TEST(relay, relay_relay_reply) relay_relay_reply(msg, msg_len, &config); - EXPECT_EQ(last_used_sock, 123); + EXPECT_EQ(last_used_sock, 125); uint8_t expected_bytes[] = { 0x07, 0x4f, 0x6d, 0x04, 0x00, 0x03, 0x00, 0x28, @@ -576,7 +576,6 @@ TEST(relay, get_relay_int_from_relay_msg) { config.servers.push_back("fc02:2000::1"); config.servers.push_back("fc02:2000::2"); config.interface = "Vlan1000"; - config.state_db = std::make_shared ("STATE_DB", 0); vlans["Vlan1000"] = config; addr_vlan_map[lla_str] = "Vlan1000"; @@ -584,8 +583,8 @@ TEST(relay, get_relay_int_from_relay_msg) { uint8_t relay_reply_with_opt18[] = { 0x0d,0x00,0xfc,0x02,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x01,0xfe,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x70,0xfd,0xff,0xfe,0xcb, - 0x0c,0x06,0x00,0x09,0x00,0x04,0x07,0x00,0x30,0x39,0x00,0x12,0x00,0x0c,0x66,0x63, - 0x30,0x32,0x3a,0x31,0x30,0x30,0x30,0x3a,0x3a,0x31 + 0x0c,0x06,0x00,0x09,0x00,0x04,0x07,0x00,0x30,0x39,0x00,0x12,0x00,0x10,0xfc,0x02, + 0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 }; auto cfg = get_relay_int_from_relay_msg(relay_reply_with_opt18, sizeof(relay_reply_with_opt18), &vlans);