aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/charon/control/interfaces/stroke_interface.c13
-rw-r--r--src/charon/daemon.c12
-rw-r--r--src/charon/kernel/kernel_interface.c522
-rw-r--r--src/charon/kernel/kernel_interface.h10
-rw-r--r--src/charon/sa/tasks/ike_natd.c11
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 045d588f2..9bae90832 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 aa81442cd..088bbf63b 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 c1764b5a5..f00cbab81 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 2a3eaff7a..ef576b9ef 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 50b5d652b..9b355d773 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
{