wireguard: move buffer when insufficient pre_data left
Currently wg-output-tun() doesn't check if a buffer has enough space for
prepending an ethernet header (wg header over ipv6 vxlan header case
leaves only 8 bytes free).
In such a case move buffer's content.
Type: fix
Change-Id: Iad18860e6b86a3d81f3d96d782de7c59556152d0
Signed-off-by: Alexander Skorichenko <askorichenko@netgate.com>
diff --git a/src/plugins/wireguard/wireguard_output_tun.c b/src/plugins/wireguard/wireguard_output_tun.c
index f613d6c..c009d0c 100644
--- a/src/plugins/wireguard/wireguard_output_tun.c
+++ b/src/plugins/wireguard/wireguard_output_tun.c
@@ -423,20 +423,7 @@
goto out;
}
- is_ip4_out = ip46_address_is_ip4 (&peer->src.addr);
- if (is_ip4_out)
- {
- hdr4_out = vlib_buffer_get_current (b[0]);
- message_data_wg = &hdr4_out->wg;
- }
- else
- {
- hdr6_out = vlib_buffer_get_current (b[0]);
- message_data_wg = &hdr6_out->wg;
- }
-
iph_offset = vnet_buffer (b[0])->ip.save_rewrite_length;
- plain_data = vlib_buffer_get_current (b[0]) + iph_offset;
plain_data_len = vlib_buffer_length_in_chain (vm, b[0]) - iph_offset;
u8 *iv_data = b[0]->pre_data;
@@ -447,13 +434,36 @@
* into the packet
*/
if (PREDICT_FALSE (encrypted_packet_len >= WG_DEFAULT_DATA_SIZE) ||
- PREDICT_FALSE ((b[0]->current_data + encrypted_packet_len) >=
+ PREDICT_FALSE ((iph_offset + encrypted_packet_len) >=
vlib_buffer_get_default_data_size (vm)))
{
b[0]->error = node->errors[WG_OUTPUT_ERROR_TOO_BIG];
goto out;
}
+ /*
+ * Move the buffer to fit ethernet header
+ */
+ if (b[0]->current_data + VLIB_BUFFER_PRE_DATA_SIZE <
+ sizeof (ethernet_header_t))
+ {
+ vlib_buffer_move (vm, b[0], 0);
+ }
+
+ plain_data = vlib_buffer_get_current (b[0]) + iph_offset;
+
+ is_ip4_out = ip46_address_is_ip4 (&peer->src.addr);
+ if (is_ip4_out)
+ {
+ hdr4_out = vlib_buffer_get_current (b[0]);
+ message_data_wg = &hdr4_out->wg;
+ }
+ else
+ {
+ hdr6_out = vlib_buffer_get_current (b[0]);
+ message_data_wg = &hdr6_out->wg;
+ }
+
if (PREDICT_FALSE (last_adj_index != adj_index))
{
wg_timers_any_authenticated_packet_sent_opt (peer, time);