From fc2d1c420f0cbe032f74bd51e8737e5635ef8743 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 27 Jun 2007 13:10:55 +0000 Subject: [PATCH] further mobike improvements, regarding to NAT-T --- src/charon/bus/bus.c | 2 +- src/charon/kernel/kernel_interface.c | 10 +++---- src/charon/kernel/kernel_interface.h | 18 ++---------- src/charon/sa/child_sa.c | 28 ++++++------------ src/charon/sa/child_sa.h | 13 ++++----- src/charon/sa/ike_sa.c | 13 +++++++-- src/charon/sa/ike_sa_manager.c | 2 ++ src/charon/sa/tasks/ike_mobike.c | 43 ++++++++++++++++++++++++---- src/charon/sa/tasks/ike_natd.c | 24 ++++++++-------- 9 files changed, 83 insertions(+), 70 deletions(-) diff --git a/src/charon/bus/bus.c b/src/charon/bus/bus.c index d1984d7f7..5fda36925 100644 --- a/src/charon/bus/bus.c +++ b/src/charon/bus/bus.c @@ -372,7 +372,7 @@ static void vsignal(private_bus_t *this, signal_t signal, level_t level, active_listener->format = format; va_copy(active_listener->args, args); active_listener->state = REGISTERED; - pthread_cond_signal(&active_listener->cond); + pthread_cond_broadcast(&active_listener->cond); } } diff --git a/src/charon/kernel/kernel_interface.c b/src/charon/kernel/kernel_interface.c index 76b488eee..63e265a94 100644 --- a/src/charon/kernel/kernel_interface.c +++ b/src/charon/kernel/kernel_interface.c @@ -1645,7 +1645,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, mode_t mode, + prf_plus_t *prf_plus, mode_t mode, bool encap, bool replace) { unsigned char request[BUFFER_SIZE]; @@ -1743,7 +1743,7 @@ static status_t add_sa(private_kernel_interface_t *this, /* TODO: add IPComp here */ - if (natt) + if (encap) { rthdr->rta_type = XFRMA_ENCAP; rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl)); @@ -1756,8 +1756,8 @@ static status_t add_sa(private_kernel_interface_t *this, struct xfrm_encap_tmpl* encap = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr); encap->encap_type = UDP_ENCAP_ESPINUDP; - encap->encap_sport = htons(natt->sport); - encap->encap_dport = htons(natt->dport); + encap->encap_sport = htons(src->get_port(src)); + encap->encap_dport = htons(dst->get_port(dst)); memset(&encap->encap_oa, 0, sizeof (xfrm_address_t)); /* encap_oa could probably be derived from the * traffic selectors [rfc4306, p39]. In the netlink kernel implementation @@ -2314,7 +2314,7 @@ 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*,mode_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*,mode_t,bool,bool))add_sa; this->public.update_sa = (status_t(*)(kernel_interface_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_t*,host_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; diff --git a/src/charon/kernel/kernel_interface.h b/src/charon/kernel/kernel_interface.h index d3d3c9b70..4474e7058 100644 --- a/src/charon/kernel/kernel_interface.h +++ b/src/charon/kernel/kernel_interface.h @@ -25,7 +25,6 @@ #ifndef KERNEL_INTERFACE_H_ #define KERNEL_INTERFACE_H_ -typedef struct natt_conf_t natt_conf_t; typedef enum policy_dir_t policy_dir_t; typedef struct kernel_interface_t kernel_interface_t; @@ -33,17 +32,6 @@ typedef struct kernel_interface_t kernel_interface_t; #include #include -/** - * Configuration for NAT-T - * - * @ingroup kernel - */ -struct natt_conf_t { - /** source port to use for UDP-encapsulated packets */ - u_int16_t sport; - /** dest port to use for UDP-encapsulated packets */ - u_int16_t dport; -}; /** * Direction of a policy. These are equal to those @@ -121,8 +109,8 @@ struct kernel_interface_t { * @param enc_alg Algorithm to use for encryption (ESP only) * @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 encap enable UDP encapsulation for NAT traversal * @param replace Should an already installed SA be updated? * @return * - SUCCESS @@ -133,8 +121,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, - mode_t mode, bool update); + prf_plus_t *prf_plus, mode_t mode, bool encap, + bool update); /** * @brief Update the hosts on an installed SA. diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index e5cddf04f..9fe19bcc7 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -138,9 +138,9 @@ struct private_child_sa_t { child_sa_state_t state; /** - * Specifies if NAT traversal is used + * Specifies if UDP encapsulation is enabled (NAT traversal) */ - bool use_natt; + bool encap; /** * mode this SA uses, tunnel/transport @@ -494,7 +494,6 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, algorithm_t int_algo_none = {AUTH_UNDEFINED, 0}; host_t *src; host_t *dst; - natt_conf_t *natt; status_t status; this->protocol = proposal->get_protocol(proposal); @@ -561,18 +560,6 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, int_algo = &int_algo_none; } - /* setup nat-t */ - if (this->use_natt) - { - natt = alloca(sizeof(natt_conf_t)); - natt->sport = src->get_port(src); - natt->dport = dst->get_port(dst); - } - else - { - natt = NULL; - } - soft = this->config->get_lifetime(this->config, TRUE); hard = this->config->get_lifetime(this->config, FALSE); @@ -582,7 +569,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, src, dst, spi, this->protocol, this->reqid, mine ? soft : 0, hard, enc_algo, int_algo, - prf_plus, natt, mode, mine); + prf_plus, mode, this->encap, mine); this->encryption = *enc_algo; this->integrity = *int_algo; @@ -784,7 +771,8 @@ static status_t get_use_time(private_child_sa_t *this, bool inbound, time_t *use /** * Implementation of child_sa_t.update_hosts. */ -static status_t update_hosts(private_child_sa_t *this, host_t *me, host_t *other) +static status_t update_hosts(private_child_sa_t *this, + host_t *me, host_t *other, bool encap) { /* anything changed at all? */ if (me->equals(me, this->me.addr) && other->equals(other, this->other.addr)) @@ -937,7 +925,7 @@ static void destroy(private_child_sa_t *this) */ child_sa_t * child_sa_create(host_t *me, host_t* other, identification_t *my_id, identification_t *other_id, - child_cfg_t *config, u_int32_t rekey, bool use_natt) + child_cfg_t *config, u_int32_t rekey, bool encap) { static u_int32_t reqid = 0; private_child_sa_t *this = malloc_thing(private_child_sa_t); @@ -951,7 +939,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc; 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*))update_hosts; + this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,bool))update_hosts; this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,mode_t))add_policies; this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors; this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time; @@ -970,7 +958,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->other.spi = 0; this->alloc_ah_spi = 0; this->alloc_esp_spi = 0; - this->use_natt = use_natt; + this->encap = encap; this->state = CHILD_CREATED; /* reuse old reqid if we are rekeying an existing CHILD_SA */ this->reqid = rekey ? rekey : ++reqid; diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index 0118df49f..b801dd012 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -34,11 +34,6 @@ typedef struct child_sa_t child_sa_t; #include #include -/** - * Where we should start with reqid enumeration - */ -#define REQID_START 2000000000 - /** * @brief States of a CHILD_SA */ @@ -207,9 +202,11 @@ struct child_sa_t { * @param this calling object * @param me the new local host * @param other the new remote host + * @param TRUE to use UDP encapsulation for NAT traversal * @return SUCCESS or FAILED */ - status_t (*update_hosts)(child_sa_t *this, host_t *me, host_t *other); + status_t (*update_hosts)(child_sa_t *this, host_t *me, host_t *other, + bool encap); /** * @brief Install the policies using some traffic selectors. @@ -295,13 +292,13 @@ struct child_sa_t { * @param other_id id of remote peer * @param config config to use for this CHILD_SA * @param reqid reqid of old CHILD_SA when rekeying, 0 otherwise - * @param use_natt TRUE if NAT traversal is used + * @param encap TRUE to enable UDP encapsulation (NAT traversal) * @return child_sa_t object * * @ingroup sa */ child_sa_t * child_sa_create(host_t *me, host_t *other, identification_t *my_id, identification_t* other_id, - child_cfg_t *config, u_int32_t reqid, bool use_natt); + child_cfg_t *config, u_int32_t reqid, bool encap); #endif /*CHILD_SA_H_*/ diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 1d6b8ec01..ab66b6d79 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -469,6 +469,7 @@ static void set_condition(private_ike_sa_t *this, ike_condition_t condition, { if (enable) { + this->conditions |= condition; switch (condition) { case COND_STALE: @@ -487,19 +488,24 @@ static void set_condition(private_ike_sa_t *this, ike_condition_t condition, default: break; } - this->conditions |= condition; } else { + this->conditions &= ~condition; switch (condition) { case COND_STALE: DBG1(DBG_IKE, "new route to %H found", this->other_host); break; + case COND_NAT_HERE: + case COND_NAT_THERE: + set_condition(this, COND_NAT_ANY, + has_condition(this, COND_NAT_HERE) || + has_condition(this, COND_NAT_THERE)); + break; default: break; } - this->conditions &= ~condition; } } } @@ -695,7 +701,8 @@ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other) iterator = this->child_sas->create_iterator(this->child_sas, TRUE); while (iterator->iterate(iterator, (void**)&child_sa)) { - child_sa->update_hosts(child_sa, this->my_host, this->other_host); + child_sa->update_hosts(child_sa, this->my_host, this->other_host, + has_condition(this, COND_NAT_ANY)); } iterator->destroy(iterator); } diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index 0a0d5e5cf..984811448 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -503,6 +503,8 @@ static ike_sa_t* checkout_by_peer(private_ike_sa_manager_t *this, host_t *found_my_host, *found_other_host; int wc; + break; + if (!wait_for_entry(this, entry)) { continue; diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c index 43ede2e57..1a6d76cb7 100644 --- a/src/charon/sa/tasks/ike_mobike.c +++ b/src/charon/sa/tasks/ike_mobike.c @@ -143,6 +143,16 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message) flush_additional_addresses(this); break; } + case NAT_DETECTION_SOURCE_IP: + case NAT_DETECTION_DESTINATION_IP: + { + /* NAT check in this MOBIKE exchange, create subtask for it */ + if (this->natd == NULL) + { + this->natd = ike_natd_create(this->ike_sa, this->initiator); + } + break; + } default: break; } @@ -205,10 +215,12 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message) { /* address change */ message->add_notify(message, FALSE, UPDATE_SA_ADDRESSES, chunk_empty); build_address_list(this, message); - /* TODO: NAT discovery */ - /* set new addresses */ this->ike_sa->update_hosts(this->ike_sa, this->me, this->other); + if (this->natd) + { + this->natd->task.build(&this->natd->task, message); + } } return NEED_MORE; @@ -219,13 +231,19 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message) */ static status_t process_r(private_ike_mobike_t *this, message_t *message) { - if ((message->get_exchange_type(message) == IKE_AUTH && - message->get_payload(message, SECURITY_ASSOCIATION)) || - message->get_exchange_type(message) == INFORMATIONAL) + if (message->get_exchange_type(message) == IKE_AUTH && + message->get_payload(message, SECURITY_ASSOCIATION)) { process_payloads(this, message); } - + else if (message->get_exchange_type(message) == INFORMATIONAL) + { + process_payloads(this, message); + if (this->natd) + { + this->natd->task.process(&this->natd->task, message); + } + } return NEED_MORE; } @@ -246,6 +264,10 @@ static status_t build_r(private_ike_mobike_t *this, message_t *message) } else if (message->get_exchange_type(message) == INFORMATIONAL) { + if (this->natd) + { + this->natd->task.build(&this->natd->task, message); + } return SUCCESS; } return NEED_MORE; @@ -260,10 +282,16 @@ static status_t process_i(private_ike_mobike_t *this, message_t *message) message->get_payload(message, SECURITY_ASSOCIATION)) { process_payloads(this, message); + return SUCCESS; } else if (message->get_exchange_type(message) == INFORMATIONAL) { + process_payloads(this, message); + if (this->natd) + { + this->natd->task.process(&this->natd->task, message); + } return SUCCESS; } return NEED_MORE; @@ -276,6 +304,9 @@ static void roam(private_ike_mobike_t *this, host_t *me, host_t *other) { this->me = me; this->other = other; + + /* include NAT detection when roaming */ + this->natd = ike_natd_create(this->ike_sa, this->initiator); } /** diff --git a/src/charon/sa/tasks/ike_natd.c b/src/charon/sa/tasks/ike_natd.c index db8a400cc..84a28d024 100644 --- a/src/charon/sa/tasks/ike_natd.c +++ b/src/charon/sa/tasks/ike_natd.c @@ -204,15 +204,11 @@ static void process_payloads(private_ike_natd_t *this, message_t *message) if (this->src_seen && this->dst_seen) { this->ike_sa->enable_extension(this->ike_sa, EXT_NATT); - - if (!this->dst_matched) - { - this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE, TRUE); - } - if (!this->src_matched) - { - this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE, TRUE); - } + + this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE, + !this->dst_matched); + this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE, + !this->src_matched); } } @@ -222,8 +218,11 @@ static void process_payloads(private_ike_natd_t *this, message_t *message) static status_t process_i(private_ike_natd_t *this, message_t *message) { process_payloads(this, message); - - if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) + + /* if peer supports NAT-T, we switch to port 4500 even + * if no NAT is detected. MOBIKE requires this. */ + if (message->get_exchange_type(message) == IKE_SA_INIT && + this->ike_sa->supports_extension(this->ike_sa, EXT_NATT)) { host_t *me, *other; @@ -297,7 +296,8 @@ static status_t build_r(private_ike_natd_t *this, message_t *message) host_t *me, *other; /* only add notifies on successfull responses. */ - if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL) + if (message->get_exchange_type(message) == IKE_SA_INIT && + message->get_payload(message, SECURITY_ASSOCIATION) == NULL) { return SUCCESS; }