implemented more flexible iterator hook API

kernel interface handles interface changes and updates address list
This commit is contained in:
Martin Willi
2007-06-15 13:23:18 +00:00
parent 02b3ec0a10
commit 08a8f4496f
5 changed files with 439 additions and 255 deletions
+366 -216
View File
@@ -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);
}
@@ -279,41 +282,41 @@ struct private_kernel_interface_t {
*/
kernel_interface_t public;
/**
* mutex to lock access to the various lists
*/
pthread_mutex_t mutex;
/**
* List of installed policies (kernel_entry_t)
*/
linked_list_t *policies;
/**
* Mutex locks access to policies
*/
pthread_mutex_t policies_mutex;
/**
* List of installed virtual IPs. (vip_entry_t)
*/
linked_list_t *vips;
/**
* Mutex to lock access to vips.
* Cached list of interfaces and its adresses (interface_entry_t)
*/
pthread_mutex_t vips_mutex;
linked_list_t *interfaces;
/**
* Cached list of IP adresses (address_entry_t)
* iterator used in hook()
*/
linked_list_t *addrs;
/**
* Mutex to lock access to addr.
*/
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)
*/
@@ -517,18 +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 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;
while(RTA_OK(rta, rtasize))
{
switch (rta->rta_type)
{
case IFLA_IFNAME:
name = RTA_DATA(rta);
break;
}
rta = RTA_NEXT(rta, rtasize);
}
if (!name)
{
name = "(unknown)";
}
switch (hdr->nlmsg_type)
{
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;
}
case RTM_DELLINK:
{
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;
}
}
}
/**
* process RTM_NEWADDR/RTM_DELADDR from kernel
*/
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;
char *name = 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)
@@ -541,9 +636,6 @@ static void process_newaddr(private_kernel_interface_t *this,
address.ptr = RTA_DATA(rta);
address.len = RTA_PAYLOAD(rta);
break;
case IFA_LABEL:
name = RTA_DATA(rta);
break;
}
rta = RTA_NEXT(rta, rtasize);
}
@@ -560,95 +652,66 @@ static void process_newaddr(private_kernel_interface_t *this,
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)");
}
if (initial)
{
DBG1(DBG_KNL, " %H on %s", host, entry->ifname);
}
else
{
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);
}
}
/**
* 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;
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);
if (host == NULL)
{ /* bad family? */
return;
}
/* same stuff as in newaddr */
if (local.ptr)
switch (hdr->nlmsg_type)
{
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;
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(&this->mutex);
pthread_mutex_lock(&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;
}