2 * Copyright (c) 2020 Doc.ai and/or its affiliates.
3 * Copyright (c) 2020 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <vnet/adj/adj_midchain.h>
18 #include <vnet/fib/fib_table.h>
19 #include <vnet/fib/fib_entry_track.h>
20 #include <wireguard/wireguard_peer.h>
21 #include <wireguard/wireguard_if.h>
22 #include <wireguard/wireguard_messages.h>
23 #include <wireguard/wireguard_key.h>
24 #include <wireguard/wireguard_send.h>
25 #include <wireguard/wireguard.h>
26 #include <vnet/tunnel/tunnel_dp.h>
28 wg_peer_t *wg_peer_pool;
30 index_t *wg_peer_by_adj_index;
33 wg_peer_endpoint_reset (wg_peer_endpoint_t * ep)
35 ip46_address_reset (&ep->addr);
40 wg_peer_endpoint_init (wg_peer_endpoint_t *ep, const ip46_address_t *addr,
43 ip46_address_copy (&ep->addr, addr);
48 wg_peer_clear (vlib_main_t * vm, wg_peer_t * peer)
50 index_t perri = peer - wg_peer_pool;
51 wg_timers_stop (peer);
52 wg_peer_update_flags (perri, WG_PEER_ESTABLISHED, false);
53 wg_peer_update_flags (perri, WG_PEER_STATUS_DEAD, true);
54 for (int i = 0; i < WG_N_TIMERS; i++)
57 peer->timers_dispatched[i] = 0;
60 peer->last_sent_handshake = vlib_time_now (vm) - (REKEY_TIMEOUT + 1);
62 clib_memset (&peer->cookie_maker, 0, sizeof (peer->cookie_maker));
64 wg_peer_endpoint_reset (&peer->src);
65 wg_peer_endpoint_reset (&peer->dst);
67 wg_peer_adj_t *peer_adj;
68 vec_foreach (peer_adj, peer->adjs)
70 wg_peer_by_adj_index[peer_adj->adj_index] = INDEX_INVALID;
71 if (FIB_NODE_INDEX_INVALID != peer_adj->fib_entry_index)
72 fib_entry_untrack (peer_adj->fib_entry_index, peer_adj->sibling_index);
73 if (adj_is_valid (peer_adj->adj_index))
74 adj_nbr_midchain_unstack (peer_adj->adj_index);
76 peer->input_thread_index = ~0;
77 peer->output_thread_index = ~0;
78 peer->timer_wheel = 0;
79 peer->persistent_keepalive_interval = 0;
80 peer->timer_handshake_attempts = 0;
81 peer->last_sent_packet = 0;
82 peer->last_received_packet = 0;
83 peer->session_derived = 0;
84 peer->rehandshake_started = 0;
85 peer->new_handshake_interval_tick = 0;
86 peer->rehandshake_interval_tick = 0;
87 peer->timer_need_another_keepalive = false;
88 vec_free (peer->rewrite);
89 vec_free (peer->allowed_ips);
90 vec_free (peer->adjs);
94 wg_peer_init (vlib_main_t * vm, wg_peer_t * peer)
96 peer->api_client_by_client_index = hash_create (0, sizeof (u32));
97 peer->api_clients = NULL;
98 wg_peer_clear (vm, peer);
102 wg_peer_adj_stack (wg_peer_t *peer, wg_peer_adj_t *peer_adj)
107 fib_protocol_t fib_proto;
109 if (!adj_is_valid (peer_adj->adj_index))
112 adj = adj_get (peer_adj->adj_index);
113 sw_if_index = adj->rewrite_header.sw_if_index;
114 u8 is_ip4 = ip46_address_is_ip4 (&peer->src.addr);
115 fib_proto = is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
117 wgi = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index));
122 if (!vnet_sw_interface_is_admin_up (vnet_get_main (), wgi->sw_if_index) ||
123 !wg_peer_can_send (peer))
125 adj_nbr_midchain_unstack (peer_adj->adj_index);
131 .fp_len = is_ip4 ? 32 : 128,
132 .fp_proto = fib_proto,
133 .fp_addr = peer->dst.addr,
138 fib_index = fib_table_find (fib_proto, peer->table_id);
139 peer_adj->fib_entry_index =
140 fib_entry_track (fib_index, &dst, FIB_NODE_TYPE_ADJ,
141 peer_adj->adj_index, &peer_adj->sibling_index);
143 adj_nbr_midchain_stack_on_fib_entry (
144 peer_adj->adj_index, peer_adj->fib_entry_index,
145 fib_forw_chain_type_from_fib_proto (dst.fp_proto));
150 wg_peer_66_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b,
154 ip6_header_t *ip6_out;
155 ip6_header_t *ip6_in;
157 /* Must set locally originated otherwise we're not allowed to
158 fragment the packet later */
159 b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
161 ip6_out = vlib_buffer_get_current (b);
162 iph_offset = vnet_buffer (b)->ip.save_rewrite_length;
163 ip6_in = vlib_buffer_get_current (b) + iph_offset;
165 ip6_out->ip_version_traffic_class_and_flow_label =
166 ip6_in->ip_version_traffic_class_and_flow_label;
170 wg_peer_46_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b,
174 ip6_header_t *ip6_out;
175 ip4_header_t *ip4_in;
177 /* Must set locally originated otherwise we're not allowed to
178 fragment the packet later */
179 b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
181 ip6_out = vlib_buffer_get_current (b);
182 iph_offset = vnet_buffer (b)->ip.save_rewrite_length;
183 ip4_in = vlib_buffer_get_current (b) + iph_offset;
185 u32 vtcfl = 0x6 << 28;
186 vtcfl |= ip4_in->tos << 20;
187 vtcfl |= vnet_buffer (b)->ip.flow_hash & 0x000fffff;
189 ip6_out->ip_version_traffic_class_and_flow_label =
190 clib_host_to_net_u32 (vtcfl);
193 static adj_midchain_fixup_t
194 wg_peer_get_fixup (wg_peer_t *peer, vnet_link_t lt)
196 if (!ip46_address_is_ip4 (&peer->dst.addr))
198 if (lt == VNET_LINK_IP4)
199 return (wg_peer_46_fixup);
200 if (lt == VNET_LINK_IP6)
201 return (wg_peer_66_fixup);
207 wg_peer_if_admin_state_change (index_t peeri, void *data)
210 wg_peer_adj_t *peer_adj;
211 peer = wg_peer_get (peeri);
212 vec_foreach (peer_adj, peer->adjs)
214 wg_peer_adj_stack (peer, peer_adj);
216 return (WALK_CONTINUE);
220 wg_peer_if_adj_change (index_t peeri, void *data)
222 adj_index_t *adj_index = data;
223 adj_midchain_fixup_t fixup;
226 fib_prefix_t *allowed_ip;
227 wg_peer_adj_t *peer_adj;
229 adj = adj_get (*adj_index);
231 peer = wg_peer_get (peeri);
232 vec_foreach (allowed_ip, peer->allowed_ips)
234 if (fib_prefix_is_cover_addr_46 (allowed_ip,
235 &adj->sub_type.nbr.next_hop))
237 vec_add2 (peer->adjs, peer_adj, 1);
238 peer_adj->adj_index = *adj_index;
239 peer_adj->fib_entry_index = FIB_NODE_INDEX_INVALID;
240 peer_adj->sibling_index = ~0;
242 vec_validate_init_empty (wg_peer_by_adj_index, *adj_index,
244 wg_peer_by_adj_index[*adj_index] = peeri;
246 fixup = wg_peer_get_fixup (peer, adj_get_link_type (*adj_index));
247 adj_nbr_midchain_update_rewrite (*adj_index, fixup, NULL,
248 ADJ_FLAG_MIDCHAIN_IP_STACK,
249 vec_dup (peer->rewrite));
251 wg_peer_adj_stack (peer, peer_adj);
256 return (WALK_CONTINUE);
260 wg_peer_adj_walk (adj_index_t ai, void *data)
262 return wg_peer_if_adj_change ((*(index_t *) (data)), &ai) == WALK_CONTINUE ?
263 ADJ_WALK_RC_CONTINUE :
268 wg_peer_if_delete (index_t peeri, void *data)
270 wg_peer_remove (peeri);
271 return (WALK_CONTINUE);
275 wg_peer_fill (vlib_main_t *vm, wg_peer_t *peer, u32 table_id,
276 const ip46_address_t *dst, u16 port,
277 u16 persistent_keepalive_interval,
278 const fib_prefix_t *allowed_ips, u32 wg_sw_if_index)
280 index_t perri = peer - wg_peer_pool;
281 wg_peer_endpoint_init (&peer->dst, dst, port);
283 peer->table_id = table_id;
284 peer->wg_sw_if_index = wg_sw_if_index;
285 peer->timer_wheel = &wg_main.timer_wheel;
286 peer->persistent_keepalive_interval = persistent_keepalive_interval;
287 peer->last_sent_handshake = vlib_time_now (vm) - (REKEY_TIMEOUT + 1);
288 wg_peer_update_flags (perri, WG_PEER_STATUS_DEAD, false);
290 const wg_if_t *wgi = wg_if_get (wg_if_find_by_sw_if_index (wg_sw_if_index));
293 return (VNET_API_ERROR_INVALID_INTERFACE);
295 ip_address_to_46 (&wgi->src_ip, &peer->src.addr);
296 peer->src.port = wgi->port;
298 u8 is_ip4 = ip46_address_is_ip4 (&peer->dst.addr);
299 peer->rewrite = wg_build_rewrite (&peer->src.addr, peer->src.port,
300 &peer->dst.addr, peer->dst.port, is_ip4);
303 vec_validate (peer->allowed_ips, vec_len (allowed_ips) - 1);
304 vec_foreach_index (ii, allowed_ips)
306 peer->allowed_ips[ii] = allowed_ips[ii];
309 fib_protocol_t proto;
310 FOR_EACH_FIB_IP_PROTOCOL (proto)
312 adj_nbr_walk (wg_sw_if_index, proto, wg_peer_adj_walk, &perri);
318 wg_peer_update_flags (index_t peeri, wg_peer_flags flag, bool add_del)
320 wg_peer_t *peer = wg_peer_get (peeri);
321 if ((add_del && (peer->flags & flag)) || (!add_del && !(peer->flags & flag)))
327 wg_api_peer_event (peeri, peer->flags);
331 wg_peer_update_endpoint (index_t peeri, const ip46_address_t *addr, u16 port)
333 wg_peer_t *peer = wg_peer_get (peeri);
335 if (ip46_address_is_equal (&peer->dst.addr, addr) && peer->dst.port == port)
338 wg_peer_endpoint_init (&peer->dst, addr, port);
340 u8 is_ip4 = ip46_address_is_ip4 (&peer->dst.addr);
341 vec_free (peer->rewrite);
342 peer->rewrite = wg_build_rewrite (&peer->src.addr, peer->src.port,
343 &peer->dst.addr, peer->dst.port, is_ip4);
345 wg_peer_adj_t *peer_adj;
346 vec_foreach (peer_adj, peer->adjs)
348 if (FIB_NODE_INDEX_INVALID != peer_adj->fib_entry_index)
350 fib_entry_untrack (peer_adj->fib_entry_index,
351 peer_adj->sibling_index);
352 peer_adj->fib_entry_index = FIB_NODE_INDEX_INVALID;
353 peer_adj->sibling_index = ~0;
356 if (adj_is_valid (peer_adj->adj_index))
358 adj_midchain_fixup_t fixup =
359 wg_peer_get_fixup (peer, adj_get_link_type (peer_adj->adj_index));
360 adj_nbr_midchain_update_rewrite (peer_adj->adj_index, fixup, NULL,
361 ADJ_FLAG_MIDCHAIN_IP_STACK,
362 vec_dup (peer->rewrite));
363 wg_peer_adj_stack (peer, peer_adj);
368 typedef struct wg_peer_upd_ep_args_t_
373 } wg_peer_upd_ep_args_t;
376 wg_peer_update_endpoint_thread_fn (wg_peer_upd_ep_args_t *args)
378 wg_peer_update_endpoint (args->peeri, &args->addr, args->port);
382 wg_peer_update_endpoint_from_mt (index_t peeri, const ip46_address_t *addr,
385 wg_peer_upd_ep_args_t args = {
390 ip46_address_copy (&args.addr, addr);
391 vlib_rpc_call_main_thread (wg_peer_update_endpoint_thread_fn, (u8 *) &args,
396 wg_peer_add (u32 tun_sw_if_index, const u8 public_key[NOISE_PUBLIC_KEY_LEN],
397 u32 table_id, const ip46_address_t *endpoint,
398 const fib_prefix_t *allowed_ips, u16 port,
399 u16 persistent_keepalive, u32 *peer_index)
405 vlib_main_t *vm = vlib_get_main ();
407 if (tun_sw_if_index == ~0)
408 return (VNET_API_ERROR_INVALID_SW_IF_INDEX);
410 wg_if = wg_if_get (wg_if_find_by_sw_if_index (tun_sw_if_index));
412 return (VNET_API_ERROR_INVALID_SW_IF_INDEX);
415 pool_foreach (peer, wg_peer_pool)
417 if (!memcmp (peer->remote.r_public, public_key, NOISE_PUBLIC_KEY_LEN))
419 return (VNET_API_ERROR_ENTRY_ALREADY_EXISTS);
424 if (pool_elts (wg_peer_pool) > MAX_PEERS)
425 return (VNET_API_ERROR_LIMIT_EXCEEDED);
427 pool_get_zero (wg_peer_pool, peer);
429 wg_peer_init (vm, peer);
431 rv = wg_peer_fill (vm, peer, table_id, endpoint, (u16) port,
432 persistent_keepalive, allowed_ips, tun_sw_if_index);
436 wg_peer_clear (vm, peer);
437 pool_put (wg_peer_pool, peer);
441 noise_remote_init (&peer->remote, peer - wg_peer_pool, public_key,
443 cookie_maker_init (&peer->cookie_maker, public_key);
445 wg_send_handshake (vm, peer, false);
446 if (peer->persistent_keepalive_interval != 0)
448 wg_send_keepalive (vm, peer);
451 *peer_index = peer - wg_peer_pool;
452 wg_if_peer_add (wg_if, *peer_index);
458 wg_peer_remove (index_t peeri)
460 wg_main_t *wmp = &wg_main;
461 wg_peer_t *peer = NULL;
464 if (pool_is_free_index (wg_peer_pool, peeri))
465 return VNET_API_ERROR_NO_SUCH_ENTRY;
467 peer = pool_elt_at_index (wg_peer_pool, peeri);
469 wgi = wg_if_get (wg_if_find_by_sw_if_index (peer->wg_sw_if_index));
470 wg_if_peer_remove (wgi, peeri);
472 noise_remote_clear (wmp->vlib_main, &peer->remote);
473 wg_peer_clear (wmp->vlib_main, peer);
474 pool_put (wg_peer_pool, peer);
480 wg_peer_walk (wg_peer_walk_cb_t fn, void *data)
485 pool_foreach_index (peeri, wg_peer_pool)
487 if (WALK_STOP == fn(peeri, data))
491 return INDEX_INVALID;
495 format_wg_peer_endpoint (u8 * s, va_list * args)
497 wg_peer_endpoint_t *ep = va_arg (*args, wg_peer_endpoint_t *);
499 s = format (s, "%U:%d", format_ip46_address, &ep->addr, IP46_TYPE_ANY,
506 format_wg_peer (u8 * s, va_list * va)
508 index_t peeri = va_arg (*va, index_t);
509 fib_prefix_t *allowed_ip;
510 u8 key[NOISE_KEY_LEN_BASE64];
512 wg_peer_adj_t *peer_adj;
514 peer = wg_peer_get (peeri);
515 key_to_base64 (peer->remote.r_public, NOISE_PUBLIC_KEY_LEN, key);
519 "[%d] endpoint:[%U->%U] %U keep-alive:%d flags: %d, api-clients count: %d",
520 peeri, format_wg_peer_endpoint, &peer->src, format_wg_peer_endpoint,
521 &peer->dst, format_vnet_sw_if_index_name, vnet_get_main (),
522 peer->wg_sw_if_index, peer->persistent_keepalive_interval, peer->flags,
523 pool_elts (peer->api_clients));
524 s = format (s, "\n adj:");
525 vec_foreach (peer_adj, peer->adjs)
527 s = format (s, " %d", peer_adj->adj_index);
529 s = format (s, "\n key:%=s %U", key, format_hex_bytes,
530 peer->remote.r_public, NOISE_PUBLIC_KEY_LEN);
531 s = format (s, "\n allowed-ips:");
532 vec_foreach (allowed_ip, peer->allowed_ips)
534 s = format (s, " %U", format_fib_prefix, allowed_ip);
541 * fd.io coding-style-patch-verification: ON
544 * eval: (c-set-style "gnu")