diff options
Diffstat (limited to 'src/plugins/wireguard/wireguard_peer.c')
-rw-r--r-- | src/plugins/wireguard/wireguard_peer.c | 210 |
1 files changed, 86 insertions, 124 deletions
diff --git a/src/plugins/wireguard/wireguard_peer.c b/src/plugins/wireguard/wireguard_peer.c index 0c93a25f4d7..5e2011b401e 100644 --- a/src/plugins/wireguard/wireguard_peer.c +++ b/src/plugins/wireguard/wireguard_peer.c @@ -23,7 +23,6 @@ #include <wireguard/wireguard_send.h> #include <wireguard/wireguard.h> -static fib_source_t wg_fib_source; wg_peer_t *wg_peer_pool; index_t *wg_peer_by_adj_index; @@ -36,45 +35,14 @@ wg_peer_endpoint_reset (wg_peer_endpoint_t * ep) } static void -wg_peer_endpoint_init (wg_peer_endpoint_t * ep, - const ip46_address_t * addr, u16 port) +wg_peer_endpoint_init (wg_peer_endpoint_t *ep, const ip46_address_t *addr, + u16 port) { ip46_address_copy (&ep->addr, addr); ep->port = port; } static void -wg_peer_fib_flush (wg_peer_t * peer) -{ - wg_peer_allowed_ip_t *allowed_ip; - - vec_foreach (allowed_ip, peer->allowed_ips) - { - fib_table_entry_delete_index (allowed_ip->fib_entry_index, wg_fib_source); - allowed_ip->fib_entry_index = FIB_NODE_INDEX_INVALID; - } -} - -static void -wg_peer_fib_populate (wg_peer_t * peer, u32 fib_index) -{ - wg_peer_allowed_ip_t *allowed_ip; - - vec_foreach (allowed_ip, peer->allowed_ips) - { - allowed_ip->fib_entry_index = - fib_table_entry_path_add (fib_index, - &allowed_ip->prefix, - wg_fib_source, - FIB_ENTRY_FLAG_NONE, - fib_proto_to_dpo (allowed_ip-> - prefix.fp_proto), - &peer->dst.addr, peer->wg_sw_if_index, ~0, 1, - NULL, FIB_ROUTE_PATH_FLAG_NONE); - } -} - -static void wg_peer_clear (vlib_main_t * vm, wg_peer_t * peer) { wg_timers_stop (peer); @@ -91,16 +59,16 @@ wg_peer_clear (vlib_main_t * vm, wg_peer_t * peer) wg_peer_endpoint_reset (&peer->src); wg_peer_endpoint_reset (&peer->dst); - if (INDEX_INVALID != peer->adj_index) + adj_index_t *adj_index; + vec_foreach (adj_index, peer->adj_indices) { - adj_unlock (peer->adj_index); - wg_peer_by_adj_index[peer->adj_index] = INDEX_INVALID; + if (INDEX_INVALID != *adj_index) + { + wg_peer_by_adj_index[*adj_index] = INDEX_INVALID; + } } - wg_peer_fib_flush (peer); - peer->input_thread_index = ~0; peer->output_thread_index = ~0; - peer->adj_index = INDEX_INVALID; peer->timer_wheel = 0; peer->persistent_keepalive_interval = 0; peer->timer_handshake_attempts = 0; @@ -113,12 +81,12 @@ wg_peer_clear (vlib_main_t * vm, wg_peer_t * peer) peer->timer_need_another_keepalive = false; peer->is_dead = true; vec_free (peer->allowed_ips); + vec_free (peer->adj_indices); } static void wg_peer_init (vlib_main_t * vm, wg_peer_t * peer) { - peer->adj_index = INDEX_INVALID; wg_peer_clear (vm, peer); } @@ -147,13 +115,16 @@ wg_peer_build_rewrite (const wg_peer_t * peer) } static void -wg_peer_adj_stack (wg_peer_t * peer) +wg_peer_adj_stack (wg_peer_t *peer, adj_index_t ai) { ip_adjacency_t *adj; u32 sw_if_index; wg_if_t *wgi; - adj = adj_get (peer->adj_index); + if (!adj_is_valid (ai)) + return; + + adj = adj_get (ai); sw_if_index = adj->rewrite_header.sw_if_index; wgi = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index)); @@ -163,7 +134,7 @@ wg_peer_adj_stack (wg_peer_t * peer) if (!vnet_sw_interface_is_admin_up (vnet_get_main (), wgi->sw_if_index)) { - adj_midchain_delegate_unstack (peer->adj_index); + adj_midchain_delegate_unstack (ai); } else { @@ -178,39 +149,69 @@ wg_peer_adj_stack (wg_peer_t * peer) fib_index = fib_table_find (FIB_PROTOCOL_IP4, peer->table_id); - adj_midchain_delegate_stack (peer->adj_index, fib_index, &dst); + adj_midchain_delegate_stack (ai, fib_index, &dst); } } walk_rc_t -wg_peer_if_admin_state_change (wg_if_t * wgi, index_t peeri, void *data) +wg_peer_if_admin_state_change (index_t peeri, void *data) { - wg_peer_adj_stack (wg_peer_get (peeri)); - + wg_peer_t *peer; + adj_index_t *adj_index; + peer = wg_peer_get (peeri); + vec_foreach (adj_index, peer->adj_indices) + { + wg_peer_adj_stack (peer, *adj_index); + } return (WALK_CONTINUE); } walk_rc_t -wg_peer_if_table_change (wg_if_t * wgi, index_t peeri, void *data) +wg_peer_if_adj_change (index_t peeri, void *data) { - wg_peer_table_bind_ctx_t *ctx = data; + adj_index_t *adj_index = data; + ip_adjacency_t *adj; wg_peer_t *peer; + fib_prefix_t *allowed_ip; - peer = wg_peer_get (peeri); + adj = adj_get (*adj_index); - wg_peer_fib_flush (peer); - wg_peer_fib_populate (peer, ctx->new_fib_index); + peer = wg_peer_get (peeri); + vec_foreach (allowed_ip, peer->allowed_ips) + { + if (fib_prefix_is_cover_addr_4 (allowed_ip, + &adj->sub_type.nbr.next_hop.ip4)) + { + vec_add1 (peer->adj_indices, *adj_index); + vec_validate_init_empty (wg_peer_by_adj_index, *adj_index, + INDEX_INVALID); + wg_peer_by_adj_index[*adj_index] = peer - wg_peer_pool; + + adj_nbr_midchain_update_rewrite (*adj_index, NULL, NULL, + ADJ_FLAG_MIDCHAIN_IP_STACK, + vec_dup (peer->rewrite)); + + wg_peer_adj_stack (peer, *adj_index); + return (WALK_STOP); + } + } return (WALK_CONTINUE); } +adj_walk_rc_t +wg_peer_adj_walk (adj_index_t ai, void *data) +{ + return wg_peer_if_adj_change ((*(index_t *) (data)), &ai) == WALK_CONTINUE ? + ADJ_WALK_RC_CONTINUE : + ADJ_WALK_RC_STOP; +} + static int -wg_peer_fill (vlib_main_t * vm, wg_peer_t * peer, - u32 table_id, - const ip46_address_t * dst, - u16 port, +wg_peer_fill (vlib_main_t *vm, wg_peer_t *peer, u32 table_id, + const ip46_address_t *dst, u16 port, u16 persistent_keepalive_interval, - const fib_prefix_t * allowed_ips, u32 wg_sw_if_index) + const fib_prefix_t *allowed_ips, u32 wg_sw_if_index) { wg_peer_endpoint_init (&peer->dst, dst, port); @@ -228,54 +229,29 @@ wg_peer_fill (vlib_main_t * vm, wg_peer_t * peer, ip_address_to_46 (&wgi->src_ip, &peer->src.addr); peer->src.port = wgi->port; - - /* - * and an adjacency for the endpoint address in the overlay - * on the wg interface - */ peer->rewrite = wg_peer_build_rewrite (peer); - peer->adj_index = adj_nbr_add_or_lock (FIB_PROTOCOL_IP4, - VNET_LINK_IP4, - &peer->dst.addr, wgi->sw_if_index); - - vec_validate_init_empty (wg_peer_by_adj_index, - peer->adj_index, INDEX_INVALID); - wg_peer_by_adj_index[peer->adj_index] = peer - wg_peer_pool; - - adj_nbr_midchain_update_rewrite (peer->adj_index, - NULL, - NULL, - ADJ_FLAG_MIDCHAIN_IP_STACK, - vec_dup (peer->rewrite)); - wg_peer_adj_stack (peer); - - /* - * add a route in the overlay to each of the allowed-ips - */ u32 ii; - vec_validate (peer->allowed_ips, vec_len (allowed_ips) - 1); - vec_foreach_index (ii, allowed_ips) { - peer->allowed_ips[ii].prefix = allowed_ips[ii]; + peer->allowed_ips[ii] = allowed_ips[ii]; } - wg_peer_fib_populate (peer, - fib_table_get_index_for_sw_if_index - (FIB_PROTOCOL_IP4, peer->wg_sw_if_index)); - + index_t perri = peer - wg_peer_pool; + fib_protocol_t proto; + FOR_EACH_FIB_IP_PROTOCOL (proto) + { + adj_nbr_walk (wg_sw_if_index, proto, wg_peer_adj_walk, &perri); + } return (0); } int -wg_peer_add (u32 tun_sw_if_index, - const u8 public_key[NOISE_PUBLIC_KEY_LEN], - u32 table_id, - const ip46_address_t * endpoint, - const fib_prefix_t * allowed_ips, - u16 port, u16 persistent_keepalive, u32 * peer_index) +wg_peer_add (u32 tun_sw_if_index, const u8 public_key[NOISE_PUBLIC_KEY_LEN], + u32 table_id, const ip46_address_t *endpoint, + const fib_prefix_t *allowed_ips, u16 port, + u16 persistent_keepalive, u32 *peer_index) { wg_if_t *wg_if; wg_peer_t *peer; @@ -374,8 +350,8 @@ format_wg_peer_endpoint (u8 * s, va_list * args) { wg_peer_endpoint_t *ep = va_arg (*args, wg_peer_endpoint_t *); - s = format (s, "%U:%d", - format_ip46_address, &ep->addr, IP46_TYPE_ANY, ep->port); + s = format (s, "%U:%d", format_ip46_address, &ep->addr, IP46_TYPE_ANY, + ep->port); return (s); } @@ -384,48 +360,34 @@ u8 * format_wg_peer (u8 * s, va_list * va) { index_t peeri = va_arg (*va, index_t); - wg_peer_allowed_ip_t *allowed_ip; + fib_prefix_t *allowed_ip; + adj_index_t *adj_index; u8 key[NOISE_KEY_LEN_BASE64]; wg_peer_t *peer; peer = wg_peer_get (peeri); key_to_base64 (peer->remote.r_public, NOISE_PUBLIC_KEY_LEN, key); - s = format (s, "[%d] endpoint:[%U->%U] %U keep-alive:%d adj:%d", - peeri, - format_wg_peer_endpoint, &peer->src, - format_wg_peer_endpoint, &peer->dst, - format_vnet_sw_if_index_name, vnet_get_main (), - peer->wg_sw_if_index, - peer->persistent_keepalive_interval, peer->adj_index); - s = format (s, "\n key:%=s %U", - key, format_hex_bytes, peer->remote.r_public, - NOISE_PUBLIC_KEY_LEN); + s = format (s, "[%d] endpoint:[%U->%U] %U keep-alive:%d", peeri, + format_wg_peer_endpoint, &peer->src, format_wg_peer_endpoint, + &peer->dst, format_vnet_sw_if_index_name, vnet_get_main (), + peer->wg_sw_if_index, peer->persistent_keepalive_interval); + s = format (s, "\n adj:"); + vec_foreach (adj_index, peer->adj_indices) + { + s = format (s, " %d", adj_index); + } + s = format (s, "\n key:%=s %U", key, format_hex_bytes, + peer->remote.r_public, NOISE_PUBLIC_KEY_LEN); s = format (s, "\n allowed-ips:"); vec_foreach (allowed_ip, peer->allowed_ips) { - s = format (s, " %U", format_fib_prefix, &allowed_ip->prefix); + s = format (s, " %U", format_fib_prefix, allowed_ip); } return s; } -static clib_error_t * -wg_peer_module_init (vlib_main_t * vm) -{ - /* - * use a priority better than interface source, so that - * if the same subnet is added to the wg interface and is - * used as an allowed IP, then the wireguard soueced prefix - * wins and traffic is routed to the endpoint rather than dropped - */ - wg_fib_source = fib_source_allocate ("wireguard", 0x2, FIB_SOURCE_BH_API); - - return (NULL); -} - -VLIB_INIT_FUNCTION (wg_peer_module_init); - /* * fd.io coding-style-patch-verification: ON * |