option status="in_progress";
};
+/** \brief IKEv2: Disable NAT traversal
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param name - IKEv2 profile name
+*/
+autoreply define ikev2_profile_disable_natt
+{
+ u32 client_index;
+ u32 context;
+
+ string name[64];
+ option status="in_progress";
+};
+
/** \brief IKEv2: Set IKEv2 profile traffic selector parameters
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
static_always_inline u16
ikev2_get_port (ikev2_sa_t * sa)
{
- return sa->natt ? IKEV2_PORT_NATT : IKEV2_PORT;
+ return ikev2_natt_active (sa) ? IKEV2_PORT_NATT : IKEV2_PORT;
}
static_always_inline int
sa->profile_index = sai->profile_index;
sa->tun_itf = sai->tun_itf;
sa->is_tun_itf_set = sai->is_tun_itf_set;
+ sa->natt_state = sai->natt_state;
sa->i_id.data = _(sai->i_id.data);
sa->r_id.data = _(sai->r_id.data);
sa->i_auth.method = sai->i_auth.method;
udp->src_port);
if (clib_memcmp (src_sha, n->data, vec_len (src_sha)))
{
- sa->natt = 1;
+ if (sa->natt_state == IKEV2_NATT_ENABLED)
+ sa->natt_state = IKEV2_NATT_ACTIVE;
ikev2_elog_uint (IKEV2_LOG_DEBUG, "ispi %lx initiator"
" behind NAT", sa->ispi);
}
udp->dst_port);
if (clib_memcmp (dst_sha, n->data, vec_len (dst_sha)))
{
- sa->natt = 1;
+ if (sa->natt_state == IKEV2_NATT_ENABLED)
+ sa->natt_state = IKEV2_NATT_ACTIVE;
ikev2_elog_uint (IKEV2_LOG_DEBUG, "ispi %lx responder"
" (self) behind NAT", sa->ispi);
}
udp->dst_port);
if (clib_memcmp (dst_sha, n->data, vec_len (dst_sha)))
{
- sa->natt = 1;
+ if (sa->natt_state == IKEV2_NATT_ENABLED)
+ sa->natt_state = IKEV2_NATT_ACTIVE;
ikev2_elog_uint (IKEV2_LOG_DEBUG, "ispi %lx initiator"
" (self) behind NAT", sa->ispi);
}
a.flags |= IPSEC_SA_FLAG_IS_TUNNEL;
a.flags |= IPSEC_SA_FLAG_UDP_ENCAP;
}
- if (sa->natt)
+ if (ikev2_natt_active (sa))
a.flags |= IPSEC_SA_FLAG_UDP_ENCAP;
a.is_rekey = is_rekey;
a.salt_remote = child->salt_ei;
a.salt_local = child->salt_er;
}
- a.dst_port = sa->natt ? sa->dst_port : sa->ipsec_over_udp_port;
+ a.dst_port =
+ ikev2_natt_active (sa) ? sa->dst_port : sa->ipsec_over_udp_port;
a.src_port = sa->ipsec_over_udp_port;
}
clib_net_to_host_u16 (ikev2_get_port (sa0));
if (udp0->dst_port == clib_net_to_host_u16 (IKEV2_PORT_NATT)
- && sa0->natt)
+ && ikev2_natt_active (sa0))
{
if (!has_non_esp_marker)
slen = ikev2_insert_non_esp_marker (ike0, slen);
if (~0 == len)
return;
- if (sa->natt)
+ if (ikev2_natt_active (sa))
len = ikev2_insert_non_esp_marker (ike0, len);
if (sa->is_initiator)
sa.state = IKEV2_STATE_SA_INIT;
sa.tun_itf = p->tun_itf;
sa.udp_encap = p->udp_encap;
+ if (p->natt_disabled)
+ sa.natt_state = IKEV2_NATT_DISABLED;
sa.ipsec_over_udp_port = p->ipsec_over_udp_port;
sa.is_tun_itf_set = 1;
sa.initial_contact = 1;
if (~0 == len)
return;
- if (sa->natt)
+ if (ikev2_natt_active (sa))
len = ikev2_insert_non_esp_marker (ike0, len);
ikev2_send_ike (vm, &sa->iaddr, &sa->raddr, bi0, len,
ikev2_get_port (sa), sa->dst_port, sa->sw_if_index);
if (~0 == len)
return;
- if (sa->natt)
+ if (ikev2_natt_active (sa))
len = ikev2_insert_non_esp_marker (ike0, len);
ikev2_send_ike (vm, &sa->iaddr, &sa->raddr, bi0, len,
ikev2_get_port (sa), ikev2_get_port (sa), sa->sw_if_index);
return 0;
}
+clib_error_t *
+ikev2_profile_natt_disable (u8 * name)
+{
+ ikev2_profile_t *p = ikev2_profile_index_by_name (name);
+ if (!p)
+ return clib_error_return (0, "unknown profile %v", name);
+
+ p->natt_disabled = 1;
+ return 0;
+}
+
static void
ikev2_mngr_process_ipsec_sa (ipsec_sa_t * ipsec_sa)
{
if (~0 == len)
return;
- if (sa->natt)
+ if (ikev2_natt_active (sa))
len = ikev2_insert_non_esp_marker (ike0, len);
if (sa->is_initiator)
rmp->profile.udp_encap = profile->udp_encap;
rmp->profile.tun_itf = profile->tun_itf;
-
+ rmp->profile.natt_disabled = profile->natt_disabled;
rmp->profile.ipsec_over_udp_port = profile->ipsec_over_udp_port;
rmp->profile.lifetime = profile->lifetime;
REPLY_MACRO (VL_API_IKEV2_INITIATE_DEL_CHILD_SA_REPLY);
}
+static void
+ vl_api_ikev2_profile_disable_natt_t_handler
+ (vl_api_ikev2_profile_disable_natt_t * mp)
+{
+ vl_api_ikev2_profile_disable_natt_reply_t *rmp;
+ int rv = 0;
+
+#if WITH_LIBSSL > 0
+ clib_error_t *error;
+
+ u8 *tmp = format (0, "%s", mp->name);
+ error = ikev2_profile_natt_disable (tmp);
+ vec_free (tmp);
+ if (error)
+ rv = VNET_API_ERROR_UNSPECIFIED;
+#else
+ rv = VNET_API_ERROR_UNIMPLEMENTED;
+#endif
+
+ REPLY_MACRO (VL_API_IKEV2_PROFILE_DISABLE_NATT_REPLY);
+}
+
static void
vl_api_ikev2_initiate_rekey_child_sa_t_handler
(vl_api_ikev2_initiate_rekey_child_sa_t * mp)
r = clib_error_return (0, "Error: %U", format_vnet_api_errno, rv);
goto done;
}
+ else if (unformat (line_input, "set %U disable natt",
+ unformat_ikev2_token, &name))
+ {
+ r = ikev2_profile_natt_disable (name);
+ goto done;
+ }
else
break;
}
"ikev2 profile set <id> ike-crypto-alg <crypto alg> <key size> ike-integ-alg <integ alg> ike-dh <dh type>\n"
"ikev2 profile set <id> esp-crypto-alg <crypto alg> <key size> "
"[esp-integ-alg <integ alg>]\n"
- "ikev2 profile set <id> sa-lifetime <seconds> <jitter> <handover> <max bytes>",
+ "ikev2 profile set <id> sa-lifetime <seconds> <jitter> <handover> <max bytes>"
+ "ikev2 profile set <id> disable natt\n",
.function = ikev2_profile_add_del_command_fn,
};
/* *INDENT-ON* */
if (p->udp_encap)
vlib_cli_output(vm, " udp-encap");
+ if (p->natt_disabled)
+ vlib_cli_output(vm, " NAT-T disabled");
+
if (p->ipsec_over_udp_port != IPSEC_UDP_PORT_NONE)
vlib_cli_output(vm, " ipsec-over-udp port %d", p->ipsec_over_udp_port);
u32 tun_itf;
u8 udp_encap;
+ u8 natt_disabled;
} ikev2_profile_t;
+typedef enum
+{
+ /* SA will switch to port 4500 when NAT is detected.
+ * This is the default. */
+ IKEV2_NATT_ENABLED,
+
+ /* Do nothing when NAT is detected */
+ IKEV2_NATT_DISABLED,
+
+ /* NAT was detected and port switched to 4500 */
+ IKEV2_NATT_ACTIVE,
+} ikev2_natt_state_t;
+
+#define ikev2_natt_active(_sa) ((_sa)->natt_state == IKEV2_NATT_ACTIVE)
+
typedef struct
{
ikev2_state_t state;
u32 sw_if_index;
/* is NAT traversal mode */
- u8 natt;
+ ikev2_natt_state_t natt_state;
u8 keys_generated;
} ikev2_sa_t;
int ikev2_set_log_level (ikev2_log_level_t log_level);
u8 *ikev2_find_ike_notify_payload (ike_header_t * ike, u32 msg_type);
void ikev2_disable_dpd (void);
+clib_error_t *ikev2_profile_natt_disable (u8 * name);
static_always_inline ikev2_main_per_thread_data_t *
ikev2_get_per_thread_data ()
vat_main_t *vat_main;
} ikev2_test_main_t;
+static const char *valid_chars = "a-zA-Z0-9_";
ikev2_test_main_t ikev2_test_main;
uword
return s;
}
+static int
+api_ikev2_profile_disable_natt (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_ikev2_profile_disable_natt_t *mp;
+ u8 *name = 0;
+ int ret;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "%U", unformat_token, valid_chars, &name))
+ vec_add1 (name, 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_PROFILE_DISABLE_NATT, mp);
+
+ clib_memcpy (mp->name, name, vec_len (name));
+ vec_free (name);
+
+ S (mp);
+ W (ret);
+ return ret;
+}
+
static int
api_ikev2_profile_dump (vat_main_t * vam)
{
if (p->udp_encap)
fformat (vam->ofp, " udp-encap\n");
+ if (p->natt_disabled)
+ fformat (vam->ofp, " NAT-T disabled\n");
+
u32 ipsec_over_udp_port = clib_net_to_host_u16 (p->ipsec_over_udp_port);
if (ipsec_over_udp_port != IPSEC_UDP_PORT_NONE)
fformat (vam->ofp, " ipsec-over-udp port %d\n", ipsec_over_udp_port);
u8 *name = 0;
int ret;
- const char *valid_chars = "a-zA-Z0-9_";
-
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "del"))
u8 is_hex = 0;
int ret;
- const char *valid_chars = "a-zA-Z0-9_";
-
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "name %U", unformat_token, valid_chars, &name))
ip_address_t ip;
int ret;
- const char *valid_chars = "a-zA-Z0-9_";
-
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "name %U", unformat_token, valid_chars, &name))
u32 proto = 0, start_port = 0, end_port = (u32) ~ 0;
ip_address_t start_addr, end_addr;
u8 start_addr_set = 0, end_addr_set = 0;
-
- const char *valid_chars = "a-zA-Z0-9_";
int ret;
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
int ret;
u8 *name = 0;
- const char *valid_chars = "a-zA-Z0-9_";
-
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "%U udp-encap", unformat_token, valid_chars, &name))
u32 sw_if_index = ~0;
ip_address_t address;
- const char *valid_chars = "a-zA-Z0-9_";
-
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat
u8 *name = 0;
u32 crypto_alg, crypto_key_size, integ_alg, dh_group;
- const char *valid_chars = "a-zA-Z0-9_";
-
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "%U %d %d %d %d", unformat_token, valid_chars, &name,
u8 *name = 0;
u32 crypto_alg, crypto_key_size, integ_alg;
- const char *valid_chars = "a-zA-Z0-9_";
-
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "%U %d %d %d", unformat_token, valid_chars, &name,
u64 lifetime, lifetime_maxdata;
u32 lifetime_jitter, handover;
- const char *valid_chars = "a-zA-Z0-9_";
-
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "%U %lu %u %u %lu", unformat_token, valid_chars, &name,
int ret;
u8 *name = 0;
- const char *valid_chars = "a-zA-Z0-9_";
-
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "%U", unformat_token, valid_chars, &name))
u16 ipsec_over_udp_port;
u32 tun_itf;
bool udp_encap;
+ bool natt_disabled;
vl_api_ikev2_auth_t auth;
};
p.set_lifetime_data(cfg['lifetime_data'])
if 'tun_itf' in cfg:
p.set_tunnel_interface(cfg['tun_itf'])
+ if 'natt_disabled' in cfg and cfg['natt_disabled']:
+ p.disable_natt()
p.add_vpp_config()
return p
conf = {
'p1': {
'name': 'p1',
+ 'natt_disabled': True,
'loc_id': ('fqdn', b'vpp.home'),
'rem_id': ('fqdn', b'roadwarrior.example.com'),
'loc_ts': loc_ts4,
self.verify_ike_transforms(ap.ike_ts, cp['ike_ts'])
self.verify_esp_transforms(ap.esp_ts, cp['esp_ts'])
self.verify_auth(ap.auth, cp['auth'])
+ natt_dis = False if 'natt_disabled' not in cp else cp['natt_disabled']
+ self.assertTrue(natt_dis == ap.natt_disabled)
+
if 'lifetime_data' in cp:
self.verify_lifetime_data(ap, cp['lifetime_data'])
self.assertEqual(ap.ipsec_over_udp_port, cp['ipsec_over_udp_port'])
self.vapi = test.vapi
self.profile_name = profile_name
self.udp_encap = False
+ self.natt = True
+
+ def disable_natt(self):
+ self.natt = False
def add_auth(self, method, data, is_hex=False):
if isinstance(method, int):
self.vapi.ikev2_set_tunnel_interface(name=self.profile_name,
sw_if_index=self.tun_itf)
+ if not self.natt:
+ self.vapi.ikev2_profile_disable_natt(name=self.profile_name)
+
def query_vpp_config(self):
res = self.vapi.ikev2_profile_dump()
for r in res: