implemented address change notification (for MOBIKE)

implemented up to date address list cache to list interfaces
This commit is contained in:
Martin Willi 2007-06-14 15:16:15 +00:00
parent fede28be8b
commit 02b3ec0a10
5 changed files with 376 additions and 216 deletions

View File

@ -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);

View File

@ -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);

View File

@ -298,26 +298,41 @@ 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
*/
callback_job_t *job;
/**
* netlink xfrm socket to receive acquire and expire events
*/
int socket_xfrm_events;
/**
* Netlink xfrm socket (IPsec)
*/
int socket_xfrm;
/**
* netlink xfrm socket to receive acquire and expire events
*/
int socket_xfrm_events;
/**
* Netlink rt socket (routing)
*/
int socket_rt;
/**
* Netlink rt socket to receive address change events
*/
int socket_rt_events;
};
/**
@ -442,99 +457,294 @@ static void add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data,
hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + rta->rta_len;
}
/**
* process a XFRM_MSG_ACQUIRE from kernel
*/
static void process_acquire(private_kernel_interface_t *this, struct nlmsghdr *hdr)
{
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))
{
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;
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;
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
{
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;
}
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)");
}
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);
}
/* 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;
iterator = this->addrs->create_iterator_locked(this->addrs,
&this->addrs_mutex);
while (iterator->iterate(iterator, (void**)&entry))
{
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);
}
}
iterator->destroy(iterator);
host->destroy(host);
}
}
/**
* Receives events from kernel
*/
static job_requeue_t receive_events(private_kernel_interface_t *this)
{
unsigned char response[512];
struct nlmsghdr *hdr;
char response[512];
struct nlmsghdr *hdr = (struct nlmsghdr*)response;
struct sockaddr_nl addr;
socklen_t addr_len = sizeof(addr);
int len, oldstate;
hdr = (struct nlmsghdr*)response;
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);
len = recvfrom(this->socket_xfrm_events, response, sizeof(response), 0,
(struct sockaddr*)&addr, &addr_len);
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)
{
if (errno == EINTR)
{ /* interrupted, try again */
return JOB_REQUEUE_DIRECT;
}
charon->kill(charon, "unable to receive netlink events");
}
if (!NLMSG_OK(hdr, len))
{
/* bad netlink message */
return JOB_REQUEUE_DIRECT;
}
if (addr.nl_pid != 0)
{
/* not from kernel. not interested, try another one */
return JOB_REQUEUE_DIRECT;
}
/* we handle ACQUIRE and EXPIRE messages directly */
if (hdr->nlmsg_type == XFRM_MSG_ACQUIRE)
{
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))
switch (errno)
{
if (rtattr->rta_type == XFRMA_TMPL)
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;
}
}
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)
{
struct xfrm_user_tmpl* tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rtattr);
reqid = tmpl->reqid;
case XFRM_MSG_ACQUIRE:
process_acquire(this, hdr);
break;
case XFRM_MSG_EXPIRE:
process_expire(this, hdr);
break;
default:
break;
}
}
if (reqid == 0)
else if (selected == this->socket_rt_events)
{
DBG1(DBG_KNL, "received a XFRM_MSG_ACQUIRE, but no reqid found");
switch (hdr->nlmsg_type)
{
case RTM_NEWADDR:
process_newaddr(this, hdr, FALSE);
break;
case RTM_DELADDR:
process_deladdr(this, hdr);
break;
default:
break;
}
}
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);
}
}
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;
hdr = NLMSG_NEXT(hdr, len);
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;
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
{
job = (job_t*)rekey_child_sa_job_create(reqid, protocol, spi);
}
charon->processor->queue_job(charon->processor, job);
}
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;
}
/**
* Implements kernel_interface_t.create_address_list.
* iterator hook to return address, not address_entry_t
*/
static linked_list_t *create_address_list_public(private_kernel_interface_t *this)
bool address_iterator_hook(private_kernel_interface_t *this,
address_entry_t *in, host_t **out)
{
linked_list_t *result, *list;
address_entry_t *entry;
*out = in->host;
return TRUE;
}
/**
* Implements kernel_interface_t.create_address_iterator.
*/
static iterator_t *create_address_iterator(private_kernel_interface_t *this)
{
iterator_t *iterator;
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);
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;
}

View File

@ -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.

View File

@ -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
{