wireguard: add ipv6 support
Type: improvement Signed-off-by: Artem Glazychev <artem.glazychev@xored.com> Change-Id: If1a7e82ce163c4c4acaa5acf45ad2b88371396f6
This commit is contained in:

committed by
Ed Warnicke

parent
0c4931cb35
commit
7dd3b5b5e3
21
src/plugins/wireguard/wireguard.c
Executable file → Normal file
21
src/plugins/wireguard/wireguard.c
Executable file → Normal file
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
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);
|
||||
}
|
||||
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:
|
||||
|
12
src/plugins/wireguard/wireguard_cli.c
Executable file → Normal file
12
src/plugins/wireguard/wireguard_cli.c
Executable file → Normal file
@ -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)
|
||||
{
|
||||
|
25
src/plugins/wireguard/wireguard_cookie.c
Executable file → Normal file
25
src/plugins/wireguard/wireguard_cookie.c
Executable file → Normal file
@ -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);
|
||||
}
|
||||
|
12
src/plugins/wireguard/wireguard_cookie.h
Executable file → Normal file
12
src/plugins/wireguard/wireguard_cookie.h
Executable file → Normal file
@ -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__ */
|
||||
|
||||
|
@ -129,40 +129,64 @@ 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 (wg_output_tun_handoff) (vlib_main_t * vm,
|
||||
vlib_node_runtime_t * node,
|
||||
vlib_frame_t * from_frame)
|
||||
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->out_fq_index,
|
||||
return wg_handoff (vm, node, from_frame, wmp->in6_fq_index,
|
||||
WG_HANDOFF_INP_DATA);
|
||||
}
|
||||
|
||||
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->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 = "wg-handshake-handoff",
|
||||
.name = "wg4-handshake-handoff",
|
||||
.vector_size = sizeof (u32),
|
||||
.format_trace = format_wg_handoff_trace,
|
||||
.type = VLIB_NODE_TYPE_INTERNAL,
|
||||
@ -174,9 +198,9 @@ VLIB_REGISTER_NODE (wg_handshake_handoff) =
|
||||
},
|
||||
};
|
||||
|
||||
VLIB_REGISTER_NODE (wg_input_data_handoff) =
|
||||
VLIB_REGISTER_NODE (wg6_handshake_handoff) =
|
||||
{
|
||||
.name = "wg-input-data-handoff",
|
||||
.name = "wg6-handshake-handoff",
|
||||
.vector_size = sizeof (u32),
|
||||
.format_trace = format_wg_handoff_trace,
|
||||
.type = VLIB_NODE_TYPE_INTERNAL,
|
||||
@ -188,9 +212,51 @@ VLIB_REGISTER_NODE (wg_input_data_handoff) =
|
||||
},
|
||||
};
|
||||
|
||||
VLIB_REGISTER_NODE (wg_output_tun_handoff) =
|
||||
VLIB_REGISTER_NODE (wg4_input_data_handoff) =
|
||||
{
|
||||
.name = "wg-output-tun-handoff",
|
||||
.name = "wg4-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 (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 = "wg6-output-tun-handoff",
|
||||
.vector_size = sizeof (u32),
|
||||
.format_trace = format_wg_handoff_trace,
|
||||
.type = VLIB_NODE_TYPE_INTERNAL,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,22 @@ VLIB_NODE_FN (wg_input_node) (vlib_main_t * vm,
|
||||
return frame->n_vectors;
|
||||
}
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
VLIB_REGISTER_NODE (wg_input_node) =
|
||||
VLIB_NODE_FN (wg4_input_node)
|
||||
(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
|
||||
{
|
||||
.name = "wg-input",
|
||||
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 (wg4_input_node) =
|
||||
{
|
||||
.name = "wg4-input",
|
||||
.vector_size = sizeof (u32),
|
||||
.format_trace = format_wg_input_trace,
|
||||
.type = VLIB_NODE_TYPE_INTERNAL,
|
||||
@ -457,9 +503,30 @@ 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] = "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 = "wg6-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] = "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",
|
||||
},
|
||||
|
136
src/plugins/wireguard/wireguard_output_tun.c
Executable file → Normal file
136
src/plugins/wireguard/wireguard_output_tun.c
Executable file → Normal file
@ -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,22 @@ VLIB_NODE_FN (wg_output_tun_node) (vlib_main_t * vm,
|
||||
return frame->n_vectors;
|
||||
}
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
VLIB_REGISTER_NODE (wg_output_tun_node) =
|
||||
VLIB_NODE_FN (wg4_output_tun_node)
|
||||
(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
|
||||
{
|
||||
.name = "wg-output-tun",
|
||||
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 (wg4_output_tun_node) =
|
||||
{
|
||||
.name = "wg4-output-tun",
|
||||
.vector_size = sizeof (u32),
|
||||
.format_trace = format_wg_output_tun_trace,
|
||||
.type = VLIB_NODE_TYPE_INTERNAL,
|
||||
@ -225,7 +281,23 @@ 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] = "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 = "wg6-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] = "wg6-output-tun-handoff",
|
||||
[WG_OUTPUT_NEXT_INTERFACE_OUTPUT] = "adj-midchain-tx",
|
||||
[WG_OUTPUT_NEXT_ERROR] = "error-drop",
|
||||
},
|
||||
|
@ -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;
|
||||
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->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;
|
||||
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 = (ip6_udp_header_t *) rewrite;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
65
src/plugins/wireguard/wireguard_send.c
Executable file → Normal file
65
src/plugins/wireguard/wireguard_send.c
Executable file → Normal file
@ -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 (*hdr));
|
||||
vlib_buffer_advance (b0, -sizeof (*hdr4));
|
||||
|
||||
hdr = vlib_buffer_get_current (b0);
|
||||
clib_memcpy (hdr, peer->rewrite, vec_len (peer->rewrite));
|
||||
hdr4 = vlib_buffer_get_current (b0);
|
||||
clib_memcpy (hdr4, peer->rewrite, vec_len (peer->rewrite));
|
||||
|
||||
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));
|
||||
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;
|
||||
|
||||
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;
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user