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);
}
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)
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;
}
/**
- * 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**)¤t))
+ {
+ 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**)¤t))
+ {
+ 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)
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);
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**)¤t))
+ {
+ 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);
}
/**
*/
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);
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;
}
/**
* 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;
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));
/* 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;
}
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;
}
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;
*out_len = result.len;
*out = (struct nlmsghdr*)clalloc(result.ptr, result.len);
- pthread_mutex_unlock(&mutex);
+ pthread_mutex_unlock(&this->mutex);
return SUCCESS;
}
/**
* 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;
}
/**
* 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;
}
/**
{
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;
}
*/
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;
}
}
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;
}
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;
}
}
*/
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);
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);
}
/**
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);
}
}
/* 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 &&
}
/* 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 &&
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))
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;
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))
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);
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))
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;
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**)¤t))
{
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;
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;
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))
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**)¤t))
{
if (memcmp(¤t->sel, &policy.sel, sizeof(struct xfrm_selector)) == 0 &&
/* 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 */
}
}
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);
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;
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);
}
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;
/* 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;
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");
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;
}