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 <vlib/vlib.h>
18 #include <vnet/vnet.h>
19 #include <vppinfra/error.h>
20 #include <wireguard/wireguard.h>
22 #include <wireguard/wireguard_send.h>
23 #include <wireguard/wireguard_if.h>
25 #define foreach_wg_input_error \
26 _ (NONE, "No error") \
27 _ (HANDSHAKE_MAC, "Invalid MAC handshake") \
28 _ (PEER, "Peer error") \
29 _ (INTERFACE, "Interface error") \
30 _ (DECRYPTION, "Failed during decryption") \
31 _ (KEEPALIVE_SEND, "Failed while sending Keepalive") \
32 _ (HANDSHAKE_SEND, "Failed while sending Handshake") \
33 _ (HANDSHAKE_RECEIVE, "Failed while receiving Handshake") \
34 _ (TOO_BIG, "Packet too big") \
35 _ (UNDEFINED, "Undefined error")
39 #define _(sym,str) WG_INPUT_ERROR_##sym,
40 foreach_wg_input_error
45 static char *wg_input_error_strings[] = {
46 #define _(sym,string) string,
47 foreach_wg_input_error
60 format_wg_message_type (u8 * s, va_list * args)
62 message_type_t type = va_arg (*args, message_type_t);
66 #define _(v,a) case MESSAGE_##v: return (format (s, "%s", a));
67 foreach_wg_message_type
70 return (format (s, "unknown"));
73 /* packet trace format function */
75 format_wg_input_trace (u8 * s, va_list * args)
77 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
78 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
80 wg_input_trace_t *t = va_arg (*args, wg_input_trace_t *);
82 s = format (s, "Wireguard input: \n");
83 s = format (s, " Type: %U\n", format_wg_message_type, t->type);
84 s = format (s, " Peer: %d\n", t->peer);
85 s = format (s, " Length: %d\n", t->current_length);
86 s = format (s, " Keepalive: %s", t->is_keepalive ? "true" : "false");
93 WG_INPUT_NEXT_HANDOFF_HANDSHAKE,
94 WG_INPUT_NEXT_HANDOFF_DATA,
95 WG_INPUT_NEXT_IP4_INPUT,
96 WG_INPUT_NEXT_IP6_INPUT,
103 /* set_peer_address (wg_peer_t * peer, ip4_address_t ip4, u16 udp_port) */
107 /* ip46_address_set_ip4 (&peer->dst.addr, &ip4); */
108 /* peer->dst.port = udp_port; */
113 is_ip4_header (u8 *data)
115 return (data[0] >> 4) == 0x4;
118 static wg_input_error_t
119 wg_handshake_process (vlib_main_t *vm, wg_main_t *wmp, vlib_buffer_t *b,
120 u32 node_idx, u8 is_ip4)
122 ASSERT (vm->thread_index == 0);
124 enum cookie_mac_state mac_state;
125 bool packet_needs_cookie;
129 wg_peer_t *peer = NULL;
131 void *current_b_data = vlib_buffer_get_current (b);
133 ip46_address_t src_ip;
137 current_b_data - sizeof (udp_header_t) - sizeof (ip4_header_t);
138 ip46_address_set_ip4 (&src_ip, &iph4->src_address);
143 current_b_data - sizeof (udp_header_t) - sizeof (ip6_header_t);
144 ip46_address_set_ip6 (&src_ip, &iph6->src_address);
147 udp_header_t *uhd = current_b_data - sizeof (udp_header_t);
148 u16 udp_src_port = clib_host_to_net_u16 (uhd->src_port);;
149 u16 udp_dst_port = clib_host_to_net_u16 (uhd->dst_port);;
151 message_header_t *header = current_b_data;
154 if (PREDICT_FALSE (header->type == MESSAGE_HANDSHAKE_COOKIE))
156 message_handshake_cookie_t *packet =
157 (message_handshake_cookie_t *) current_b_data;
159 wg_index_table_lookup (&wmp->index_table, packet->receiver_index);
161 peer = wg_peer_get (*entry);
163 return WG_INPUT_ERROR_PEER;
165 // TODO: Implement cookie_maker_consume_payload
167 return WG_INPUT_ERROR_NONE;
170 u32 len = (header->type == MESSAGE_HANDSHAKE_INITIATION ?
171 sizeof (message_handshake_initiation_t) :
172 sizeof (message_handshake_response_t));
174 message_macs_t *macs = (message_macs_t *)
175 ((u8 *) current_b_data + len - sizeof (*macs));
178 wg_ifs = wg_if_indexes_get_by_port (udp_dst_port);
180 return WG_INPUT_ERROR_INTERFACE;
182 vec_foreach (ii, wg_ifs)
184 wg_if = wg_if_get (*ii);
188 mac_state = cookie_checker_validate_macs (
189 vm, &wg_if->cookie_checker, macs, current_b_data, len, under_load,
190 &src_ip, udp_src_port);
191 if (mac_state == INVALID_MAC)
200 return WG_INPUT_ERROR_HANDSHAKE_MAC;
202 if ((under_load && mac_state == VALID_MAC_WITH_COOKIE)
203 || (!under_load && mac_state == VALID_MAC_BUT_NO_COOKIE))
204 packet_needs_cookie = false;
205 else if (under_load && mac_state == VALID_MAC_BUT_NO_COOKIE)
206 packet_needs_cookie = true;
208 return WG_INPUT_ERROR_HANDSHAKE_MAC;
210 switch (header->type)
212 case MESSAGE_HANDSHAKE_INITIATION:
214 message_handshake_initiation_t *message = current_b_data;
216 if (packet_needs_cookie)
218 // TODO: Add processing
221 if (noise_consume_initiation
222 (vm, noise_local_get (wg_if->local_idx), &rp,
223 message->sender_index, message->unencrypted_ephemeral,
224 message->encrypted_static, message->encrypted_timestamp))
226 peer = wg_peer_get (rp->r_peer_idx);
230 return WG_INPUT_ERROR_PEER;
233 // set_peer_address (peer, ip4_src, udp_src_port);
234 if (PREDICT_FALSE (!wg_send_handshake_response (vm, peer)))
236 vlib_node_increment_counter (vm, node_idx,
237 WG_INPUT_ERROR_HANDSHAKE_SEND, 1);
241 wg_peer_update_flags (rp->r_peer_idx, WG_PEER_ESTABLISHED, true);
245 case MESSAGE_HANDSHAKE_RESPONSE:
247 message_handshake_response_t *resp = current_b_data;
248 index_t peeri = INDEX_INVALID;
250 wg_index_table_lookup (&wmp->index_table, resp->receiver_index);
252 if (PREDICT_TRUE (entry != NULL))
255 peer = wg_peer_get (peeri);
256 if (wg_peer_is_dead (peer))
257 return WG_INPUT_ERROR_PEER;
260 return WG_INPUT_ERROR_PEER;
262 if (!noise_consume_response
263 (vm, &peer->remote, resp->sender_index,
264 resp->receiver_index, resp->unencrypted_ephemeral,
265 resp->encrypted_nothing))
267 return WG_INPUT_ERROR_PEER;
269 if (packet_needs_cookie)
271 // TODO: Add processing
274 // set_peer_address (peer, ip4_src, udp_src_port);
275 if (noise_remote_begin_session (vm, &peer->remote))
278 wg_timers_session_derived (peer);
279 wg_timers_handshake_complete (peer);
280 if (PREDICT_FALSE (!wg_send_keepalive (vm, peer)))
282 vlib_node_increment_counter (vm, node_idx,
283 WG_INPUT_ERROR_KEEPALIVE_SEND, 1);
287 wg_peer_update_flags (peeri, WG_PEER_ESTABLISHED, true);
293 return WG_INPUT_ERROR_HANDSHAKE_RECEIVE;
296 wg_timers_any_authenticated_packet_received (peer);
297 wg_timers_any_authenticated_packet_traversal (peer);
298 return WG_INPUT_ERROR_NONE;
301 static_always_inline void
302 wg_input_process_ops (vlib_main_t *vm, vlib_node_runtime_t *node,
303 vnet_crypto_op_t *ops, vlib_buffer_t *b[], u16 *nexts,
306 u32 n_fail, n_ops = vec_len (ops);
307 vnet_crypto_op_t *op = ops;
312 n_fail = n_ops - vnet_crypto_process_ops (vm, op, n_ops);
316 ASSERT (op - ops < n_ops);
318 if (op->status != VNET_CRYPTO_OP_STATUS_COMPLETED)
320 u32 bi = op->user_data;
321 b[bi]->error = node->errors[WG_INPUT_ERROR_DECRYPTION];
322 nexts[bi] = drop_next;
330 wg_input_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
331 vlib_frame_t *frame, u8 is_ip4)
333 wg_main_t *wmp = &wg_main;
334 wg_per_thread_data_t *ptd =
335 vec_elt_at_index (wmp->per_thread_data, vm->thread_index);
336 u32 *from = vlib_frame_vector_args (frame);
337 u32 n_left_from = frame->n_vectors;
339 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
340 u32 thread_index = vm->thread_index;
341 vnet_crypto_op_t **crypto_ops = &ptd->crypto_ops;
342 const u16 drop_next = WG_INPUT_NEXT_PUNT;
343 message_type_t header_type;
344 vlib_buffer_t *data_bufs[VLIB_FRAME_SIZE];
345 u32 data_bi[VLIB_FRAME_SIZE]; /* buffer index for data */
346 u32 other_bi[VLIB_FRAME_SIZE]; /* buffer index for drop or handoff */
347 u16 other_nexts[VLIB_FRAME_SIZE], *other_next = other_nexts, n_other = 0;
348 u16 data_nexts[VLIB_FRAME_SIZE], *data_next = data_nexts, n_data = 0;
350 vlib_get_buffers (vm, from, bufs, n_left_from);
351 vec_reset_length (ptd->crypto_ops);
353 f64 time = clib_time_now (&vm->clib_time) + vm->time_offset;
355 wg_peer_t *peer = NULL;
356 u32 *last_peer_time_idx = NULL;
357 u32 last_rec_idx = ~0;
359 bool is_keepalive = false;
360 u32 *peer_idx = NULL;
362 while (n_left_from > 0)
367 vlib_prefetch_buffer_header (b[2], LOAD);
368 p = vlib_buffer_get_current (b[1]);
369 CLIB_PREFETCH (p, CLIB_CACHE_LINE_BYTES, LOAD);
370 CLIB_PREFETCH (vlib_buffer_get_tail (b[1]), CLIB_CACHE_LINE_BYTES,
374 other_next[n_other] = WG_INPUT_NEXT_PUNT;
375 data_nexts[n_data] = WG_INPUT_N_NEXT;
378 ((message_header_t *) vlib_buffer_get_current (b[0]))->type;
380 if (PREDICT_TRUE (header_type == MESSAGE_DATA))
382 message_data_t *data = vlib_buffer_get_current (b[0]);
383 u8 *iv_data = b[0]->pre_data;
384 peer_idx = wg_index_table_lookup (&wmp->index_table,
385 data->receiver_index);
387 if (data->receiver_index != last_rec_idx)
389 peer_idx = wg_index_table_lookup (&wmp->index_table,
390 data->receiver_index);
391 if (PREDICT_TRUE (peer_idx != NULL))
393 peer = wg_peer_get (*peer_idx);
395 last_rec_idx = data->receiver_index;
398 if (PREDICT_FALSE (!peer_idx))
400 other_next[n_other] = WG_INPUT_NEXT_ERROR;
401 b[0]->error = node->errors[WG_INPUT_ERROR_PEER];
402 other_bi[n_other] = from[b - bufs];
407 if (PREDICT_FALSE (~0 == peer->input_thread_index))
409 /* this is the first packet to use this peer, claim the peer
412 clib_atomic_cmp_and_swap (&peer->input_thread_index, ~0,
413 wg_peer_assign_thread (thread_index));
416 if (PREDICT_TRUE (thread_index != peer->input_thread_index))
418 other_next[n_other] = WG_INPUT_NEXT_HANDOFF_DATA;
419 other_bi[n_other] = from[b - bufs];
424 u16 encr_len = b[0]->current_length - sizeof (message_data_t);
425 u16 decr_len = encr_len - NOISE_AUTHTAG_LEN;
426 if (PREDICT_FALSE (decr_len >= WG_DEFAULT_DATA_SIZE))
428 b[0]->error = node->errors[WG_INPUT_ERROR_TOO_BIG];
429 other_bi[n_other] = from[b - bufs];
434 enum noise_state_crypt state_cr = noise_sync_remote_decrypt (
435 vm, crypto_ops, &peer->remote, data->receiver_index, data->counter,
436 data->encrypted_data, decr_len, data->encrypted_data, n_data,
439 if (PREDICT_FALSE (state_cr == SC_CONN_RESET))
441 wg_timers_handshake_complete (peer);
442 data_bufs[n_data] = b[0];
443 data_bi[n_data] = from[b - bufs];
447 else if (PREDICT_FALSE (state_cr == SC_KEEP_KEY_FRESH))
449 wg_send_handshake_from_mt (*peer_idx, false);
450 data_bufs[n_data] = b[0];
451 data_bi[n_data] = from[b - bufs];
455 else if (PREDICT_FALSE (state_cr == SC_FAILED))
457 wg_peer_update_flags (*peer_idx, WG_PEER_ESTABLISHED, false);
458 other_next[n_other] = WG_INPUT_NEXT_ERROR;
459 b[0]->error = node->errors[WG_INPUT_ERROR_DECRYPTION];
460 other_bi[n_other] = from[b - bufs];
464 else if (PREDICT_TRUE (state_cr == SC_OK))
466 data_bufs[n_data] = b[0];
467 data_bi[n_data] = from[b - bufs];
476 /* Handshake packets should be processed in main thread */
477 if (thread_index != 0)
479 other_next[n_other] = WG_INPUT_NEXT_HANDOFF_HANDSHAKE;
480 other_bi[n_other] = from[b - bufs];
485 wg_input_error_t ret =
486 wg_handshake_process (vm, wmp, b[0], node->node_index, is_ip4);
487 if (ret != WG_INPUT_ERROR_NONE)
489 other_next[n_other] = WG_INPUT_NEXT_ERROR;
490 b[0]->error = node->errors[ret];
491 other_bi[n_other] = from[b - bufs];
496 other_bi[n_other] = from[b - bufs];
502 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
503 (b[0]->flags & VLIB_BUFFER_IS_TRACED)))
505 wg_input_trace_t *t = vlib_add_trace (vm, node, b[0], sizeof (*t));
506 t->type = header_type;
507 t->current_length = b[0]->current_length;
508 t->is_keepalive = is_keepalive;
509 t->peer = peer_idx ? *peer_idx : INDEX_INVALID;
517 /* decrypt packets */
518 wg_input_process_ops (vm, node, ptd->crypto_ops, data_bufs, data_nexts,
521 /* process after decryption */
523 n_left_from = n_data;
526 last_peer_time_idx = NULL;
527 while (n_left_from > 0)
529 bool is_keepalive = false;
530 u32 *peer_idx = NULL;
532 if (data_next[n_data] == WG_INPUT_NEXT_PUNT)
538 data_next[n_data] = WG_INPUT_NEXT_PUNT;
541 message_data_t *data = vlib_buffer_get_current (b[0]);
543 if (data->receiver_index != last_rec_idx)
546 wg_index_table_lookup (&wmp->index_table, data->receiver_index);
547 /* already checked and excisting */
548 peer = wg_peer_get (*peer_idx);
549 last_rec_idx = data->receiver_index;
552 noise_keypair_t *kp =
553 wg_get_active_keypair (&peer->remote, data->receiver_index);
555 if (!noise_counter_recv (&kp->kp_ctr, data->counter))
560 u16 encr_len = b[0]->current_length - sizeof (message_data_t);
561 u16 decr_len = encr_len - NOISE_AUTHTAG_LEN;
563 vlib_buffer_advance (b[0], sizeof (message_data_t));
564 b[0]->current_length = decr_len;
565 vnet_buffer_offload_flags_clear (b[0], VNET_BUFFER_OFFLOAD_F_UDP_CKSUM);
567 if (PREDICT_FALSE (peer_idx && (last_peer_time_idx != peer_idx)))
569 wg_timers_any_authenticated_packet_received_opt (peer, time);
570 wg_timers_any_authenticated_packet_traversal (peer);
571 last_peer_time_idx = peer_idx;
574 /* Keepalive packet has zero length */
581 wg_timers_data_received (peer);
583 ip46_address_t src_ip;
584 u8 is_ip4_inner = is_ip4_header (vlib_buffer_get_current (b[0]));
587 ip46_address_set_ip4 (
589 &((ip4_header_t *) vlib_buffer_get_current (b[0]))->src_address);
593 ip46_address_set_ip6 (
595 &((ip6_header_t *) vlib_buffer_get_current (b[0]))->src_address);
598 const fib_prefix_t *allowed_ip;
599 bool allowed = false;
602 * we could make this into an ACL, but the expectation
603 * is that there aren't many allowed IPs and thus a linear
604 * walk is fater than an ACL
607 vec_foreach (allowed_ip, peer->allowed_ips)
609 if (fib_prefix_is_cover_addr_46 (allowed_ip, &src_ip))
617 vnet_buffer (b[0])->sw_if_index[VLIB_RX] = peer->wg_sw_if_index;
619 is_ip4_inner ? WG_INPUT_NEXT_IP4_INPUT : WG_INPUT_NEXT_IP6_INPUT;
622 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
623 (b[0]->flags & VLIB_BUFFER_IS_TRACED)))
625 wg_input_trace_t *t = vlib_add_trace (vm, node, b[0], sizeof (*t));
626 t->type = header_type;
627 t->current_length = b[0]->current_length;
628 t->is_keepalive = is_keepalive;
629 t->peer = peer_idx ? *peer_idx : INDEX_INVALID;
636 /* enqueue other bufs */
637 vlib_buffer_enqueue_to_next (vm, node, other_bi, other_next, n_other);
639 /* enqueue data bufs */
640 vlib_buffer_enqueue_to_next (vm, node, data_bi, data_nexts, n_data);
642 return frame->n_vectors;
645 VLIB_NODE_FN (wg4_input_node)
646 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
648 return wg_input_inline (vm, node, frame, /* is_ip4 */ 1);
651 VLIB_NODE_FN (wg6_input_node)
652 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
654 return wg_input_inline (vm, node, frame, /* is_ip4 */ 0);
658 VLIB_REGISTER_NODE (wg4_input_node) =
661 .vector_size = sizeof (u32),
662 .format_trace = format_wg_input_trace,
663 .type = VLIB_NODE_TYPE_INTERNAL,
664 .n_errors = ARRAY_LEN (wg_input_error_strings),
665 .error_strings = wg_input_error_strings,
666 .n_next_nodes = WG_INPUT_N_NEXT,
667 /* edit / add dispositions here */
669 [WG_INPUT_NEXT_HANDOFF_HANDSHAKE] = "wg4-handshake-handoff",
670 [WG_INPUT_NEXT_HANDOFF_DATA] = "wg4-input-data-handoff",
671 [WG_INPUT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
672 [WG_INPUT_NEXT_IP6_INPUT] = "ip6-input",
673 [WG_INPUT_NEXT_PUNT] = "error-punt",
674 [WG_INPUT_NEXT_ERROR] = "error-drop",
678 VLIB_REGISTER_NODE (wg6_input_node) =
681 .vector_size = sizeof (u32),
682 .format_trace = format_wg_input_trace,
683 .type = VLIB_NODE_TYPE_INTERNAL,
684 .n_errors = ARRAY_LEN (wg_input_error_strings),
685 .error_strings = wg_input_error_strings,
686 .n_next_nodes = WG_INPUT_N_NEXT,
687 /* edit / add dispositions here */
689 [WG_INPUT_NEXT_HANDOFF_HANDSHAKE] = "wg6-handshake-handoff",
690 [WG_INPUT_NEXT_HANDOFF_DATA] = "wg6-input-data-handoff",
691 [WG_INPUT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
692 [WG_INPUT_NEXT_IP6_INPUT] = "ip6-input",
693 [WG_INPUT_NEXT_PUNT] = "error-punt",
694 [WG_INPUT_NEXT_ERROR] = "error-drop",
700 * fd.io coding-style-patch-verification: ON
703 * eval: (c-set-style "gnu")