wireguard: initial implementation of wireguard protocol
[vpp.git] / src / plugins / wireguard / wireguard_timer.c
1 /*
2  * Copyright (c) 2020 Doc.ai and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <wireguard/wireguard.h>
17 #include <wireguard/wireguard_send.h>
18 #include <wireguard/wireguard_timer.h>
19
20 static u32
21 get_random_u32_max (u32 max)
22 {
23   vlib_main_t *vm = vlib_get_main ();
24   u32 seed = (u32) (vlib_time_now (vm) * 1e6);
25   return random_u32 (&seed) % max;
26 }
27
28 static void
29 stop_timer (wg_peer_t * peer, u32 timer_id)
30 {
31   if (peer->timers[timer_id] != ~0)
32     {
33       tw_timer_stop_16t_2w_512sl (&peer->timer_wheel, peer->timers[timer_id]);
34       peer->timers[timer_id] = ~0;
35     }
36 }
37
38 static void
39 start_or_update_timer (wg_peer_t * peer, u32 timer_id, u32 interval)
40 {
41   if (peer->timers[timer_id] == ~0)
42     {
43       wg_main_t *wmp = &wg_main;
44       peer->timers[timer_id] =
45         tw_timer_start_16t_2w_512sl (&peer->timer_wheel, peer - wmp->peers,
46                                      timer_id, interval);
47     }
48   else
49     {
50       tw_timer_update_16t_2w_512sl (&peer->timer_wheel,
51                                     peer->timers[timer_id], interval);
52     }
53 }
54
55 static void
56 wg_expired_retransmit_handshake (vlib_main_t * vm, wg_peer_t * peer)
57 {
58
59   if (peer->timer_handshake_attempts > MAX_TIMER_HANDSHAKES)
60     {
61       stop_timer (peer, WG_TIMER_SEND_KEEPALIVE);
62
63       /* We set a timer for destroying any residue that might be left
64        * of a partial exchange.
65        */
66
67       if (peer->timers[WG_TIMER_KEY_ZEROING] == ~0)
68         {
69           wg_main_t *wmp = &wg_main;
70
71           peer->timers[WG_TIMER_KEY_ZEROING] =
72             tw_timer_start_16t_2w_512sl (&peer->timer_wheel,
73                                          peer - wmp->peers,
74                                          WG_TIMER_KEY_ZEROING,
75                                          REJECT_AFTER_TIME * 3 * WHZ);
76         }
77     }
78   else
79     {
80       ++peer->timer_handshake_attempts;
81       wg_send_handshake (vm, peer, true);
82     }
83 }
84
85 static void
86 wg_expired_send_keepalive (vlib_main_t * vm, wg_peer_t * peer)
87 {
88   wg_send_keepalive (vm, peer);
89
90   if (peer->timer_need_another_keepalive)
91     {
92       peer->timer_need_another_keepalive = false;
93       start_or_update_timer (peer, WG_TIMER_SEND_KEEPALIVE,
94                              KEEPALIVE_TIMEOUT * WHZ);
95     }
96 }
97
98 static void
99 wg_expired_send_persistent_keepalive (vlib_main_t * vm, wg_peer_t * peer)
100 {
101   if (peer->persistent_keepalive_interval)
102     {
103       wg_send_keepalive (vm, peer);
104     }
105 }
106
107 static void
108 wg_expired_new_handshake (vlib_main_t * vm, wg_peer_t * peer)
109 {
110   wg_send_handshake (vm, peer, false);
111 }
112
113 static void
114 wg_expired_zero_key_material (vlib_main_t * vm, wg_peer_t * peer)
115 {
116   if (!peer->is_dead)
117     {
118       noise_remote_clear (vm, &peer->remote);
119     }
120 }
121
122
123 void
124 wg_timers_any_authenticated_packet_traversal (wg_peer_t * peer)
125 {
126   if (peer->persistent_keepalive_interval)
127     {
128       start_or_update_timer (peer, WG_TIMER_PERSISTENT_KEEPALIVE,
129                              peer->persistent_keepalive_interval * WHZ);
130     }
131 }
132
133 void
134 wg_timers_any_authenticated_packet_sent (wg_peer_t * peer)
135 {
136   stop_timer (peer, WG_TIMER_SEND_KEEPALIVE);
137 }
138
139 void
140 wg_timers_handshake_initiated (wg_peer_t * peer)
141 {
142   u32 interval =
143     REKEY_TIMEOUT * WHZ + get_random_u32_max (REKEY_TIMEOUT_JITTER);
144   start_or_update_timer (peer, WG_TIMER_RETRANSMIT_HANDSHAKE, interval);
145 }
146
147 void
148 wg_timers_session_derived (wg_peer_t * peer)
149 {
150   start_or_update_timer (peer, WG_TIMER_KEY_ZEROING,
151                          REJECT_AFTER_TIME * 3 * WHZ);
152 }
153
154 /* Should be called after an authenticated data packet is sent. */
155 void
156 wg_timers_data_sent (wg_peer_t * peer)
157 {
158   u32 interval = (KEEPALIVE_TIMEOUT + REKEY_TIMEOUT) * WHZ +
159     get_random_u32_max (REKEY_TIMEOUT_JITTER);
160
161   if (peer->timers[WG_TIMER_NEW_HANDSHAKE] == ~0)
162     {
163       wg_main_t *wmp = &wg_main;
164       peer->timers[WG_TIMER_NEW_HANDSHAKE] =
165         tw_timer_start_16t_2w_512sl (&peer->timer_wheel, peer - wmp->peers,
166                                      WG_TIMER_NEW_HANDSHAKE, interval);
167     }
168 }
169
170 /* Should be called after an authenticated data packet is received. */
171 void
172 wg_timers_data_received (wg_peer_t * peer)
173 {
174   if (peer->timers[WG_TIMER_SEND_KEEPALIVE] == ~0)
175     {
176       wg_main_t *wmp = &wg_main;
177       peer->timers[WG_TIMER_SEND_KEEPALIVE] =
178         tw_timer_start_16t_2w_512sl (&peer->timer_wheel, peer - wmp->peers,
179                                      WG_TIMER_SEND_KEEPALIVE,
180                                      KEEPALIVE_TIMEOUT * WHZ);
181     }
182   else
183     {
184       peer->timer_need_another_keepalive = true;
185     }
186 }
187
188 /* Should be called after a handshake response message is received and processed
189  * or when getting key confirmation via the first data message.
190  */
191 void
192 wg_timers_handshake_complete (wg_peer_t * peer)
193 {
194   stop_timer (peer, WG_TIMER_RETRANSMIT_HANDSHAKE);
195
196   peer->timer_handshake_attempts = 0;
197 }
198
199 void
200 wg_timers_any_authenticated_packet_received (wg_peer_t * peer)
201 {
202   stop_timer (peer, WG_TIMER_NEW_HANDSHAKE);
203 }
204
205 static vlib_node_registration_t wg_timer_mngr_node;
206
207 static void
208 expired_timer_callback (u32 * expired_timers)
209 {
210   int i;
211   u32 timer_id;
212   u32 pool_index;
213
214   wg_main_t *wmp = &wg_main;
215   vlib_main_t *vm = wmp->vlib_main;
216
217   wg_peer_t *peer;
218
219   /* Need to invalidate all of them because one can restart other */
220   for (i = 0; i < vec_len (expired_timers); i++)
221     {
222       pool_index = expired_timers[i] & 0x0FFFFFFF;
223       timer_id = expired_timers[i] >> 28;
224
225       peer = pool_elt_at_index (wmp->peers, pool_index);
226       peer->timers[timer_id] = ~0;
227     }
228
229   for (i = 0; i < vec_len (expired_timers); i++)
230     {
231       pool_index = expired_timers[i] & 0x0FFFFFFF;
232       timer_id = expired_timers[i] >> 28;
233
234       peer = pool_elt_at_index (wmp->peers, pool_index);
235       switch (timer_id)
236         {
237         case WG_TIMER_RETRANSMIT_HANDSHAKE:
238           wg_expired_retransmit_handshake (vm, peer);
239           break;
240         case WG_TIMER_PERSISTENT_KEEPALIVE:
241           wg_expired_send_persistent_keepalive (vm, peer);
242           break;
243         case WG_TIMER_SEND_KEEPALIVE:
244           wg_expired_send_keepalive (vm, peer);
245           break;
246         case WG_TIMER_NEW_HANDSHAKE:
247           wg_expired_new_handshake (vm, peer);
248           break;
249         case WG_TIMER_KEY_ZEROING:
250           wg_expired_zero_key_material (vm, peer);
251           break;
252         default:
253           break;
254         }
255     }
256 }
257
258 void
259 wg_timers_init (wg_peer_t * peer, f64 now)
260 {
261   for (int i = 0; i < WG_N_TIMERS; i++)
262     {
263       peer->timers[i] = ~0;
264     }
265   tw_timer_wheel_16t_2w_512sl_t *tw = &peer->timer_wheel;
266   tw_timer_wheel_init_16t_2w_512sl (tw,
267                                     expired_timer_callback,
268                                     WG_TICK /* timer period in s */ , ~0);
269   tw->last_run_time = now;
270   peer->adj_index = INDEX_INVALID;
271 }
272
273 static uword
274 wg_timer_mngr_fn (vlib_main_t * vm, vlib_node_runtime_t * rt,
275                   vlib_frame_t * f)
276 {
277   wg_main_t *wmp = &wg_main;
278   wg_peer_t *peers;
279   wg_peer_t *peer;
280
281   while (1)
282     {
283       vlib_process_wait_for_event_or_clock (vm, WG_TICK);
284       vlib_process_get_events (vm, NULL);
285
286       peers = wmp->peers;
287       /* *INDENT-OFF* */
288       pool_foreach (peer, peers,
289       ({
290         tw_timer_expire_timers_16t_2w_512sl
291         (&peer->timer_wheel, vlib_time_now (vm));
292       }));
293       /* *INDENT-ON* */
294     }
295
296   return 0;
297 }
298
299 void
300 wg_timers_stop (wg_peer_t * peer)
301 {
302   stop_timer (peer, WG_TIMER_RETRANSMIT_HANDSHAKE);
303   stop_timer (peer, WG_TIMER_PERSISTENT_KEEPALIVE);
304   stop_timer (peer, WG_TIMER_SEND_KEEPALIVE);
305   stop_timer (peer, WG_TIMER_NEW_HANDSHAKE);
306   stop_timer (peer, WG_TIMER_KEY_ZEROING);
307 }
308
309 /* *INDENT-OFF* */
310 VLIB_REGISTER_NODE (wg_timer_mngr_node, static) = {
311     .function = wg_timer_mngr_fn,
312     .type = VLIB_NODE_TYPE_PROCESS,
313     .name =
314     "wg-timer-manager",
315 };
316 /* *INDENT-ON* */
317
318 /*
319  * fd.io coding-style-patch-verification: ON
320  *
321  * Local Variables:
322  * eval: (c-set-style "gnu")
323  * End:
324  */