aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xsrc/charon/control/interfaces/stroke_interface.c3
-rw-r--r--src/charon/kernel/kernel_interface.c540
-rw-r--r--src/charon/sa/ike_sa_manager.c8
-rw-r--r--src/libstrongswan/utils/iterator.h42
-rw-r--r--src/libstrongswan/utils/linked_list.c59
5 files changed, 418 insertions, 234 deletions
diff --git a/src/charon/control/interfaces/stroke_interface.c b/src/charon/control/interfaces/stroke_interface.c
index 9bae90832..09846fe59 100755
--- a/src/charon/control/interfaces/stroke_interface.c
+++ b/src/charon/control/interfaces/stroke_interface.c
@@ -1216,8 +1216,7 @@ static void stroke_status(stroke_msg_t *msg, FILE *out, bool all)
charon->scheduler->get_job_load(charon->scheduler));
iterator = charon->kernel_interface->create_address_iterator(
charon->kernel_interface);
- fprintf(out, "Listening on %d IP addresses:\n",
- iterator->get_count(iterator));
+ fprintf(out, "Listening IP addresses:\n");
while (iterator->iterate(iterator, (void**)&host))
{
fprintf(out, " %H\n", host);
diff --git a/src/charon/kernel/kernel_interface.c b/src/charon/kernel/kernel_interface.c
index f00cbab81..8212841df 100644
--- a/src/charon/kernel/kernel_interface.c
+++ b/src/charon/kernel/kernel_interface.c
@@ -242,29 +242,32 @@ static void vip_entry_destroy(vip_entry_t *this)
free(this);
}
-typedef struct address_entry_t address_entry_t;
+typedef struct interface_entry_t interface_entry_t;
/**
- * an address found on the system, containg address and interface info
+ * A network interface on this system, containing addresses
*/
-struct address_entry_t {
-
- /** address of this entry */
- host_t *host;
+struct interface_entry_t {
/** interface index */
int ifindex;
- /** name of the index */
+ /** name of the interface */
char ifname[IFNAMSIZ];
+
+ /** interface flags, as in netdevice(7) SIOCGIFFLAGS */
+ u_int flags;
+
+ /** list of addresses as host_t */
+ linked_list_t *addresses;
};
/**
- * destroy an address entry
+ * destroy an interface entry
*/
-static void address_entry_destroy(address_entry_t *this)
+static void interface_entry_destroy(interface_entry_t *this)
{
- this->host->destroy(this->host);
+ this->addresses->destroy_offset(this->addresses, offsetof(host_t, destroy));
free(this);
}
@@ -280,14 +283,14 @@ struct private_kernel_interface_t {
kernel_interface_t public;
/**
- * List of installed policies (kernel_entry_t)
+ * mutex to lock access to the various lists
*/
- linked_list_t *policies;
+ pthread_mutex_t mutex;
/**
- * Mutex locks access to policies
+ * List of installed policies (kernel_entry_t)
*/
- pthread_mutex_t policies_mutex;
+ linked_list_t *policies;
/**
* List of installed virtual IPs. (vip_entry_t)
@@ -295,26 +298,26 @@ struct private_kernel_interface_t {
linked_list_t *vips;
/**
- * Mutex to lock access to vips.
- */
- pthread_mutex_t vips_mutex;
-
- /**
- * Cached list of IP adresses (address_entry_t)
+ * Cached list of interfaces and its adresses (interface_entry_t)
*/
- linked_list_t *addrs;
+ linked_list_t *interfaces;
/**
- * Mutex to lock access to addr.
+ * iterator used in hook()
*/
- pthread_mutex_t addrs_mutex;
+ iterator_t *hiter;
/**
- * job receiving xfrm events
+ * job receiving netlink events
*/
callback_job_t *job;
/**
+ * current sequence number for netlink request
+ */
+ int seq;
+
+ /**
* Netlink xfrm socket (IPsec)
*/
int socket_xfrm;
@@ -517,92 +520,110 @@ static void process_expire(private_kernel_interface_t *this, struct nlmsghdr *hd
}
/**
- * process a RTM_NEWADDR from kernel
+ * process RTM_NEWLINK/RTM_DELLINK from kernel
*/
-static void process_newaddr(private_kernel_interface_t *this,
- struct nlmsghdr *hdr, bool initial)
+static void process_link(private_kernel_interface_t *this,
+ struct nlmsghdr *hdr, bool event)
{
- struct ifaddrmsg* msg = (struct ifaddrmsg*)(NLMSG_DATA(hdr));
- struct rtattr *rta = IFA_RTA(msg);
- size_t rtasize = IFA_PAYLOAD (hdr);
- host_t *host = NULL;
+ struct ifinfomsg* msg = (struct ifinfomsg*)(NLMSG_DATA(hdr));
+ struct rtattr *rta = IFLA_RTA(msg);
+ size_t rtasize = IFLA_PAYLOAD (hdr);
+ iterator_t *iterator;
+ interface_entry_t *current, *entry = 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:
+ case IFLA_IFNAME:
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)
+ if (!name)
{
- host = host_create_from_chunk(msg->ifa_family, address, 0);
+ name = "(unknown)";
}
- if (host)
+ switch (hdr->nlmsg_type)
{
- address_entry_t *entry;
-
- entry = malloc_thing(address_entry_t);
- entry->host = host;
- entry->ifindex = msg->ifa_index;
- if (name)
+ case RTM_NEWLINK:
{
+ if (msg->ifi_flags & IFF_LOOPBACK)
+ { /* ignore loopback interfaces */
+ break;
+ }
+ iterator = this->interfaces->create_iterator_locked(this->interfaces,
+ &this->mutex);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (current->ifindex == msg->ifi_index)
+ {
+ entry = current;
+ break;
+ }
+ }
+ if (!entry)
+ {
+ entry = malloc_thing(interface_entry_t);
+ entry->ifindex = msg->ifi_index;
+ entry->flags = 0;
+ entry->addresses = linked_list_create();
+ this->interfaces->insert_last(this->interfaces, entry);
+ }
memcpy(entry->ifname, name, IFNAMSIZ);
+ entry->ifname[IFNAMSIZ-1] = '\0';
+ if (event)
+ {
+ if (!(entry->flags & IFF_UP) && (msg->ifi_flags & IFF_UP))
+ {
+ DBG1(DBG_KNL, "interface %s activated", name);
+ }
+ if ((entry->flags & IFF_UP) && !(msg->ifi_flags & IFF_UP))
+ {
+ DBG1(DBG_KNL, "interface %s deactivated", name);
+ }
+ }
+ entry->flags = msg->ifi_flags;
+ iterator->destroy(iterator);
+ break;
}
- else
- {
- strcpy(entry->ifname, "(unknown)");
- }
-
- if (initial)
- {
- DBG1(DBG_KNL, " %H on %s", host, entry->ifname);
- }
- else
+ case RTM_DELLINK:
{
- DBG1(DBG_KNL, "%H appeared on %s", host, entry->ifname);
+ iterator = this->interfaces->create_iterator_locked(this->interfaces,
+ &this->mutex);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (current->ifindex == msg->ifi_index)
+ {
+ /* we do not remove it, as an address may be added to a
+ * "down" interface and we wan't to know that. */
+ current->flags = msg->ifi_flags;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ break;
}
-
- pthread_mutex_lock(&this->addrs_mutex);
- this->addrs->insert_last(this->addrs, entry);
- pthread_mutex_unlock(&this->addrs_mutex);
}
}
-
/**
- * process a RTM_DELADDR from kernel
+ * process RTM_NEWADDR/RTM_DELADDR from kernel
*/
-static void process_deladdr(private_kernel_interface_t *this, struct nlmsghdr *hdr)
+static void process_addr(private_kernel_interface_t *this,
+ struct nlmsghdr *hdr, bool event)
{
struct ifaddrmsg* msg = (struct ifaddrmsg*)(NLMSG_DATA(hdr));
struct rtattr *rta = IFA_RTA(msg);
size_t rtasize = IFA_PAYLOAD (hdr);
host_t *host = NULL;
+ iterator_t *iterator;
+ interface_entry_t *entry;
chunk_t local = chunk_empty, address = chunk_empty;
-
+
while(RTA_OK(rta, rtasize))
{
switch (rta->rta_type)
@@ -619,7 +640,9 @@ static void process_deladdr(private_kernel_interface_t *this, struct nlmsghdr *h
rta = RTA_NEXT(rta, rtasize);
}
- /* same stuff as in newaddr */
+ /* 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);
@@ -629,26 +652,66 @@ static void process_deladdr(private_kernel_interface_t *this, struct nlmsghdr *h
host = host_create_from_chunk(msg->ifa_family, address, 0);
}
- if (host)
+ if (host == NULL)
+ { /* bad family? */
+ return;
+ }
+
+ switch (hdr->nlmsg_type)
{
- address_entry_t *entry;
- iterator_t *iterator;
-
- iterator = this->addrs->create_iterator_locked(this->addrs,
- &this->addrs_mutex);
- while (iterator->iterate(iterator, (void**)&entry))
+ case RTM_NEWADDR:
{
- if (entry->ifindex == msg->ifa_index &&
- host->equals(host, entry->host))
+ iterator = this->interfaces->create_iterator_locked(this->interfaces,
+ &this->mutex);
+ while (iterator->iterate(iterator, (void**)&entry))
{
- iterator->remove(iterator);
- DBG1(DBG_KNL, "%H disappeared from %s", host, entry->ifname);
- address_entry_destroy(entry);
+ if (entry->ifindex == msg->ifa_index)
+ {
+ entry->addresses->insert_last(entry->addresses,
+ host->clone(host));
+ if (event)
+ {
+ DBG1(DBG_KNL, "%H appeared on %s", host, entry->ifname);
+ }
+ break;
+ }
}
+ iterator->destroy(iterator);
+ break;
}
- iterator->destroy(iterator);
- host->destroy(host);
+ case RTM_DELADDR:
+ {
+ iterator = this->interfaces->create_iterator_locked(this->interfaces,
+ &this->mutex);
+ while (iterator->iterate(iterator, (void**)&entry))
+ {
+ if (entry->ifindex == msg->ifa_index)
+ {
+ iterator_t *addresses;
+ host_t *current;
+
+ addresses = entry->addresses->create_iterator(
+ entry->addresses, TRUE);
+ while (addresses->iterate(addresses, (void**)&current))
+ {
+ if (current->equals(current, host))
+ {
+ addresses->remove(addresses);
+ current->destroy(current);
+ DBG1(DBG_KNL, "%H disappeared from %s",
+ host, entry->ifname);
+ }
+ }
+ addresses->destroy(addresses);
+ }
+ }
+ iterator->destroy(iterator);
+ break;
+ }
+ default:
+ break;
}
+ host->destroy(host);
}
/**
@@ -656,7 +719,7 @@ static void process_deladdr(private_kernel_interface_t *this, struct nlmsghdr *h
*/
static job_requeue_t receive_events(private_kernel_interface_t *this)
{
- char response[512];
+ char response[1024];
struct nlmsghdr *hdr = (struct nlmsghdr*)response;
struct sockaddr_nl addr;
socklen_t addr_len = sizeof(addr);
@@ -734,17 +797,18 @@ static job_requeue_t receive_events(private_kernel_interface_t *this)
switch (hdr->nlmsg_type)
{
case RTM_NEWADDR:
- process_newaddr(this, hdr, FALSE);
- break;
case RTM_DELADDR:
- process_deladdr(this, hdr);
+ process_addr(this, hdr, TRUE);
+ break;
+ case RTM_NEWLINK:
+ case RTM_DELLINK:
+ process_link(this, hdr, TRUE);
break;
default:
break;
}
}
hdr = NLMSG_NEXT(hdr, len);
-
}
return JOB_REQUEUE_DIRECT;
}
@@ -752,7 +816,8 @@ static job_requeue_t receive_events(private_kernel_interface_t *this)
/**
* send a netlink message and wait for a reply
*/
-static status_t netlink_send(int socket, struct nlmsghdr *in,
+static status_t netlink_send(private_kernel_interface_t *this,
+ int socket, struct nlmsghdr *in,
struct nlmsghdr **out, size_t *out_len)
{
int len, addr_len;
@@ -760,13 +825,9 @@ static status_t netlink_send(int socket, struct nlmsghdr *in,
chunk_t result = chunk_empty, tmp;
struct nlmsghdr *msg, peek;
- static int seq = 200;
- static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-
-
- pthread_mutex_lock(&mutex);
+ pthread_mutex_lock(&this->mutex);
- in->nlmsg_seq = ++seq;
+ in->nlmsg_seq = ++this->seq;
in->nlmsg_pid = getpid();
memset(&addr, 0, sizeof(addr));
@@ -786,7 +847,7 @@ static status_t netlink_send(int socket, struct nlmsghdr *in,
/* interrupted, try again */
continue;
}
- pthread_mutex_unlock(&mutex);
+ pthread_mutex_unlock(&this->mutex);
DBG1(DBG_KNL, "error sending to netlink socket: %s", strerror(errno));
return FAILED;
}
@@ -818,23 +879,23 @@ static status_t netlink_send(int socket, struct nlmsghdr *in,
continue;
}
DBG1(DBG_IKE, "error reading from netlink socket: %s", strerror(errno));
- pthread_mutex_unlock(&mutex);
+ pthread_mutex_unlock(&this->mutex);
return FAILED;
}
if (!NLMSG_OK(msg, len))
{
DBG1(DBG_IKE, "received corrupted netlink message");
- pthread_mutex_unlock(&mutex);
+ pthread_mutex_unlock(&this->mutex);
return FAILED;
}
- if (msg->nlmsg_seq != seq)
+ if (msg->nlmsg_seq != this->seq)
{
DBG1(DBG_IKE, "received invalid netlink sequence number");
- if (msg->nlmsg_seq < seq)
+ if (msg->nlmsg_seq < this->seq)
{
continue;
}
- pthread_mutex_unlock(&mutex);
+ pthread_mutex_unlock(&this->mutex);
return FAILED;
}
@@ -846,7 +907,7 @@ static status_t netlink_send(int socket, struct nlmsghdr *in,
len = recvfrom(socket, &peek, sizeof(peek), MSG_PEEK | MSG_DONTWAIT,
(struct sockaddr*)&addr, &addr_len);
- if (len == sizeof(peek) && peek.nlmsg_seq == seq)
+ if (len == sizeof(peek) && peek.nlmsg_seq == this->seq)
{
/* seems to be multipart */
continue;
@@ -857,7 +918,7 @@ static status_t netlink_send(int socket, struct nlmsghdr *in,
*out_len = result.len;
*out = (struct nlmsghdr*)clalloc(result.ptr, result.len);
- pthread_mutex_unlock(&mutex);
+ pthread_mutex_unlock(&this->mutex);
return SUCCESS;
}
@@ -865,12 +926,13 @@ static status_t netlink_send(int socket, struct nlmsghdr *in,
/**
* send a netlink message and wait for its acknowlegde
*/
-static status_t netlink_send_ack(int socket, struct nlmsghdr *in)
+static status_t netlink_send_ack(private_kernel_interface_t *this,
+ int socket, struct nlmsghdr *in)
{
struct nlmsghdr *out, *hdr;
size_t len;
- if (netlink_send(socket, in, &out, &len) != SUCCESS)
+ if (netlink_send(this, socket, in, &out, &len) != SUCCESS)
{
return FAILED;
}
@@ -909,61 +971,116 @@ static status_t netlink_send_ack(int socket, struct nlmsghdr *in)
/**
* Initialize a list of local addresses.
*/
-static void init_address_list(private_kernel_interface_t *this)
+static status_t init_address_list(private_kernel_interface_t *this)
{
char request[BUFFER_SIZE];
- struct nlmsghdr *out, *hdr;
+ struct nlmsghdr *out, *current, *in;
struct rtgenmsg *msg;
size_t len;
+ iterator_t *i_iface, *i_addr;
+ host_t *address;
+ interface_entry_t *entry;
DBG1(DBG_IKE, "listening on interfaces:");
memset(&request, 0, sizeof(request));
- hdr = (struct nlmsghdr*)&request;
- hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
- hdr->nlmsg_type = RTM_GETADDR;
- hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT;
- msg = (struct rtgenmsg*)NLMSG_DATA(hdr);
+ in = (struct nlmsghdr*)&request;
+ in->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
+ in->nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT;
+ msg = (struct rtgenmsg*)NLMSG_DATA(in);
msg->rtgen_family = AF_UNSPEC;
-
- if (netlink_send(this->socket_rt, hdr, &out, &len) == SUCCESS)
+
+ /* get all links */
+ in->nlmsg_type = RTM_GETLINK;
+ if (netlink_send(this, this->socket_rt, in, &out, &len) != SUCCESS)
{
- hdr = out;
- while (NLMSG_OK(hdr, len))
+ return FAILED;
+ }
+ current = out;
+ while (NLMSG_OK(current, len))
+ {
+ switch (current->nlmsg_type)
{
- switch (hdr->nlmsg_type)
- {
- case RTM_NEWADDR:
- {
- process_newaddr(this, hdr, TRUE);
- hdr = NLMSG_NEXT(hdr, len);
- continue;
- }
- default:
- hdr = NLMSG_NEXT(hdr, len);
- continue;
- case NLMSG_DONE:
- break;
- }
- break;
+ case NLMSG_DONE:
+ break;
+ case RTM_NEWLINK:
+ process_link(this, current, FALSE);
+ /* fall through */
+ default:
+ current = NLMSG_NEXT(current, len);
+ continue;
}
- free(out);
+ break;
}
- else
+ free(out);
+
+ /* get all interface addresses */
+ in->nlmsg_type = RTM_GETADDR;
+ if (netlink_send(this, this->socket_rt, in, &out, &len) != SUCCESS)
{
- DBG1(DBG_IKE, "unable to get local address list");
+ return FAILED;
}
+ current = out;
+ while (NLMSG_OK(current, len))
+ {
+ switch (current->nlmsg_type)
+ {
+ case NLMSG_DONE:
+ break;
+ case RTM_NEWADDR:
+ process_addr(this, current, FALSE);
+ /* fall through */
+ default:
+ current = NLMSG_NEXT(current, len);
+ continue;
+ }
+ break;
+ }
+ free(out);
+
+ i_iface = this->interfaces->create_iterator_locked(this->interfaces,
+ &this->mutex);
+ while (i_iface->iterate(i_iface, (void**)&entry))
+ {
+ if (entry->flags & IFF_UP)
+ {
+ DBG1(DBG_KNL, " %s", entry->ifname);
+ i_addr = entry->addresses->create_iterator(entry->addresses, TRUE);
+ while (i_addr->iterate(i_addr, (void**)&address))
+ {
+ DBG1(DBG_KNL, " %H", address);
+ }
+ i_addr->destroy(i_addr);
+ }
+ }
+ i_iface->destroy(i_iface);
+
+ return SUCCESS;
}
/**
* 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)
+static hook_result_t hook(private_kernel_interface_t *this,
+ interface_entry_t *in, host_t **out)
{
- *out = in->host;
- return TRUE;
+ if (!(in->flags & IFF_UP))
+ { /* skip interfaces not up */
+ return HOOK_SKIP;
+ }
+
+ if (this->hiter == NULL)
+ {
+ this->hiter = in->addresses->create_iterator(in->addresses, TRUE);
+ }
+ while (this->hiter->iterate(this->hiter, (void**)out))
+ {
+ return HOOK_AGAIN;
+ }
+ this->hiter->destroy(this->hiter);
+ this->hiter = NULL;
+ return HOOK_SKIP;
}
/**
@@ -973,9 +1090,9 @@ static iterator_t *create_address_iterator(private_kernel_interface_t *this)
{
iterator_t *iterator;
- iterator = this->addrs->create_iterator_locked(this->addrs, &this->addrs_mutex);
- iterator->set_iterator_hook(iterator,
- (iterator_hook_t*)address_iterator_hook, this);
+ iterator = this->interfaces->create_iterator_locked(this->interfaces,
+ &this->mutex);
+ iterator->set_iterator_hook(iterator, (iterator_hook_t*)hook, this);
return iterator;
}
@@ -984,18 +1101,29 @@ static iterator_t *create_address_iterator(private_kernel_interface_t *this)
*/
static char *get_interface_name(private_kernel_interface_t *this, host_t* ip)
{
- iterator_t *iterator;
- address_entry_t *entry;
+ iterator_t *iterator, *addresses;
+ interface_entry_t *entry;
+ host_t *host;
char *name = NULL;
DBG2(DBG_IKE, "getting interface name for %H", ip);
- iterator = this->addrs->create_iterator_locked(this->addrs, &this->addrs_mutex);
+ iterator = this->interfaces->create_iterator_locked(this->interfaces,
+ &this->mutex);
while (iterator->iterate(iterator, (void**)&entry))
{
- if (ip->ip_equals(ip, entry->host))
+ addresses = entry->addresses->create_iterator(entry->addresses, TRUE);
+ while (addresses->iterate(addresses, (void**)&host))
+ {
+ if (ip->ip_equals(ip, host))
+ {
+ name = strdup(entry->ifname);
+ break;
+ }
+ }
+ addresses->destroy(addresses);
+ if (name)
{
- name = strdup(entry->ifname);
break;
}
}
@@ -1019,8 +1147,8 @@ 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;
+ iterator_t *iterator, *addresses;
+ interface_entry_t *entry;
host_t *host;
int family;
bool found = FALSE;
@@ -1049,13 +1177,23 @@ static status_t get_address_by_ts(private_kernel_interface_t *this,
}
host->destroy(host);
- iterator = this->addrs->create_iterator_locked(this->addrs, &this->addrs_mutex);
+ iterator = this->interfaces->create_iterator_locked(this->interfaces,
+ &this->mutex);
while (iterator->iterate(iterator, (void**)&entry))
{
- if (ts->includes(ts, entry->host))
+ addresses = entry->addresses->create_iterator(entry->addresses, TRUE);
+ while (addresses->iterate(addresses, (void**)&host))
+ {
+ if (ts->includes(ts, host))
+ {
+ found = TRUE;
+ *ip = host->clone(host);
+ break;
+ }
+ }
+ addresses->destroy(addresses);
+ if (found)
{
- found = TRUE;
- *ip = entry->host->clone(entry->host);
break;
}
}
@@ -1075,23 +1213,34 @@ 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)
{
- iterator_t *iterator;
- address_entry_t *entry;
+ iterator_t *iterator, *addresses;
+ interface_entry_t *entry;
+ host_t *host;
int ifindex = 0;
DBG2(DBG_IKE, "getting iface for %H", ip);
- iterator = this->addrs->create_iterator_locked(this->addrs, &this->addrs_mutex);
+ iterator = this->interfaces->create_iterator_locked(this->interfaces,
+ &this->mutex);
while (iterator->iterate(iterator, (void**)&entry))
{
- if (ip->ip_equals(ip, entry->host))
+ addresses = entry->addresses->create_iterator(entry->addresses, TRUE);
+ while (addresses->iterate(addresses, (void**)&host))
+ {
+ if (ip->ip_equals(ip, host))
+ {
+ ifindex = entry->ifindex;
+ break;
+ }
+ }
+ addresses->destroy(addresses);
+ if (ifindex)
{
- ifindex = entry->ifindex;
break;
}
}
iterator->destroy(iterator);
-
+
if (ifindex == 0)
{
DBG1(DBG_IKE, "unable to get interface for %H", ip);
@@ -1129,7 +1278,7 @@ static status_t manage_ipaddr(private_kernel_interface_t *this, int nlmsg_type,
add_attribute(hdr, IFA_LOCAL, chunk, sizeof(request));
- return netlink_send_ack(this->socket_rt, hdr);
+ return netlink_send_ack(this, this->socket_rt, hdr);
}
/**
@@ -1190,7 +1339,7 @@ static status_t manage_srcroute(private_kernel_interface_t *this, int nlmsg_type
chunk.len = sizeof(route->if_index);
add_attribute(hdr, RTA_OIF, chunk, sizeof(request));
- return netlink_send_ack(this->socket_rt, hdr);
+ return netlink_send_ack(this, this->socket_rt, hdr);
}
@@ -1215,7 +1364,7 @@ static status_t add_ip(private_kernel_interface_t *this,
}
/* beware of deadlocks (e.g. send/receive packets while holding the lock) */
- iterator = this->vips->create_iterator_locked(this->vips, &(this->vips_mutex));
+ iterator = this->vips->create_iterator_locked(this->vips, &this->mutex);
while (iterator->iterate(iterator, (void**)&listed))
{
if (listed->if_index == targetif &&
@@ -1269,7 +1418,7 @@ static status_t del_ip(private_kernel_interface_t *this,
}
/* beware of deadlocks (e.g. send/receive packets while holding the lock) */
- iterator = this->vips->create_iterator_locked(this->vips, &(this->vips_mutex));
+ iterator = this->vips->create_iterator_locked(this->vips, &this->mutex);
while (iterator->iterate(iterator, (void**)&listed))
{
if (listed->if_index == targetif &&
@@ -1328,7 +1477,7 @@ static status_t get_spi(private_kernel_interface_t *this,
userspi->min = 0xc0000000;
userspi->max = 0xcFFFFFFF;
- if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
+ if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS)
{
hdr = out;
while (NLMSG_OK(hdr, len))
@@ -1506,7 +1655,7 @@ static status_t add_sa(private_kernel_interface_t *this,
rthdr = XFRM_RTA_NEXT(rthdr);
}
- if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS)
+ if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS)
{
DBG1(DBG_KNL, "unalbe to add SAD entry with SPI 0x%x", spi);
return FAILED;
@@ -1544,7 +1693,7 @@ static status_t update_sa(private_kernel_interface_t *this,
sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
sa_id->family = dst->get_family(dst);
- if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
+ if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS)
{
hdr = out;
while (NLMSG_OK(hdr, len))
@@ -1613,7 +1762,7 @@ static status_t update_sa(private_kernel_interface_t *this,
rtattr = RTA_NEXT(rtattr, rtsize);
}
}
- if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS)
+ if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS)
{
DBG1(DBG_KNL, "unalbe to update SAD entry with SPI 0x%x", spi);
free(out);
@@ -1655,7 +1804,7 @@ static status_t query_sa(private_kernel_interface_t *this, host_t *dst,
sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
sa_id->family = dst->get_family(dst);
- if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
+ if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS)
{
hdr = out;
while (NLMSG_OK(hdr, len))
@@ -1721,7 +1870,7 @@ static status_t del_sa(private_kernel_interface_t *this, host_t *dst,
sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
sa_id->family = dst->get_family(dst);
- if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS)
+ if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS)
{
DBG1(DBG_KNL, "unalbe to delete SAD entry with SPI 0x%x", spi);
return FAILED;
@@ -1755,7 +1904,7 @@ static status_t add_policy(private_kernel_interface_t *this,
policy->direction = direction;
/* find the policy, which matches EXACTLY */
- pthread_mutex_lock(&this->policies_mutex);
+ pthread_mutex_lock(&this->mutex);
iterator = this->policies->create_iterator(this->policies, TRUE);
while (iterator->iterate(iterator, (void**)&current))
{
@@ -1800,7 +1949,7 @@ static status_t add_policy(private_kernel_interface_t *this,
policy_info->priority -= policy->sel.sport_mask ? 1 : 0;
policy_info->action = XFRM_POLICY_ALLOW;
policy_info->share = XFRM_SHARE_ANY;
- pthread_mutex_unlock(&this->policies_mutex);
+ pthread_mutex_unlock(&this->mutex);
/* policies don't expire */
policy_info->lft.soft_byte_limit = XFRM_INF;
@@ -1834,7 +1983,7 @@ static status_t add_policy(private_kernel_interface_t *this,
host2xfrm(src, &tmpl->saddr);
host2xfrm(dst, &tmpl->id.daddr);
- if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS)
+ if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS)
{
DBG1(DBG_KNL, "unable to add policy %R===%R", src_ts, dst_ts);
return FAILED;
@@ -1904,7 +2053,7 @@ static status_t query_policy(private_kernel_interface_t *this,
policy_id->sel = ts2selector(src_ts, dst_ts);
policy_id->dir = direction;
- if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
+ if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS)
{
hdr = out;
while (NLMSG_OK(hdr, len))
@@ -1968,8 +2117,7 @@ static status_t del_policy(private_kernel_interface_t *this,
policy.direction = direction;
/* find the policy */
- pthread_mutex_lock(&this->policies_mutex);
- iterator = this->policies->create_iterator(this->policies, TRUE);
+ iterator = this->policies->create_iterator_locked(this->policies, &this->mutex);
while (iterator->iterate(iterator, (void**)&current))
{
if (memcmp(&current->sel, &policy.sel, sizeof(struct xfrm_selector)) == 0 &&
@@ -1981,7 +2129,6 @@ static status_t del_policy(private_kernel_interface_t *this,
/* is used by more SAs, keep in kernel */
DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed");
iterator->destroy(iterator);
- pthread_mutex_unlock(&this->policies_mutex);
return SUCCESS;
}
/* remove if last reference */
@@ -1990,7 +2137,6 @@ static status_t del_policy(private_kernel_interface_t *this,
}
}
iterator->destroy(iterator);
- pthread_mutex_unlock(&this->policies_mutex);
if (!to_delete)
{
DBG1(DBG_KNL, "deleting policy %R===%R failed, not found", src_ts, dst_ts);
@@ -2011,7 +2157,7 @@ static status_t del_policy(private_kernel_interface_t *this,
route = to_delete->route;
free(to_delete);
- if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS)
+ if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS)
{
DBG1(DBG_KNL, "unable to delete policy %R===%R", src_ts, dst_ts);
return FAILED;
@@ -2041,7 +2187,7 @@ static void destroy(private_kernel_interface_t *this)
close(this->socket_rt);
this->vips->destroy(this->vips);
this->policies->destroy(this->policies);
- this->addrs->destroy_function(this->addrs, (void*)address_entry_destroy);
+ this->interfaces->destroy_function(this->interfaces, (void*)interface_entry_destroy);
free(this);
}
@@ -2053,6 +2199,7 @@ 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;
@@ -2072,10 +2219,10 @@ 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);
+ this->interfaces = linked_list_create();
+ this->hiter = NULL;
+ this->seq = 200;
+ pthread_mutex_init(&this->mutex,NULL);
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
@@ -2092,13 +2239,13 @@ kernel_interface_t *kernel_interface_create()
charon->kill(charon, "unable to bind RT netlink socket");
}
- /* create and bind RT socket for events (address changes) */
+ /* create and bind RT socket for events (address/interface 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;
+ addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_LINK;
if (bind(this->socket_rt_events, (struct sockaddr*)&addr, sizeof(addr)))
{
charon->kill(charon, "unable to bind RT event socket");
@@ -2132,7 +2279,10 @@ kernel_interface_t *kernel_interface_create()
this, NULL, NULL);
charon->processor->queue_job(charon->processor, (job_t*)this->job);
- init_address_list(this);
+ if (init_address_list(this) != SUCCESS)
+ {
+ charon->kill(charon, "unable to get interface list");
+ }
return &this->public;
}
diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c
index a62ec5e3c..bc9094023 100644
--- a/src/charon/sa/ike_sa_manager.c
+++ b/src/charon/sa/ike_sa_manager.c
@@ -682,16 +682,16 @@ static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name,
/**
* Iterator hook for iterate, gets ike_sas instead of entries
*/
-static bool iterator_hook(private_ike_sa_manager_t* this, entry_t *in,
- ike_sa_t **out)
+static hook_result_t iterator_hook(private_ike_sa_manager_t* this, entry_t *in,
+ ike_sa_t **out)
{
/* check out entry */
if (wait_for_entry(this, in))
{
*out = in->ike_sa;
- return TRUE;
+ return HOOK_NEXT;
}
- return FALSE;
+ return HOOK_SKIP;
}
/**
diff --git a/src/libstrongswan/utils/iterator.h b/src/libstrongswan/utils/iterator.h
index 02a15c534..b4ff85bfb 100644
--- a/src/libstrongswan/utils/iterator.h
+++ b/src/libstrongswan/utils/iterator.h
@@ -26,15 +26,46 @@
#include <library.h>
+typedef enum hook_result_t hook_result_t;
+
+/**
+ * @brief Return value of an iterator hook.
+ *
+ * Returning HOOK_AGAIN is useful to "inject" additional elements in an
+ * iteration, HOOK_NEXT is the normal iterator behavior, and HOOK_SKIP may
+ * be used to filter elements out.
+ *
+ * @ingroup utils
+ */
+enum hook_result_t {
+
+ /**
+ * A value was placed in out, hook is called again with the same "in"
+ */
+ HOOK_AGAIN,
+
+ /**
+ * A value was placed in out, hook is called again with next "in" (if any)
+ */
+ HOOK_NEXT,
+
+ /**
+ * No value in out, call again with next "in" (if any)
+ */
+ HOOK_SKIP,
+};
+
/**
* @brief Iterator hook function prototype.
*
* @param param user supplied parameter
* @param in the value the hook receives from the iterator
* @param out the value supplied as a result to the iterator
- * @return TRUE to return "out", FALSE to skip this value
+ * @return a hook_result_t
+ *
+ * @ingroup utils
*/
-typedef bool (iterator_hook_t)(void *param, void *in, void **out);
+typedef hook_result_t (iterator_hook_t)(void *param, void *in, void **out);
typedef struct iterator_t iterator_t;
@@ -45,8 +76,6 @@ typedef struct iterator_t iterator_t;
* iterator_t defines an interface for iterating over collections.
* It allows searching, deleting, updating and inserting.
*
- * Thanks to JMP for iterator lessons :-)
- *
* @b Constructors:
* - via linked_list_t.create_iterator, or
* - any other class which supports the iterator_t interface
@@ -84,8 +113,11 @@ struct iterator_t {
* Sometimes it is useful to hook in an iterator. The hook function is
* called before any successful return of iterate(). It takes the
* iterator value, may manipulate it (or the references object), and returns
- * the value that the iterate() function returns.
+ * the value that the iterate() function returns. Depending on the hook
+ * return value, the hook is called again, called with next, or skipped.
* A value of NULL deactivates the iterator hook.
+ * If an iterator is hooked, only the iterate() method is valid,
+ * all other methods behave undefined.
*
* @param this calling object
* @param hook iterator hook which manipulates the iterated value
diff --git a/src/libstrongswan/utils/linked_list.c b/src/libstrongswan/utils/linked_list.c
index de043a02e..de52ea46a 100644
--- a/src/libstrongswan/utils/linked_list.c
+++ b/src/libstrongswan/utils/linked_list.c
@@ -151,10 +151,10 @@ static int get_list_count(private_iterator_t *this)
/**
* default iterator hook which does nothing
*/
-static bool iterator_hook(void *param, void *in, void **out)
+static hook_result_t iterator_hook(void *param, void *in, void **out)
{
*out = in;
- return TRUE;
+ return HOOK_NEXT;
}
/**
@@ -180,40 +180,43 @@ static void set_iterator_hook(private_iterator_t *this, iterator_hook_t *hook,
*/
static bool iterate(private_iterator_t *this, void** value)
{
- if (this->list->count == 0)
- {
- return FALSE;
- }
- if (this->current == NULL)
+ while (TRUE)
{
- this->current = (this->forward) ? this->list->first : this->list->last;
- if (!this->hook(this->hook_param, this->current->value, value))
+ if (this->forward)
{
- return iterate(this, value);
+ this->current = this->current ? this->current->next : this->list->first;
}
- return TRUE;
- }
- if (this->forward)
- {
- if (this->current->next == NULL)
+ else
+ {
+ this->current = this->current ? this->current->previous : this->list->last;
+ }
+
+ if (this->current == NULL)
{
return FALSE;
}
- this->current = this->current->next;
- if (!this->hook(this->hook_param, this->current->value, value))
+
+ switch (this->hook(this->hook_param, this->current->value, value))
{
- return iterate(this, value);
+ case HOOK_AGAIN:
+ /* rewind */
+ if (this->forward)
+ {
+ this->current = this->current->previous;
+ }
+ else
+ {
+ this->current = this->current->next;
+ }
+ break;
+ case HOOK_NEXT:
+ /* normal iteration */
+ break;
+ case HOOK_SKIP:
+ /* advance */
+ continue;
}
- return TRUE;
- }
- if (this->current->previous == NULL)
- {
- return FALSE;
- }
- this->current = this->current->previous;
- if (!this->hook(this->hook_param, this->current->value, value))
- {
- return iterate(this, value);
+ break;
}
return TRUE;
}