fb540141e08e49eb28fc23291302b9cf3d7ee469
[vpp.git] / src / plugins / wireguard / wireguard_peer.c
1 /*
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:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <vnet/adj/adj_midchain.h>
18 #include <vnet/fib/fib_table.h>
19 #include <wireguard/wireguard_peer.h>
20 #include <wireguard/wireguard_if.h>
21 #include <wireguard/wireguard_messages.h>
22 #include <wireguard/wireguard_key.h>
23 #include <wireguard/wireguard_send.h>
24 #include <wireguard/wireguard.h>
25 #include <vnet/tunnel/tunnel_dp.h>
26
27 wg_peer_t *wg_peer_pool;
28
29 index_t *wg_peer_by_adj_index;
30
31 static void
32 wg_peer_endpoint_reset (wg_peer_endpoint_t * ep)
33 {
34   ip46_address_reset (&ep->addr);
35   ep->port = 0;
36 }
37
38 static void
39 wg_peer_endpoint_init (wg_peer_endpoint_t *ep, const ip46_address_t *addr,
40                        u16 port)
41 {
42   ip46_address_copy (&ep->addr, addr);
43   ep->port = port;
44 }
45
46 static void
47 wg_peer_clear (vlib_main_t * vm, wg_peer_t * peer)
48 {
49   wg_timers_stop (peer);
50   for (int i = 0; i < WG_N_TIMERS; i++)
51     {
52       peer->timers[i] = ~0;
53       peer->timers_dispatched[i] = 0;
54     }
55
56   peer->last_sent_handshake = vlib_time_now (vm) - (REKEY_TIMEOUT + 1);
57
58   clib_memset (&peer->cookie_maker, 0, sizeof (peer->cookie_maker));
59
60   wg_peer_endpoint_reset (&peer->src);
61   wg_peer_endpoint_reset (&peer->dst);
62
63   adj_index_t *adj_index;
64   vec_foreach (adj_index, peer->adj_indices)
65     {
66       if (INDEX_INVALID != *adj_index)
67         {
68           wg_peer_by_adj_index[*adj_index] = INDEX_INVALID;
69         }
70     }
71   peer->input_thread_index = ~0;
72   peer->output_thread_index = ~0;
73   peer->timer_wheel = 0;
74   peer->persistent_keepalive_interval = 0;
75   peer->timer_handshake_attempts = 0;
76   peer->last_sent_packet = 0;
77   peer->last_received_packet = 0;
78   peer->session_derived = 0;
79   peer->rehandshake_started = 0;
80   peer->new_handshake_interval_tick = 0;
81   peer->rehandshake_interval_tick = 0;
82   peer->timer_need_another_keepalive = false;
83   peer->is_dead = true;
84   vec_free (peer->allowed_ips);
85   vec_free (peer->adj_indices);
86 }
87
88 static void
89 wg_peer_init (vlib_main_t * vm, wg_peer_t * peer)
90 {
91   wg_peer_clear (vm, peer);
92 }
93
94 static u8 *
95 wg_peer_build_rewrite (const wg_peer_t *peer, u8 is_ip4)
96 {
97   u8 *rewrite = NULL;
98   if (is_ip4)
99     {
100       ip4_udp_header_t *hdr;
101
102       vec_validate (rewrite, sizeof (*hdr) - 1);
103       hdr = (ip4_udp_header_t *) rewrite;
104
105       hdr->ip4.ip_version_and_header_length = 0x45;
106       hdr->ip4.ttl = 64;
107       hdr->ip4.src_address = peer->src.addr.ip4;
108       hdr->ip4.dst_address = peer->dst.addr.ip4;
109       hdr->ip4.protocol = IP_PROTOCOL_UDP;
110       hdr->ip4.checksum = ip4_header_checksum (&hdr->ip4);
111
112       hdr->udp.src_port = clib_host_to_net_u16 (peer->src.port);
113       hdr->udp.dst_port = clib_host_to_net_u16 (peer->dst.port);
114       hdr->udp.checksum = 0;
115     }
116   else
117     {
118       ip6_udp_header_t *hdr;
119
120       vec_validate (rewrite, sizeof (*hdr) - 1);
121       hdr = (ip6_udp_header_t *) rewrite;
122
123       hdr->ip6.ip_version_traffic_class_and_flow_label = 0x60;
124       ip6_address_copy (&hdr->ip6.src_address, &peer->src.addr.ip6);
125       ip6_address_copy (&hdr->ip6.dst_address, &peer->dst.addr.ip6);
126       hdr->ip6.protocol = IP_PROTOCOL_UDP;
127       hdr->ip6.hop_limit = 64;
128
129       hdr->udp.src_port = clib_host_to_net_u16 (peer->src.port);
130       hdr->udp.dst_port = clib_host_to_net_u16 (peer->dst.port);
131       hdr->udp.checksum = 0;
132     }
133
134   return (rewrite);
135 }
136
137 static void
138 wg_peer_adj_stack (wg_peer_t *peer, adj_index_t ai)
139 {
140   ip_adjacency_t *adj;
141   u32 sw_if_index;
142   wg_if_t *wgi;
143   fib_protocol_t fib_proto;
144
145   if (!adj_is_valid (ai))
146     return;
147
148   adj = adj_get (ai);
149   sw_if_index = adj->rewrite_header.sw_if_index;
150   u8 is_ip4 = ip46_address_is_ip4 (&peer->src.addr);
151   fib_proto = is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
152
153   wgi = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index));
154
155   if (!wgi)
156     return;
157
158   if (!vnet_sw_interface_is_admin_up (vnet_get_main (), wgi->sw_if_index))
159     {
160       adj_midchain_delegate_unstack (ai);
161     }
162   else
163     {
164       /* *INDENT-OFF* */
165       fib_prefix_t dst = {
166         .fp_len = is_ip4 ? 32 : 128,
167         .fp_proto = fib_proto,
168         .fp_addr = peer->dst.addr,
169       };
170       /* *INDENT-ON* */
171       u32 fib_index;
172
173       fib_index = fib_table_find (fib_proto, peer->table_id);
174
175       adj_midchain_delegate_stack (ai, fib_index, &dst);
176     }
177 }
178
179 static void
180 wg_peer_66_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b,
181                   const void *data)
182 {
183   u8 iph_offset = 0;
184   ip6_header_t *ip6_out;
185   ip6_header_t *ip6_in;
186
187   /* Must set locally originated otherwise we're not allowed to
188      fragment the packet later */
189   b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
190
191   ip6_out = vlib_buffer_get_current (b);
192   iph_offset = vnet_buffer (b)->ip.save_rewrite_length;
193   ip6_in = vlib_buffer_get_current (b) + iph_offset;
194
195   ip6_out->ip_version_traffic_class_and_flow_label =
196     ip6_in->ip_version_traffic_class_and_flow_label;
197 }
198
199 static void
200 wg_peer_46_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b,
201                   const void *data)
202 {
203   u8 iph_offset = 0;
204   ip6_header_t *ip6_out;
205   ip4_header_t *ip4_in;
206
207   /* Must set locally originated otherwise we're not allowed to
208      fragment the packet later */
209   b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
210
211   ip6_out = vlib_buffer_get_current (b);
212   iph_offset = vnet_buffer (b)->ip.save_rewrite_length;
213   ip4_in = vlib_buffer_get_current (b) + iph_offset;
214
215   u32 vtcfl = 0x6 << 28;
216   vtcfl |= ip4_in->tos << 20;
217   vtcfl |= vnet_buffer (b)->ip.flow_hash & 0x000fffff;
218
219   ip6_out->ip_version_traffic_class_and_flow_label =
220     clib_host_to_net_u32 (vtcfl);
221 }
222
223 static adj_midchain_fixup_t
224 wg_peer_get_fixup (wg_peer_t *peer, vnet_link_t lt)
225 {
226   if (!ip46_address_is_ip4 (&peer->dst.addr))
227     {
228       if (lt == VNET_LINK_IP4)
229         return (wg_peer_46_fixup);
230       if (lt == VNET_LINK_IP6)
231         return (wg_peer_66_fixup);
232     }
233   return (NULL);
234 }
235
236 walk_rc_t
237 wg_peer_if_admin_state_change (index_t peeri, void *data)
238 {
239   wg_peer_t *peer;
240   adj_index_t *adj_index;
241   peer = wg_peer_get (peeri);
242   vec_foreach (adj_index, peer->adj_indices)
243     {
244       wg_peer_adj_stack (peer, *adj_index);
245     }
246   return (WALK_CONTINUE);
247 }
248
249 walk_rc_t
250 wg_peer_if_adj_change (index_t peeri, void *data)
251 {
252   adj_index_t *adj_index = data;
253   adj_midchain_fixup_t fixup;
254   ip_adjacency_t *adj;
255   wg_peer_t *peer;
256   fib_prefix_t *allowed_ip;
257
258   adj = adj_get (*adj_index);
259
260   peer = wg_peer_get (peeri);
261   vec_foreach (allowed_ip, peer->allowed_ips)
262     {
263       if (fib_prefix_is_cover_addr_46 (allowed_ip,
264                                        &adj->sub_type.nbr.next_hop))
265         {
266           vec_add1 (peer->adj_indices, *adj_index);
267           vec_validate_init_empty (wg_peer_by_adj_index, *adj_index,
268                                    INDEX_INVALID);
269           wg_peer_by_adj_index[*adj_index] = peer - wg_peer_pool;
270
271           fixup = wg_peer_get_fixup (peer, adj_get_link_type (*adj_index));
272           adj_nbr_midchain_update_rewrite (*adj_index, fixup, NULL,
273                                            ADJ_FLAG_MIDCHAIN_IP_STACK,
274                                            vec_dup (peer->rewrite));
275
276           wg_peer_adj_stack (peer, *adj_index);
277           return (WALK_STOP);
278         }
279     }
280
281   return (WALK_CONTINUE);
282 }
283
284 adj_walk_rc_t
285 wg_peer_adj_walk (adj_index_t ai, void *data)
286 {
287   return wg_peer_if_adj_change ((*(index_t *) (data)), &ai) == WALK_CONTINUE ?
288            ADJ_WALK_RC_CONTINUE :
289            ADJ_WALK_RC_STOP;
290 }
291
292 walk_rc_t
293 wg_peer_if_delete (index_t peeri, void *data)
294 {
295   wg_peer_remove (peeri);
296   return (WALK_CONTINUE);
297 }
298
299 static int
300 wg_peer_fill (vlib_main_t *vm, wg_peer_t *peer, u32 table_id,
301               const ip46_address_t *dst, u16 port,
302               u16 persistent_keepalive_interval,
303               const fib_prefix_t *allowed_ips, u32 wg_sw_if_index)
304 {
305   wg_peer_endpoint_init (&peer->dst, dst, port);
306
307   peer->table_id = table_id;
308   peer->wg_sw_if_index = wg_sw_if_index;
309   peer->timer_wheel = &wg_main.timer_wheel;
310   peer->persistent_keepalive_interval = persistent_keepalive_interval;
311   peer->last_sent_handshake = vlib_time_now (vm) - (REKEY_TIMEOUT + 1);
312   peer->is_dead = false;
313
314   const wg_if_t *wgi = wg_if_get (wg_if_find_by_sw_if_index (wg_sw_if_index));
315
316   if (NULL == wgi)
317     return (VNET_API_ERROR_INVALID_INTERFACE);
318
319   ip_address_to_46 (&wgi->src_ip, &peer->src.addr);
320   peer->src.port = wgi->port;
321
322   u8 is_ip4 = ip46_address_is_ip4 (&peer->dst.addr);
323   peer->rewrite = wg_peer_build_rewrite (peer, is_ip4);
324
325   u32 ii;
326   vec_validate (peer->allowed_ips, vec_len (allowed_ips) - 1);
327   vec_foreach_index (ii, allowed_ips)
328   {
329     peer->allowed_ips[ii] = allowed_ips[ii];
330   }
331
332   index_t perri = peer - wg_peer_pool;
333   fib_protocol_t proto;
334   FOR_EACH_FIB_IP_PROTOCOL (proto)
335   {
336     adj_nbr_walk (wg_sw_if_index, proto, wg_peer_adj_walk, &perri);
337   }
338   return (0);
339 }
340
341 int
342 wg_peer_add (u32 tun_sw_if_index, const u8 public_key[NOISE_PUBLIC_KEY_LEN],
343              u32 table_id, const ip46_address_t *endpoint,
344              const fib_prefix_t *allowed_ips, u16 port,
345              u16 persistent_keepalive, u32 *peer_index)
346 {
347   wg_if_t *wg_if;
348   wg_peer_t *peer;
349   int rv;
350
351   vlib_main_t *vm = vlib_get_main ();
352
353   if (tun_sw_if_index == ~0)
354     return (VNET_API_ERROR_INVALID_SW_IF_INDEX);
355
356   wg_if = wg_if_get (wg_if_find_by_sw_if_index (tun_sw_if_index));
357   if (!wg_if)
358     return (VNET_API_ERROR_INVALID_SW_IF_INDEX);
359
360   /* *INDENT-OFF* */
361   pool_foreach (peer, wg_peer_pool)
362    {
363     if (!memcmp (peer->remote.r_public, public_key, NOISE_PUBLIC_KEY_LEN))
364     {
365       return (VNET_API_ERROR_ENTRY_ALREADY_EXISTS);
366     }
367   }
368   /* *INDENT-ON* */
369
370   if (pool_elts (wg_peer_pool) > MAX_PEERS)
371     return (VNET_API_ERROR_LIMIT_EXCEEDED);
372
373   pool_get (wg_peer_pool, peer);
374
375   wg_peer_init (vm, peer);
376
377   rv = wg_peer_fill (vm, peer, table_id, endpoint, (u16) port,
378                      persistent_keepalive, allowed_ips, tun_sw_if_index);
379
380   if (rv)
381     {
382       wg_peer_clear (vm, peer);
383       pool_put (wg_peer_pool, peer);
384       return (rv);
385     }
386
387   noise_remote_init (&peer->remote, peer - wg_peer_pool, public_key,
388                      wg_if->local_idx);
389   cookie_maker_init (&peer->cookie_maker, public_key);
390
391   if (peer->persistent_keepalive_interval != 0)
392     {
393       wg_send_keepalive (vm, peer);
394     }
395
396   *peer_index = peer - wg_peer_pool;
397   wg_if_peer_add (wg_if, *peer_index);
398
399   return (0);
400 }
401
402 int
403 wg_peer_remove (index_t peeri)
404 {
405   wg_main_t *wmp = &wg_main;
406   wg_peer_t *peer = NULL;
407   wg_if_t *wgi;
408
409   if (pool_is_free_index (wg_peer_pool, peeri))
410     return VNET_API_ERROR_NO_SUCH_ENTRY;
411
412   peer = pool_elt_at_index (wg_peer_pool, peeri);
413
414   wgi = wg_if_get (wg_if_find_by_sw_if_index (peer->wg_sw_if_index));
415   wg_if_peer_remove (wgi, peeri);
416
417   noise_remote_clear (wmp->vlib_main, &peer->remote);
418   wg_peer_clear (wmp->vlib_main, peer);
419   pool_put (wg_peer_pool, peer);
420
421   return (0);
422 }
423
424 index_t
425 wg_peer_walk (wg_peer_walk_cb_t fn, void *data)
426 {
427   index_t peeri;
428
429   /* *INDENT-OFF* */
430   pool_foreach_index (peeri, wg_peer_pool)
431   {
432     if (WALK_STOP == fn(peeri, data))
433       return peeri;
434   }
435   /* *INDENT-ON* */
436   return INDEX_INVALID;
437 }
438
439 static u8 *
440 format_wg_peer_endpoint (u8 * s, va_list * args)
441 {
442   wg_peer_endpoint_t *ep = va_arg (*args, wg_peer_endpoint_t *);
443
444   s = format (s, "%U:%d", format_ip46_address, &ep->addr, IP46_TYPE_ANY,
445               ep->port);
446
447   return (s);
448 }
449
450 u8 *
451 format_wg_peer (u8 * s, va_list * va)
452 {
453   index_t peeri = va_arg (*va, index_t);
454   fib_prefix_t *allowed_ip;
455   adj_index_t *adj_index;
456   u8 key[NOISE_KEY_LEN_BASE64];
457   wg_peer_t *peer;
458
459   peer = wg_peer_get (peeri);
460   key_to_base64 (peer->remote.r_public, NOISE_PUBLIC_KEY_LEN, key);
461
462   s = format (s, "[%d] endpoint:[%U->%U] %U keep-alive:%d", peeri,
463               format_wg_peer_endpoint, &peer->src, format_wg_peer_endpoint,
464               &peer->dst, format_vnet_sw_if_index_name, vnet_get_main (),
465               peer->wg_sw_if_index, peer->persistent_keepalive_interval);
466   s = format (s, "\n  adj:");
467   vec_foreach (adj_index, peer->adj_indices)
468     {
469       s = format (s, " %d", adj_index);
470     }
471   s = format (s, "\n  key:%=s %U", key, format_hex_bytes,
472               peer->remote.r_public, NOISE_PUBLIC_KEY_LEN);
473   s = format (s, "\n  allowed-ips:");
474   vec_foreach (allowed_ip, peer->allowed_ips)
475   {
476     s = format (s, " %U", format_fib_prefix, allowed_ip);
477   }
478
479   return s;
480 }
481
482 /*
483  * fd.io coding-style-patch-verification: ON
484  *
485  * Local Variables:
486  * eval: (c-set-style "gnu")
487  * End:
488  */