From 7dd3b5b5e37a4019ae335296ba9c4bd1e465fd17 Mon Sep 17 00:00:00 2001 From: Artem Glazychev Date: Thu, 3 Jun 2021 20:11:54 +0700 Subject: wireguard: add ipv6 support Type: improvement Signed-off-by: Artem Glazychev Change-Id: If1a7e82ce163c4c4acaa5acf45ad2b88371396f6 --- src/plugins/wireguard/wireguard_input.c | 117 +++++++++++++++++++++++++------- 1 file changed, 92 insertions(+), 25 deletions(-) (limited to 'src/plugins/wireguard/wireguard_input.c') diff --git a/src/plugins/wireguard/wireguard_input.c b/src/plugins/wireguard/wireguard_input.c index ad002dcb3c2..6a0623e0a76 100644 --- a/src/plugins/wireguard/wireguard_input.c +++ b/src/plugins/wireguard/wireguard_input.c @@ -79,11 +79,11 @@ format_wg_input_trace (u8 * s, va_list * args) wg_input_trace_t *t = va_arg (*args, wg_input_trace_t *); - s = format (s, "WG input: \n"); - s = format (s, " Type: %U\n", format_wg_message_type, t->type); - s = format (s, " peer: %d\n", t->peer); - s = format (s, " Length: %d\n", t->current_length); - s = format (s, " Keepalive: %s", t->is_keepalive ? "true" : "false"); + s = format (s, "Wireguard input: \n"); + s = format (s, " Type: %U\n", format_wg_message_type, t->type); + s = format (s, " Peer: %d\n", t->peer); + s = format (s, " Length: %d\n", t->current_length); + s = format (s, " Keepalive: %s", t->is_keepalive ? "true" : "false"); return s; } @@ -93,6 +93,7 @@ typedef enum WG_INPUT_NEXT_HANDOFF_HANDSHAKE, WG_INPUT_NEXT_HANDOFF_DATA, WG_INPUT_NEXT_IP4_INPUT, + WG_INPUT_NEXT_IP6_INPUT, WG_INPUT_NEXT_PUNT, WG_INPUT_NEXT_ERROR, WG_INPUT_N_NEXT, @@ -108,8 +109,15 @@ typedef enum /* } */ /* } */ +static u8 +is_ip4_header (u8 *data) +{ + return (data[0] >> 4) == 0x4; +} + static wg_input_error_t -wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b) +wg_handshake_process (vlib_main_t *vm, wg_main_t *wmp, vlib_buffer_t *b, + u32 node_idx, u8 is_ip4) { ASSERT (vm->thread_index == 0); @@ -122,10 +130,21 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b) void *current_b_data = vlib_buffer_get_current (b); + ip46_address_t src_ip; + if (is_ip4) + { + ip4_header_t *iph4 = + current_b_data - sizeof (udp_header_t) - sizeof (ip4_header_t); + ip46_address_set_ip4 (&src_ip, &iph4->src_address); + } + else + { + ip6_header_t *iph6 = + current_b_data - sizeof (udp_header_t) - sizeof (ip6_header_t); + ip46_address_set_ip6 (&src_ip, &iph6->src_address); + } + udp_header_t *uhd = current_b_data - sizeof (udp_header_t); - ip4_header_t *iph = - current_b_data - sizeof (udp_header_t) - sizeof (ip4_header_t); - ip4_address_t ip4_src = iph->src_address; u16 udp_src_port = clib_host_to_net_u16 (uhd->src_port);; u16 udp_dst_port = clib_host_to_net_u16 (uhd->dst_port);; @@ -168,7 +187,7 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b) mac_state = cookie_checker_validate_macs ( vm, &wg_if->cookie_checker, macs, current_b_data, len, under_load, - ip4_src, udp_src_port); + &src_ip, udp_src_port); if (mac_state == INVALID_MAC) { wg_if = NULL; @@ -214,7 +233,7 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b) // set_peer_address (peer, ip4_src, udp_src_port); if (PREDICT_FALSE (!wg_send_handshake_response (vm, peer))) { - vlib_node_increment_counter (vm, wg_input_node.index, + vlib_node_increment_counter (vm, node_idx, WG_INPUT_ERROR_HANDSHAKE_SEND, 1); } break; @@ -254,9 +273,8 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b) wg_timers_handshake_complete (peer); if (PREDICT_FALSE (!wg_send_keepalive (vm, peer))) { - vlib_node_increment_counter (vm, wg_input_node.index, - WG_INPUT_ERROR_KEEPALIVE_SEND, - 1); + vlib_node_increment_counter (vm, node_idx, + WG_INPUT_ERROR_KEEPALIVE_SEND, 1); } } break; @@ -270,9 +288,9 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b) return WG_INPUT_ERROR_NONE; } -VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) +always_inline uword +wg_input_inline (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame, u8 is_ip4) { message_type_t header_type; u32 n_left_from; @@ -382,7 +400,20 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm, wg_timers_data_received (peer); - ip4_header_t *iph = vlib_buffer_get_current (b[0]); + ip46_address_t src_ip; + u8 is_ip4_inner = is_ip4_header (vlib_buffer_get_current (b[0])); + if (is_ip4_inner) + { + ip46_address_set_ip4 ( + &src_ip, &((ip4_header_t *) vlib_buffer_get_current (b[0])) + ->src_address); + } + else + { + ip46_address_set_ip6 ( + &src_ip, &((ip6_header_t *) vlib_buffer_get_current (b[0])) + ->src_address); + } const fib_prefix_t *allowed_ip; bool allowed = false; @@ -392,9 +423,10 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm, * is that there aren't many allowed IPs and thus a linear * walk is fater than an ACL */ + vec_foreach (allowed_ip, peer->allowed_ips) { - if (fib_prefix_is_cover_addr_4 (allowed_ip, &iph->src_address)) + if (fib_prefix_is_cover_addr_46 (allowed_ip, &src_ip)) { allowed = true; break; @@ -403,7 +435,8 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm, if (allowed) { vnet_buffer (b[0])->sw_if_index[VLIB_RX] = peer->wg_sw_if_index; - next[0] = WG_INPUT_NEXT_IP4_INPUT; + next[0] = is_ip4_inner ? WG_INPUT_NEXT_IP4_INPUT : + WG_INPUT_NEXT_IP6_INPUT; } } else @@ -417,7 +450,8 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm, goto next; } - wg_input_error_t ret = wg_handshake_process (vm, wmp, b[0]); + wg_input_error_t ret = + wg_handshake_process (vm, wmp, b[0], node->node_index, is_ip4); if (ret != WG_INPUT_ERROR_NONE) { next[0] = WG_INPUT_NEXT_ERROR; @@ -445,10 +479,42 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm, return frame->n_vectors; } +VLIB_NODE_FN (wg4_input_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return wg_input_inline (vm, node, frame, /* is_ip4 */ 1); +} + +VLIB_NODE_FN (wg6_input_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return wg_input_inline (vm, node, frame, /* is_ip4 */ 0); +} + /* *INDENT-OFF* */ -VLIB_REGISTER_NODE (wg_input_node) = +VLIB_REGISTER_NODE (wg4_input_node) = +{ + .name = "wg4-input", + .vector_size = sizeof (u32), + .format_trace = format_wg_input_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (wg_input_error_strings), + .error_strings = wg_input_error_strings, + .n_next_nodes = WG_INPUT_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = { + [WG_INPUT_NEXT_HANDOFF_HANDSHAKE] = "wg4-handshake-handoff", + [WG_INPUT_NEXT_HANDOFF_DATA] = "wg4-input-data-handoff", + [WG_INPUT_NEXT_IP4_INPUT] = "ip4-input-no-checksum", + [WG_INPUT_NEXT_IP6_INPUT] = "ip6-input", + [WG_INPUT_NEXT_PUNT] = "error-punt", + [WG_INPUT_NEXT_ERROR] = "error-drop", + }, +}; + +VLIB_REGISTER_NODE (wg6_input_node) = { - .name = "wg-input", + .name = "wg6-input", .vector_size = sizeof (u32), .format_trace = format_wg_input_trace, .type = VLIB_NODE_TYPE_INTERNAL, @@ -457,9 +523,10 @@ VLIB_REGISTER_NODE (wg_input_node) = .n_next_nodes = WG_INPUT_N_NEXT, /* edit / add dispositions here */ .next_nodes = { - [WG_INPUT_NEXT_HANDOFF_HANDSHAKE] = "wg-handshake-handoff", - [WG_INPUT_NEXT_HANDOFF_DATA] = "wg-input-data-handoff", + [WG_INPUT_NEXT_HANDOFF_HANDSHAKE] = "wg6-handshake-handoff", + [WG_INPUT_NEXT_HANDOFF_DATA] = "wg6-input-data-handoff", [WG_INPUT_NEXT_IP4_INPUT] = "ip4-input-no-checksum", + [WG_INPUT_NEXT_IP6_INPUT] = "ip6-input", [WG_INPUT_NEXT_PUNT] = "error-punt", [WG_INPUT_NEXT_ERROR] = "error-drop", }, -- cgit 1.2.3-korg