aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/ikev2
diff options
context:
space:
mode:
authorFilip Tehlar <ftehlar@cisco.com>2021-02-22 16:15:51 +0000
committerDamjan Marion <dmarion@me.com>2021-03-15 17:38:05 +0000
commitaf2cc6425e7615cb90359254ae8fd429e4fea198 (patch)
tree2968103d6c0ccbf1c55883d5d56e9a93720652e5 /src/plugins/ikev2
parent418abe2a259bc8c04c3b8839099204d56ae504ba (diff)
ikev2: support responder hostname
Type: feature Ticket: VPP-1901 Change-Id: I1ad222b54363fd35679d0132d458345a9a18362c Signed-off-by: Filip Tehlar <ftehlar@cisco.com>
Diffstat (limited to 'src/plugins/ikev2')
-rw-r--r--src/plugins/ikev2/ikev2.api11
-rw-r--r--src/plugins/ikev2/ikev2.c147
-rw-r--r--src/plugins/ikev2/ikev2.h3
-rw-r--r--src/plugins/ikev2/ikev2_api.c32
-rw-r--r--src/plugins/ikev2/ikev2_cli.c16
-rw-r--r--src/plugins/ikev2/ikev2_priv.h5
-rw-r--r--src/plugins/ikev2/ikev2_test.c47
-rw-r--r--src/plugins/ikev2/test/test_ikev2.py20
-rw-r--r--src/plugins/ikev2/test/vpp_ikev2.py8
9 files changed, 255 insertions, 34 deletions
diff --git a/src/plugins/ikev2/ikev2.api b/src/plugins/ikev2/ikev2.api
index 32e1a91d1e8..ff9ed72e888 100644
--- a/src/plugins/ikev2/ikev2.api
+++ b/src/plugins/ikev2/ikev2.api
@@ -331,6 +331,17 @@ autoreply define ikev2_set_responder
option status="in_progress";
};
+autoreply define ikev2_set_responder_hostname
+{
+ u32 client_index;
+ u32 context;
+
+ string name[64];
+ string hostname[64];
+ vl_api_interface_index_t sw_if_index;
+ option status="in_progress";
+};
+
/** \brief IKEv2: Set IKEv2 IKE transforms in SA_INIT proposal (RFC 7296)
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c
index aeed73ecdc3..fa653760b1d 100644
--- a/src/plugins/ikev2/ikev2.c
+++ b/src/plugins/ikev2/ikev2.c
@@ -26,6 +26,7 @@
#include <vnet/ipip/ipip.h>
#include <plugins/ikev2/ikev2.h>
#include <plugins/ikev2/ikev2_priv.h>
+#include <plugins/dns/dns.h>
#include <openssl/sha.h>
#include <vnet/ipsec/ipsec_punt.h>
#include <plugins/ikev2/ikev2.api_enum.h>
@@ -3857,6 +3858,12 @@ ikev2_cleanup_profile_sessions (ikev2_main_t * km, ikev2_profile_t * p)
}
static void
+ikev2_profile_responder_free (ikev2_responder_t *r)
+{
+ vec_free (r->hostname);
+}
+
+static void
ikev2_profile_free (ikev2_profile_t * p)
{
vec_free (p->name);
@@ -3865,6 +3872,8 @@ ikev2_profile_free (ikev2_profile_t * p)
if (p->auth.key)
EVP_PKEY_free (p->auth.key);
+ ikev2_profile_responder_free (&p->responder);
+
vec_free (p->loc_id.data);
vec_free (p->rem_id.data);
}
@@ -4042,6 +4051,27 @@ ikev2_set_profile_ts (vlib_main_t * vm, u8 * name, u8 protocol_id,
return 0;
}
+clib_error_t *
+ikev2_set_profile_responder_hostname (vlib_main_t *vm, u8 *name, u8 *hostname,
+ u32 sw_if_index)
+{
+ ikev2_profile_t *p;
+ clib_error_t *r;
+
+ p = ikev2_profile_index_by_name (name);
+
+ if (!p)
+ {
+ r = clib_error_return (0, "unknown profile %v", name);
+ return r;
+ }
+
+ p->responder.is_resolved = 0;
+ p->responder.sw_if_index = sw_if_index;
+ p->responder.hostname = vec_dup (hostname);
+
+ return 0;
+}
clib_error_t *
ikev2_set_profile_responder (vlib_main_t * vm, u8 * name,
@@ -4058,6 +4088,7 @@ ikev2_set_profile_responder (vlib_main_t * vm, u8 * name,
return r;
}
+ p->responder.is_resolved = 1;
p->responder.sw_if_index = sw_if_index;
ip_address_copy (&p->responder.addr, &addr);
@@ -4226,6 +4257,31 @@ ikev2_get_if_address (u32 sw_if_index, ip_address_family_t af,
return 0;
}
+static clib_error_t *
+ikev2_resolve_responder_hostname (vlib_main_t *vm, ikev2_responder_t *r)
+{
+ ikev2_main_t *km = &ikev2_main;
+ dns_cache_entry_t *ep = 0;
+ dns_pending_request_t _t0, *t0 = &_t0;
+ dns_resolve_name_t _rn, *rn = &_rn;
+ int rv;
+
+ if (!km->dns_resolve_name)
+ return clib_error_return (0, "cannot load symbols from dns plugin");
+
+ t0->request_type = DNS_API_PENDING_NAME_TO_IP;
+ rv = km->dns_resolve_name (r->hostname, &ep, t0, rn);
+ if (rv < 0)
+ return clib_error_return (0, "dns lookup failure");
+
+ if (ep == 0)
+ return 0;
+
+ ip_address_copy (&r->addr, &rn->address);
+ r->is_resolved = 1;
+ return 0;
+}
+
clib_error_t *
ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name)
{
@@ -4236,7 +4292,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name)
ike_header_t *ike0;
u32 bi0 = 0;
int len = sizeof (ike_header_t), valid_ip = 0;
- ip_address_t if_ip = ip_address_initializer;
+ ip_address_t src_if_ip = ip_address_initializer;
p = ikev2_profile_index_by_name (name);
@@ -4246,15 +4302,26 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name)
return r;
}
- if (p->responder.sw_if_index == ~0
- || ip_address_is_zero (&p->responder.addr))
+ if (p->responder.sw_if_index == ~0 ||
+ (ip_address_is_zero (&p->responder.addr) &&
+ vec_len (p->responder.hostname) == 0))
{
r = clib_error_return (0, "responder not set for profile %v", name);
return r;
}
- if (ikev2_get_if_address (p->responder.sw_if_index,
- ip_addr_version (&p->responder.addr), &if_ip))
+ if (!p->responder.is_resolved)
+ {
+ /* try to resolve using dns plugin
+ * success does not mean we have resolved the name */
+ r = ikev2_resolve_responder_hostname (vm, &p->responder);
+ if (r)
+ return r;
+ }
+
+ if (p->responder.is_resolved &&
+ ikev2_get_if_address (p->responder.sw_if_index,
+ ip_addr_version (&p->responder.addr), &src_if_ip))
{
valid_ip = 1;
}
@@ -4308,10 +4375,9 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name)
sizeof (sa.childs[0].i_proposals[0].spi));
/* Add NAT detection notification messages (mandatory) */
- u8 *nat_detection_sha1 =
- ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa.ispi),
- clib_host_to_net_u64 (sa.rspi),
- &if_ip, clib_host_to_net_u16 (IKEV2_PORT));
+ u8 *nat_detection_sha1 = ikev2_compute_nat_sha1 (
+ clib_host_to_net_u64 (sa.ispi), clib_host_to_net_u64 (sa.rspi), &src_if_ip,
+ clib_host_to_net_u16 (IKEV2_PORT));
ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP,
nat_detection_sha1);
@@ -4365,7 +4431,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name)
vec_add (sa.last_sa_init_req_packet_data, ike0, len);
/* add data to the SA then add it to the pool */
- ip_address_copy (&sa.iaddr, &if_ip);
+ ip_address_copy (&sa.iaddr, &src_if_ip);
ip_address_copy (&sa.raddr, &p->responder.addr);
sa.i_id.type = p->loc_id.type;
sa.i_id.data = vec_dup (p->loc_id.data);
@@ -4388,8 +4454,8 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name)
if (valid_ip)
{
- ikev2_send_ike (vm, &if_ip, &p->responder.addr, bi0, len,
- IKEV2_PORT, sa.dst_port, sa.sw_if_index);
+ ikev2_send_ike (vm, &src_if_ip, &p->responder.addr, bi0, len, IKEV2_PORT,
+ sa.dst_port, sa.sw_if_index);
ikev2_elog_exchange
("ispi %lx rspi %lx IKEV2_EXCHANGE_SA_INIT sent to ",
@@ -4397,14 +4463,6 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name)
ip_addr_v4 (&p->responder.addr).as_u32,
ip_addr_version (&p->responder.addr) == AF_IP4);
}
- else
- {
- r =
- clib_error_return (0, "interface %U does not have any IP address!",
- format_vnet_sw_if_index_name, vnet_get_main (),
- p->responder.sw_if_index);
- return r;
- }
return 0;
}
@@ -4732,15 +4790,19 @@ ikev2_init (vlib_main_t * vm)
"ikev2-ip4-natt");
ikev2_cli_reference ();
+ km->dns_resolve_name =
+ vlib_get_plugin_symbol ("dns_plugin.so", "dns_resolve_name");
+ if (!km->dns_resolve_name)
+ ikev2_log_error ("cannot load symbols from dns plugin");
+
km->log_level = IKEV2_LOG_ERROR;
km->log_class = vlib_log_register_class ("ikev2", 0);
return 0;
}
/* *INDENT-OFF* */
-VLIB_INIT_FUNCTION (ikev2_init) =
-{
- .runs_after = VLIB_INITS("ipsec_init", "ipsec_punt_init"),
+VLIB_INIT_FUNCTION (ikev2_init) = {
+ .runs_after = VLIB_INITS ("ipsec_init", "ipsec_punt_init", "dns_init"),
};
/* *INDENT-ON* */
@@ -4928,15 +4990,44 @@ ikev2_mngr_process_ipsec_sa (ipsec_sa_t * ipsec_sa)
}
static void
-ikev2_process_pending_sa_init_one (ikev2_main_t * km, ikev2_sa_t * sa)
+ikev2_process_pending_sa_init_one (vlib_main_t *vm, ikev2_main_t *km,
+ ikev2_sa_t *sa)
{
ikev2_profile_t *p;
u32 bi0;
u8 *nat_sha, *np;
+ p = pool_elt_at_index (km->profiles, sa->profile_index);
+
+ if (!p->responder.is_resolved)
+ {
+ clib_error_t *r = ikev2_resolve_responder_hostname (vm, &p->responder);
+ if (r)
+ {
+ clib_error_free (r);
+ return;
+ }
+
+ if (!p->responder.is_resolved)
+ return;
+
+ ip_address_copy (&sa->raddr, &p->responder.addr);
+
+ /* update nat detection destination hash */
+ np = ikev2_find_ike_notify_payload (
+ (ike_header_t *) sa->last_sa_init_req_packet_data,
+ IKEV2_NOTIFY_MSG_NAT_DETECTION_DESTINATION_IP);
+ if (np)
+ {
+ nat_sha = ikev2_compute_nat_sha1 (
+ clib_host_to_net_u64 (sa->ispi), clib_host_to_net_u64 (sa->rspi),
+ &sa->raddr, clib_host_to_net_u16 (sa->dst_port));
+ clib_memcpy_fast (np, nat_sha, vec_len (nat_sha));
+ vec_free (nat_sha);
+ }
+ }
if (ip_address_is_zero (&sa->iaddr))
{
- p = pool_elt_at_index (km->profiles, sa->profile_index);
if (!ikev2_get_if_address (p->responder.sw_if_index,
ip_addr_version (&p->responder.addr),
&sa->iaddr))
@@ -4973,7 +5064,7 @@ ikev2_process_pending_sa_init_one (ikev2_main_t * km, ikev2_sa_t * sa)
}
static void
-ikev2_process_pending_sa_init (ikev2_main_t * km)
+ikev2_process_pending_sa_init (vlib_main_t *vm, ikev2_main_t *km)
{
u32 sai;
u64 ispi;
@@ -4986,7 +5077,7 @@ ikev2_process_pending_sa_init (ikev2_main_t * km)
if (sa->init_response_received)
continue;
- ikev2_process_pending_sa_init_one (km, sa);
+ ikev2_process_pending_sa_init_one (vm, km, sa);
}));
/* *INDENT-ON* */
}
@@ -5153,7 +5244,7 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt,
}
/* *INDENT-ON* */
- ikev2_process_pending_sa_init (km);
+ ikev2_process_pending_sa_init (vm, km);
}
return 0;
}
diff --git a/src/plugins/ikev2/ikev2.h b/src/plugins/ikev2/ikev2.h
index 893d9544aa8..308ffe52ba4 100644
--- a/src/plugins/ikev2/ikev2.h
+++ b/src/plugins/ikev2/ikev2.h
@@ -395,6 +395,9 @@ clib_error_t *ikev2_set_profile_ts (vlib_main_t * vm, u8 * name,
clib_error_t *ikev2_set_profile_responder (vlib_main_t * vm, u8 * name,
u32 sw_if_index,
ip_address_t addr);
+clib_error_t *ikev2_set_profile_responder_hostname (vlib_main_t *vm, u8 *name,
+ u8 *hostname,
+ u32 sw_if_index);
clib_error_t *ikev2_set_profile_ike_transforms (vlib_main_t * vm, u8 * name,
ikev2_transform_encr_type_t
crypto_alg,
diff --git a/src/plugins/ikev2/ikev2_api.c b/src/plugins/ikev2/ikev2_api.c
index 9dab6928fbc..d104e54579a 100644
--- a/src/plugins/ikev2/ikev2_api.c
+++ b/src/plugins/ikev2/ikev2_api.c
@@ -686,6 +686,38 @@ vl_api_ikev2_set_local_key_t_handler (vl_api_ikev2_set_local_key_t * mp)
}
static void
+vl_api_ikev2_set_responder_hostname_t_handler (
+ vl_api_ikev2_set_responder_hostname_t *mp)
+{
+ vl_api_ikev2_set_responder_hostname_reply_t *rmp;
+ int rv = 0;
+
+#if WITH_LIBSSL > 0
+ vlib_main_t *vm = vlib_get_main ();
+ clib_error_t *error;
+
+ u8 *tmp = format (0, "%s", mp->name);
+ u8 *hn = format (0, "%s", mp->hostname);
+ u32 sw_if_index = clib_net_to_host_u32 (mp->sw_if_index);
+
+ error = ikev2_set_profile_responder_hostname (vm, tmp, hn, sw_if_index);
+ vec_free (tmp);
+ vec_free (hn);
+
+ if (error)
+ {
+ ikev2_log_error ("%U", format_clib_error, error);
+ clib_error_free (error);
+ rv = VNET_API_ERROR_UNSPECIFIED;
+ }
+#else
+ rv = VNET_API_ERROR_UNIMPLEMENTED;
+#endif
+
+ REPLY_MACRO (VL_API_IKEV2_SET_RESPONDER_HOSTNAME_REPLY);
+}
+
+static void
vl_api_ikev2_set_responder_t_handler (vl_api_ikev2_set_responder_t * mp)
{
vl_api_ikev2_set_responder_reply_t *rmp;
diff --git a/src/plugins/ikev2/ikev2_cli.c b/src/plugins/ikev2/ikev2_cli.c
index 7778166254c..3523ce079b6 100644
--- a/src/plugins/ikev2/ikev2_cli.c
+++ b/src/plugins/ikev2/ikev2_cli.c
@@ -444,6 +444,15 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm,
ikev2_set_profile_responder (vm, name, responder_sw_if_index, ip);
goto done;
}
+ else if (unformat (line_input, "set %U responder %U %v",
+ unformat_ikev2_token, &name,
+ unformat_vnet_sw_interface, vnm,
+ &responder_sw_if_index, &data))
+ {
+ r = ikev2_set_profile_responder_hostname (vm, name, data,
+ responder_sw_if_index);
+ goto done;
+ }
else if (unformat (line_input, "set %U tunnel %U",
unformat_ikev2_token, &name,
unformat_vnet_sw_interface, vnm, &tun_sw_if_index))
@@ -615,9 +624,10 @@ show_ikev2_profile_command_fn (vlib_main_t * vm,
vlib_cli_output(vm, " protected tunnel %U",
format_vnet_sw_if_index_name, vnet_get_main(), p->tun_itf);
if (~0 != p->responder.sw_if_index)
- vlib_cli_output(vm, " responder %U %U",
- format_vnet_sw_if_index_name, vnet_get_main(), p->responder.sw_if_index,
- format_ip_address, &p->responder.addr);
+ vlib_cli_output (vm, " responder %U %U %v",
+ format_vnet_sw_if_index_name, vnet_get_main (),
+ p->responder.sw_if_index, format_ip_address,
+ &p->responder.addr, p->responder.hostname);
if (p->udp_encap)
vlib_cli_output(vm, " udp-encap");
diff --git a/src/plugins/ikev2/ikev2_priv.h b/src/plugins/ikev2/ikev2_priv.h
index ea630b86de4..4c56b980f1c 100644
--- a/src/plugins/ikev2/ikev2_priv.h
+++ b/src/plugins/ikev2/ikev2_priv.h
@@ -257,6 +257,8 @@ typedef struct
{
u32 sw_if_index;
ip_address_t addr;
+ u8 *hostname;
+ u8 is_resolved;
} ikev2_responder_t;
typedef struct
@@ -526,6 +528,9 @@ typedef struct
/* dead peer detection */
u8 dpd_disabled;
+
+ /* pointer to name resolver function in dns plugin */
+ int (*dns_resolve_name) ();
} ikev2_main_t;
extern ikev2_main_t ikev2_main;
diff --git a/src/plugins/ikev2/ikev2_test.c b/src/plugins/ikev2/ikev2_test.c
index 98b3fa054ae..b63778ed103 100644
--- a/src/plugins/ikev2/ikev2_test.c
+++ b/src/plugins/ikev2/ikev2_test.c
@@ -1061,6 +1061,53 @@ api_ikev2_set_tunnel_interface (vat_main_t * vam)
}
static int
+api_ikev2_set_responder_hostname (vat_main_t *vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_ikev2_set_responder_hostname_t *mp;
+ int ret;
+ u8 *name = 0, *hn = 0;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "%U hostname %v", unformat_token, valid_chars, &name,
+ &hn))
+ {
+ vec_add1 (name, 0);
+ vec_add1 (hn, 0);
+ }
+ else
+ {
+ errmsg ("parse error '%U'", format_unformat_error, i);
+ return -99;
+ }
+ }
+
+ if (!vec_len (name))
+ {
+ errmsg ("profile name must be specified");
+ return -99;
+ }
+
+ if (vec_len (name) > 64)
+ {
+ errmsg ("profile name too long");
+ return -99;
+ }
+
+ M (IKEV2_SET_RESPONDER_HOSTNAME, mp);
+
+ clib_memcpy (mp->name, name, vec_len (name));
+ clib_memcpy (mp->hostname, hn, vec_len (hn));
+ vec_free (name);
+ vec_free (hn);
+
+ S (mp);
+ W (ret);
+ return ret;
+}
+
+static int
api_ikev2_set_responder (vat_main_t * vam)
{
unformat_input_t *i = vam->input;
diff --git a/src/plugins/ikev2/test/test_ikev2.py b/src/plugins/ikev2/test/test_ikev2.py
index dea9a6a41c8..558e8a02f87 100644
--- a/src/plugins/ikev2/test/test_ikev2.py
+++ b/src/plugins/ikev2/test/test_ikev2.py
@@ -1422,6 +1422,20 @@ class Ikev2Params(object):
if udp_encap:
self.p.set_udp_encap(True)
+ if 'responder_hostname' in params:
+ hn = params['responder_hostname']
+ self.p.add_responder_hostname(hn)
+
+ # configure static dns record
+ self.vapi.dns_name_server_add_del(
+ is_ip6=0, is_add=1,
+ server_address=IPv4Address(u'8.8.8.8').packed)
+ self.vapi.dns_enable_disable(enable=1)
+
+ cmd = "dns cache add {} {}".format(hn['hostname'],
+ self.pg0.remote_ip4)
+ self.vapi.cli(cmd)
+
self.sa = IKEv2SA(self, i_id=idi['data'], r_id=idr['data'],
is_initiator=is_init,
id_type=self.p.local_id['id_type'],
@@ -1683,8 +1697,6 @@ class TestInitiatorPsk(TemplateInitiator, Ikev2Params):
self.config_params({
'is_initiator': False, # seen from test case perspective
# thus vpp is initiator
- 'responder': {'sw_if_index': self.pg0.sw_if_index,
- 'addr': self.pg0.remote_ip4},
'ike-crypto': ('AES-GCM-16ICV', 32),
'ike-integ': 'NULL',
'ike-dh': '3072MODPgr',
@@ -1697,7 +1709,9 @@ class TestInitiatorPsk(TemplateInitiator, Ikev2Params):
'crypto_alg': 12, # "aes-cbc"
'crypto_key_size': 256,
# "hmac-sha2-256-128"
- 'integ_alg': 12}})
+ 'integ_alg': 12},
+ 'responder_hostname': {'hostname': 'vpp.responder.org',
+ 'sw_if_index': self.pg0.sw_if_index}})
@tag_fixme_vpp_workers
diff --git a/src/plugins/ikev2/test/vpp_ikev2.py b/src/plugins/ikev2/test/vpp_ikev2.py
index dd1c3fc986e..de2081268ee 100644
--- a/src/plugins/ikev2/test/vpp_ikev2.py
+++ b/src/plugins/ikev2/test/vpp_ikev2.py
@@ -82,6 +82,9 @@ class Profile(VppObject):
'start_addr': start_addr,
'end_addr': end_addr}
+ def add_responder_hostname(self, hn):
+ self.responder_hostname = hn
+
def add_responder(self, responder):
self.responder = responder
@@ -138,6 +141,11 @@ class Profile(VppObject):
self.vapi.ikev2_set_responder(name=self.profile_name,
responder=self.responder)
+ if hasattr(self, 'responder_hostname'):
+ print(self.responder_hostname)
+ self.vapi.ikev2_set_responder_hostname(name=self.profile_name,
+ **self.responder_hostname)
+
if hasattr(self, 'ike_transforms'):
self.vapi.ikev2_set_ike_transforms(name=self.profile_name,
tr=self.ike_transforms)