diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/charon/daemon.c | 3 | ||||
-rw-r--r-- | src/charon/encoding/payloads/notify_payload.c | 8 | ||||
-rw-r--r-- | src/charon/encoding/payloads/notify_payload.h | 2 | ||||
-rw-r--r-- | src/charon/kernel/kernel_interface.c | 32 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.c | 33 | ||||
-rw-r--r-- | src/charon/sa/ike_sa_manager.c | 1 | ||||
-rw-r--r-- | src/charon/sa/task_manager.c | 63 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_mobike.c | 51 |
8 files changed, 153 insertions, 40 deletions
diff --git a/src/charon/daemon.c b/src/charon/daemon.c index 088bbf63b..37699f83f 100644 --- a/src/charon/daemon.c +++ b/src/charon/daemon.c @@ -381,6 +381,9 @@ private_daemon_t *daemon_create(void) sigaddset(&action.sa_mask, SIGHUP); sigaction(SIGSEGV, &action, NULL); sigaction(SIGILL, &action, NULL); + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); + pthread_sigmask(SIG_SETMASK, &action.sa_mask, 0); return this; diff --git a/src/charon/encoding/payloads/notify_payload.c b/src/charon/encoding/payloads/notify_payload.c index ca92fc1bf..d700965d6 100644 --- a/src/charon/encoding/payloads/notify_payload.c +++ b/src/charon/encoding/payloads/notify_payload.c @@ -47,14 +47,16 @@ ENUM_NEXT(notify_type_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL "INVALID_KE_PAYLOAD"); ENUM_NEXT(notify_type_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD, "AUTHENTICATION_FAILED"); -ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, INVALID_SELECTORS, AUTHENTICATION_FAILED, +ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, UNEXPECTED_NAT_DETECTED, AUTHENTICATION_FAILED, "SINGLE_PAIR_REQUIRED", "NO_ADDITIONAL_SAS", "INTERNAL_ADDRESS_FAILURE", "FAILED_CP_REQUIRED", "TS_UNACCEPTABLE", - "INVALID_SELECTORS"); -ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, INVALID_SELECTORS, + "INVALID_SELECTORS", + "UNACCEPTABLE_ADDRESSES", + "UNEXPECTED_NAT_DETECTED"); +ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NAT_DETECTED, "INITIAL_CONTACT", "SET_WINDOW_SIZE", "ADDITIONAL_TS_POSSIBLE", diff --git a/src/charon/encoding/payloads/notify_payload.h b/src/charon/encoding/payloads/notify_payload.h index 431932631..ca1fe3a96 100644 --- a/src/charon/encoding/payloads/notify_payload.h +++ b/src/charon/encoding/payloads/notify_payload.h @@ -65,6 +65,8 @@ enum notify_type_t { FAILED_CP_REQUIRED = 37, TS_UNACCEPTABLE = 38, INVALID_SELECTORS = 39, + UNACCEPTABLE_ADDRESSES = 40, + UNEXPECTED_NAT_DETECTED = 41, /* notify status messages */ INITIAL_CONTACT = 16384, SET_WINDOW_SIZE = 16385, diff --git a/src/charon/kernel/kernel_interface.c b/src/charon/kernel/kernel_interface.c index 9847f30a3..bf5479bfe 100644 --- a/src/charon/kernel/kernel_interface.c +++ b/src/charon/kernel/kernel_interface.c @@ -228,6 +228,9 @@ struct addr_entry_t { /** The ip address */ host_t *ip; + /** virtual IP managed by us */ + bool virtual; + /** Number of times this IP is used, if virtual */ u_int refcount; }; @@ -690,6 +693,7 @@ static void process_addr(private_kernel_interface_t *this, found = TRUE; addr = malloc_thing(addr_entry_t); addr->ip = host->clone(host); + addr->virtual = FALSE; addr->refcount = 1; iface->addrs->insert_last(iface->addrs, addr); @@ -1070,6 +1074,10 @@ static status_t init_address_list(private_kernel_interface_t *this) static hook_result_t addr_hook(private_kernel_interface_t *this, addr_entry_t *in, host_t **out) { + if (in->virtual) + { /* skip virtual interfaces added by us */ + return HOOK_SKIP; + } *out = in->ip; return HOOK_NEXT; } @@ -1107,6 +1115,11 @@ static iterator_t *create_address_iterator(private_kernel_interface_t *this) { iterator_t *iterator; + /* This iterator is not only hooked, is is double-hooked. As we have stored + * our addresses in iface_entry->addr_entry->ip, we need to iterate the + * entries in each interface we iterate. This does the iface_hook. The + * addr_hook returns the ip instead of the addr_entry. */ + iterator = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex); iterator->set_iterator_hook(iterator, (iterator_hook_t*)iface_hook, this); return iterator; @@ -1368,6 +1381,8 @@ static host_t* get_source_addr(private_kernel_interface_t *this, host_t *dest) size_t len; host_t *source = NULL; + DBG2(DBG_KNL, "getting source address to reach %H", dest); + memset(&request, 0, sizeof(request)); hdr = (struct nlmsghdr*)request; @@ -1378,10 +1393,10 @@ static host_t* get_source_addr(private_kernel_interface_t *this, host_t *dest) msg = (struct rtmsg*)NLMSG_DATA(hdr); msg->rtm_family = dest->get_family(dest); msg->rtm_dst_len = msg->rtm_family == AF_INET ? 32 : 128; - msg->rtm_table = RT_TABLE_MAIN; - msg->rtm_protocol = RTPROT_STATIC; + msg->rtm_table = RT_TABLE_UNSPEC; + msg->rtm_protocol = RTPROT_UNSPEC; msg->rtm_type = RTN_UNICAST; - msg->rtm_scope = RT_SCOPE_UNIVERSE; + msg->rtm_scope = RT_SCOPE_HOST; chunk = dest->get_address(dest); add_attribute(hdr, RTA_DST, chunk, sizeof(request)); @@ -1427,12 +1442,13 @@ static host_t* get_source_addr(private_kernel_interface_t *this, host_t *dest) } break; } - if (source == NULL) + free(out); + if (source) { - DBG2(DBG_KNL, "no route found to %H", dest); + return source; } - free(out); - return source; + DBG2(DBG_KNL, "no route found to %H", dest); + return NULL; } /** @@ -1481,6 +1497,7 @@ static status_t add_ip(private_kernel_interface_t *this, addr = malloc_thing(addr_entry_t); addr->ip = virtual_ip->clone(virtual_ip); addr->refcount = 1; + addr->virtual = TRUE; pthread_mutex_lock(&this->mutex); iface->addrs->insert_last(iface->addrs, addr); pthread_mutex_unlock(&this->mutex); @@ -2298,7 +2315,6 @@ kernel_interface_t *kernel_interface_create() private_kernel_interface_t *this = malloc_thing(private_kernel_interface_t); struct sockaddr_nl addr; - /* 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; diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 00f95960a..5406cb70e 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -1681,7 +1681,13 @@ static status_t roam(private_ike_sa_t *this) } me = charon->kernel_interface->get_source_addr(charon->kernel_interface, - this->other_host); + this->other_host); + if (me && me->ip_equals(me, this->my_virtual_ip)) + { /* do not roam to the virtual IP of this IKE_SA */ + me->destroy(me); + me = NULL; + } + if (me) { set_condition(this, COND_STALE, FALSE); @@ -1695,12 +1701,8 @@ static status_t roam(private_ike_sa_t *this) } me->set_port(me, this->my_host->get_port(this->my_host)); -#ifndef MOBIKE - set_my_host(this, me); - return reestablish(this); -#endif /* our attachement changed, update if we have mobike */ - if (this->extensions & EXT_MOBIKE) + if (supports_extension(this, EXT_MOBIKE)) { mobike = ike_mobike_create(&this->public, TRUE); mobike->roam(mobike, me, NULL); @@ -1713,15 +1715,11 @@ static status_t roam(private_ike_sa_t *this) } /* there is nothing we can do without mobike */ - if (!(this->extensions & EXT_MOBIKE)) + if (!supports_extension(this, EXT_MOBIKE)) { set_condition(this, COND_STALE, TRUE); return FAILED; } -#ifndef MOBIKE - set_condition(this, COND_STALE, TRUE); - return FAILED; -#endif /* we are unable to reach the peer. Try an alternative address */ iterator = create_additional_address_iterator(this); @@ -1729,10 +1727,18 @@ static status_t roam(private_ike_sa_t *this) { me = charon->kernel_interface->get_source_addr(charon->kernel_interface, other); + if (me && me->ip_equals(me, this->my_virtual_ip)) + { /* do not roam to the virtual IP of this IKE_SA */ + me->destroy(me); + me = NULL; + } + if (me) { /* good, we have a new route. Use MOBIKE to update */ iterator->destroy(iterator); + me->set_port(me, this->my_host->get_port(this->my_host)); + other->set_port(other, this->other_host->get_port(this->other_host)); mobike = ike_mobike_create(&this->public, TRUE); mobike->roam(mobike, me, other); this->task_manager->queue_task(this->task_manager, (task_t*)mobike); @@ -1740,7 +1746,10 @@ static status_t roam(private_ike_sa_t *this) } } iterator->destroy(iterator); - return SUCCESS; + + /* no route found to host, give up (temporary) */ + set_condition(this, COND_STALE, TRUE); + return FAILED; } /** diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index bc9094023..0a0d5e5cf 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -701,6 +701,7 @@ static iterator_t *create_iterator(private_ike_sa_manager_t* this) { iterator_t *iterator = this->ike_sa_list->create_iterator_locked( this->ike_sa_list, &this->mutex); + /* register hook to iterator over ike_sas, not entries */ iterator->set_iterator_hook(iterator, (iterator_hook_t*)iterator_hook, this); return iterator; diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c index 84ce1fb54..fc2a13061 100644 --- a/src/charon/sa/task_manager.c +++ b/src/charon/sa/task_manager.c @@ -314,6 +314,11 @@ static status_t build_request(private_task_manager_t *this) exchange = INFORMATIONAL; break; } + if (activate_task(this, IKE_MOBIKE)) + { + exchange = INFORMATIONAL; + break; + } if (activate_task(this, IKE_DPD)) { exchange = INFORMATIONAL; @@ -592,6 +597,7 @@ static status_t process_request(private_task_manager_t *this, exchange_type_t exchange; payload_t *payload; notify_payload_t *notify; + delete_payload_t *delete; exchange = message->get_exchange_type(message); @@ -669,27 +675,56 @@ static status_t process_request(private_task_manager_t *this, } case INFORMATIONAL: { - delete_payload_t *delete; - - delete = (delete_payload_t*)message->get_payload(message, DELETE); - if (delete) + iterator = message->get_payload_iterator(message); + while (iterator->iterate(iterator, (void**)&payload)) { - if (delete->get_protocol_id(delete) == PROTO_IKE) - { - task = (task_t*)ike_delete_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); - } - else + switch (payload->get_type(payload)) { - task = (task_t*)child_delete_create(this->ike_sa, NULL); - this->passive_tasks->insert_last(this->passive_tasks, task); + case NOTIFY: + { + notify = (notify_payload_t*)payload; + switch (notify->get_notify_type(notify)) + { + case ADDITIONAL_IP4_ADDRESS: + case ADDITIONAL_IP6_ADDRESS: + case NO_ADDITIONAL_ADDRESSES: + case UPDATE_SA_ADDRESSES: + case NO_NATS_ALLOWED: + case UNACCEPTABLE_ADDRESSES: + case UNEXPECTED_NAT_DETECTED: + case COOKIE2: + task = (task_t*)ike_mobike_create(this->ike_sa, + FALSE); + break; + default: + break; + } + break; + } + case DELETE: + { + delete = (delete_payload_t*)payload; + if (delete->get_protocol_id(delete) == PROTO_IKE) + { + task = (task_t*)ike_delete_create(this->ike_sa, FALSE); + } + else + { + task = (task_t*)child_delete_create(this->ike_sa, NULL); + } + break; + } + default: + break; } } - else + iterator->destroy(iterator); + + if (task == NULL) { task = (task_t*)ike_dpd_create(FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); } + this->passive_tasks->insert_last(this->passive_tasks, task); break; } default: diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c index 0b3bd072b..a7f5fb6d6 100644 --- a/src/charon/sa/tasks/ike_mobike.c +++ b/src/charon/sa/tasks/ike_mobike.c @@ -25,6 +25,7 @@ #include <string.h> #include <daemon.h> +#include <sa/tasks/ike_natd.h> #include <encoding/payloads/notify_payload.h> @@ -59,6 +60,16 @@ struct private_ike_mobike_t { * remote host to roam to */ host_t *other; + + /** + * cookie2 value to verify new addresses + */ + chunk_t cookie2; + + /** + * NAT discovery reusing the IKE_NATD task + */ + ike_natd_t *natd; }; /** @@ -119,6 +130,7 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message) if (first) { /* an ADDITIONAL_*_ADDRESS means replace, so flush once */ flush_additional_addresses(this); + first = FALSE; } data = notify->get_notification_data(notify); host = host_create_from_chunk(family, data, 0); @@ -185,10 +197,26 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message) { if (message->get_exchange_type(message) == IKE_AUTH && message->get_payload(message, SECURITY_ASSOCIATION)) - { + { message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty); build_address_list(this, message); } + else if (this->me || this->other) + { /* address change */ + message->add_notify(message, FALSE, UPDATE_SA_ADDRESSES, chunk_empty); + build_address_list(this, message); + /* TODO: NAT discovery */ + + /* set new addresses */ + if (this->me) + { + this->ike_sa->set_my_host(this->ike_sa, this->me->clone(this->me)); + } + if (this->other) + { + this->ike_sa->set_other_host(this->ike_sa, this->other->clone(this->other)); + } + } return NEED_MORE; } @@ -197,8 +225,13 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message) * Implementation of task_t.process for responder */ static status_t process_r(private_ike_mobike_t *this, message_t *message) -{ - process_payloads(this, message); +{ + if ((message->get_exchange_type(message) == IKE_AUTH && + message->get_payload(message, SECURITY_ASSOCIATION)) || + message->get_exchange_type(message) == INFORMATIONAL) + { + process_payloads(this, message); + } return NEED_MORE; } @@ -259,9 +292,14 @@ static void migrate(private_ike_mobike_t *this, ike_sa_t *ike_sa) { DESTROY_IF(this->me); DESTROY_IF(this->other); + chunk_free(&this->cookie2); this->ike_sa = ike_sa; this->me = NULL; this->other = NULL; + if (this->natd) + { + this->natd->task.migrate(&this->natd->task, ike_sa); + } } /** @@ -271,6 +309,11 @@ static void destroy(private_ike_mobike_t *this) { DESTROY_IF(this->me); DESTROY_IF(this->other); + chunk_free(&this->cookie2); + if (this->natd) + { + this->natd->task.destroy(&this->natd->task); + } free(this); } @@ -301,6 +344,8 @@ ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator) this->initiator = initiator; this->me = NULL; this->other = NULL; + this->cookie2 = chunk_empty; + this->natd = NULL; return &this->public; } |