diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/charon/config/policies/policy.c | 18 | ||||
-rw-r--r-- | src/charon/config/policies/policy.h | 30 | ||||
-rw-r--r-- | src/charon/config/traffic_selector.c | 28 | ||||
-rw-r--r-- | src/charon/config/traffic_selector.h | 2 | ||||
-rw-r--r-- | src/charon/encoding/payloads/notify_payload.h | 3 | ||||
-rw-r--r-- | src/charon/sa/child_sa.c | 56 | ||||
-rw-r--r-- | src/charon/sa/child_sa.h | 14 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.c | 3 | ||||
-rw-r--r-- | src/charon/sa/transactions/create_child_sa.c | 167 | ||||
-rw-r--r-- | src/charon/sa/transactions/ike_auth.c | 184 | ||||
-rw-r--r-- | src/charon/threads/kernel_interface.c | 15 | ||||
-rw-r--r-- | src/charon/threads/kernel_interface.h | 8 | ||||
-rwxr-xr-x | src/charon/threads/stroke_interface.c | 2 | ||||
-rw-r--r-- | src/starter/ipsec.conf.5 | 6 | ||||
-rw-r--r-- | src/starter/starterstroke.c | 1 | ||||
-rw-r--r-- | src/stroke/stroke.c | 1 | ||||
-rw-r--r-- | src/stroke/stroke.h | 1 |
17 files changed, 436 insertions, 103 deletions
diff --git a/src/charon/config/policies/policy.c b/src/charon/config/policies/policy.c index b52ae33ac..f7e2eb43c 100644 --- a/src/charon/config/policies/policy.c +++ b/src/charon/config/policies/policy.c @@ -130,6 +130,11 @@ struct private_policy_t { * 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; }; /** @@ -378,7 +383,6 @@ static dpd_action_t get_dpd_action(private_policy_t *this) return this->dpd_action; } - /** * Implementation of policy_t.add_my_traffic_selector */ @@ -424,6 +428,14 @@ static u_int32_t get_hard_lifetime(private_policy_t *this) } /** + * Implementation of policy_t.get_mode. + */ +static mode_t get_mode(private_policy_t *this) +{ + return this->mode; +} + +/** * Implements policy_t.get_ref. */ static void get_ref(private_policy_t *this) @@ -475,7 +487,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o 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); @@ -501,6 +513,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o 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; @@ -515,6 +528,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o this->updown = (updown == NULL) ? NULL : strdup(updown); this->hostaccess = hostaccess; this->dpd_action = dpd_action; + this->mode = mode; /* initialize private members*/ this->refcount = 1; diff --git a/src/charon/config/policies/policy.h b/src/charon/config/policies/policy.h index a040434c1..76b20f69b 100644 --- a/src/charon/config/policies/policy.h +++ b/src/charon/config/policies/policy.h @@ -53,6 +53,22 @@ enum dpd_action_t { }; /** + * @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. */ extern enum_name_t *dpd_action_names; @@ -291,6 +307,14 @@ struct policy_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. * * Get a new reference to this policy by increasing @@ -334,6 +358,7 @@ struct policy_t { * @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 * @@ -343,8 +368,7 @@ policy_t *policy_create(char *name, 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_ */ diff --git a/src/charon/config/traffic_selector.c b/src/charon/config/traffic_selector.c index 2b99b9180..2afeb5e48 100644 --- a/src/charon/config/traffic_selector.c +++ b/src/charon/config/traffic_selector.c @@ -447,15 +447,27 @@ static u_int8_t get_protocol(private_traffic_selector_t *this) */ 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; } diff --git a/src/charon/config/traffic_selector.h b/src/charon/config/traffic_selector.h index b611b611a..5d1ccaf2f 100644 --- a/src/charon/config/traffic_selector.h +++ b/src/charon/config/traffic_selector.h @@ -164,6 +164,8 @@ struct traffic_selector_t { * 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 diff --git a/src/charon/encoding/payloads/notify_payload.h b/src/charon/encoding/payloads/notify_payload.h index 2b419bb98..8861b9f4b 100644 --- a/src/charon/encoding/payloads/notify_payload.h +++ b/src/charon/encoding/payloads/notify_payload.h @@ -88,6 +88,8 @@ enum notify_type_t { NO_NATS_ALLOWED = 16402, /* repeated authentication extension, RFC4478 */ AUTH_LIFETIME = 16403, + /* BEET mode, not even a draft yet. private use */ + USE_BEET_MODE = 40960, }; /** @@ -97,7 +99,6 @@ enum notify_type_t { */ extern enum_name_t *notify_type_names; - /** * @brief Class representing an IKEv2-Notify Payload. * diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 343397787..874937dd2 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -167,6 +167,11 @@ struct private_child_sa_t { * Specifies if NAT traversal is used */ bool use_natt; + + /** + * mode this SA uses, tunnel/transport + */ + mode_t mode; }; /** @@ -439,7 +444,8 @@ static status_t alloc(private_child_sa_t *this, linked_list_t *proposals) 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; @@ -536,7 +542,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus 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; @@ -545,7 +551,8 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus 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; @@ -560,14 +567,14 @@ static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t * 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; } @@ -576,7 +583,8 @@ static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t * 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; @@ -584,7 +592,7 @@ static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_ 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; } @@ -592,7 +600,7 @@ static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_ /* 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; } @@ -600,7 +608,9 @@ static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_ 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; @@ -637,16 +647,16 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list /* 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) { @@ -673,7 +683,8 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list { this->state = CHILD_ROUTED; } - + /* needed to update hosts */ + this->mode = mode; return SUCCESS; } @@ -928,19 +939,19 @@ static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, ho 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) { @@ -1085,10 +1096,10 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other, 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; @@ -1124,6 +1135,7 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other, 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; diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index 5b1df9e6d..06362f35e 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -167,10 +167,12 @@ struct child_sa_t { * * @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. @@ -179,10 +181,12 @@ struct child_sa_t { * * @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 @@ -208,11 +212,11 @@ struct child_sa_t { * @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. diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 5aed70bda..af6060be9 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -1173,7 +1173,8 @@ static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t 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); diff --git a/src/charon/sa/transactions/create_child_sa.c b/src/charon/sa/transactions/create_child_sa.c index cd53c5eb9..37f35ec4c 100644 --- a/src/charon/sa/transactions/create_child_sa.c +++ b/src/charon/sa/transactions/create_child_sa.c @@ -120,6 +120,11 @@ struct private_create_child_sa_t { 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? */ bool lost; @@ -187,6 +192,31 @@ static void cancel(private_create_child_sa_t *this) } /** + * 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. */ static status_t get_request(private_create_child_sa_t *this, message_t **result) @@ -293,6 +323,28 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result) 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; @@ -374,6 +426,16 @@ static status_t process_notifys(private_create_child_sa_t *this, notify_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; @@ -414,28 +476,20 @@ static status_t process_notifys(private_create_child_sa_t *this, notify_payload_ } /** - * 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; } /** @@ -455,11 +509,11 @@ static status_t install_child_sa(private_create_child_sa_t *this, bool initiator 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) @@ -468,11 +522,11 @@ static status_t install_child_sa(private_create_child_sa_t *this, bool initiator } 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) { @@ -697,6 +751,44 @@ static status_t get_response(private_create_child_sa_t *this, message_t *request 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"); @@ -855,6 +947,38 @@ static status_t conclude(private_create_child_sa_t *this, message_t *response, 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) { @@ -985,6 +1109,7 @@ create_child_sa_t *create_child_sa_create(ike_sa_t *ike_sa) this->policy = NULL; this->tsi = NULL; this->tsr = NULL; + this->mode = MODE_TUNNEL; this->randomizer = randomizer_create(); this->failsig = CHILD_UP_FAILED; diff --git a/src/charon/sa/transactions/ike_auth.c b/src/charon/sa/transactions/ike_auth.c index ae155ec88..3ab4d8ae4 100644 --- a/src/charon/sa/transactions/ike_auth.c +++ b/src/charon/sa/transactions/ike_auth.c @@ -128,6 +128,11 @@ struct private_ike_auth_t { * reqid to use for CHILD_SA setup */ u_int32_t reqid; + + /** + * mode the CHILD_SA uses: tranport, tunnel, BEET + */ + mode_t mode; }; /** @@ -183,6 +188,30 @@ static void set_init_messages(private_ike_auth_t *this, chunk_t init_request, ch } /** + * 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. */ static status_t get_request(private_ike_auth_t *this, message_t **result) @@ -319,6 +348,28 @@ static status_t get_request(private_ike_auth_t *this, message_t **result) 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; @@ -376,6 +427,16 @@ static status_t process_notifies(private_ike_auth_t *this, notify_payload_t *not 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) @@ -395,30 +456,6 @@ static status_t process_notifies(private_ike_auth_t *this, notify_payload_t *not } /** - * 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 */ static void add_certificate_request(certreq_payload_t *certreq_payload, @@ -502,6 +539,23 @@ static void import_certificate(cert_payload_t *cert_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 */ static status_t install_child_sa(private_ike_auth_t *this, bool initiator) @@ -518,11 +572,13 @@ static status_t install_child_sa(private_ike_auth_t *this, bool initiator) 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) @@ -531,11 +587,13 @@ static status_t install_child_sa(private_ike_auth_t *this, bool initiator) } 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) { @@ -850,6 +908,44 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, 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"); @@ -1048,6 +1144,37 @@ static status_t conclude(private_ike_auth_t *this, message_t *response, } 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"); @@ -1126,6 +1253,7 @@ ike_auth_t *ike_auth_create(ike_sa_t *ike_sa) this->tsr = NULL; this->build_child = TRUE; this->reqid = 0; + this->mode = MODE_TUNNEL; return &this->public; } diff --git a/src/charon/threads/kernel_interface.c b/src/charon/threads/kernel_interface.c index 092e57ca4..074e7fcc8 100644 --- a/src/charon/threads/kernel_interface.c +++ b/src/charon/threads/kernel_interface.c @@ -503,7 +503,7 @@ static status_t add_sa(private_kernel_interface_t *this, 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]; @@ -529,7 +529,7 @@ static status_t add_sa(private_kernel_interface_t *this, 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 */ @@ -970,7 +970,8 @@ static status_t add_policy(private_kernel_interface_t *this, 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; @@ -992,7 +993,7 @@ static status_t add_policy(private_kernel_interface_t *this, 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); @@ -1068,7 +1069,7 @@ static status_t add_policy(private_kernel_interface_t *this, 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); @@ -1266,11 +1267,11 @@ kernel_interface_t *kernel_interface_create() /* 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; diff --git a/src/charon/threads/kernel_interface.h b/src/charon/threads/kernel_interface.h index 2655745a8..991d8e17c 100644 --- a/src/charon/threads/kernel_interface.h +++ b/src/charon/threads/kernel_interface.h @@ -118,6 +118,7 @@ struct kernel_interface_t { * @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 @@ -128,7 +129,8 @@ struct kernel_interface_t { 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. @@ -206,6 +208,7 @@ struct kernel_interface_t { * @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 @@ -216,7 +219,8 @@ struct kernel_interface_t { 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. diff --git a/src/charon/threads/stroke_interface.c b/src/charon/threads/stroke_interface.c index dd646aa85..a98284509 100755 --- a/src/charon/threads/stroke_interface.c +++ b/src/charon/threads/stroke_interface.c @@ -398,7 +398,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg) 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); diff --git a/src/starter/ipsec.conf.5 b/src/starter/ipsec.conf.5 index 981b8d33c..9ca2e6776 100644 --- a/src/starter/ipsec.conf.5 +++ b/src/starter/ipsec.conf.5 @@ -234,9 +234,11 @@ signifying that no IPsec processing should be done at all; 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) diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c index eff157add..41f67c891 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -194,6 +194,7 @@ int starter_stroke_add_conn(starter_conn_t *conn) 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) { diff --git a/src/stroke/stroke.c b/src/stroke/stroke.c index 2221915f0..31293a7d3 100644 --- a/src/stroke/stroke.c +++ b/src/stroke/stroke.c @@ -106,6 +106,7 @@ static int add_connection(char *name, 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; diff --git a/src/stroke/stroke.h b/src/stroke/stroke.h index c818075ac..bbc1e6e01 100644 --- a/src/stroke/stroke.h +++ b/src/stroke/stroke.h @@ -137,6 +137,7 @@ struct stroke_msg_t { char *name; int ikev2; int auth_method; + int mode; struct { char *ike; char *esp; |