Line data Source code
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 <vlibmemory/api.h>
17 : #include <wireguard/wireguard.h>
18 : #include <wireguard/wireguard_send.h>
19 : #include <wireguard/wireguard_timer.h>
20 :
21 : static u32
22 298 : get_random_u32_max (u32 max)
23 : {
24 298 : vlib_main_t *vm = vlib_get_main ();
25 298 : u32 seed = (u32) (vlib_time_now (vm) * 1e6);
26 298 : return random_u32 (&seed) % max;
27 : }
28 :
29 : static u32
30 41 : get_random_u32_max_opt (u32 max, f64 time)
31 : {
32 41 : u32 seed = (u32) (time * 1e6);
33 41 : return random_u32 (&seed) % max;
34 : }
35 :
36 : static void
37 750 : stop_timer (wg_peer_t * peer, u32 timer_id)
38 : {
39 750 : if (peer->timers[timer_id] != ~0)
40 : {
41 437 : tw_timer_stop_16t_2w_512sl (peer->timer_wheel, peer->timers[timer_id]);
42 437 : peer->timers[timer_id] = ~0;
43 : }
44 750 : }
45 :
46 : static void
47 591 : start_timer (wg_peer_t * peer, u32 timer_id, u32 interval_ticks)
48 : {
49 591 : ASSERT (vlib_get_thread_index () == 0);
50 :
51 591 : if (peer->timers[timer_id] == ~0)
52 : {
53 591 : peer->timers[timer_id] =
54 591 : tw_timer_start_16t_2w_512sl (peer->timer_wheel, peer - wg_peer_pool,
55 : timer_id, interval_ticks);
56 : }
57 591 : }
58 :
59 : typedef struct
60 : {
61 : u32 peer_idx;
62 : u32 timer_id;
63 : u32 interval_ticks;
64 :
65 : } wg_timers_args;
66 :
67 : static void *
68 591 : start_timer_thread_fn (void *arg)
69 : {
70 591 : wg_timers_args *a = arg;
71 591 : wg_peer_t *peer = wg_peer_get (a->peer_idx);
72 591 : start_timer (peer, a->timer_id, a->interval_ticks);
73 591 : return 0;
74 : }
75 :
76 : static_always_inline void
77 1419 : start_timer_from_mt (u32 peer_idx, u32 timer_id, u32 interval_ticks)
78 : {
79 1419 : wg_timers_args a = {
80 : .peer_idx = peer_idx,
81 : .timer_id = timer_id,
82 : .interval_ticks = interval_ticks,
83 : };
84 1419 : wg_peer_t *peer = wg_peer_get (peer_idx);
85 1419 : if (PREDICT_FALSE (!peer->timers_dispatched[timer_id]))
86 591 : if (!clib_atomic_cmp_and_swap (&peer->timers_dispatched[timer_id], 0, 1))
87 591 : vl_api_rpc_call_main_thread (start_timer_thread_fn, (u8 *) &a,
88 : sizeof (a));
89 1419 : }
90 :
91 : static inline u32
92 150 : timer_ticks_left (vlib_main_t * vm, f64 init_time_sec, u32 interval_ticks)
93 : {
94 : static const int32_t rounding = (int32_t) (WHZ / 2);
95 : int32_t ticks_remain;
96 :
97 150 : ticks_remain = (init_time_sec - vlib_time_now (vm)) * WHZ + interval_ticks;
98 150 : return (ticks_remain > rounding) ? (u32) ticks_remain : 0;
99 : }
100 :
101 : static void
102 16 : wg_expired_retransmit_handshake (vlib_main_t * vm, wg_peer_t * peer)
103 : {
104 16 : if (peer->rehandshake_started == ~0)
105 4 : return;
106 :
107 12 : u32 ticks = timer_ticks_left (vm, peer->rehandshake_started,
108 : peer->rehandshake_interval_tick);
109 12 : if (ticks)
110 : {
111 0 : start_timer (peer, WG_TIMER_RETRANSMIT_HANDSHAKE, ticks);
112 0 : return;
113 : }
114 :
115 12 : if (peer->timer_handshake_attempts > MAX_TIMER_HANDSHAKES)
116 : {
117 0 : stop_timer (peer, WG_TIMER_SEND_KEEPALIVE);
118 :
119 : /* We set a timer for destroying any residue that might be left
120 : * of a partial exchange.
121 : */
122 0 : start_timer (peer, WG_TIMER_KEY_ZEROING, REJECT_AFTER_TIME * 3 * WHZ);
123 :
124 : }
125 : else
126 : {
127 12 : ++peer->timer_handshake_attempts;
128 12 : wg_send_handshake (vm, peer, true);
129 : }
130 : }
131 :
132 : static void
133 0 : wg_expired_send_keepalive (vlib_main_t * vm, wg_peer_t * peer)
134 : {
135 0 : if (peer->last_sent_packet < peer->last_received_packet)
136 : {
137 0 : u32 ticks = timer_ticks_left (vm, peer->last_received_packet,
138 : KEEPALIVE_TIMEOUT * WHZ);
139 0 : if (ticks)
140 : {
141 0 : start_timer (peer, WG_TIMER_SEND_KEEPALIVE, ticks);
142 0 : return;
143 : }
144 :
145 0 : wg_send_keepalive (vm, peer);
146 0 : if (peer->timer_need_another_keepalive)
147 : {
148 0 : peer->timer_need_another_keepalive = false;
149 0 : start_timer (peer, WG_TIMER_SEND_KEEPALIVE,
150 : KEEPALIVE_TIMEOUT * WHZ);
151 : }
152 : }
153 : }
154 :
155 : static void
156 0 : wg_expired_send_persistent_keepalive (vlib_main_t * vm, wg_peer_t * peer)
157 : {
158 0 : if (peer->persistent_keepalive_interval)
159 : {
160 0 : f64 latest_time = peer->last_sent_packet > peer->last_received_packet
161 0 : ? peer->last_sent_packet : peer->last_received_packet;
162 :
163 0 : u32 ticks = timer_ticks_left (vm, latest_time,
164 0 : peer->persistent_keepalive_interval *
165 : WHZ);
166 0 : if (ticks)
167 : {
168 0 : start_timer (peer, WG_TIMER_PERSISTENT_KEEPALIVE, ticks);
169 0 : return;
170 : }
171 :
172 0 : wg_send_keepalive (vm, peer);
173 : }
174 : }
175 :
176 : static void
177 138 : wg_expired_new_handshake (vlib_main_t * vm, wg_peer_t * peer)
178 : {
179 138 : u32 ticks = timer_ticks_left (vm, peer->last_sent_packet,
180 : peer->new_handshake_interval_tick);
181 138 : if (ticks)
182 : {
183 0 : start_timer (peer, WG_TIMER_NEW_HANDSHAKE, ticks);
184 0 : return;
185 : }
186 :
187 138 : wg_send_handshake (vm, peer, false);
188 : }
189 :
190 : static void
191 0 : wg_expired_zero_key_material (vlib_main_t * vm, wg_peer_t * peer)
192 : {
193 : u32 ticks =
194 0 : timer_ticks_left (vm, peer->session_derived, REJECT_AFTER_TIME * 3 * WHZ);
195 0 : if (ticks)
196 : {
197 0 : start_timer (peer, WG_TIMER_KEY_ZEROING, ticks);
198 0 : return;
199 : }
200 :
201 0 : if (!wg_peer_is_dead (peer))
202 : {
203 0 : noise_remote_clear (vm, &peer->remote);
204 : }
205 : }
206 :
207 : inline void
208 433 : wg_timers_any_authenticated_packet_traversal (wg_peer_t *peer)
209 : {
210 433 : if (peer->persistent_keepalive_interval)
211 : {
212 433 : start_timer_from_mt (peer - wg_peer_pool,
213 : WG_TIMER_PERSISTENT_KEEPALIVE,
214 433 : peer->persistent_keepalive_interval * WHZ);
215 : }
216 433 : }
217 :
218 : void
219 244 : wg_timers_any_authenticated_packet_sent (wg_peer_t * peer)
220 : {
221 244 : peer->last_sent_packet = vlib_time_now (vlib_get_main ());
222 244 : }
223 :
224 : inline void
225 41 : wg_timers_any_authenticated_packet_sent_opt (wg_peer_t *peer, f64 time)
226 : {
227 41 : peer->last_sent_packet = time;
228 41 : }
229 :
230 : void
231 150 : wg_timers_handshake_initiated (wg_peer_t * peer)
232 : {
233 150 : peer->rehandshake_started = vlib_time_now (vlib_get_main ());
234 150 : peer->rehandshake_interval_tick =
235 150 : REKEY_TIMEOUT * WHZ + get_random_u32_max (REKEY_TIMEOUT_JITTER);
236 :
237 150 : start_timer_from_mt (peer - wg_peer_pool, WG_TIMER_RETRANSMIT_HANDSHAKE,
238 : peer->rehandshake_interval_tick);
239 150 : }
240 :
241 : void
242 148 : wg_timers_send_first_handshake (wg_peer_t *peer)
243 : {
244 : // zero value is not allowed
245 148 : peer->new_handshake_interval_tick =
246 148 : get_random_u32_max (REKEY_TIMEOUT_JITTER) + 1;
247 148 : start_timer_from_mt (peer - wg_peer_pool, WG_TIMER_NEW_HANDSHAKE,
248 : peer->new_handshake_interval_tick);
249 148 : }
250 :
251 : void
252 94 : wg_timers_session_derived (wg_peer_t * peer)
253 : {
254 94 : peer->session_derived = vlib_time_now (vlib_get_main ());
255 :
256 94 : start_timer_from_mt (peer - wg_peer_pool, WG_TIMER_KEY_ZEROING,
257 : REJECT_AFTER_TIME * 3 * WHZ);
258 94 : }
259 :
260 : /* Should be called after an authenticated data packet is sent. */
261 : void
262 0 : wg_timers_data_sent (wg_peer_t * peer)
263 : {
264 0 : peer->new_handshake_interval_tick =
265 0 : (KEEPALIVE_TIMEOUT + REKEY_TIMEOUT) * WHZ +
266 0 : get_random_u32_max (REKEY_TIMEOUT_JITTER);
267 :
268 0 : start_timer_from_mt (peer - wg_peer_pool, WG_TIMER_NEW_HANDSHAKE,
269 : peer->new_handshake_interval_tick);
270 0 : }
271 :
272 : inline void
273 41 : wg_timers_data_sent_opt (wg_peer_t *peer, f64 time)
274 : {
275 41 : peer->new_handshake_interval_tick =
276 41 : (KEEPALIVE_TIMEOUT + REKEY_TIMEOUT) * WHZ +
277 41 : get_random_u32_max_opt (REKEY_TIMEOUT_JITTER, time);
278 :
279 41 : start_timer_from_mt (peer - wg_peer_pool, WG_TIMER_NEW_HANDSHAKE,
280 : peer->new_handshake_interval_tick);
281 41 : }
282 :
283 : /* Should be called after an authenticated data packet is received. */
284 : void
285 3624 : wg_timers_data_received (wg_peer_t * peer)
286 : {
287 3624 : if (peer->timers[WG_TIMER_SEND_KEEPALIVE] == ~0)
288 : {
289 553 : start_timer_from_mt (peer - wg_peer_pool, WG_TIMER_SEND_KEEPALIVE,
290 : KEEPALIVE_TIMEOUT * WHZ);
291 : }
292 : else
293 3071 : peer->timer_need_another_keepalive = true;
294 3624 : }
295 :
296 : /* Should be called after a handshake response message is received and processed
297 : * or when getting key confirmation via the first data message.
298 : */
299 : void
300 56 : wg_timers_handshake_complete (wg_peer_t * peer)
301 : {
302 56 : peer->rehandshake_started = ~0;
303 56 : peer->timer_handshake_attempts = 0;
304 56 : }
305 :
306 : void
307 94 : wg_timers_any_authenticated_packet_received (wg_peer_t * peer)
308 : {
309 94 : peer->last_received_packet = vlib_time_now (vlib_get_main ());
310 94 : }
311 :
312 : inline void
313 54 : wg_timers_any_authenticated_packet_received_opt (wg_peer_t *peer, f64 time)
314 : {
315 54 : peer->last_received_packet = time;
316 54 : }
317 :
318 : static vlib_node_registration_t wg_timer_mngr_node;
319 :
320 : static void
321 133 : expired_timer_callback (u32 * expired_timers)
322 : {
323 : int i;
324 : u32 timer_id;
325 : u32 pool_index;
326 :
327 133 : wg_main_t *wmp = &wg_main;
328 133 : vlib_main_t *vm = wmp->vlib_main;
329 :
330 : wg_peer_t *peer;
331 :
332 : /* Need to invalidate all of them because one can restart other */
333 287 : for (i = 0; i < vec_len (expired_timers); i++)
334 : {
335 154 : pool_index = expired_timers[i] & 0x0FFFFFFF;
336 154 : timer_id = expired_timers[i] >> 28;
337 :
338 154 : peer = wg_peer_get (pool_index);
339 154 : peer->timers[timer_id] = ~0;
340 :
341 : /* Under barrier, no sync needed */
342 154 : peer->timers_dispatched[timer_id] = 0;
343 : }
344 :
345 287 : for (i = 0; i < vec_len (expired_timers); i++)
346 : {
347 154 : pool_index = expired_timers[i] & 0x0FFFFFFF;
348 154 : timer_id = expired_timers[i] >> 28;
349 :
350 154 : peer = wg_peer_get (pool_index);
351 154 : switch (timer_id)
352 : {
353 16 : case WG_TIMER_RETRANSMIT_HANDSHAKE:
354 16 : wg_expired_retransmit_handshake (vm, peer);
355 16 : break;
356 0 : case WG_TIMER_PERSISTENT_KEEPALIVE:
357 0 : wg_expired_send_persistent_keepalive (vm, peer);
358 0 : break;
359 0 : case WG_TIMER_SEND_KEEPALIVE:
360 0 : wg_expired_send_keepalive (vm, peer);
361 0 : break;
362 138 : case WG_TIMER_NEW_HANDSHAKE:
363 138 : wg_expired_new_handshake (vm, peer);
364 138 : break;
365 0 : case WG_TIMER_KEY_ZEROING:
366 0 : wg_expired_zero_key_material (vm, peer);
367 0 : break;
368 0 : default:
369 0 : break;
370 : }
371 : }
372 133 : }
373 :
374 : void
375 575 : wg_timer_wheel_init ()
376 : {
377 575 : wg_main_t *wmp = &wg_main;
378 575 : tw_timer_wheel_16t_2w_512sl_t *tw = &wmp->timer_wheel;
379 575 : tw_timer_wheel_init_16t_2w_512sl (tw,
380 : expired_timer_callback,
381 : WG_TICK /* timer period in s */ , ~0);
382 575 : }
383 :
384 : static uword
385 575 : wg_timer_mngr_fn (vlib_main_t * vm, vlib_node_runtime_t * rt,
386 : vlib_frame_t * f)
387 : {
388 575 : wg_main_t *wmp = &wg_main;
389 575 : uword event_type = 0;
390 :
391 : /* Park the process until the feature is configured */
392 : while (1)
393 : {
394 575 : vlib_process_wait_for_event (vm);
395 3 : event_type = vlib_process_get_events (vm, 0);
396 3 : if (event_type == WG_START_EVENT)
397 : {
398 3 : break;
399 : }
400 : else
401 : {
402 0 : clib_warning ("Unknown event type %d", event_type);
403 : }
404 : }
405 : /*
406 : * Reset the timer wheel time so it won't try to
407 : * expire Avogadro's number of time slots.
408 : */
409 3 : wmp->timer_wheel.last_run_time = vlib_time_now (vm);
410 :
411 : while (1)
412 : {
413 28200 : vlib_process_wait_for_event_or_clock (vm, WG_TICK);
414 28197 : vlib_process_get_events (vm, NULL);
415 :
416 28197 : tw_timer_expire_timers_16t_2w_512sl (&wmp->timer_wheel,
417 : vlib_time_now (vm));
418 : }
419 :
420 : return 0;
421 : }
422 :
423 : void
424 296 : wg_timers_stop (wg_peer_t * peer)
425 : {
426 296 : ASSERT (vlib_get_thread_index () == 0);
427 296 : if (peer->timer_wheel)
428 : {
429 150 : stop_timer (peer, WG_TIMER_RETRANSMIT_HANDSHAKE);
430 150 : stop_timer (peer, WG_TIMER_PERSISTENT_KEEPALIVE);
431 150 : stop_timer (peer, WG_TIMER_SEND_KEEPALIVE);
432 150 : stop_timer (peer, WG_TIMER_NEW_HANDSHAKE);
433 150 : stop_timer (peer, WG_TIMER_KEY_ZEROING);
434 : }
435 296 : }
436 :
437 : /* *INDENT-OFF* */
438 1151 : VLIB_REGISTER_NODE (wg_timer_mngr_node, static) = {
439 : .function = wg_timer_mngr_fn,
440 : .type = VLIB_NODE_TYPE_PROCESS,
441 : .name =
442 : "wg-timer-manager",
443 : };
444 : /* *INDENT-ON* */
445 :
446 : void
447 855 : wg_feature_init (wg_main_t * wmp)
448 : {
449 855 : if (wmp->feature_init)
450 852 : return;
451 3 : vlib_process_signal_event (wmp->vlib_main, wg_timer_mngr_node.index,
452 : WG_START_EVENT, 0);
453 3 : wmp->feature_init = 1;
454 : }
455 :
456 :
457 :
458 : /*
459 : * fd.io coding-style-patch-verification: ON
460 : *
461 : * Local Variables:
462 : * eval: (c-set-style "gnu")
463 : * End:
464 : */
|