aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArtem Glazychev <artem.glazychev@xored.com>2021-06-03 20:11:54 +0700
committerEd Warnicke <hagbard@gmail.com>2021-10-06 17:57:46 +0000
commit7dd3b5b5e37a4019ae335296ba9c4bd1e465fd17 (patch)
tree0cd0a76ebce52b2907514e4e4394af32094d2ab7
parent0c4931cb351929a1ccdb6b29431def3705f101d7 (diff)
wireguard: add ipv6 support
Type: improvement Signed-off-by: Artem Glazychev <artem.glazychev@xored.com> Change-Id: If1a7e82ce163c4c4acaa5acf45ad2b88371396f6
-rw-r--r--[-rwxr-xr-x]src/plugins/wireguard/wireguard.c21
-rwxr-xr-xsrc/plugins/wireguard/wireguard.h12
-rw-r--r--src/plugins/wireguard/wireguard_api.c35
-rw-r--r--[-rwxr-xr-x]src/plugins/wireguard/wireguard_cli.c12
-rw-r--r--[-rwxr-xr-x]src/plugins/wireguard/wireguard_cookie.c25
-rw-r--r--[-rwxr-xr-x]src/plugins/wireguard/wireguard_cookie.h12
-rw-r--r--src/plugins/wireguard/wireguard_handoff.c102
-rw-r--r--src/plugins/wireguard/wireguard_if.c29
-rw-r--r--src/plugins/wireguard/wireguard_if.h2
-rw-r--r--src/plugins/wireguard/wireguard_input.c117
-rw-r--r--[-rwxr-xr-x]src/plugins/wireguard/wireguard_output_tun.c134
-rw-r--r--src/plugins/wireguard/wireguard_peer.c128
-rw-r--r--src/plugins/wireguard/wireguard_peer.h16
-rw-r--r--[-rwxr-xr-x]src/plugins/wireguard/wireguard_send.c65
-rwxr-xr-xtest/test_wireguard.py499
15 files changed, 965 insertions, 244 deletions
diff --git a/src/plugins/wireguard/wireguard.c b/src/plugins/wireguard/wireguard.c
index 58422299069..8438cc126a6 100755..100644
--- a/src/plugins/wireguard/wireguard.c
+++ b/src/plugins/wireguard/wireguard.c
@@ -15,7 +15,6 @@
#include <vnet/vnet.h>
#include <vnet/plugin/plugin.h>
-#include <vnet/ipip/ipip.h>
#include <vpp/app/version.h>
#include <wireguard/wireguard_send.h>
@@ -32,9 +31,12 @@ wg_init (vlib_main_t * vm)
wmp->vlib_main = vm;
- wmp->in_fq_index = vlib_frame_queue_main_init (wg_input_node.index, 0);
- wmp->out_fq_index =
- vlib_frame_queue_main_init (wg_output_tun_node.index, 0);
+ wmp->in4_fq_index = vlib_frame_queue_main_init (wg4_input_node.index, 0);
+ wmp->in6_fq_index = vlib_frame_queue_main_init (wg6_input_node.index, 0);
+ wmp->out4_fq_index =
+ vlib_frame_queue_main_init (wg4_output_tun_node.index, 0);
+ wmp->out6_fq_index =
+ vlib_frame_queue_main_init (wg6_output_tun_node.index, 0);
vlib_thread_main_t *tm = vlib_get_thread_main ();
@@ -50,13 +52,18 @@ VLIB_INIT_FUNCTION (wg_init);
/* *INDENT-OFF* */
-VNET_FEATURE_INIT (wg_output_tun, static) =
-{
+VNET_FEATURE_INIT (wg4_output_tun, static) = {
.arc_name = "ip4-output",
- .node_name = "wg-output-tun",
+ .node_name = "wg4-output-tun",
.runs_after = VNET_FEATURES ("gso-ip4"),
};
+VNET_FEATURE_INIT (wg6_output_tun, static) = {
+ .arc_name = "ip6-output",
+ .node_name = "wg6-output-tun",
+ .runs_after = VNET_FEATURES ("gso-ip6"),
+};
+
VLIB_PLUGIN_REGISTER () =
{
.version = VPP_BUILD_VER,
diff --git a/src/plugins/wireguard/wireguard.h b/src/plugins/wireguard/wireguard.h
index ef308c4c397..829c9e6f22b 100755
--- a/src/plugins/wireguard/wireguard.h
+++ b/src/plugins/wireguard/wireguard.h
@@ -21,8 +21,10 @@
#define WG_DEFAULT_DATA_SIZE 2048
-extern vlib_node_registration_t wg_input_node;
-extern vlib_node_registration_t wg_output_tun_node;
+extern vlib_node_registration_t wg4_input_node;
+extern vlib_node_registration_t wg6_input_node;
+extern vlib_node_registration_t wg4_output_tun_node;
+extern vlib_node_registration_t wg6_output_tun_node;
typedef struct wg_per_thread_data_t_
{
@@ -37,8 +39,10 @@ typedef struct
wg_index_table_t index_table;
- u32 in_fq_index;
- u32 out_fq_index;
+ u32 in4_fq_index;
+ u32 in6_fq_index;
+ u32 out4_fq_index;
+ u32 out6_fq_index;
wg_per_thread_data_t *per_thread_data;
u8 feature_init;
diff --git a/src/plugins/wireguard/wireguard_api.c b/src/plugins/wireguard/wireguard_api.c
index 3f17f658869..5dd4f86f910 100644
--- a/src/plugins/wireguard/wireguard_api.c
+++ b/src/plugins/wireguard/wireguard_api.c
@@ -47,19 +47,13 @@ static void
ip_address_decode2 (&mp->interface.src_ip, &src);
- if (AF_IP6 == ip_addr_version (&src))
- rv = VNET_API_ERROR_INVALID_PROTOCOL;
+ if (mp->generate_key)
+ curve25519_gen_secret (private_key);
else
- {
- if (mp->generate_key)
- curve25519_gen_secret (private_key);
- else
- clib_memcpy (private_key, mp->interface.private_key,
- NOISE_PUBLIC_KEY_LEN);
-
- rv = wg_if_create (ntohl (mp->interface.user_instance), private_key,
- ntohs (mp->interface.port), &src, &sw_if_index);
- }
+ clib_memcpy (private_key, mp->interface.private_key, NOISE_PUBLIC_KEY_LEN);
+
+ rv = wg_if_create (ntohl (mp->interface.user_instance), private_key,
+ ntohs (mp->interface.port), &src, &sw_if_index);
/* *INDENT-OFF* */
REPLY_MACRO2(VL_API_WIREGUARD_INTERFACE_CREATE_REPLY,
@@ -177,19 +171,10 @@ vl_api_wireguard_peer_add_t_handler (vl_api_wireguard_peer_add_t * mp)
for (ii = 0; ii < mp->peer.n_allowed_ips; ii++)
ip_prefix_decode (&mp->peer.allowed_ips[ii], &allowed_ips[ii]);
- if (AF_IP6 == ip_addr_version (&endpoint) ||
- FIB_PROTOCOL_IP6 == allowed_ips[0].fp_proto)
- /* ip6 currently not supported, but the API needs to support it
- * else we'll need to change it later, and that's a PITA */
- rv = VNET_API_ERROR_INVALID_PROTOCOL;
- else
- rv = wg_peer_add (ntohl (mp->peer.sw_if_index),
- mp->peer.public_key,
- ntohl (mp->peer.table_id),
- &ip_addr_46 (&endpoint),
- allowed_ips,
- ntohs (mp->peer.port),
- ntohs (mp->peer.persistent_keepalive), &peeri);
+ rv = wg_peer_add (ntohl (mp->peer.sw_if_index), mp->peer.public_key,
+ ntohl (mp->peer.table_id), &ip_addr_46 (&endpoint),
+ allowed_ips, ntohs (mp->peer.port),
+ ntohs (mp->peer.persistent_keepalive), &peeri);
vec_free (allowed_ips);
done:
diff --git a/src/plugins/wireguard/wireguard_cli.c b/src/plugins/wireguard/wireguard_cli.c
index 3b4bf56a3dc..05275f74aad 100755..100644
--- a/src/plugins/wireguard/wireguard_cli.c
+++ b/src/plugins/wireguard/wireguard_cli.c
@@ -213,16 +213,8 @@ wg_peer_add_command_fn (vlib_main_t * vm,
}
}
- if (AF_IP6 == ip_addr_version (&ip) ||
- FIB_PROTOCOL_IP6 == allowed_ip.fp_proto)
- rv = VNET_API_ERROR_INVALID_PROTOCOL;
- else
- rv = wg_peer_add (tun_sw_if_index,
- public_key,
- table_id,
- &ip_addr_46 (&ip),
- allowed_ips,
- portDst, persistent_keepalive, &peer_index);
+ rv = wg_peer_add (tun_sw_if_index, public_key, table_id, &ip_addr_46 (&ip),
+ allowed_ips, portDst, persistent_keepalive, &peer_index);
switch (rv)
{
diff --git a/src/plugins/wireguard/wireguard_cookie.c b/src/plugins/wireguard/wireguard_cookie.c
index f54ce715906..c4279b7407f 100755..100644
--- a/src/plugins/wireguard/wireguard_cookie.c
+++ b/src/plugins/wireguard/wireguard_cookie.c
@@ -29,9 +29,9 @@ static void cookie_macs_mac1 (message_macs_t *, const void *, size_t,
const uint8_t[COOKIE_KEY_SIZE]);
static void cookie_macs_mac2 (message_macs_t *, const void *, size_t,
const uint8_t[COOKIE_COOKIE_SIZE]);
-static void cookie_checker_make_cookie (vlib_main_t * vm, cookie_checker_t *,
+static void cookie_checker_make_cookie (vlib_main_t *vm, cookie_checker_t *,
uint8_t[COOKIE_COOKIE_SIZE],
- ip4_address_t ip4, u16 udp_port);
+ ip46_address_t *ip, u16 udp_port);
/* Public Functions */
void
@@ -76,9 +76,9 @@ cookie_maker_mac (cookie_maker_t * cp, message_macs_t * cm, void *buf,
}
enum cookie_mac_state
-cookie_checker_validate_macs (vlib_main_t * vm, cookie_checker_t * cc,
- message_macs_t * cm, void *buf, size_t len,
- bool busy, ip4_address_t ip4, u16 udp_port)
+cookie_checker_validate_macs (vlib_main_t *vm, cookie_checker_t *cc,
+ message_macs_t *cm, void *buf, size_t len,
+ bool busy, ip46_address_t *ip, u16 udp_port)
{
message_macs_t our_cm;
uint8_t cookie[COOKIE_COOKIE_SIZE];
@@ -93,7 +93,7 @@ cookie_checker_validate_macs (vlib_main_t * vm, cookie_checker_t * cc,
if (!busy)
return VALID_MAC_BUT_NO_COOKIE;
- cookie_checker_make_cookie (vm, cc, cookie, ip4, udp_port);
+ cookie_checker_make_cookie (vm, cc, cookie, ip, udp_port);
cookie_macs_mac2 (&our_cm, buf, len, cookie);
/* If the mac2 is invalid, we want to send a cookie response */
@@ -139,9 +139,9 @@ cookie_macs_mac2 (message_macs_t * cm, const void *buf, size_t len,
}
static void
-cookie_checker_make_cookie (vlib_main_t * vm, cookie_checker_t * cc,
+cookie_checker_make_cookie (vlib_main_t *vm, cookie_checker_t *cc,
uint8_t cookie[COOKIE_COOKIE_SIZE],
- ip4_address_t ip4, u16 udp_port)
+ ip46_address_t *ip, u16 udp_port)
{
blake2s_state_t state;
@@ -155,7 +155,14 @@ cookie_checker_make_cookie (vlib_main_t * vm, cookie_checker_t * cc,
blake2s_init_key (&state, COOKIE_COOKIE_SIZE, cc->cc_secret,
COOKIE_SECRET_SIZE);
- blake2s_update (&state, ip4.as_u8, sizeof (ip4_address_t)); //TODO: IP6
+ if (ip46_address_is_ip4 (ip))
+ {
+ blake2s_update (&state, ip->ip4.as_u8, sizeof (ip4_address_t));
+ }
+ else
+ {
+ blake2s_update (&state, ip->ip6.as_u8, sizeof (ip6_address_t));
+ }
blake2s_update (&state, (u8 *) & udp_port, sizeof (u16));
blake2s_final (&state, cookie, COOKIE_COOKIE_SIZE);
}
diff --git a/src/plugins/wireguard/wireguard_cookie.h b/src/plugins/wireguard/wireguard_cookie.h
index 489cce81325..6ef418f55fa 100755..100644
--- a/src/plugins/wireguard/wireguard_cookie.h
+++ b/src/plugins/wireguard/wireguard_cookie.h
@@ -18,7 +18,7 @@
#ifndef __included_wg_cookie_h__
#define __included_wg_cookie_h__
-#include <vnet/ip/ip4_packet.h>
+#include <vnet/ip/ip46_address.h>
#include <wireguard/wireguard_noise.h>
enum cookie_mac_state
@@ -83,12 +83,10 @@ typedef struct cookie_checker
void cookie_maker_init (cookie_maker_t *, const uint8_t[COOKIE_INPUT_SIZE]);
void cookie_checker_update (cookie_checker_t *, uint8_t[COOKIE_INPUT_SIZE]);
void cookie_maker_mac (cookie_maker_t *, message_macs_t *, void *, size_t);
-enum cookie_mac_state cookie_checker_validate_macs (vlib_main_t * vm,
- cookie_checker_t *,
- message_macs_t *, void *,
- size_t, bool,
- ip4_address_t ip4,
- u16 udp_port);
+enum cookie_mac_state
+cookie_checker_validate_macs (vlib_main_t *vm, cookie_checker_t *,
+ message_macs_t *, void *, size_t, bool,
+ ip46_address_t *ip, u16 udp_port);
#endif /* __included_wg_cookie_h__ */
diff --git a/src/plugins/wireguard/wireguard_handoff.c b/src/plugins/wireguard/wireguard_handoff.c
index d3e37b30c88..5f3dc14b412 100644
--- a/src/plugins/wireguard/wireguard_handoff.c
+++ b/src/plugins/wireguard/wireguard_handoff.c
@@ -129,40 +129,78 @@ wg_handoff (vlib_main_t * vm,
return n_enq;
}
-VLIB_NODE_FN (wg_handshake_handoff) (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * from_frame)
+VLIB_NODE_FN (wg4_handshake_handoff)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
{
wg_main_t *wmp = &wg_main;
- return wg_handoff (vm, node, from_frame, wmp->in_fq_index,
+ return wg_handoff (vm, node, from_frame, wmp->in4_fq_index,
WG_HANDOFF_HANDSHAKE);
}
-VLIB_NODE_FN (wg_input_data_handoff) (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * from_frame)
+VLIB_NODE_FN (wg6_handshake_handoff)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
{
wg_main_t *wmp = &wg_main;
- return wg_handoff (vm, node, from_frame, wmp->in_fq_index,
+ return wg_handoff (vm, node, from_frame, wmp->in6_fq_index,
+ WG_HANDOFF_HANDSHAKE);
+}
+
+VLIB_NODE_FN (wg4_input_data_handoff)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
+{
+ wg_main_t *wmp = &wg_main;
+
+ return wg_handoff (vm, node, from_frame, wmp->in4_fq_index,
+ WG_HANDOFF_INP_DATA);
+}
+
+VLIB_NODE_FN (wg6_input_data_handoff)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
+{
+ wg_main_t *wmp = &wg_main;
+
+ return wg_handoff (vm, node, from_frame, wmp->in6_fq_index,
WG_HANDOFF_INP_DATA);
}
-VLIB_NODE_FN (wg_output_tun_handoff) (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * from_frame)
+VLIB_NODE_FN (wg4_output_tun_handoff)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
{
wg_main_t *wmp = &wg_main;
- return wg_handoff (vm, node, from_frame, wmp->out_fq_index,
+ return wg_handoff (vm, node, from_frame, wmp->out4_fq_index,
+ WG_HANDOFF_OUT_TUN);
+}
+
+VLIB_NODE_FN (wg6_output_tun_handoff)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
+{
+ wg_main_t *wmp = &wg_main;
+
+ return wg_handoff (vm, node, from_frame, wmp->out6_fq_index,
WG_HANDOFF_OUT_TUN);
}
/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (wg_handshake_handoff) =
+VLIB_REGISTER_NODE (wg4_handshake_handoff) =
+{
+ .name = "wg4-handshake-handoff",
+ .vector_size = sizeof (u32),
+ .format_trace = format_wg_handoff_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = ARRAY_LEN (wg_handoff_error_strings),
+ .error_strings = wg_handoff_error_strings,
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [0] = "error-drop",
+ },
+};
+
+VLIB_REGISTER_NODE (wg6_handshake_handoff) =
{
- .name = "wg-handshake-handoff",
+ .name = "wg6-handshake-handoff",
.vector_size = sizeof (u32),
.format_trace = format_wg_handoff_trace,
.type = VLIB_NODE_TYPE_INTERNAL,
@@ -174,9 +212,9 @@ VLIB_REGISTER_NODE (wg_handshake_handoff) =
},
};
-VLIB_REGISTER_NODE (wg_input_data_handoff) =
+VLIB_REGISTER_NODE (wg4_input_data_handoff) =
{
- .name = "wg-input-data-handoff",
+ .name = "wg4-input-data-handoff",
.vector_size = sizeof (u32),
.format_trace = format_wg_handoff_trace,
.type = VLIB_NODE_TYPE_INTERNAL,
@@ -188,9 +226,37 @@ VLIB_REGISTER_NODE (wg_input_data_handoff) =
},
};
-VLIB_REGISTER_NODE (wg_output_tun_handoff) =
+VLIB_REGISTER_NODE (wg6_input_data_handoff) =
+{
+ .name = "wg6-input-data-handoff",
+ .vector_size = sizeof (u32),
+ .format_trace = format_wg_handoff_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = ARRAY_LEN (wg_handoff_error_strings),
+ .error_strings = wg_handoff_error_strings,
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [0] = "error-drop",
+ },
+};
+
+VLIB_REGISTER_NODE (wg4_output_tun_handoff) =
+{
+ .name = "wg4-output-tun-handoff",
+ .vector_size = sizeof (u32),
+ .format_trace = format_wg_handoff_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = ARRAY_LEN (wg_handoff_error_strings),
+ .error_strings = wg_handoff_error_strings,
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [0] = "error-drop",
+ },
+};
+
+VLIB_REGISTER_NODE (wg6_output_tun_handoff) =
{
- .name = "wg-output-tun-handoff",
+ .name = "wg6-output-tun-handoff",
.vector_size = sizeof (u32),
.format_trace = format_wg_handoff_trace,
.type = VLIB_NODE_TYPE_INTERNAL,
diff --git a/src/plugins/wireguard/wireguard_if.c b/src/plugins/wireguard/wireguard_if.c
index 0866d24e775..ad8f42c1969 100644
--- a/src/plugins/wireguard/wireguard_if.c
+++ b/src/plugins/wireguard/wireguard_if.c
@@ -49,7 +49,6 @@ format_wg_if (u8 * s, va_list * args)
noise_local_t *local = noise_local_get (wgi->local_idx);
u8 key[NOISE_KEY_LEN_BASE64];
-
s = format (s, "[%d] %U src:%U port:%d",
wgii,
format_vnet_sw_if_index_name, vnet_get_main (),
@@ -290,7 +289,12 @@ wg_if_create (u32 user_instance,
vec_validate_init_empty (wg_if_indexes_by_port, port, NULL);
if (vec_len (wg_if_indexes_by_port[port]) == 0)
- udp_register_dst_port (vlib_get_main (), port, wg_input_node.index, 1);
+ {
+ udp_register_dst_port (vlib_get_main (), port, wg4_input_node.index,
+ UDP_IP4);
+ udp_register_dst_port (vlib_get_main (), port, wg6_input_node.index,
+ UDP_IP6);
+ }
vec_add1 (wg_if_indexes_by_port[port], t_idx);
@@ -350,7 +354,10 @@ wg_if_delete (u32 sw_if_index)
}
}
if (vec_len (ifs) == 0)
- udp_unregister_dst_port (vlib_get_main (), wg_if->port, 1);
+ {
+ udp_unregister_dst_port (vlib_get_main (), wg_if->port, 1);
+ udp_unregister_dst_port (vlib_get_main (), wg_if->port, 0);
+ }
vnet_delete_hw_interface (vnm, hw->hw_if_index);
pool_put_index (noise_local_pool, wg_if->local_idx);
@@ -365,8 +372,12 @@ wg_if_peer_add (wg_if_t * wgi, index_t peeri)
hash_set (wgi->peers, peeri, peeri);
if (1 == hash_elts (wgi->peers))
- vnet_feature_enable_disable ("ip4-output", "wg-output-tun",
- wgi->sw_if_index, 1, 0, 0);
+ {
+ vnet_feature_enable_disable ("ip4-output", "wg4-output-tun",
+ wgi->sw_if_index, 1, 0, 0);
+ vnet_feature_enable_disable ("ip6-output", "wg6-output-tun",
+ wgi->sw_if_index, 1, 0, 0);
+ }
}
void
@@ -375,8 +386,12 @@ wg_if_peer_remove (wg_if_t * wgi, index_t peeri)
hash_unset (wgi->peers, peeri);
if (0 == hash_elts (wgi->peers))
- vnet_feature_enable_disable ("ip4-output", "wg-output-tun",
- wgi->sw_if_index, 0, 0, 0);
+ {
+ vnet_feature_enable_disable ("ip4-output", "wg4-output-tun",
+ wgi->sw_if_index, 0, 0, 0);
+ vnet_feature_enable_disable ("ip6-output", "wg6-output-tun",
+ wgi->sw_if_index, 0, 0, 0);
+ }
}
void
diff --git a/src/plugins/wireguard/wireguard_if.h b/src/plugins/wireguard/wireguard_if.h
index 3153a380066..0a042cb2d9b 100644
--- a/src/plugins/wireguard/wireguard_if.h
+++ b/src/plugins/wireguard/wireguard_if.h
@@ -31,8 +31,6 @@ typedef struct wg_if_t_
cookie_checker_t cookie_checker;
u16 port;
- wg_index_table_t index_table;
-
/* Source IP address for originated packets */
ip_address_t src_ip;
diff --git a/src/plugins/wireguard/wireguard_input.c b/src/plugins/wireguard/wireguard_input.c
index ad002dcb3c2..6a0623e0a76 100644
--- a/src/plugins/wireguard/wireguard_input.c
+++ b/src/plugins/wireguard/wireguard_input.c
@@ -79,11 +79,11 @@ format_wg_input_trace (u8 * s, va_list * args)
wg_input_trace_t *t = va_arg (*args, wg_input_trace_t *);
- s = format (s, "WG input: \n");
- s = format (s, " Type: %U\n", format_wg_message_type, t->type);
- s = format (s, " peer: %d\n", t->peer);
- s = format (s, " Length: %d\n", t->current_length);
- s = format (s, " Keepalive: %s", t->is_keepalive ? "true" : "false");
+ s = format (s, "Wireguard input: \n");
+ s = format (s, " Type: %U\n", format_wg_message_type, t->type);
+ s = format (s, " Peer: %d\n", t->peer);
+ s = format (s, " Length: %d\n", t->current_length);
+ s = format (s, " Keepalive: %s", t->is_keepalive ? "true" : "false");
return s;
}
@@ -93,6 +93,7 @@ typedef enum
WG_INPUT_NEXT_HANDOFF_HANDSHAKE,
WG_INPUT_NEXT_HANDOFF_DATA,
WG_INPUT_NEXT_IP4_INPUT,
+ WG_INPUT_NEXT_IP6_INPUT,
WG_INPUT_NEXT_PUNT,
WG_INPUT_NEXT_ERROR,
WG_INPUT_N_NEXT,
@@ -108,8 +109,15 @@ typedef enum
/* } */
/* } */
+static u8
+is_ip4_header (u8 *data)
+{
+ return (data[0] >> 4) == 0x4;
+}
+
static wg_input_error_t
-wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b)
+wg_handshake_process (vlib_main_t *vm, wg_main_t *wmp, vlib_buffer_t *b,
+ u32 node_idx, u8 is_ip4)
{
ASSERT (vm->thread_index == 0);
@@ -122,10 +130,21 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b)
void *current_b_data = vlib_buffer_get_current (b);
+ ip46_address_t src_ip;
+ if (is_ip4)
+ {
+ ip4_header_t *iph4 =
+ current_b_data - sizeof (udp_header_t) - sizeof (ip4_header_t);
+ ip46_address_set_ip4 (&src_ip, &iph4->src_address);
+ }
+ else
+ {
+ ip6_header_t *iph6 =
+ current_b_data - sizeof (udp_header_t) - sizeof (ip6_header_t);
+ ip46_address_set_ip6 (&src_ip, &iph6->src_address);
+ }
+
udp_header_t *uhd = current_b_data - sizeof (udp_header_t);
- ip4_header_t *iph =
- current_b_data - sizeof (udp_header_t) - sizeof (ip4_header_t);
- ip4_address_t ip4_src = iph->src_address;
u16 udp_src_port = clib_host_to_net_u16 (uhd->src_port);;
u16 udp_dst_port = clib_host_to_net_u16 (uhd->dst_port);;
@@ -168,7 +187,7 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b)
mac_state = cookie_checker_validate_macs (
vm, &wg_if->cookie_checker, macs, current_b_data, len, under_load,
- ip4_src, udp_src_port);
+ &src_ip, udp_src_port);
if (mac_state == INVALID_MAC)
{
wg_if = NULL;
@@ -214,7 +233,7 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b)
// set_peer_address (peer, ip4_src, udp_src_port);
if (PREDICT_FALSE (!wg_send_handshake_response (vm, peer)))
{
- vlib_node_increment_counter (vm, wg_input_node.index,
+ vlib_node_increment_counter (vm, node_idx,
WG_INPUT_ERROR_HANDSHAKE_SEND, 1);
}
break;
@@ -254,9 +273,8 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b)
wg_timers_handshake_complete (peer);
if (PREDICT_FALSE (!wg_send_keepalive (vm, peer)))
{
- vlib_node_increment_counter (vm, wg_input_node.index,
- WG_INPUT_ERROR_KEEPALIVE_SEND,
- 1);
+ vlib_node_increment_counter (vm, node_idx,
+ WG_INPUT_ERROR_KEEPALIVE_SEND, 1);
}
}
break;
@@ -270,9 +288,9 @@ wg_handshake_process (vlib_main_t * vm, wg_main_t * wmp, vlib_buffer_t * b)
return WG_INPUT_ERROR_NONE;
}
-VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * frame)
+always_inline uword
+wg_input_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+ vlib_frame_t *frame, u8 is_ip4)
{
message_type_t header_type;
u32 n_left_from;
@@ -382,7 +400,20 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm,
wg_timers_data_received (peer);
- ip4_header_t *iph = vlib_buffer_get_current (b[0]);
+ ip46_address_t src_ip;
+ u8 is_ip4_inner = is_ip4_header (vlib_buffer_get_current (b[0]));
+ if (is_ip4_inner)
+ {
+ ip46_address_set_ip4 (
+ &src_ip, &((ip4_header_t *) vlib_buffer_get_current (b[0]))
+ ->src_address);
+ }
+ else
+ {
+ ip46_address_set_ip6 (
+ &src_ip, &((ip6_header_t *) vlib_buffer_get_current (b[0]))
+ ->src_address);
+ }
const fib_prefix_t *allowed_ip;
bool allowed = false;
@@ -392,9 +423,10 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm,
* is that there aren't many allowed IPs and thus a linear
* walk is fater than an ACL
*/
+
vec_foreach (allowed_ip, peer->allowed_ips)
{
- if (fib_prefix_is_cover_addr_4 (allowed_ip, &iph->src_address))
+ if (fib_prefix_is_cover_addr_46 (allowed_ip, &src_ip))
{
allowed = true;
break;
@@ -403,7 +435,8 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm,
if (allowed)
{
vnet_buffer (b[0])->sw_if_index[VLIB_RX] = peer->wg_sw_if_index;
- next[0] = WG_INPUT_NEXT_IP4_INPUT;
+ next[0] = is_ip4_inner ? WG_INPUT_NEXT_IP4_INPUT :
+ WG_INPUT_NEXT_IP6_INPUT;
}
}
else
@@ -417,7 +450,8 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm,
goto next;
}
- wg_input_error_t ret = wg_handshake_process (vm, wmp, b[0]);
+ wg_input_error_t ret =
+ wg_handshake_process (vm, wmp, b[0], node->node_index, is_ip4);
if (ret != WG_INPUT_ERROR_NONE)
{
next[0] = WG_INPUT_NEXT_ERROR;
@@ -445,10 +479,42 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm,
return frame->n_vectors;
}
+VLIB_NODE_FN (wg4_input_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+ return wg_input_inline (vm, node, frame, /* is_ip4 */ 1);
+}
+
+VLIB_NODE_FN (wg6_input_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+ return wg_input_inline (vm, node, frame, /* is_ip4 */ 0);
+}
+
/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (wg_input_node) =
+VLIB_REGISTER_NODE (wg4_input_node) =
+{
+ .name = "wg4-input",
+ .vector_size = sizeof (u32),
+ .format_trace = format_wg_input_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = ARRAY_LEN (wg_input_error_strings),
+ .error_strings = wg_input_error_strings,
+ .n_next_nodes = WG_INPUT_N_NEXT,
+ /* edit / add dispositions here */
+ .next_nodes = {
+ [WG_INPUT_NEXT_HANDOFF_HANDSHAKE] = "wg4-handshake-handoff",
+ [WG_INPUT_NEXT_HANDOFF_DATA] = "wg4-input-data-handoff",
+ [WG_INPUT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
+ [WG_INPUT_NEXT_IP6_INPUT] = "ip6-input",
+ [WG_INPUT_NEXT_PUNT] = "error-punt",
+ [WG_INPUT_NEXT_ERROR] = "error-drop",
+ },
+};
+
+VLIB_REGISTER_NODE (wg6_input_node) =
{
- .name = "wg-input",
+ .name = "wg6-input",
.vector_size = sizeof (u32),
.format_trace = format_wg_input_trace,
.type = VLIB_NODE_TYPE_INTERNAL,
@@ -457,9 +523,10 @@ VLIB_REGISTER_NODE (wg_input_node) =
.n_next_nodes = WG_INPUT_N_NEXT,
/* edit / add dispositions here */
.next_nodes = {
- [WG_INPUT_NEXT_HANDOFF_HANDSHAKE] = "wg-handshake-handoff",
- [WG_INPUT_NEXT_HANDOFF_DATA] = "wg-input-data-handoff",
+ [WG_INPUT_NEXT_HANDOFF_HANDSHAKE] = "wg6-handshake-handoff",
+ [WG_INPUT_NEXT_HANDOFF_DATA] = "wg6-input-data-handoff",
[WG_INPUT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
+ [WG_INPUT_NEXT_IP6_INPUT] = "ip6-input",
[WG_INPUT_NEXT_PUNT] = "error-punt",
[WG_INPUT_NEXT_ERROR] = "error-drop",
},
diff --git a/src/plugins/wireguard/wireguard_output_tun.c b/src/plugins/wireguard/wireguard_output_tun.c
index 53a8797c973..80ba9504f0e 100755..100644
--- a/src/plugins/wireguard/wireguard_output_tun.c
+++ b/src/plugins/wireguard/wireguard_output_tun.c
@@ -51,18 +51,28 @@ typedef enum
typedef struct
{
- ip4_udp_header_t hdr;
index_t peer;
+ u8 header[sizeof (ip6_udp_header_t)];
+ u8 is_ip4;
} wg_output_tun_trace_t;
u8 *
format_ip4_udp_header (u8 * s, va_list * args)
{
- ip4_udp_header_t *hdr = va_arg (*args, ip4_udp_header_t *);
+ ip4_udp_header_t *hdr4 = va_arg (*args, ip4_udp_header_t *);
- s = format (s, "%U:$U",
- format_ip4_header, &hdr->ip4, format_udp_header, &hdr->udp);
+ s = format (s, "%U:$U", format_ip4_header, &hdr4->ip4, format_udp_header,
+ &hdr4->udp);
+ return (s);
+}
+
+u8 *
+format_ip6_udp_header (u8 *s, va_list *args)
+{
+ ip6_udp_header_t *hdr6 = va_arg (*args, ip6_udp_header_t *);
+ s = format (s, "%U:$U", format_ip6_header, &hdr6->ip6, format_udp_header,
+ &hdr6->udp);
return (s);
}
@@ -76,16 +86,22 @@ format_wg_output_tun_trace (u8 * s, va_list * args)
wg_output_tun_trace_t *t = va_arg (*args, wg_output_tun_trace_t *);
s = format (s, "peer: %d\n", t->peer);
- s = format (s, " Encrypted packet: %U", format_ip4_udp_header, &t->hdr);
+ s = format (s, " Encrypted packet: ");
+
+ s = t->is_ip4 ? format (s, "%U", format_ip4_udp_header, t->header) :
+ format (s, "%U", format_ip6_udp_header, t->header);
return s;
}
-VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * frame)
+/* is_ip4 - inner header flag */
+always_inline uword
+wg_output_tun_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+ vlib_frame_t *frame, u8 is_ip4)
{
u32 n_left_from;
u32 *from;
+ ip4_udp_header_t *hdr4_out = NULL;
+ ip6_udp_header_t *hdr6_out = NULL;
vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
u16 nexts[VLIB_FRAME_SIZE], *next;
u32 thread_index = vm->thread_index;
@@ -102,12 +118,11 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
while (n_left_from > 0)
{
- ip4_udp_header_t *hdr = vlib_buffer_get_current (b[0]);
- u8 *plain_data = (vlib_buffer_get_current (b[0]) +
- sizeof (ip4_udp_header_t));
- u16 plain_data_len =
- clib_net_to_host_u16 (((ip4_header_t *) plain_data)->length);
index_t peeri;
+ u8 iph_offset = 0;
+ u8 is_ip4_out = 1;
+ u8 *plain_data;
+ u16 plain_data_len;
next[0] = WG_OUTPUT_NEXT_ERROR;
peeri =
@@ -119,7 +134,6 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
b[0]->error = node->errors[WG_OUTPUT_ERROR_PEER];
goto out;
}
-
if (PREDICT_FALSE (~0 == peer->output_thread_index))
{
/* this is the first packet to use this peer, claim the peer
@@ -141,6 +155,21 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
b[0]->error = node->errors[WG_OUTPUT_ERROR_KEYPAIR];
goto out;
}
+
+ is_ip4_out = ip46_address_is_ip4 (&peer->src.addr);
+ if (is_ip4_out)
+ {
+ hdr4_out = vlib_buffer_get_current (b[0]);
+ }
+ else
+ {
+ hdr6_out = vlib_buffer_get_current (b[0]);
+ }
+
+ 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;
+
size_t encrypted_packet_len = message_data_len (plain_data_len);
/*
@@ -159,13 +188,10 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
(message_data_t *) wmp->per_thread_data[thread_index].data;
enum noise_state_crypt state;
- state =
- noise_remote_encrypt (vm,
- &peer->remote,
- &encrypted_packet->receiver_index,
- &encrypted_packet->counter, plain_data,
- plain_data_len,
- encrypted_packet->encrypted_data);
+ state = noise_remote_encrypt (
+ vm, &peer->remote, &encrypted_packet->receiver_index,
+ &encrypted_packet->counter, plain_data, plain_data_len,
+ encrypted_packet->encrypted_data);
if (PREDICT_FALSE (state == SC_KEEP_KEY_FRESH))
{
@@ -184,12 +210,24 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
clib_memcpy (plain_data, (u8 *) encrypted_packet, encrypted_packet_len);
- hdr->udp.length = clib_host_to_net_u16 (encrypted_packet_len +
- sizeof (udp_header_t));
- b[0]->current_length = (encrypted_packet_len +
- sizeof (ip4_header_t) + sizeof (udp_header_t));
- ip4_header_set_len_w_chksum
- (&hdr->ip4, clib_host_to_net_u16 (b[0]->current_length));
+ if (is_ip4_out)
+ {
+ hdr4_out->udp.length = clib_host_to_net_u16 (encrypted_packet_len +
+ sizeof (udp_header_t));
+ b[0]->current_length =
+ (encrypted_packet_len + sizeof (ip4_udp_header_t));
+ ip4_header_set_len_w_chksum (
+ &hdr4_out->ip4, clib_host_to_net_u16 (b[0]->current_length));
+ }
+ else
+ {
+ hdr6_out->udp.length = clib_host_to_net_u16 (encrypted_packet_len +
+ sizeof (udp_header_t));
+ b[0]->current_length =
+ (encrypted_packet_len + sizeof (ip6_udp_header_t));
+ hdr6_out->ip6.payload_length =
+ clib_host_to_net_u16 (b[0]->current_length);
+ }
wg_timers_any_authenticated_packet_sent (peer);
wg_timers_data_sent (peer);
@@ -201,9 +239,15 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
{
wg_output_tun_trace_t *t =
vlib_add_trace (vm, node, b[0], sizeof (*t));
- t->hdr = *hdr;
+
t->peer = peeri;
+ t->is_ip4 = is_ip4_out;
+ if (hdr4_out)
+ clib_memcpy (t->header, hdr4_out, sizeof (*hdr4_out));
+ else if (hdr6_out)
+ clib_memcpy (t->header, hdr6_out, sizeof (*hdr6_out));
}
+
next:
n_left_from -= 1;
next += 1;
@@ -214,10 +258,38 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
return frame->n_vectors;
}
+VLIB_NODE_FN (wg4_output_tun_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+ return wg_output_tun_inline (vm, node, frame, /* is_ip4 */ 1);
+}
+
+VLIB_NODE_FN (wg6_output_tun_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+ return wg_output_tun_inline (vm, node, frame, /* is_ip4 */ 0);
+}
+
/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (wg_output_tun_node) =
+VLIB_REGISTER_NODE (wg4_output_tun_node) =
+{
+ .name = "wg4-output-tun",
+ .vector_size = sizeof (u32),
+ .format_trace = format_wg_output_tun_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = ARRAY_LEN (wg_output_error_strings),
+ .error_strings = wg_output_error_strings,
+ .n_next_nodes = WG_OUTPUT_N_NEXT,
+ .next_nodes = {
+ [WG_OUTPUT_NEXT_HANDOFF] = "wg4-output-tun-handoff",
+ [WG_OUTPUT_NEXT_INTERFACE_OUTPUT] = "adj-midchain-tx",
+ [WG_OUTPUT_NEXT_ERROR] = "error-drop",
+ },
+};
+
+VLIB_REGISTER_NODE (wg6_output_tun_node) =
{
- .name = "wg-output-tun",
+ .name = "wg6-output-tun",
.vector_size = sizeof (u32),
.format_trace = format_wg_output_tun_trace,
.type = VLIB_NODE_TYPE_INTERNAL,
@@ -225,7 +297,7 @@ VLIB_REGISTER_NODE (wg_output_tun_node) =
.error_strings = wg_output_error_strings,
.n_next_nodes = WG_OUTPUT_N_NEXT,
.next_nodes = {
- [WG_OUTPUT_NEXT_HANDOFF] = "wg-output-tun-handoff",
+ [WG_OUTPUT_NEXT_HANDOFF] = "wg6-output-tun-handoff",
[WG_OUTPUT_NEXT_INTERFACE_OUTPUT] = "adj-midchain-tx",
[WG_OUTPUT_NEXT_ERROR] = "error-drop",
},
diff --git a/src/plugins/wireguard/wireguard_peer.c b/src/plugins/wireguard/wireguard_peer.c
index d4a85a20cf6..fb540141e08 100644
--- a/src/plugins/wireguard/wireguard_peer.c
+++ b/src/plugins/wireguard/wireguard_peer.c
@@ -22,6 +22,7 @@
#include <wireguard/wireguard_key.h>
#include <wireguard/wireguard_send.h>
#include <wireguard/wireguard.h>
+#include <vnet/tunnel/tunnel_dp.h>
wg_peer_t *wg_peer_pool;
@@ -91,25 +92,44 @@ wg_peer_init (vlib_main_t * vm, wg_peer_t * peer)
}
static u8 *
-wg_peer_build_rewrite (const wg_peer_t * peer)
+wg_peer_build_rewrite (const wg_peer_t *peer, u8 is_ip4)
{
- // v4 only for now
- ip4_udp_header_t *hdr;
u8 *rewrite = NULL;
+ if (is_ip4)
+ {
+ ip4_udp_header_t *hdr;
+
+ vec_validate (rewrite, sizeof (*hdr) - 1);
+ hdr = (ip4_udp_header_t *) rewrite;
+
+ hdr->ip4.ip_version_and_header_length = 0x45;
+ hdr->ip4.ttl = 64;
+ hdr->ip4.src_address = peer->src.addr.ip4;
+ hdr->ip4.dst_address = peer->dst.addr.ip4;
+ hdr->ip4.protocol = IP_PROTOCOL_UDP;
+ hdr->ip4.checksum = ip4_header_checksum (&hdr->ip4);
+
+ hdr->udp.src_port = clib_host_to_net_u16 (peer->src.port);
+ hdr->udp.dst_port = clib_host_to_net_u16 (peer->dst.port);
+ hdr->udp.checksum = 0;
+ }
+ else
+ {
+ ip6_udp_header_t *hdr;
- vec_validate (rewrite, sizeof (*hdr) - 1);
- hdr = (ip4_udp_header_t *) rewrite;
+ vec_validate (rewrite, sizeof (*hdr) - 1);
+ hdr = (ip6_udp_header_t *) rewrite;
- hdr->ip4.ip_version_and_header_length = 0x45;
- hdr->ip4.ttl = 64;
- hdr->ip4.src_address = peer->src.addr.ip4;
- hdr->ip4.dst_address = peer->dst.addr.ip4;
- hdr->ip4.protocol = IP_PROTOCOL_UDP;
- hdr->ip4.checksum = ip4_header_checksum (&hdr->ip4);
+ hdr->ip6.ip_version_traffic_class_and_flow_label = 0x60;
+ ip6_address_copy (&hdr->ip6.src_address, &peer->src.addr.ip6);
+ ip6_address_copy (&hdr->ip6.dst_address, &peer->dst.addr.ip6);
+ hdr->ip6.protocol = IP_PROTOCOL_UDP;
+ hdr->ip6.hop_limit = 64;
- hdr->udp.src_port = clib_host_to_net_u16 (peer->src.port);
- hdr->udp.dst_port = clib_host_to_net_u16 (peer->dst.port);
- hdr->udp.checksum = 0;
+ hdr->udp.src_port = clib_host_to_net_u16 (peer->src.port);
+ hdr->udp.dst_port = clib_host_to_net_u16 (peer->dst.port);
+ hdr->udp.checksum = 0;
+ }
return (rewrite);
}
@@ -120,12 +140,15 @@ wg_peer_adj_stack (wg_peer_t *peer, adj_index_t ai)
ip_adjacency_t *adj;
u32 sw_if_index;
wg_if_t *wgi;
+ fib_protocol_t fib_proto;
if (!adj_is_valid (ai))
return;
adj = adj_get (ai);
sw_if_index = adj->rewrite_header.sw_if_index;
+ u8 is_ip4 = ip46_address_is_ip4 (&peer->src.addr);
+ fib_proto = is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
wgi = wg_if_get (wg_if_find_by_sw_if_index (sw_if_index));
@@ -140,19 +163,76 @@ wg_peer_adj_stack (wg_peer_t *peer, adj_index_t ai)
{
/* *INDENT-OFF* */
fib_prefix_t dst = {
- .fp_len = 32,
- .fp_proto = FIB_PROTOCOL_IP4,
- .fp_addr = peer->dst.addr,
+ .fp_len = is_ip4 ? 32 : 128,
+ .fp_proto = fib_proto,
+ .fp_addr = peer->dst.addr,
};
/* *INDENT-ON* */
u32 fib_index;
- fib_index = fib_table_find (FIB_PROTOCOL_IP4, peer->table_id);
+ fib_index = fib_table_find (fib_proto, peer->table_id);
adj_midchain_delegate_stack (ai, fib_index, &dst);
}
}
+static void
+wg_peer_66_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b,
+ const void *data)
+{
+ u8 iph_offset = 0;
+ ip6_header_t *ip6_out;
+ ip6_header_t *ip6_in;
+
+ /* Must set locally originated otherwise we're not allowed to
+ fragment the packet later */
+ b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
+
+ ip6_out = vlib_buffer_get_current (b);
+ iph_offset = vnet_buffer (b)->ip.save_rewrite_length;
+ ip6_in = vlib_buffer_get_current (b) + iph_offset;
+
+ ip6_out->ip_version_traffic_class_and_flow_label =
+ ip6_in->ip_version_traffic_class_and_flow_label;
+}
+
+static void
+wg_peer_46_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b,
+ const void *data)
+{
+ u8 iph_offset = 0;
+ ip6_header_t *ip6_out;
+ ip4_header_t *ip4_in;
+
+ /* Must set locally originated otherwise we're not allowed to
+ fragment the packet later */
+ b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
+
+ ip6_out = vlib_buffer_get_current (b);
+ iph_offset = vnet_buffer (b)->ip.save_rewrite_length;
+ ip4_in = vlib_buffer_get_current (b) + iph_offset;
+
+ u32 vtcfl = 0x6 << 28;
+ vtcfl |= ip4_in->tos << 20;
+ vtcfl |= vnet_buffer (b)->ip.flow_hash & 0x000fffff;
+
+ ip6_out->ip_version_traffic_class_and_flow_label =
+ clib_host_to_net_u32 (vtcfl);
+}
+
+static adj_midchain_fixup_t
+wg_peer_get_fixup (wg_peer_t *peer, vnet_link_t lt)
+{
+ if (!ip46_address_is_ip4 (&peer->dst.addr))
+ {
+ if (lt == VNET_LINK_IP4)
+ return (wg_peer_46_fixup);
+ if (lt == VNET_LINK_IP6)
+ return (wg_peer_66_fixup);
+ }
+ return (NULL);
+}
+
walk_rc_t
wg_peer_if_admin_state_change (index_t peeri, void *data)
{
@@ -170,6 +250,7 @@ walk_rc_t
wg_peer_if_adj_change (index_t peeri, void *data)
{
adj_index_t *adj_index = data;
+ adj_midchain_fixup_t fixup;
ip_adjacency_t *adj;
wg_peer_t *peer;
fib_prefix_t *allowed_ip;
@@ -179,15 +260,16 @@ wg_peer_if_adj_change (index_t peeri, void *data)
peer = wg_peer_get (peeri);
vec_foreach (allowed_ip, peer->allowed_ips)
{
- if (fib_prefix_is_cover_addr_4 (allowed_ip,
- &adj->sub_type.nbr.next_hop.ip4))
+ if (fib_prefix_is_cover_addr_46 (allowed_ip,
+ &adj->sub_type.nbr.next_hop))
{
vec_add1 (peer->adj_indices, *adj_index);
vec_validate_init_empty (wg_peer_by_adj_index, *adj_index,
INDEX_INVALID);
wg_peer_by_adj_index[*adj_index] = peer - wg_peer_pool;
- adj_nbr_midchain_update_rewrite (*adj_index, NULL, NULL,
+ fixup = wg_peer_get_fixup (peer, adj_get_link_type (*adj_index));
+ adj_nbr_midchain_update_rewrite (*adj_index, fixup, NULL,
ADJ_FLAG_MIDCHAIN_IP_STACK,
vec_dup (peer->rewrite));
@@ -236,7 +318,9 @@ wg_peer_fill (vlib_main_t *vm, wg_peer_t *peer, u32 table_id,
ip_address_to_46 (&wgi->src_ip, &peer->src.addr);
peer->src.port = wgi->port;
- peer->rewrite = wg_peer_build_rewrite (peer);
+
+ u8 is_ip4 = ip46_address_is_ip4 (&peer->dst.addr);
+ peer->rewrite = wg_peer_build_rewrite (peer, is_ip4);
u32 ii;
vec_validate (peer->allowed_ips, vec_len (allowed_ips) - 1);
diff --git a/src/plugins/wireguard/wireguard_peer.h b/src/plugins/wireguard/wireguard_peer.h
index e23feb7866f..c719ac19511 100644
--- a/src/plugins/wireguard/wireguard_peer.h
+++ b/src/plugins/wireguard/wireguard_peer.h
@@ -31,7 +31,14 @@ typedef struct ip4_udp_header_t_
udp_header_t udp;
} __clib_packed ip4_udp_header_t;
+typedef struct ip6_udp_header_t_
+{
+ ip6_header_t ip6;
+ udp_header_t udp;
+} __clib_packed ip6_udp_header_t;
+
u8 *format_ip4_udp_header (u8 * s, va_list * va);
+u8 *format_ip6_udp_header (u8 *s, va_list *va);
typedef struct wg_peer_endpoint_t_
{
@@ -141,15 +148,16 @@ wg_peer_assign_thread (u32 thread_id)
}
static_always_inline bool
-fib_prefix_is_cover_addr_4 (const fib_prefix_t *p1, const ip4_address_t *ip4)
+fib_prefix_is_cover_addr_46 (const fib_prefix_t *p1, const ip46_address_t *ip)
{
switch (p1->fp_proto)
{
case FIB_PROTOCOL_IP4:
- return (ip4_destination_matches_route (&ip4_main, &p1->fp_addr.ip4, ip4,
- p1->fp_len) != 0);
+ return (ip4_destination_matches_route (&ip4_main, &p1->fp_addr.ip4,
+ &ip->ip4, p1->fp_len) != 0);
case FIB_PROTOCOL_IP6:
- return (false);
+ return (ip6_destination_matches_route (&ip6_main, &p1->fp_addr.ip6,
+ &ip->ip6, p1->fp_len) != 0);
case FIB_PROTOCOL_MPLS:
break;
}
diff --git a/src/plugins/wireguard/wireguard_send.c b/src/plugins/wireguard/wireguard_send.c
index f492e05c175..4451e000776 100755..100644
--- a/src/plugins/wireguard/wireguard_send.c
+++ b/src/plugins/wireguard/wireguard_send.c
@@ -22,11 +22,11 @@
#include <wireguard/wireguard_send.h>
static int
-ip46_enqueue_packet (vlib_main_t * vm, u32 bi0, int is_ip6)
+ip46_enqueue_packet (vlib_main_t *vm, u32 bi0, int is_ip4)
{
vlib_frame_t *f = 0;
u32 lookup_node_index =
- is_ip6 ? ip6_lookup_node.index : ip4_lookup_node.index;
+ is_ip4 ? ip4_lookup_node.index : ip6_lookup_node.index;
f = vlib_get_frame_to_node (vm, lookup_node_index);
/* f can not be NULL here - frame allocation failure causes panic */
@@ -41,25 +41,41 @@ ip46_enqueue_packet (vlib_main_t * vm, u32 bi0, int is_ip6)
}
static void
-wg_buffer_prepend_rewrite (vlib_buffer_t * b0, const wg_peer_t * peer)
+wg_buffer_prepend_rewrite (vlib_buffer_t *b0, const wg_peer_t *peer, u8 is_ip4)
{
- ip4_udp_header_t *hdr;
+ if (is_ip4)
+ {
+ ip4_udp_header_t *hdr4;
+
+ vlib_buffer_advance (b0, -sizeof (*hdr4));
- vlib_buffer_advance (b0, -sizeof (*hdr));
+ hdr4 = vlib_buffer_get_current (b0);
+ clib_memcpy (hdr4, peer->rewrite, vec_len (peer->rewrite));
- hdr = vlib_buffer_get_current (b0);
- clib_memcpy (hdr, peer->rewrite, vec_len (peer->rewrite));
+ hdr4->udp.length =
+ clib_host_to_net_u16 (b0->current_length - sizeof (ip4_header_t));
+ ip4_header_set_len_w_chksum (&hdr4->ip4,
+ clib_host_to_net_u16 (b0->current_length));
+ }
+ else
+ {
+ ip6_udp_header_t *hdr6;
- hdr->udp.length =
- clib_host_to_net_u16 (b0->current_length - sizeof (ip4_header_t));
- ip4_header_set_len_w_chksum (&hdr->ip4,
- clib_host_to_net_u16 (b0->current_length));
+ vlib_buffer_advance (b0, -sizeof (*hdr6));
+
+ hdr6 = vlib_buffer_get_current (b0);
+ clib_memcpy (hdr6, peer->rewrite, vec_len (peer->rewrite));
+
+ hdr6->udp.length =
+ clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
+
+ hdr6->ip6.payload_length = clib_host_to_net_u16 (b0->current_length);
+ }
}
static bool
-wg_create_buffer (vlib_main_t * vm,
- const wg_peer_t * peer,
- const u8 * packet, u32 packet_len, u32 * bi)
+wg_create_buffer (vlib_main_t *vm, const wg_peer_t *peer, const u8 *packet,
+ u32 packet_len, u32 *bi, u8 is_ip4)
{
u32 n_buf0 = 0;
vlib_buffer_t *b0;
@@ -75,7 +91,7 @@ wg_create_buffer (vlib_main_t * vm,
b0->current_length = packet_len;
- wg_buffer_prepend_rewrite (b0, peer);
+ wg_buffer_prepend_rewrite (b0, peer, is_ip4);
return true;
}
@@ -113,11 +129,13 @@ wg_send_handshake (vlib_main_t * vm, wg_peer_t * peer, bool is_retry)
else
return false;
+ u8 is_ip4 = ip46_address_is_ip4 (&peer->dst.addr);
u32 bi0 = 0;
- if (!wg_create_buffer (vm, peer, (u8 *) & packet, sizeof (packet), &bi0))
+ if (!wg_create_buffer (vm, peer, (u8 *) &packet, sizeof (packet), &bi0,
+ is_ip4))
return false;
- ip46_enqueue_packet (vm, bi0, false);
+ ip46_enqueue_packet (vm, bi0, is_ip4);
return true;
}
@@ -185,15 +203,17 @@ wg_send_keepalive (vlib_main_t * vm, wg_peer_t * peer)
goto out;
}
+ u8 is_ip4 = ip46_address_is_ip4 (&peer->dst.addr);
packet->header.type = MESSAGE_DATA;
- if (!wg_create_buffer (vm, peer, (u8 *) packet, size_of_packet, &bi0))
+ if (!wg_create_buffer (vm, peer, (u8 *) packet, size_of_packet, &bi0,
+ is_ip4))
{
ret = false;
goto out;
}
- ip46_enqueue_packet (vm, bi0, false);
+ ip46_enqueue_packet (vm, bi0, is_ip4);
wg_timers_any_authenticated_packet_sent (peer);
wg_timers_any_authenticated_packet_traversal (peer);
@@ -226,11 +246,12 @@ wg_send_handshake_response (vlib_main_t * vm, wg_peer_t * peer)
peer->last_sent_handshake = vlib_time_now (vm);
u32 bi0 = 0;
- if (!wg_create_buffer (vm, peer, (u8 *) & packet,
- sizeof (packet), &bi0))
+ u8 is_ip4 = ip46_address_is_ip4 (&peer->dst.addr);
+ if (!wg_create_buffer (vm, peer, (u8 *) &packet, sizeof (packet),
+ &bi0, is_ip4))
return false;
- ip46_enqueue_packet (vm, bi0, false);
+ ip46_enqueue_packet (vm, bi0, is_ip4);
}
else
return false;
diff --git a/test/test_wireguard.py b/test/test_wireguard.py
index 96c1bc0f5fd..65ebd8d2c08 100755
--- a/test/test_wireguard.py
+++ b/test/test_wireguard.py
@@ -9,6 +9,7 @@ from scapy.packet import Packet
from scapy.packet import Raw
from scapy.layers.l2 import Ether, ARP
from scapy.layers.inet import IP, UDP
+from scapy.layers.inet6 import IPv6
from scapy.contrib.wireguard import Wireguard, WireguardResponse, \
WireguardInitiation, WireguardTransport
from cryptography.hazmat.primitives.asymmetric.x25519 import \
@@ -98,8 +99,8 @@ class VppWgInterface(VppInterface):
return "wireguard-%d" % self._sw_if_index
-def find_route(test, prefix, table_id=0):
- routes = test.vapi.ip_route_dump(table_id, False)
+def find_route(test, prefix, is_ip6, table_id=0):
+ routes = test.vapi.ip_route_dump(table_id, is_ip6)
for e in routes:
if table_id == e.route.table_id \
@@ -134,7 +135,7 @@ class VppWgPeer(VppObject):
self.noise = NoiseConnection.from_name(NOISE_HANDSHAKE_NAME)
- def add_vpp_config(self):
+ def add_vpp_config(self, is_ip6=False):
rv = self._test.vapi.wireguard_peer_add(
peer={
'public_key': self.public_key_bytes(),
@@ -179,10 +180,15 @@ class VppWgPeer(VppObject):
def set_responder(self):
self.noise.set_as_responder()
- def mk_tunnel_header(self, tx_itf):
- return (Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac) /
- IP(src=self.endpoint, dst=self.itf.src) /
- UDP(sport=self.port, dport=self.itf.port))
+ def mk_tunnel_header(self, tx_itf, is_ip6=False):
+ if is_ip6 is False:
+ return (Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac) /
+ IP(src=self.endpoint, dst=self.itf.src) /
+ UDP(sport=self.port, dport=self.itf.port))
+ else:
+ return (Ether(dst=tx_itf.local_mac, src=tx_itf.remote_mac) /
+ IPv6(src=self.endpoint, dst=self.itf.src) /
+ UDP(sport=self.port, dport=self.itf.port))
def noise_init(self, public_key=None):
self.noise.set_prologue(NOISE_IDENTIFIER_NAME)
@@ -202,7 +208,7 @@ class VppWgPeer(VppObject):
self.noise.start_handshake()
- def mk_handshake(self, tx_itf, public_key=None):
+ def mk_handshake(self, tx_itf, is_ip6=False, public_key=None):
self.noise.set_as_initiator()
self.noise_init(public_key)
@@ -232,21 +238,25 @@ class VppWgPeer(VppObject):
key=mac_key).digest()
p[WireguardInitiation].mac2 = bytearray(16)
- p = (self.mk_tunnel_header(tx_itf) / p)
+ p = (self.mk_tunnel_header(tx_itf, is_ip6) / p)
return p
- def verify_header(self, p):
- self._test.assertEqual(p[IP].src, self.itf.src)
- self._test.assertEqual(p[IP].dst, self.endpoint)
+ def verify_header(self, p, is_ip6=False):
+ if is_ip6 is False:
+ self._test.assertEqual(p[IP].src, self.itf.src)
+ self._test.assertEqual(p[IP].dst, self.endpoint)
+ else:
+ self._test.assertEqual(p[IPv6].src, self.itf.src)
+ self._test.assertEqual(p[IPv6].dst, self.endpoint)
self._test.assertEqual(p[UDP].sport, self.itf.port)
self._test.assertEqual(p[UDP].dport, self.port)
self._test.assert_packet_checksums_valid(p)
- def consume_init(self, p, tx_itf):
+ def consume_init(self, p, tx_itf, is_ip6=False):
self.noise.set_as_responder()
self.noise_init(self.itf.public_key)
- self.verify_header(p)
+ self.verify_header(p, is_ip6)
init = Wireguard(p[Raw])
@@ -281,13 +291,13 @@ class VppWgPeer(VppObject):
key=mac_key).digest()
resp[WireguardResponse].mac1 = mac1
- resp = (self.mk_tunnel_header(tx_itf) / resp)
+ resp = (self.mk_tunnel_header(tx_itf, is_ip6) / resp)
self._test.assertTrue(self.noise.handshake_finished)
return resp
- def consume_response(self, p):
- self.verify_header(p)
+ def consume_response(self, p, is_ip6=False):
+ self.verify_header(p, is_ip6)
resp = Wireguard(p[Raw])
@@ -302,8 +312,8 @@ class VppWgPeer(VppObject):
self._test.assertEqual(payload, b'')
self._test.assertTrue(self.noise.handshake_finished)
- def decrypt_transport(self, p):
- self.verify_header(p)
+ def decrypt_transport(self, p, is_ip6=False):
+ self.verify_header(p, is_ip6)
p = Wireguard(p[Raw])
self._test.assertEqual(p[Wireguard].message_type, 4)
@@ -318,13 +328,20 @@ class VppWgPeer(VppObject):
def encrypt_transport(self, p):
return self.noise.encrypt(bytes(p))
- def validate_encapped(self, rxs, tx):
+ def validate_encapped(self, rxs, tx, is_ip6=False):
for rx in rxs:
- rx = IP(self.decrypt_transport(rx))
+ if is_ip6 is False:
+ rx = IP(self.decrypt_transport(rx))
- # chech the oringial packet is present
- self._test.assertEqual(rx[IP].dst, tx[IP].dst)
- self._test.assertEqual(rx[IP].ttl, tx[IP].ttl-1)
+ # chech the oringial packet is present
+ self._test.assertEqual(rx[IP].dst, tx[IP].dst)
+ self._test.assertEqual(rx[IP].ttl, tx[IP].ttl-1)
+ else:
+ rx = IPv6(self.decrypt_transport(rx))
+
+ # chech the oringial packet is present
+ self._test.assertEqual(rx[IPv6].dst, tx[IPv6].dst)
+ self._test.assertEqual(rx[IPv6].ttl, tx[IPv6].ttl-1)
class TestWg(VppTestCase):
@@ -332,6 +349,17 @@ class TestWg(VppTestCase):
error_str = compile(r"Error")
+ wg4_output_node_name = '/err/wg4-output-tun/'
+ wg4_input_node_name = '/err/wg4-input/'
+ wg6_output_node_name = '/err/wg6-output-tun/'
+ wg6_input_node_name = '/err/wg6-input/'
+ kp4_error = wg4_output_node_name + "Keypair error"
+ mac4_error = wg4_input_node_name + "Invalid MAC handshake"
+ peer4_error = wg4_input_node_name + "Peer error"
+ kp6_error = wg6_output_node_name + "Keypair error"
+ mac6_error = wg6_input_node_name + "Invalid MAC handshake"
+ peer6_error = wg6_input_node_name + "Peer error"
+
@classmethod
def setUpClass(cls):
super(TestWg, cls).setUpClass()
@@ -340,7 +368,9 @@ class TestWg(VppTestCase):
for i in cls.pg_interfaces:
i.admin_up()
i.config_ip4()
+ i.config_ip6()
i.resolve_arp()
+ i.resolve_ndp()
except Exception:
super(TestWg, cls).tearDownClass()
@@ -350,6 +380,15 @@ class TestWg(VppTestCase):
def tearDownClass(cls):
super(TestWg, cls).tearDownClass()
+ def setUp(self):
+ super(VppTestCase, self).setUp()
+ self.base_kp4_err = self.statistics.get_err_counter(self.kp4_error)
+ self.base_mac4_err = self.statistics.get_err_counter(self.mac4_error)
+ self.base_peer4_err = self.statistics.get_err_counter(self.peer4_error)
+ self.base_kp6_err = self.statistics.get_err_counter(self.kp6_error)
+ self.base_mac6_err = self.statistics.get_err_counter(self.mac6_error)
+ self.base_peer6_err = self.statistics.get_err_counter(self.peer6_error)
+
def test_wg_interface(self):
""" Simple interface creation """
port = 12312
@@ -409,9 +448,6 @@ class TestWg(VppTestCase):
def test_wg_peer_resp(self):
""" Send handshake response """
- wg_output_node_name = '/err/wg-output-tun/'
- wg_input_node_name = '/err/wg-input/'
-
port = 12323
# Create interfaces
@@ -481,10 +517,8 @@ class TestWg(VppTestCase):
peer_1.remove_vpp_config()
wg0.remove_vpp_config()
- def test_wg_peer_init(self):
- """ Send handshake init """
- wg_output_node_name = '/err/wg-output-tun/'
- wg_input_node_name = '/err/wg-input/'
+ def test_wg_peer_v4o4(self):
+ """ Test v4o4"""
port = 12333
@@ -514,23 +548,23 @@ class TestWg(VppTestCase):
UDP(sport=555, dport=556) /
Raw())
self.send_and_assert_no_replies(self.pg0, [p])
-
- kp_error = wg_output_node_name + "Keypair error"
- self.assertEqual(1, self.statistics.get_err_counter(kp_error))
+ self.assertEqual(self.base_kp4_err + 1,
+ self.statistics.get_err_counter(self.kp4_error))
# send a handsake from the peer with an invalid MAC
p = peer_1.mk_handshake(self.pg1)
p[WireguardInitiation].mac1 = b'foobar'
self.send_and_assert_no_replies(self.pg1, [p])
- self.assertEqual(1, self.statistics.get_err_counter(
- wg_input_node_name + "Invalid MAC handshake"))
+ self.assertEqual(self.base_mac4_err + 1,
+ self.statistics.get_err_counter(self.mac4_error))
# send a handsake from the peer but signed by the wrong key.
p = peer_1.mk_handshake(self.pg1,
+ False,
X25519PrivateKey.generate().public_key())
self.send_and_assert_no_replies(self.pg1, [p])
- self.assertEqual(1, self.statistics.get_err_counter(
- wg_input_node_name + "Peer error"))
+ self.assertEqual(self.base_peer4_err + 1,
+ self.statistics.get_err_counter(self.peer4_error))
# send a valid handsake init for which we expect a response
p = peer_1.mk_handshake(self.pg1)
@@ -546,7 +580,8 @@ class TestWg(VppTestCase):
UDP(sport=555, dport=556) /
Raw())
self.send_and_assert_no_replies(self.pg0, [p])
- self.assertEqual(2, self.statistics.get_err_counter(kp_error))
+ self.assertEqual(self.base_kp4_err + 2,
+ self.statistics.get_err_counter(self.kp4_error))
# send a data packet from the peer through the tunnel
# this completes the handshake
@@ -602,9 +637,373 @@ class TestWg(VppTestCase):
peer_1.remove_vpp_config()
wg0.remove_vpp_config()
+ def test_wg_peer_v6o6(self):
+ """ Test v6o6"""
+
+ port = 12343
+
+ # Create interfaces
+ wg0 = VppWgInterface(self,
+ self.pg1.local_ip6,
+ port).add_vpp_config()
+ wg0.admin_up()
+ wg0.config_ip6()
+
+ peer_1 = VppWgPeer(self,
+ wg0,
+ self.pg1.remote_ip6,
+ port+1,
+ ["1::3:0/112"]).add_vpp_config(True)
+ self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
+
+ r1 = VppIpRoute(self, "1::3:0", 112,
+ [VppRoutePath("1::3:1",
+ wg0.sw_if_index)]).add_vpp_config()
+
+ # route a packet into the wg interface
+ # use the allowed-ip prefix
+ # this is dropped because the peer is not initiated
+
+ p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+ IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
+ UDP(sport=555, dport=556) /
+ Raw())
+ self.send_and_assert_no_replies(self.pg0, [p])
+
+ self.assertEqual(self.base_kp6_err + 1,
+ self.statistics.get_err_counter(self.kp6_error))
+
+ # send a handsake from the peer with an invalid MAC
+ p = peer_1.mk_handshake(self.pg1, True)
+ p[WireguardInitiation].mac1 = b'foobar'
+ self.send_and_assert_no_replies(self.pg1, [p])
+
+ self.assertEqual(self.base_mac6_err + 1,
+ self.statistics.get_err_counter(self.mac6_error))
+
+ # send a handsake from the peer but signed by the wrong key.
+ p = peer_1.mk_handshake(self.pg1,
+ True,
+ X25519PrivateKey.generate().public_key())
+ self.send_and_assert_no_replies(self.pg1, [p])
+ self.assertEqual(self.base_peer6_err + 1,
+ self.statistics.get_err_counter(self.peer6_error))
+
+ # send a valid handsake init for which we expect a response
+ p = peer_1.mk_handshake(self.pg1, True)
+
+ rx = self.send_and_expect(self.pg1, [p], self.pg1)
+
+ peer_1.consume_response(rx[0], True)
+
+ # route a packet into the wg interface
+ # this is dropped because the peer is still not initiated
+ p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+ IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
+ UDP(sport=555, dport=556) /
+ Raw())
+ self.send_and_assert_no_replies(self.pg0, [p])
+ self.assertEqual(self.base_kp6_err + 2,
+ self.statistics.get_err_counter(self.kp6_error))
+
+ # send a data packet from the peer through the tunnel
+ # this completes the handshake
+ p = (IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20) /
+ UDP(sport=222, dport=223) /
+ Raw())
+ d = peer_1.encrypt_transport(p)
+ p = (peer_1.mk_tunnel_header(self.pg1, True) /
+ (Wireguard(message_type=4, reserved_zero=0) /
+ WireguardTransport(receiver_index=peer_1.sender,
+ counter=0,
+ encrypted_encapsulated_packet=d)))
+ rxs = self.send_and_expect(self.pg1, [p], self.pg0)
+
+ for rx in rxs:
+ self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
+ self.assertEqual(rx[IPv6].hlim, 19)
+
+ # send a packets that are routed into the tunnel
+ p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+ IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
+ UDP(sport=555, dport=556) /
+ Raw(b'\x00' * 80))
+
+ rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
+
+ for rx in rxs:
+ rx = IPv6(peer_1.decrypt_transport(rx, True))
+
+ # chech the oringial packet is present
+ self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
+ self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim-1)
+
+ # send packets into the tunnel, expect to receive them on
+ # the other side
+ p = [(peer_1.mk_tunnel_header(self.pg1, True) /
+ Wireguard(message_type=4, reserved_zero=0) /
+ WireguardTransport(
+ receiver_index=peer_1.sender,
+ counter=ii+1,
+ encrypted_encapsulated_packet=peer_1.encrypt_transport(
+ (IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20) /
+ UDP(sport=222, dport=223) /
+ Raw())))) for ii in range(255)]
+
+ rxs = self.send_and_expect(self.pg1, p, self.pg0)
+
+ for rx in rxs:
+ self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
+ self.assertEqual(rx[IPv6].hlim, 19)
+
+ r1.remove_vpp_config()
+ peer_1.remove_vpp_config()
+ wg0.remove_vpp_config()
+
+ def test_wg_peer_v6o4(self):
+ """ Test v6o4"""
+
+ port = 12353
+
+ # Create interfaces
+ wg0 = VppWgInterface(self,
+ self.pg1.local_ip4,
+ port).add_vpp_config()
+ wg0.admin_up()
+ wg0.config_ip6()
+
+ peer_1 = VppWgPeer(self,
+ wg0,
+ self.pg1.remote_ip4,
+ port+1,
+ ["1::3:0/112"]).add_vpp_config(True)
+ self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
+
+ r1 = VppIpRoute(self, "1::3:0", 112,
+ [VppRoutePath("1::3:1",
+ wg0.sw_if_index)]).add_vpp_config()
+
+ # route a packet into the wg interface
+ # use the allowed-ip prefix
+ # this is dropped because the peer is not initiated
+ p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+ IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
+ UDP(sport=555, dport=556) /
+ Raw())
+ self.send_and_assert_no_replies(self.pg0, [p])
+ self.assertEqual(self.base_kp6_err + 1,
+ self.statistics.get_err_counter(self.kp6_error))
+
+ # send a handsake from the peer with an invalid MAC
+ p = peer_1.mk_handshake(self.pg1)
+ p[WireguardInitiation].mac1 = b'foobar'
+ self.send_and_assert_no_replies(self.pg1, [p])
+
+ self.assertEqual(self.base_mac4_err + 1,
+ self.statistics.get_err_counter(self.mac4_error))
+
+ # send a handsake from the peer but signed by the wrong key.
+ p = peer_1.mk_handshake(self.pg1,
+ False,
+ X25519PrivateKey.generate().public_key())
+ self.send_and_assert_no_replies(self.pg1, [p])
+ self.assertEqual(self.base_peer4_err + 1,
+ self.statistics.get_err_counter(self.peer4_error))
+
+ # send a valid handsake init for which we expect a response
+ p = peer_1.mk_handshake(self.pg1)
+
+ rx = self.send_and_expect(self.pg1, [p], self.pg1)
+
+ peer_1.consume_response(rx[0])
+
+ # route a packet into the wg interface
+ # this is dropped because the peer is still not initiated
+ p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+ IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
+ UDP(sport=555, dport=556) /
+ Raw())
+ self.send_and_assert_no_replies(self.pg0, [p])
+ self.assertEqual(self.base_kp6_err + 2,
+ self.statistics.get_err_counter(self.kp6_error))
+
+ # send a data packet from the peer through the tunnel
+ # this completes the handshake
+ p = (IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20) /
+ UDP(sport=222, dport=223) /
+ Raw())
+ d = peer_1.encrypt_transport(p)
+ p = (peer_1.mk_tunnel_header(self.pg1) /
+ (Wireguard(message_type=4, reserved_zero=0) /
+ WireguardTransport(receiver_index=peer_1.sender,
+ counter=0,
+ encrypted_encapsulated_packet=d)))
+ rxs = self.send_and_expect(self.pg1, [p], self.pg0)
+
+ for rx in rxs:
+ self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
+ self.assertEqual(rx[IPv6].hlim, 19)
+
+ # send a packets that are routed into the tunnel
+ p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+ IPv6(src=self.pg0.remote_ip6, dst="1::3:2") /
+ UDP(sport=555, dport=556) /
+ Raw(b'\x00' * 80))
+
+ rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
+
+ for rx in rxs:
+ rx = IPv6(peer_1.decrypt_transport(rx))
+
+ # chech the oringial packet is present
+ self.assertEqual(rx[IPv6].dst, p[IPv6].dst)
+ self.assertEqual(rx[IPv6].hlim, p[IPv6].hlim-1)
+
+ # send packets into the tunnel, expect to receive them on
+ # the other side
+ p = [(peer_1.mk_tunnel_header(self.pg1) /
+ Wireguard(message_type=4, reserved_zero=0) /
+ WireguardTransport(
+ receiver_index=peer_1.sender,
+ counter=ii+1,
+ encrypted_encapsulated_packet=peer_1.encrypt_transport(
+ (IPv6(src="1::3:1", dst=self.pg0.remote_ip6, hlim=20) /
+ UDP(sport=222, dport=223) /
+ Raw())))) for ii in range(255)]
+
+ rxs = self.send_and_expect(self.pg1, p, self.pg0)
+
+ for rx in rxs:
+ self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
+ self.assertEqual(rx[IPv6].hlim, 19)
+
+ r1.remove_vpp_config()
+ peer_1.remove_vpp_config()
+ wg0.remove_vpp_config()
+
+ def test_wg_peer_v4o6(self):
+ """ Test v4o6"""
+
+ port = 12363
+
+ # Create interfaces
+ wg0 = VppWgInterface(self,
+ self.pg1.local_ip6,
+ port).add_vpp_config()
+ wg0.admin_up()
+ wg0.config_ip4()
+
+ peer_1 = VppWgPeer(self,
+ wg0,
+ self.pg1.remote_ip6,
+ port+1,
+ ["10.11.3.0/24"]).add_vpp_config()
+ self.assertEqual(len(self.vapi.wireguard_peers_dump()), 1)
+
+ r1 = VppIpRoute(self, "10.11.3.0", 24,
+ [VppRoutePath("10.11.3.1",
+ wg0.sw_if_index)]).add_vpp_config()
+
+ # route a packet into the wg interface
+ # use the allowed-ip prefix
+ # this is dropped because the peer is not initiated
+ p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+ IP(src=self.pg0.remote_ip4, dst="10.11.3.2") /
+ UDP(sport=555, dport=556) /
+ Raw())
+ self.send_and_assert_no_replies(self.pg0, [p])
+ self.assertEqual(self.base_kp4_err + 1,
+ self.statistics.get_err_counter(self.kp4_error))
+
+ # send a handsake from the peer with an invalid MAC
+ p = peer_1.mk_handshake(self.pg1, True)
+ p[WireguardInitiation].mac1 = b'foobar'
+ self.send_and_assert_no_replies(self.pg1, [p])
+ self.assertEqual(self.base_mac6_err + 1,
+ self.statistics.get_err_counter(self.mac6_error))
+
+ # send a handsake from the peer but signed by the wrong key.
+ p = peer_1.mk_handshake(self.pg1,
+ True,
+ X25519PrivateKey.generate().public_key())
+ self.send_and_assert_no_replies(self.pg1, [p])
+ self.assertEqual(self.base_peer6_err + 1,
+ self.statistics.get_err_counter(self.peer6_error))
+
+ # send a valid handsake init for which we expect a response
+ p = peer_1.mk_handshake(self.pg1, True)
+
+ rx = self.send_and_expect(self.pg1, [p], self.pg1)
+
+ peer_1.consume_response(rx[0], True)
+
+ # route a packet into the wg interface
+ # this is dropped because the peer is still not initiated
+ p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+ IP(src=self.pg0.remote_ip4, dst="10.11.3.2") /
+ UDP(sport=555, dport=556) /
+ Raw())
+ self.send_and_assert_no_replies(self.pg0, [p])
+ self.assertEqual(self.base_kp4_err + 2,
+ self.statistics.get_err_counter(self.kp4_error))
+
+ # send a data packet from the peer through the tunnel
+ # this completes the handshake
+ p = (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) /
+ UDP(sport=222, dport=223) /
+ Raw())
+ d = peer_1.encrypt_transport(p)
+ p = (peer_1.mk_tunnel_header(self.pg1, True) /
+ (Wireguard(message_type=4, reserved_zero=0) /
+ WireguardTransport(receiver_index=peer_1.sender,
+ counter=0,
+ encrypted_encapsulated_packet=d)))
+ rxs = self.send_and_expect(self.pg1, [p], self.pg0)
+
+ for rx in rxs:
+ self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
+ self.assertEqual(rx[IP].ttl, 19)
+
+ # send a packets that are routed into the tunnel
+ p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+ IP(src=self.pg0.remote_ip4, dst="10.11.3.2") /
+ UDP(sport=555, dport=556) /
+ Raw(b'\x00' * 80))
+
+ rxs = self.send_and_expect(self.pg0, p * 255, self.pg1)
+
+ for rx in rxs:
+ rx = IP(peer_1.decrypt_transport(rx, True))
+
+ # chech the oringial packet is present
+ self.assertEqual(rx[IP].dst, p[IP].dst)
+ self.assertEqual(rx[IP].ttl, p[IP].ttl-1)
+
+ # send packets into the tunnel, expect to receive them on
+ # the other side
+ p = [(peer_1.mk_tunnel_header(self.pg1, True) /
+ Wireguard(message_type=4, reserved_zero=0) /
+ WireguardTransport(
+ receiver_index=peer_1.sender,
+ counter=ii+1,
+ encrypted_encapsulated_packet=peer_1.encrypt_transport(
+ (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) /
+ UDP(sport=222, dport=223) /
+ Raw())))) for ii in range(255)]
+
+ rxs = self.send_and_expect(self.pg1, p, self.pg0)
+
+ for rx in rxs:
+ self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
+ self.assertEqual(rx[IP].ttl, 19)
+
+ r1.remove_vpp_config()
+ peer_1.remove_vpp_config()
+ wg0.remove_vpp_config()
+
def test_wg_multi_peer(self):
""" multiple peer setup """
- port = 12343
+ port = 12373
# Create interfaces
wg0 = VppWgInterface(self,
@@ -784,10 +1183,8 @@ class WireguardHandoffTests(TestWg):
def test_wg_peer_init(self):
""" Handoff """
- wg_output_node_name = '/err/wg-output-tun/'
- wg_input_node_name = '/err/wg-input/'
- port = 12353
+ port = 12383
# Create interfaces
wg0 = VppWgInterface(self,
@@ -844,14 +1241,14 @@ class WireguardHandoffTests(TestWg):
# send packets into the tunnel, from the other worker
p = [(peer_1.mk_tunnel_header(self.pg1) /
- Wireguard(message_type=4, reserved_zero=0) /
- WireguardTransport(
- receiver_index=peer_1.sender,
- counter=ii+1,
- encrypted_encapsulated_packet=peer_1.encrypt_transport(
- (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) /
- UDP(sport=222, dport=223) /
- Raw())))) for ii in range(255)]
+ Wireguard(message_type=4, reserved_zero=0) /
+ WireguardTransport(
+ receiver_index=peer_1.sender,
+ counter=ii+1,
+ encrypted_encapsulated_packet=peer_1.encrypt_transport(
+ (IP(src="10.11.3.1", dst=self.pg0.remote_ip4, ttl=20) /
+ UDP(sport=222, dport=223) /
+ Raw())))) for ii in range(255)]
rxs = self.send_and_expect(self.pg1, p, self.pg0, worker=1)