From 02b3ec0a10482feabdf1017f1693deeabbfcb245 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 14 Jun 2007 15:16:15 +0000 Subject: [PATCH] implemented address change notification (for MOBIKE) implemented up to date address list cache to list interfaces --- src/charon/control/interfaces/stroke_interface.c | 13 +- src/charon/daemon.c | 12 - src/charon/kernel/kernel_interface.c | 522 +++++++++++++++-------- src/charon/kernel/kernel_interface.h | 10 +- src/charon/sa/tasks/ike_natd.c | 11 +- 5 files changed, 364 insertions(+), 204 deletions(-) diff --git a/src/charon/control/interfaces/stroke_interface.c b/src/charon/control/interfaces/stroke_interface.c index 045d588..9bae908 100755 --- a/src/charon/control/interfaces/stroke_interface.c +++ b/src/charon/control/interfaces/stroke_interface.c @@ -1189,7 +1189,6 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) static void stroke_status(stroke_msg_t *msg, FILE *out, bool all) { iterator_t *iterator, *children; - linked_list_t *list; host_t *host; peer_cfg_t *peer_cfg; ike_cfg_t *ike_cfg; @@ -1215,15 +1214,15 @@ static void stroke_status(stroke_msg_t *msg, FILE *out, bool all) charon->processor->get_job_load(charon->processor)); fprintf(out, " scheduled events: %d\n", charon->scheduler->get_job_load(charon->scheduler)); - list = charon->kernel_interface->create_address_list(charon->kernel_interface); - - fprintf(out, "Listening on %d IP addresses:\n", list->get_count(list)); - while (list->remove_first(list, (void**)&host) == SUCCESS) + iterator = charon->kernel_interface->create_address_iterator( + charon->kernel_interface); + fprintf(out, "Listening on %d IP addresses:\n", + iterator->get_count(iterator)); + while (iterator->iterate(iterator, (void**)&host)) { fprintf(out, " %H\n", host); - host->destroy(host); } - list->destroy(list); + iterator->destroy(iterator); fprintf(out, "Connections:\n"); iterator = charon->backends->create_iterator(charon->backends); diff --git a/src/charon/daemon.c b/src/charon/daemon.c index aa81442..088bbf6 100644 --- a/src/charon/daemon.c +++ b/src/charon/daemon.c @@ -426,8 +426,6 @@ int main(int argc, char *argv[]) private_daemon_t *private_charon; FILE *pid_file; struct stat stb; - linked_list_t *list; - host_t *host; level_t levels[DBG_MAX]; int signal; @@ -530,16 +528,6 @@ int main(int argc, char *argv[]) fclose(pid_file); } - /* log socket info */ - list = charon->kernel_interface->create_address_list(charon->kernel_interface); - DBG1(DBG_NET, "listening on %d addresses:", list->get_count(list)); - while (list->remove_first(list, (void**)&host) == SUCCESS) - { - DBG1(DBG_NET, " %H", host); - host->destroy(host); - } - list->destroy(list); - /* drop additional capabilites (bind & root) */ drop_capabilities(private_charon, TRUE); diff --git a/src/charon/kernel/kernel_interface.c b/src/charon/kernel/kernel_interface.c index c1764b5..f00cbab 100644 --- a/src/charon/kernel/kernel_interface.c +++ b/src/charon/kernel/kernel_interface.c @@ -298,6 +298,16 @@ struct private_kernel_interface_t { * Mutex to lock access to vips. */ pthread_mutex_t vips_mutex; + + /** + * Cached list of IP adresses (address_entry_t) + */ + linked_list_t *addrs; + + /** + * Mutex to lock access to addr. + */ + pthread_mutex_t addrs_mutex; /** * job receiving xfrm events @@ -305,19 +315,24 @@ struct private_kernel_interface_t { callback_job_t *job; /** - * netlink xfrm socket to receive acquire and expire events + * Netlink xfrm socket (IPsec) */ - int socket_xfrm_events; + int socket_xfrm; /** - * Netlink xfrm socket (IPsec) + * netlink xfrm socket to receive acquire and expire events */ - int socket_xfrm; + int socket_xfrm_events; /** * Netlink rt socket (routing) */ int socket_rt; + + /** + * Netlink rt socket to receive address change events + */ + int socket_rt_events; }; /** @@ -443,98 +458,293 @@ static void add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data, } /** - * Receives events from kernel + * process a XFRM_MSG_ACQUIRE from kernel */ -static job_requeue_t receive_events(private_kernel_interface_t *this) +static void process_acquire(private_kernel_interface_t *this, struct nlmsghdr *hdr) { - unsigned char response[512]; - struct nlmsghdr *hdr; - struct sockaddr_nl addr; - socklen_t addr_len = sizeof(addr); - int len, oldstate; + u_int32_t reqid = 0; + job_t *job; + struct rtattr *rtattr = XFRM_RTA(hdr, struct xfrm_user_acquire); + size_t rtsize = XFRM_PAYLOAD(hdr, struct xfrm_user_tmpl); - hdr = (struct nlmsghdr*)response; + if (RTA_OK(rtattr, rtsize)) + { + if (rtattr->rta_type == XFRMA_TMPL) + { + struct xfrm_user_tmpl* tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rtattr); + reqid = tmpl->reqid; + } + } + if (reqid == 0) + { + DBG1(DBG_KNL, "received a XFRM_MSG_ACQUIRE, but no reqid found"); + return; + } + DBG2(DBG_KNL, "received a XFRM_MSG_ACQUIRE"); + DBG1(DBG_KNL, "creating acquire job for CHILD_SA with reqid %d", reqid); + job = (job_t*)acquire_job_create(reqid); + charon->processor->queue_job(charon->processor, job); +} + +/** + * process a XFRM_MSG_EXPIRE from kernel + */ +static void process_expire(private_kernel_interface_t *this, struct nlmsghdr *hdr) +{ + job_t *job; + protocol_id_t protocol; + u_int32_t spi, reqid; + struct xfrm_user_expire *expire; - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); - len = recvfrom(this->socket_xfrm_events, response, sizeof(response), 0, - (struct sockaddr*)&addr, &addr_len); - pthread_setcancelstate(oldstate, NULL); + expire = (struct xfrm_user_expire*)NLMSG_DATA(hdr); + protocol = expire->state.id.proto == KERNEL_ESP ? PROTO_ESP : PROTO_AH; + spi = expire->state.id.spi; + reqid = expire->state.reqid; - if (len < 0) + DBG2(DBG_KNL, "received a XFRM_MSG_EXPIRE"); + DBG1(DBG_KNL, "creating %s job for %N CHILD_SA 0x%x (reqid %d)", + expire->hard ? "delete" : "rekey", protocol_id_names, + protocol, ntohl(spi), reqid); + if (expire->hard) + { + job = (job_t*)delete_child_sa_job_create(reqid, protocol, spi); + } + else { - if (errno == EINTR) - { /* interrupted, try again */ - return JOB_REQUEUE_DIRECT; + job = (job_t*)rekey_child_sa_job_create(reqid, protocol, spi); + } + charon->processor->queue_job(charon->processor, job); +} + +/** + * process a RTM_NEWADDR from kernel + */ +static void process_newaddr(private_kernel_interface_t *this, + struct nlmsghdr *hdr, bool initial) +{ + struct ifaddrmsg* msg = (struct ifaddrmsg*)(NLMSG_DATA(hdr)); + struct rtattr *rta = IFA_RTA(msg); + size_t rtasize = IFA_PAYLOAD (hdr); + host_t *host = NULL; + char *name = NULL; + chunk_t local = chunk_empty, address = chunk_empty; + + while(RTA_OK(rta, rtasize)) + { + switch (rta->rta_type) + { + case IFA_LOCAL: + local.ptr = RTA_DATA(rta); + local.len = RTA_PAYLOAD(rta); + break; + case IFA_ADDRESS: + address.ptr = RTA_DATA(rta); + address.len = RTA_PAYLOAD(rta); + break; + case IFA_LABEL: + name = RTA_DATA(rta); + break; } - charon->kill(charon, "unable to receive netlink events"); + rta = RTA_NEXT(rta, rtasize); } - if (!NLMSG_OK(hdr, len)) + /* For PPP interfaces, we need the IFA_LOCAL address, + * IFA_ADDRESS is the peers address. But IFA_LOCAL is + * not included in all cases, so fallback to IFA_ADDRESS. */ + if (local.ptr) { - /* bad netlink message */ - return JOB_REQUEUE_DIRECT; + host = host_create_from_chunk(msg->ifa_family, local, 0); } - - if (addr.nl_pid != 0) + else if (address.ptr) { - /* not from kernel. not interested, try another one */ - return JOB_REQUEUE_DIRECT; + host = host_create_from_chunk(msg->ifa_family, address, 0); } - /* we handle ACQUIRE and EXPIRE messages directly */ - if (hdr->nlmsg_type == XFRM_MSG_ACQUIRE) + if (host) { - u_int32_t reqid = 0; - job_t *job; - struct rtattr *rtattr = XFRM_RTA(hdr, struct xfrm_user_acquire); - size_t rtsize = XFRM_PAYLOAD(hdr, struct xfrm_user_tmpl); - if (RTA_OK(rtattr, rtsize)) + address_entry_t *entry; + + entry = malloc_thing(address_entry_t); + entry->host = host; + entry->ifindex = msg->ifa_index; + if (name) { - if (rtattr->rta_type == XFRMA_TMPL) - { - struct xfrm_user_tmpl* tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rtattr); - reqid = tmpl->reqid; - } + memcpy(entry->ifname, name, IFNAMSIZ); + } + else + { + strcpy(entry->ifname, "(unknown)"); } - if (reqid == 0) + + if (initial) { - DBG1(DBG_KNL, "received a XFRM_MSG_ACQUIRE, but no reqid found"); + DBG1(DBG_KNL, " %H on %s", host, entry->ifname); } else { - DBG2(DBG_KNL, "received a XFRM_MSG_ACQUIRE"); - DBG1(DBG_KNL, "creating acquire job for CHILD_SA with reqid %d", - reqid); - job = (job_t*)acquire_job_create(reqid); - charon->processor->queue_job(charon->processor, job); + DBG1(DBG_KNL, "%H appeared on %s", host, entry->ifname); } + + pthread_mutex_lock(&this->addrs_mutex); + this->addrs->insert_last(this->addrs, entry); + pthread_mutex_unlock(&this->addrs_mutex); } - else if (hdr->nlmsg_type == XFRM_MSG_EXPIRE) - { - job_t *job; - protocol_id_t protocol; - u_int32_t spi, reqid; - struct xfrm_user_expire *expire; +} + + +/** + * process a RTM_DELADDR from kernel + */ +static void process_deladdr(private_kernel_interface_t *this, struct nlmsghdr *hdr) +{ + struct ifaddrmsg* msg = (struct ifaddrmsg*)(NLMSG_DATA(hdr)); + struct rtattr *rta = IFA_RTA(msg); + size_t rtasize = IFA_PAYLOAD (hdr); + host_t *host = NULL; + chunk_t local = chunk_empty, address = chunk_empty; - expire = (struct xfrm_user_expire*)NLMSG_DATA(hdr); - protocol = expire->state.id.proto == KERNEL_ESP ? - PROTO_ESP : PROTO_AH; - spi = expire->state.id.spi; - reqid = expire->state.reqid; + while(RTA_OK(rta, rtasize)) + { + switch (rta->rta_type) + { + case IFA_LOCAL: + local.ptr = RTA_DATA(rta); + local.len = RTA_PAYLOAD(rta); + break; + case IFA_ADDRESS: + address.ptr = RTA_DATA(rta); + address.len = RTA_PAYLOAD(rta); + break; + } + rta = RTA_NEXT(rta, rtasize); + } + + /* same stuff as in newaddr */ + if (local.ptr) + { + host = host_create_from_chunk(msg->ifa_family, local, 0); + } + else if (address.ptr) + { + host = host_create_from_chunk(msg->ifa_family, address, 0); + } + + if (host) + { + address_entry_t *entry; + iterator_t *iterator; - DBG2(DBG_KNL, "received a XFRM_MSG_EXPIRE"); - DBG1(DBG_KNL, "creating %s job for %N CHILD_SA 0x%x (reqid %d)", - expire->hard ? "delete" : "rekey", protocol_id_names, - protocol, ntohl(spi), reqid); - if (expire->hard) + iterator = this->addrs->create_iterator_locked(this->addrs, + &this->addrs_mutex); + while (iterator->iterate(iterator, (void**)&entry)) { - job = (job_t*)delete_child_sa_job_create(reqid, protocol, spi); + if (entry->ifindex == msg->ifa_index && + host->equals(host, entry->host)) + { + iterator->remove(iterator); + DBG1(DBG_KNL, "%H disappeared from %s", host, entry->ifname); + address_entry_destroy(entry); + } } - else + iterator->destroy(iterator); + host->destroy(host); + } +} + +/** + * Receives events from kernel + */ +static job_requeue_t receive_events(private_kernel_interface_t *this) +{ + char response[512]; + struct nlmsghdr *hdr = (struct nlmsghdr*)response; + struct sockaddr_nl addr; + socklen_t addr_len = sizeof(addr); + int len, oldstate, maxfd, selected; + fd_set rfds; + + FD_ZERO(&rfds); + FD_SET(this->socket_xfrm_events, &rfds); + FD_SET(this->socket_rt_events, &rfds); + maxfd = max(this->socket_xfrm_events, this->socket_rt_events); + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + selected = select(maxfd + 1, &rfds, NULL, NULL, NULL); + pthread_setcancelstate(oldstate, NULL); + if (selected <= 0) + { + DBG1(DBG_KNL, "selecting on sockets failed: %s", strerror(errno)); + return JOB_REQUEUE_FAIR; + } + if (FD_ISSET(this->socket_xfrm_events, &rfds)) + { + selected = this->socket_xfrm_events; + } + else if (FD_ISSET(this->socket_rt_events, &rfds)) + { + selected = this->socket_rt_events; + } + else + { + return JOB_REQUEUE_DIRECT; + } + + len = recvfrom(selected, response, sizeof(response), MSG_DONTWAIT, + (struct sockaddr*)&addr, &addr_len); + if (len < 0) + { + switch (errno) { - job = (job_t*)rekey_child_sa_job_create(reqid, protocol, spi); + case EINTR: + /* interrupted, try again */ + return JOB_REQUEUE_DIRECT; + case EAGAIN: + /* no data ready, select again */ + return JOB_REQUEUE_DIRECT; + default: + DBG1(DBG_KNL, "unable to receive from xfrm event socket"); + sleep(1); + return JOB_REQUEUE_FAIR; } - charon->processor->queue_job(charon->processor, job); + } + if (addr.nl_pid != 0) + { /* not from kernel. not interested, try another one */ + return JOB_REQUEUE_DIRECT; + } + + while (NLMSG_OK(hdr, len)) + { + /* looks good so far, dispatch netlink message */ + if (selected == this->socket_xfrm_events) + { + switch (hdr->nlmsg_type) + { + case XFRM_MSG_ACQUIRE: + process_acquire(this, hdr); + break; + case XFRM_MSG_EXPIRE: + process_expire(this, hdr); + break; + default: + break; + } + } + else if (selected == this->socket_rt_events) + { + switch (hdr->nlmsg_type) + { + case RTM_NEWADDR: + process_newaddr(this, hdr, FALSE); + break; + case RTM_DELADDR: + process_deladdr(this, hdr); + break; + default: + break; + } + } + hdr = NLMSG_NEXT(hdr, len); + } return JOB_REQUEUE_DIRECT; } @@ -697,19 +907,16 @@ static status_t netlink_send_ack(int socket, struct nlmsghdr *in) } /** - * Create a list of local addresses. + * Initialize a list of local addresses. */ -static linked_list_t *create_address_list(private_kernel_interface_t *this) +static void init_address_list(private_kernel_interface_t *this) { char request[BUFFER_SIZE]; struct nlmsghdr *out, *hdr; struct rtgenmsg *msg; size_t len; - linked_list_t *list; - DBG2(DBG_IKE, "getting local address list"); - - list = linked_list_create(); + DBG1(DBG_IKE, "listening on interfaces:"); memset(&request, 0, sizeof(request)); @@ -729,61 +936,7 @@ static linked_list_t *create_address_list(private_kernel_interface_t *this) { case RTM_NEWADDR: { - struct ifaddrmsg* msg = (struct ifaddrmsg*)(NLMSG_DATA(hdr)); - struct rtattr *rta = IFA_RTA(msg); - size_t rtasize = IFA_PAYLOAD (hdr); - host_t *host = NULL; - char *name = NULL; - chunk_t local = chunk_empty, address = chunk_empty; - - while(RTA_OK(rta, rtasize)) - { - switch (rta->rta_type) - { - case IFA_LOCAL: - local.ptr = RTA_DATA(rta); - local.len = RTA_PAYLOAD(rta); - break; - case IFA_ADDRESS: - address.ptr = RTA_DATA(rta); - address.len = RTA_PAYLOAD(rta); - break; - case IFA_LABEL: - name = RTA_DATA(rta); - break; - } - rta = RTA_NEXT(rta, rtasize); - } - - /* For PPP interfaces, we need the IFA_LOCAL address, - * IFA_ADDRESS is the peers address. But IFA_LOCAL is - * not included in all cases, so fallback to IFA_ADDRESS. */ - if (local.ptr) - { - host = host_create_from_chunk(msg->ifa_family, local, 0); - } - else if (address.ptr) - { - host = host_create_from_chunk(msg->ifa_family, address, 0); - } - - if (host) - { - address_entry_t *entry; - - entry = malloc_thing(address_entry_t); - entry->host = host; - entry->ifindex = msg->ifa_index; - if (name) - { - memcpy(entry->ifname, name, IFNAMSIZ); - } - else - { - strcpy(entry->ifname, "(unknown)"); - } - list->insert_last(list, entry); - } + process_newaddr(this, hdr, TRUE); hdr = NLMSG_NEXT(hdr, len); continue; } @@ -801,28 +954,29 @@ static linked_list_t *create_address_list(private_kernel_interface_t *this) { DBG1(DBG_IKE, "unable to get local address list"); } +} - return list; +/** + * iterator hook to return address, not address_entry_t + */ +bool address_iterator_hook(private_kernel_interface_t *this, + address_entry_t *in, host_t **out) +{ + *out = in->host; + return TRUE; } /** - * Implements kernel_interface_t.create_address_list. + * Implements kernel_interface_t.create_address_iterator. */ -static linked_list_t *create_address_list_public(private_kernel_interface_t *this) +static iterator_t *create_address_iterator(private_kernel_interface_t *this) { - linked_list_t *result, *list; - address_entry_t *entry; - - result = linked_list_create(); - list = create_address_list(this); - while (list->remove_last(list, (void**)&entry) == SUCCESS) - { - result->insert_last(result, entry->host); - free(entry); - } - list->destroy(list); + iterator_t *iterator; - return result; + iterator = this->addrs->create_iterator_locked(this->addrs, &this->addrs_mutex); + iterator->set_iterator_hook(iterator, + (iterator_hook_t*)address_iterator_hook, this); + return iterator; } /** @@ -830,22 +984,22 @@ static linked_list_t *create_address_list_public(private_kernel_interface_t *thi */ static char *get_interface_name(private_kernel_interface_t *this, host_t* ip) { - linked_list_t *list; + iterator_t *iterator; address_entry_t *entry; char *name = NULL; DBG2(DBG_IKE, "getting interface name for %H", ip); - list = create_address_list(this); - while (!name && list->remove_last(list, (void**)&entry) == SUCCESS) + iterator = this->addrs->create_iterator_locked(this->addrs, &this->addrs_mutex); + while (iterator->iterate(iterator, (void**)&entry)) { if (ip->ip_equals(ip, entry->host)) { name = strdup(entry->ifname); + break; } - address_entry_destroy(entry); } - list->destroy_function(list, (void*)address_entry_destroy); + iterator->destroy(iterator); if (name) { @@ -865,10 +1019,10 @@ static char *get_interface_name(private_kernel_interface_t *this, host_t* ip) static status_t get_address_by_ts(private_kernel_interface_t *this, traffic_selector_t *ts, host_t **ip) { + iterator_t *iterator; address_entry_t *entry; host_t *host; int family; - linked_list_t *list; bool found = FALSE; DBG2(DBG_IKE, "getting a local address in traffic selector %R", ts); @@ -895,17 +1049,17 @@ static status_t get_address_by_ts(private_kernel_interface_t *this, } host->destroy(host); - list = create_address_list(this); - while (!found && list->remove_last(list, (void**)&entry) == SUCCESS) + iterator = this->addrs->create_iterator_locked(this->addrs, &this->addrs_mutex); + while (iterator->iterate(iterator, (void**)&entry)) { if (ts->includes(ts, entry->host)) { found = TRUE; *ip = entry->host->clone(entry->host); + break; } - address_entry_destroy(entry); } - list->destroy_function(list, (void*)address_entry_destroy); + iterator->destroy(iterator); if (!found) { @@ -921,22 +1075,22 @@ static status_t get_address_by_ts(private_kernel_interface_t *this, */ static int get_interface_index(private_kernel_interface_t *this, host_t* ip) { - linked_list_t *list; + iterator_t *iterator; address_entry_t *entry; int ifindex = 0; DBG2(DBG_IKE, "getting iface for %H", ip); - list = create_address_list(this); - while (!ifindex && list->remove_last(list, (void**)&entry) == SUCCESS) + iterator = this->addrs->create_iterator_locked(this->addrs, &this->addrs_mutex); + while (iterator->iterate(iterator, (void**)&entry)) { if (ip->ip_equals(ip, entry->host)) { ifindex = entry->ifindex; + break; } - address_entry_destroy(entry); } - list->destroy_function(list, (void*)address_entry_destroy); + iterator->destroy(iterator); if (ifindex == 0) { @@ -1883,9 +2037,11 @@ static void destroy(private_kernel_interface_t *this) this->job->cancel(this->job); close(this->socket_xfrm_events); close(this->socket_xfrm); + close(this->socket_rt_events); close(this->socket_rt); this->vips->destroy(this->vips); this->policies->destroy(this->policies); + this->addrs->destroy_function(this->addrs, (void*)address_entry_destroy); free(this); } @@ -1908,7 +2064,7 @@ kernel_interface_t *kernel_interface_create() this->public.del_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t))del_policy; this->public.get_interface = (char*(*)(kernel_interface_t*,host_t*))get_interface_name; - this->public.create_address_list = (linked_list_t*(*)(kernel_interface_t*))create_address_list_public; + this->public.create_address_iterator = (iterator_t*(*)(kernel_interface_t*))create_address_iterator; this->public.add_ip = (status_t(*)(kernel_interface_t*,host_t*,host_t*)) add_ip; this->public.del_ip = (status_t(*)(kernel_interface_t*,host_t*,host_t*)) del_ip; this->public.destroy = (void(*)(kernel_interface_t*)) destroy; @@ -1916,24 +2072,13 @@ kernel_interface_t *kernel_interface_create() /* private members */ this->vips = linked_list_create(); this->policies = linked_list_create(); + this->addrs = linked_list_create(); pthread_mutex_init(&this->policies_mutex,NULL); pthread_mutex_init(&this->vips_mutex,NULL); + pthread_mutex_init(&this->addrs_mutex,NULL); + memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; - addr.nl_pid = 0; - addr.nl_groups = 0; - - /* create and bind XFRM socket */ - this->socket_xfrm = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM); - if (this->socket_xfrm <= 0) - { - charon->kill(charon, "unable to create XFRM netlink socket"); - } - - if (bind(this->socket_xfrm, (struct sockaddr*)&addr, sizeof(addr))) - { - charon->kill(charon, "unable to bind XFRM netlink socket"); - } /* create and bind RT socket */ this->socket_rt = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); @@ -1941,20 +2086,43 @@ kernel_interface_t *kernel_interface_create() { charon->kill(charon, "unable to create RT netlink socket"); } - + addr.nl_groups = 0; if (bind(this->socket_rt, (struct sockaddr*)&addr, sizeof(addr))) { charon->kill(charon, "unable to bind RT netlink socket"); } + /* create and bind RT socket for events (address changes) */ + this->socket_rt_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (this->socket_rt_events <= 0) + { + charon->kill(charon, "unable to create RT event socket"); + } + addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR; + if (bind(this->socket_rt_events, (struct sockaddr*)&addr, sizeof(addr))) + { + charon->kill(charon, "unable to bind RT event socket"); + } + + /* create and bind XFRM socket */ + this->socket_xfrm = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM); + if (this->socket_xfrm <= 0) + { + charon->kill(charon, "unable to create XFRM netlink socket"); + } + addr.nl_groups = 0; + if (bind(this->socket_xfrm, (struct sockaddr*)&addr, sizeof(addr))) + { + charon->kill(charon, "unable to bind XFRM netlink socket"); + } + /* create and bind XFRM socket for ACQUIRE & EXPIRE */ - addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE; this->socket_xfrm_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM); if (this->socket_xfrm_events <= 0) { charon->kill(charon, "unable to create XFRM event socket"); } - + addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE; if (bind(this->socket_xfrm_events, (struct sockaddr*)&addr, sizeof(addr))) { charon->kill(charon, "unable to bind XFRM event socket"); @@ -1964,6 +2132,8 @@ kernel_interface_t *kernel_interface_create() this, NULL, NULL); charon->processor->queue_job(charon->processor, (job_t*)this->job); + init_address_list(this); + return &this->public; } diff --git a/src/charon/kernel/kernel_interface.h b/src/charon/kernel/kernel_interface.h index 2a3eaff..ef576b9 100644 --- a/src/charon/kernel/kernel_interface.h +++ b/src/charon/kernel/kernel_interface.h @@ -277,12 +277,16 @@ struct kernel_interface_t { char* (*get_interface) (kernel_interface_t *this, host_t *host); /** - * @brief Creates a list of all local addresses. + * @brief Creates an iterator over all local addresses. + * + * This function blocks an internal cached address list until the + * iterator gets destroyed. + * These hosts are read-only, do not modify or free. * * @param this calling object - * @return allocated list with host_t objects + * @return iterator over host_t's */ - linked_list_t *(*create_address_list) (kernel_interface_t *this); + iterator_t *(*create_address_iterator) (kernel_interface_t *this); /** * @brief Add a virtual IP to an interface. diff --git a/src/charon/sa/tasks/ike_natd.c b/src/charon/sa/tasks/ike_natd.c index 50b5d65..9b355d7 100644 --- a/src/charon/sa/tasks/ike_natd.c +++ b/src/charon/sa/tasks/ike_natd.c @@ -240,22 +240,21 @@ static status_t process_i(private_ike_natd_t *this, message_t *message) static status_t build_i(private_ike_natd_t *this, message_t *message) { notify_payload_t *notify; - linked_list_t *list; + iterator_t *iterator; host_t *host; /* include one notify if our address is defined, all addresses otherwise */ host = this->ike_sa->get_my_host(this->ike_sa); if (host->is_anyaddr(host)) { - /* TODO: we could get the src address from netlink!? */ - list = charon->kernel_interface->create_address_list(charon->kernel_interface); - while (list->remove_first(list, (void**)&host) == SUCCESS) + iterator = charon->kernel_interface->create_address_iterator( + charon->kernel_interface); + while (iterator->iterate(iterator, (void**)&host)) { notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); - host->destroy(host); message->add_payload(message, (payload_t*)notify); } - list->destroy(list); + iterator->destroy(iterator); } else { -- 2.7.4