* What to do with an SA when other peer seams to be dead?
*/
bool dpd_action;
+
+ /**
+ * Mode to propose for a initiated CHILD: tunnel/transport
+ */
+ mode_t mode;
};
/**
return this->dpd_action;
}
-
/**
* Implementation of policy_t.add_my_traffic_selector
*/
return this->hard_lifetime;
}
+/**
+ * Implementation of policy_t.get_mode.
+ */
+static mode_t get_mode(private_policy_t *this)
+{
+ return this->mode;
+}
+
/**
* Implements policy_t.get_ref.
*/
auth_method_t auth_method,
u_int32_t hard_lifetime, u_int32_t soft_lifetime,
u_int32_t jitter, char *updown, bool hostaccess,
- dpd_action_t dpd_action)
+ mode_t mode, dpd_action_t dpd_action)
{
private_policy_t *this = malloc_thing(private_policy_t);
this->public.get_dpd_action = (dpd_action_t (*) (policy_t*))get_dpd_action;
this->public.get_soft_lifetime = (u_int32_t (*) (policy_t *))get_soft_lifetime;
this->public.get_hard_lifetime = (u_int32_t (*) (policy_t *))get_hard_lifetime;
+ this->public.get_mode = (mode_t (*) (policy_t *))get_mode;
this->public.get_ref = (void (*) (policy_t*))get_ref;
this->public.destroy = (void (*) (policy_t*))destroy;
this->updown = (updown == NULL) ? NULL : strdup(updown);
this->hostaccess = hostaccess;
this->dpd_action = dpd_action;
+ this->mode = mode;
/* initialize private members*/
this->refcount = 1;
DPD_RESTART,
};
+/**
+ * @brief Mode of an IPsec SA.
+ *
+ * These are equal to those defined in XFRM, so don't change.
+ *
+ * @ingroup config
+ */
+enum mode_t {
+ /** transport mode, no inner address */
+ MODE_TRANSPORT = 0,
+ /** tunnel mode, inner and outer addresses */
+ MODE_TUNNEL = 1,
+ /** BEET mode, tunnel mode but fixed, bound inner addresses */
+ MODE_BEET = 4,
+};
+
/**
* enum names for dpd_action_t.
*/
*/
u_int32_t (*get_hard_lifetime) (policy_t *this);
+ /**
+ * @brief Get the mode to use for the CHILD_SA, tunnel, transport or BEET.
+ *
+ * @param this policy
+ * @return lifetime in seconds
+ */
+ mode_t (*get_mode) (policy_t *this);
+
/**
* @brief Get a new reference.
*
* @param jitter range of randomization time
* @param updown updown script to execute on up/down event
* @param hostaccess allow access to the host itself (used by the updown script)
+ * @param mode mode to propose for CHILD_SA, transport, tunnel or BEET
* @param dpd_action what to to with a CHILD_SA when other peer does not respond
* @return policy_t object
*
identification_t *my_id, identification_t *other_id,
auth_method_t auth_method,
u_int32_t hard_lifetime, u_int32_t soft_lifetime,
- u_int32_t jitter,
- char *updown, bool hostaccess,
- dpd_action_t dpd_action);
+ u_int32_t jitter, char *updown, bool hostaccess,
+ mode_t mode, dpd_action_t dpd_action);
#endif /* POLICY_H_ */
*/
static bool is_host(private_traffic_selector_t *this, host_t *host)
{
- chunk_t addr;
- int family = host->get_family(host);
-
- if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) ||
- (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE))
+ if (host)
{
- addr = host->get_address(host);
- if (memeq(addr.ptr, this->from, addr.len) &&
- memeq(addr.ptr, this->to, addr.len))
+ chunk_t addr;
+ int family = host->get_family(host);
+
+ if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) ||
+ (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE))
+ {
+ addr = host->get_address(host);
+ if (memeq(addr.ptr, this->from, addr.len) &&
+ memeq(addr.ptr, this->to, addr.len))
+ {
+ return TRUE;
+ }
+ }
+ }
+ else
+ {
+ size_t length = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
+
+ if (memeq(this->from, this->to, length))
{
return TRUE;
}
* Traffic selector may describe the end of *-to-host tunnel. In this
* case, the address range is a single address equal to the hosts
* peer address.
+ * If host is NULL, the traffic selector is checked if it is a single host,
+ * but not a specific one.
*
* @param this calling obect
* @param host host_t specifying the address range
NO_NATS_ALLOWED = 16402,
/* repeated authentication extension, RFC4478 */
AUTH_LIFETIME = 16403,
+ /* BEET mode, not even a draft yet. private use */
+ USE_BEET_MODE = 40960,
};
/**
*/
extern enum_name_t *notify_type_names;
-
/**
* @brief Class representing an IKEv2-Notify Payload.
*
* Specifies if NAT traversal is used
*/
bool use_natt;
+
+ /**
+ * mode this SA uses, tunnel/transport
+ */
+ mode_t mode;
};
/**
return SUCCESS;
}
-static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus, bool mine)
+static status_t install(private_child_sa_t *this, proposal_t *proposal,
+ mode_t mode, prf_plus_t *prf_plus, bool mine)
{
u_int32_t spi;
algorithm_t *enc_algo, *int_algo;
mine ? this->soft_lifetime : 0,
this->hard_lifetime,
enc_algo, int_algo,
- prf_plus, natt, mine);
+ prf_plus, natt, mode, mine);
this->encryption = *enc_algo;
this->integrity = *int_algo;
return status;
}
-static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus)
+static status_t add(private_child_sa_t *this, proposal_t *proposal,
+ mode_t mode, prf_plus_t *prf_plus)
{
u_int32_t outbound_spi, inbound_spi;
inbound_spi = proposal->get_spi(proposal);
/* install inbound SAs */
- if (install(this, proposal, prf_plus, TRUE) != SUCCESS)
+ if (install(this, proposal, mode, prf_plus, TRUE) != SUCCESS)
{
return FAILED;
}
/* install outbound SAs, restore spi*/
proposal->set_spi(proposal, outbound_spi);
- if (install(this, proposal, prf_plus, FALSE) != SUCCESS)
+ if (install(this, proposal, mode, prf_plus, FALSE) != SUCCESS)
{
return FAILED;
}
return SUCCESS;
}
-static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus)
+static status_t update(private_child_sa_t *this, proposal_t *proposal,
+ mode_t mode, prf_plus_t *prf_plus)
{
u_int32_t inbound_spi;
inbound_spi = proposal->get_spi(proposal);
/* install outbound SAs */
- if (install(this, proposal, prf_plus, FALSE) != SUCCESS)
+ if (install(this, proposal, mode, prf_plus, FALSE) != SUCCESS)
{
return FAILED;
}
/* restore spi */
proposal->set_spi(proposal, inbound_spi);
/* install inbound SAs */
- if (install(this, proposal, prf_plus, TRUE) != SUCCESS)
+ if (install(this, proposal, mode, prf_plus, TRUE) != SUCCESS)
{
return FAILED;
}
return SUCCESS;
}
-static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list, linked_list_t *other_ts_list)
+static status_t add_policies(private_child_sa_t *this,
+ linked_list_t *my_ts_list,
+ linked_list_t *other_ts_list, mode_t mode)
{
iterator_t *my_iter, *other_iter;
traffic_selector_t *my_ts, *other_ts;
/* install 3 policies: out, in and forward */
status = charon->kernel_interface->add_policy(charon->kernel_interface,
- this->me.addr, this->other.addr, my_ts, other_ts,
- POLICY_OUT, this->protocol, this->reqid, high_prio, FALSE);
+ this->me.addr, this->other.addr, my_ts, other_ts, POLICY_OUT,
+ this->protocol, this->reqid, high_prio, mode, FALSE);
status |= charon->kernel_interface->add_policy(charon->kernel_interface,
- this->other.addr, this->me.addr, other_ts, my_ts,
- POLICY_IN, this->protocol, this->reqid, high_prio, FALSE);
+ this->other.addr, this->me.addr, other_ts, my_ts, POLICY_IN,
+ this->protocol, this->reqid, high_prio, mode, FALSE);
status |= charon->kernel_interface->add_policy(charon->kernel_interface,
- this->other.addr, this->me.addr, other_ts, my_ts,
- POLICY_FWD, this->protocol, this->reqid, high_prio, FALSE);
+ this->other.addr, this->me.addr, other_ts, my_ts, POLICY_FWD,
+ this->protocol, this->reqid, high_prio, mode, FALSE);
if (status != SUCCESS)
{
{
this->state = CHILD_ROUTED;
}
-
+ /* needed to update hosts */
+ this->mode = mode;
return SUCCESS;
}
charon->kernel_interface,
new_me, new_other,
policy->my_ts, policy->other_ts,
- POLICY_OUT, this->protocol, this->reqid, TRUE, TRUE);
+ POLICY_OUT, this->protocol, this->reqid, TRUE, this->mode, TRUE);
status |= charon->kernel_interface->add_policy(
charon->kernel_interface,
new_other, new_me,
policy->other_ts, policy->my_ts,
- POLICY_IN, this->protocol, this->reqid, TRUE, TRUE);
+ POLICY_IN, this->protocol, this->reqid, TRUE, this->mode, TRUE);
status |= charon->kernel_interface->add_policy(
charon->kernel_interface,
new_other, new_me,
policy->other_ts, policy->my_ts,
- POLICY_FWD, this->protocol, this->reqid, TRUE, TRUE);
+ POLICY_FWD, this->protocol, this->reqid, TRUE, this->mode, TRUE);
if (status != SUCCESS)
{
this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi;
this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol;
this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
- this->public.add = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))add;
- this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update;
+ this->public.add = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))add;
+ this->public.update = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))update;
this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_diff_t,host_diff_t))update_hosts;
- this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies;
+ this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,mode_t))add_policies;
this->public.get_my_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_my_traffic_selectors;
this->public.get_other_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_other_traffic_selectors;
this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time;
this->my_ts = linked_list_create();
this->other_ts = linked_list_create();
this->protocol = PROTO_NONE;
+ this->mode = MODE_TUNNEL;
this->rekeying_transaction = NULL;
return &this->public;
*
* @param this calling object
* @param proposal proposal for which SPIs are allocated
+ * @param mode mode for the CHILD_SA
* @param prf_plus key material to use for key derivation
* @return SUCCESS or FAILED
*/
- status_t (*add)(child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus);
+ status_t (*add)(child_sa_t *this, proposal_t *proposal, mode_t mode,
+ prf_plus_t *prf_plus);
/**
* @brief Install the kernel SAs for a proposal, after SPIs have been allocated.
*
* @param this calling object
* @param proposal proposal for which SPIs are allocated
+ * @param mode mode for the CHILD_SA
* @param prf_plus key material to use for key derivation
* @return SUCCESS or FAILED
*/
- status_t (*update)(child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus);
+ status_t (*update)(child_sa_t *this, proposal_t *proposal, mode_t mode,
+ prf_plus_t *prf_plus);
/**
* @brief Update the hosts in the kernel SAs and policies
* @param this calling object
* @param my_ts traffic selectors for local site
* @param other_ts traffic selectors for remote site
+ * @param mode mode for the SA: tunnel/transport
* @return SUCCESS or FAILED
*/
- status_t (*add_policies)(child_sa_t *this,
- linked_list_t *my_ts_list,
- linked_list_t *other_ts_list);
+ status_t (*add_policies)(child_sa_t *this, linked_list_t *my_ts_list,
+ linked_list_t *other_ts_list, mode_t mode);
/**
* @brief Get the traffic selectors of added policies of local host.
child_sa->set_name(child_sa, policy->get_name(policy));
my_ts = policy->get_my_traffic_selectors(policy, this->my_host);
other_ts = policy->get_other_traffic_selectors(policy, this->other_host);
- status = child_sa->add_policies(child_sa, my_ts, other_ts);
+ status = child_sa->add_policies(child_sa, my_ts, other_ts,
+ policy->get_mode(policy));
my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
this->child_sas->insert_last(this->child_sas, child_sa);
*/
child_sa_t *rekeyed_sa;
+ /**
+ * mode of the CHILD_SA to create: transport/tunnel
+ */
+ mode_t mode;
+
/**
* Have we lost the simultaneous rekeying nonce compare?
*/
this->lost = TRUE;
}
+/**
+ * Build a notify message.
+ */
+static void build_notify(notify_type_t type, chunk_t data, message_t *message, bool flush_message)
+{
+ notify_payload_t *notify;
+
+ if (flush_message)
+ {
+ payload_t *payload;
+ iterator_t *iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ payload->destroy(payload);
+ iterator->remove(iterator);
+ }
+ iterator->destroy(iterator);
+ }
+
+ notify = notify_payload_create();
+ notify->set_notify_type(notify, type);
+ notify->set_notification_data(notify, data);
+ message->add_payload(message, (payload_t*)notify);
+}
+
/**
* Implementation of transaction_t.get_request.
*/
request->add_payload(request, (payload_t*)sa_payload);
}
+ /* notify for transport/BEET mode, we propose it
+ * independent of the traffic selectors */
+ switch (this->policy->get_mode(this->policy))
+ {
+ case MODE_TUNNEL:
+ /* is the default */
+ break;
+ case MODE_TRANSPORT:
+ if (this->ike_sa->is_natt_enabled(this->ike_sa))
+ {
+ DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
+ }
+ else
+ {
+ build_notify(USE_TRANSPORT_MODE, chunk_empty, request, FALSE);
+ }
+ break;
+ case MODE_BEET:
+ build_notify(USE_BEET_MODE, chunk_empty, request, FALSE);
+ break;
+ }
+
{ /* build the NONCE payload for us (initiator) */
nonce_payload_t *nonce_payload;
SIG(this->failsig, "received NO_PROPOSAL_CHOSEN notify");
return FAILED;
}
+ case USE_TRANSPORT_MODE:
+ {
+ this->mode = MODE_TRANSPORT;
+ return SUCCESS;
+ }
+ case USE_BEET_MODE:
+ {
+ this->mode = MODE_BEET;
+ return SUCCESS;
+ }
case REKEY_SA:
{
u_int32_t spi;
}
/**
- * Build a notify message.
+ * Check a list of traffic selectors if any selector belongs to host
*/
-static void build_notify(notify_type_t type, chunk_t data, message_t *message, bool flush_message)
+static bool ts_list_is_host(linked_list_t *list, host_t *host)
{
- notify_payload_t *notify;
+ traffic_selector_t *ts;
+ bool is_host = TRUE;
+ iterator_t *iterator = list->create_iterator(list, TRUE);
- if (flush_message)
+ while (is_host && iterator->iterate(iterator, (void**)&ts))
{
- payload_t *payload;
- iterator_t *iterator = message->get_payload_iterator(message);
- while (iterator->iterate(iterator, (void**)&payload))
- {
- payload->destroy(payload);
- iterator->remove(iterator);
- }
- iterator->destroy(iterator);
+ is_host = is_host && ts->is_host(ts, host);
}
-
- notify = notify_payload_create();
- notify->set_notify_type(notify, type);
- notify->set_notification_data(notify, data);
- message->add_payload(message, (payload_t*)notify);
+ iterator->destroy(iterator);
+ return is_host;
}
/**
if (initiator)
{
- status = this->child_sa->update(this->child_sa, this->proposal, prf_plus);
+ status = this->child_sa->update(this->child_sa, this->proposal, 1, prf_plus);
}
else
{
- status = this->child_sa->add(this->child_sa, this->proposal, prf_plus);
+ status = this->child_sa->add(this->child_sa, this->proposal, 1, prf_plus);
}
prf_plus->destroy(prf_plus);
if (status != SUCCESS)
}
if (initiator)
{
- status = this->child_sa->add_policies(this->child_sa, this->tsi, this->tsr);
+ status = this->child_sa->add_policies(this->child_sa, this->tsi, this->tsr, 1);
}
else
{
- status = this->child_sa->add_policies(this->child_sa, this->tsr, this->tsi);
+ status = this->child_sa->add_policies(this->child_sa, this->tsr, this->tsi, 1);
}
if (status != SUCCESS)
{
this->policy->get_hostaccess(this->policy),
use_natt);
this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
+
+ /* check mode, and include notify into reply */
+ switch (this->mode)
+ {
+ case MODE_TUNNEL:
+ /* is the default */
+ break;
+ case MODE_TRANSPORT:
+ if (!ts_list_is_host(this->tsi, other) ||
+ !ts_list_is_host(this->tsr, me))
+ {
+ this->mode = MODE_TUNNEL;
+ DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
+ }
+ else if (this->ike_sa->is_natt_enabled(this->ike_sa))
+ {
+ this->mode = MODE_TUNNEL;
+ DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
+ }
+ else
+ {
+ build_notify(USE_TRANSPORT_MODE, chunk_empty, response, FALSE);
+ }
+ break;
+ case MODE_BEET:
+ if (!ts_list_is_host(this->tsi, NULL) ||
+ !ts_list_is_host(this->tsr, NULL))
+ {
+ this->mode = MODE_TUNNEL;
+ DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
+ }
+ else
+ {
+ build_notify(USE_BEET_MODE, chunk_empty, response, FALSE);
+ }
+ break;
+ }
+
if (install_child_sa(this, FALSE) != SUCCESS)
{
SIG(this->failsig, "installing CHILD_SA failed, sending NO_PROPOSAL_CHOSEN notify");
SIG(this->failsig, "CHILD_SA negotiation failed, no CHILD_SA built");
return FAILED;
}
+
+ /* check mode if it is acceptable */
+ switch (this->mode)
+ {
+ case MODE_TUNNEL:
+ /* is the default */
+ break;
+ case MODE_TRANSPORT:
+ /* TODO: we should close the CHILD_SA if negotiated
+ * mode is not acceptable for us */
+ if (!ts_list_is_host(this->tsi, me) ||
+ !ts_list_is_host(this->tsr, other))
+ {
+ this->mode = MODE_TUNNEL;
+ DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
+ }
+ else if (this->ike_sa->is_natt_enabled(this->ike_sa))
+ {
+ this->mode = MODE_TUNNEL;
+ DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
+ }
+ break;
+ case MODE_BEET:
+ if (!ts_list_is_host(this->tsi, NULL) ||
+ !ts_list_is_host(this->tsr, NULL))
+ {
+ this->mode = MODE_TUNNEL;
+ DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
+ }
+ break;
+ }
+
new_child = this->child_sa;
if (install_child_sa(this, TRUE) != SUCCESS)
{
this->policy = NULL;
this->tsi = NULL;
this->tsr = NULL;
+ this->mode = MODE_TUNNEL;
this->randomizer = randomizer_create();
this->failsig = CHILD_UP_FAILED;
* reqid to use for CHILD_SA setup
*/
u_int32_t reqid;
+
+ /**
+ * mode the CHILD_SA uses: tranport, tunnel, BEET
+ */
+ mode_t mode;
};
/**
this->init_response = init_response;
}
+/**
+ * Build a notify message.
+ */
+static void build_notify(notify_type_t type, message_t *message, bool flush_message)
+{
+ notify_payload_t *notify;
+
+ if (flush_message)
+ {
+ payload_t *payload;
+ iterator_t *iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ payload->destroy(payload);
+ iterator->remove(iterator);
+ }
+ iterator->destroy(iterator);
+ }
+
+ notify = notify_payload_create();
+ notify->set_notify_type(notify, type);
+ message->add_payload(message, (payload_t*)notify);
+}
+
/**
* Implementation of transaction_t.get_request.
*/
request->add_payload(request, (payload_t*)sa_payload);
}
+ /* notify for transport/BEET mode, we propose it
+ * independent of the traffic selectors */
+ switch (this->policy->get_mode(this->policy))
+ {
+ case MODE_TUNNEL:
+ /* is the default */
+ break;
+ case MODE_TRANSPORT:
+ if (this->ike_sa->is_natt_enabled(this->ike_sa))
+ {
+ DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
+ }
+ else
+ {
+ build_notify(USE_TRANSPORT_MODE, request, FALSE);
+ }
+ break;
+ case MODE_BEET:
+ build_notify(USE_BEET_MODE, request, FALSE);
+ break;
+ }
+
{ /* build TSi payload */
linked_list_t *ts_list;
ts_payload_t *ts_payload;
this->build_child = FALSE;
return SUCCESS;
}
+ case USE_TRANSPORT_MODE:
+ {
+ this->mode = MODE_TRANSPORT;
+ return SUCCESS;
+ }
+ case USE_BEET_MODE:
+ {
+ this->mode = MODE_BEET;
+ return SUCCESS;
+ }
default:
{
if (notify_type < 16383)
}
}
-/**
- * Build a notify message.
- */
-static void build_notify(notify_type_t type, message_t *message, bool flush_message)
-{
- notify_payload_t *notify;
-
- if (flush_message)
- {
- payload_t *payload;
- iterator_t *iterator = message->get_payload_iterator(message);
- while (iterator->iterate(iterator, (void**)&payload))
- {
- payload->destroy(payload);
- iterator->remove(iterator);
- }
- iterator->destroy(iterator);
- }
-
- notify = notify_payload_create();
- notify->set_notify_type(notify, type);
- message->add_payload(message, (payload_t*)notify);
-}
-
/**
* Import certificate requests from a certreq payload
*/
}
}
+/**
+ * Check a list of traffic selectors if any selector belongs to host
+ */
+static bool ts_list_is_host(linked_list_t *list, host_t *host)
+{
+ traffic_selector_t *ts;
+ bool is_host = TRUE;
+ iterator_t *iterator = list->create_iterator(list, TRUE);
+
+ while (is_host && iterator->iterate(iterator, (void**)&ts))
+ {
+ is_host = is_host && ts->is_host(ts, host);
+ }
+ iterator->destroy(iterator);
+ return is_host;
+}
+
/**
* Install a CHILD_SA for usage
*/
if (initiator)
{
- status = this->child_sa->update(this->child_sa, this->proposal, prf_plus);
+ status = this->child_sa->update(this->child_sa, this->proposal,
+ this->mode, prf_plus);
}
else
{
- status = this->child_sa->add(this->child_sa, this->proposal, prf_plus);
+ status = this->child_sa->add(this->child_sa, this->proposal,
+ this->mode, prf_plus);
}
prf_plus->destroy(prf_plus);
if (status != SUCCESS)
}
if (initiator)
{
- status = this->child_sa->add_policies(this->child_sa, this->tsi, this->tsr);
+ status = this->child_sa->add_policies(this->child_sa, this->tsi,
+ this->tsr, this->mode);
}
else
{
- status = this->child_sa->add_policies(this->child_sa, this->tsr, this->tsi);
+ status = this->child_sa->add_policies(this->child_sa, this->tsr,
+ this->tsi, this->mode);
}
if (status != SUCCESS)
{
this->policy->get_hostaccess(this->policy),
use_natt);
this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
+
+ /* check mode, and include notify into reply */
+ switch (this->mode)
+ {
+ case MODE_TUNNEL:
+ /* is the default */
+ break;
+ case MODE_TRANSPORT:
+ if (!ts_list_is_host(this->tsi, other) ||
+ !ts_list_is_host(this->tsr, me))
+ {
+ this->mode = MODE_TUNNEL;
+ DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
+ }
+ else if (this->ike_sa->is_natt_enabled(this->ike_sa))
+ {
+ this->mode = MODE_TUNNEL;
+ DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
+ }
+ else
+ {
+ build_notify(USE_TRANSPORT_MODE, response, FALSE);
+ }
+ break;
+ case MODE_BEET:
+ if (!ts_list_is_host(this->tsi, NULL) ||
+ !ts_list_is_host(this->tsr, NULL))
+ {
+ this->mode = MODE_TUNNEL;
+ DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
+ }
+ else
+ {
+ build_notify(USE_BEET_MODE, response, FALSE);
+ }
+ break;
+ }
+
if (install_child_sa(this, FALSE) != SUCCESS)
{
SIG(CHILD_UP_FAILED, "installing CHILD_SA failed, no CHILD_SA created");
}
else
{
+ /* check mode if it is acceptable */
+ switch (this->mode)
+ {
+ case MODE_TUNNEL:
+ /* is the default */
+ break;
+ case MODE_TRANSPORT:
+ /* TODO: we should close the CHILD_SA if negotiated
+ * mode is not acceptable for us */
+ if (!ts_list_is_host(this->tsi, me) ||
+ !ts_list_is_host(this->tsr, other))
+ {
+ this->mode = MODE_TUNNEL;
+ DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
+ }
+ else if (this->ike_sa->is_natt_enabled(this->ike_sa))
+ {
+ this->mode = MODE_TUNNEL;
+ DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
+ }
+ break;
+ case MODE_BEET:
+ if (!ts_list_is_host(this->tsi, NULL) ||
+ !ts_list_is_host(this->tsr, NULL))
+ {
+ this->mode = MODE_TUNNEL;
+ DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
+ }
+ break;
+ }
+
if (install_child_sa(this, TRUE) != SUCCESS)
{
SIG(CHILD_UP_FAILED, "installing CHILD_SA failed, no CHILD_SA built");
this->tsr = NULL;
this->build_child = TRUE;
this->reqid = 0;
+ this->mode = MODE_TUNNEL;
return &this->public;
}
protocol_id_t protocol, u_int32_t reqid,
u_int64_t expire_soft, u_int64_t expire_hard,
algorithm_t *enc_alg, algorithm_t *int_alg,
- prf_plus_t *prf_plus, natt_conf_t *natt,
+ prf_plus_t *prf_plus, natt_conf_t *natt, mode_t mode,
bool replace)
{
unsigned char request[BUFFER_SIZE];
sa->id.spi = spi;
sa->id.proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
sa->family = src->get_family(src);
- sa->mode = TRUE; /* tunnel mode */
+ sa->mode = mode;
sa->replay_window = 32;
sa->reqid = reqid;
/* we currently do not expire SAs by volume/packet count */
traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
policy_dir_t direction, protocol_id_t protocol,
- u_int32_t reqid, bool high_prio, bool update)
+ u_int32_t reqid, bool high_prio, mode_t mode,
+ bool update)
{
iterator_t *iterator;
kernel_policy_t *current, *policy;
iterator = this->policies->create_iterator(this->policies, TRUE);
while (iterator->iterate(iterator, (void**)¤t))
{
- if (memcmp(current, policy, sizeof(struct xfrm_selector)) == 0 &&
+ if (memcmp(¤t->sel, &policy->sel, sizeof(struct xfrm_selector)) == 0 &&
policy->direction == current->direction)
{
free(policy);
tmpl->reqid = reqid;
tmpl->id.proto = (protocol == PROTO_AH) ? KERNEL_AH : KERNEL_ESP;
tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
- tmpl->mode = TRUE;
+ tmpl->mode = mode;
tmpl->family = src->get_family(src);
host2xfrm(src, &tmpl->saddr);
/* public functions */
this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
- this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,natt_conf_t*,bool))add_sa;
+ this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,natt_conf_t*,mode_t,bool))add_sa;
this->public.update_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_diff_t,host_diff_t))update_sa;
this->public.query_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t*))query_sa;
this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_sa;
- this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,bool))add_policy;
+ this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,mode_t,bool))add_policy;
this->public.query_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t*))query_policy;
this->public.del_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t))del_policy;
this->public.destroy = (void(*)(kernel_interface_t*)) destroy;
* @param int_alg Algorithm to use for integrity protection
* @param prf_plus PRF to derive keys from
* @param natt NAT-T Configuration, or NULL of no NAT-T used
+ * @param mode mode of the SA (tunnel, transport)
* @param replace Should an already installed SA be updated?
* @return
* - SUCCESS
protocol_id_t protocol, u_int32_t reqid,
u_int64_t expire_soft, u_int64_t expire_hard,
algorithm_t *enc_alg, algorithm_t *int_alg,
- prf_plus_t *prf_plus, natt_conf_t *natt, bool update);
+ prf_plus_t *prf_plus, natt_conf_t *natt,
+ mode_t mode, bool update);
/**
* @brief Update the hosts on an installed SA.
* @param protocol protocol to use to protect traffic (AH/ESP)
* @param reqid uniqe ID of an SA to use to enforce policy
* @param high_prio if TRUE, uses a higher priority than any with FALSE
+ * @param mode mode of SA (tunnel, transport)
* @param update update an existing policy, if TRUE
* @return
* - SUCCESS
traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
policy_dir_t direction, protocol_id_t protocol,
- u_int32_t reqid, bool high_prio, bool update);
+ u_int32_t reqid, bool high_prio,
+ mode_t mode, bool update);
/**
* @brief Query the use time of a policy.
msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100,
msg->add_conn.me.updown, msg->add_conn.me.hostaccess,
- msg->add_conn.dpd.action);
+ msg->add_conn.mode, msg->add_conn.dpd.action);
policy->add_my_traffic_selector(policy, my_ts);
policy->add_other_traffic_selector(policy, other_ts);
policy->add_authorities(policy, my_ca, other_ca);
signifying that packets should be discarded; and
.BR reject ,
signifying that packets should be discarded and a diagnostic ICMP returned.
-Charon currently supports only the
+Charon currently supports only
.BR tunnel
-connection type.
+and
+.BR transport
+connection types.
.TP
.B left
(required)
msg.add_conn.name = push_string(&msg, connection_name(conn));
msg.add_conn.auth_method = (conn->policy & POLICY_PSK)?
SHARED_KEY_MESSAGE_INTEGRITY_CODE : RSA_DIGITAL_SIGNATURE;
+ msg.add_conn.mode = (conn->policy & POLICY_TUNNEL) ? 1 : 0;
if (conn->policy & POLICY_DONT_REKEY)
{
msg.add_conn.name = push_string(&msg, name);
msg.add_conn.ikev2 = 1;
+ msg.add_conn.mode = 1;
msg.add_conn.rekey.reauth = 0;
msg.add_conn.rekey.ipsec_lifetime = 0;
char *name;
int ikev2;
int auth_method;
+ int mode;
struct {
char *ike;
char *esp;