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
@@ -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) static void stroke_status(stroke_msg_t *msg, FILE *out, bool all)
{ {
iterator_t *iterator, *children; iterator_t *iterator, *children;
linked_list_t *list;
host_t *host; host_t *host;
peer_cfg_t *peer_cfg; peer_cfg_t *peer_cfg;
ike_cfg_t *ike_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)); charon->processor->get_job_load(charon->processor));
fprintf(out, " scheduled events: %d\n", fprintf(out, " scheduled events: %d\n",
charon->scheduler->get_job_load(charon->scheduler)); charon->scheduler->get_job_load(charon->scheduler));
list = charon->kernel_interface->create_address_list(charon->kernel_interface); iterator = charon->kernel_interface->create_address_iterator(
charon->kernel_interface);
fprintf(out, "Listening on %d IP addresses:\n", list->get_count(list)); fprintf(out, "Listening on %d IP addresses:\n",
while (list->remove_first(list, (void**)&host) == SUCCESS) iterator->get_count(iterator));
while (iterator->iterate(iterator, (void**)&host))
{ {
fprintf(out, " %H\n", host); fprintf(out, " %H\n", host);
host->destroy(host);
} }
list->destroy(list); iterator->destroy(iterator);
fprintf(out, "Connections:\n"); fprintf(out, "Connections:\n");
iterator = charon->backends->create_iterator(charon->backends); iterator = charon->backends->create_iterator(charon->backends);
-12
View File
@@ -426,8 +426,6 @@ int main(int argc, char *argv[])
private_daemon_t *private_charon; private_daemon_t *private_charon;
FILE *pid_file; FILE *pid_file;
struct stat stb; struct stat stb;
linked_list_t *list;
host_t *host;
level_t levels[DBG_MAX]; level_t levels[DBG_MAX];
int signal; int signal;
@@ -530,16 +528,6 @@ int main(int argc, char *argv[])
fclose(pid_file); 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 additional capabilites (bind & root) */
drop_capabilities(private_charon, TRUE); drop_capabilities(private_charon, TRUE);
+358 -188
View File
@@ -298,26 +298,41 @@ struct private_kernel_interface_t {
* Mutex to lock access to vips. * Mutex to lock access to vips.
*/ */
pthread_mutex_t vips_mutex; 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 * job receiving xfrm events
*/ */
callback_job_t *job; callback_job_t *job;
/**
* netlink xfrm socket to receive acquire and expire events
*/
int socket_xfrm_events;
/** /**
* Netlink xfrm socket (IPsec) * Netlink xfrm socket (IPsec)
*/ */
int socket_xfrm; int socket_xfrm;
/**
* netlink xfrm socket to receive acquire and expire events
*/
int socket_xfrm_events;
/** /**
* Netlink rt socket (routing) * Netlink rt socket (routing)
*/ */
int socket_rt; 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; 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 * Receives events from kernel
*/ */
static job_requeue_t receive_events(private_kernel_interface_t *this) static job_requeue_t receive_events(private_kernel_interface_t *this)
{ {
unsigned char response[512]; char response[512];
struct nlmsghdr *hdr; struct nlmsghdr *hdr = (struct nlmsghdr*)response;
struct sockaddr_nl addr; struct sockaddr_nl addr;
socklen_t addr_len = sizeof(addr); socklen_t addr_len = sizeof(addr);
int len, oldstate; int len, oldstate, maxfd, selected;
fd_set rfds;
hdr = (struct nlmsghdr*)response;
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); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
len = recvfrom(this->socket_xfrm_events, response, sizeof(response), 0, selected = select(maxfd + 1, &rfds, NULL, NULL, NULL);
(struct sockaddr*)&addr, &addr_len);
pthread_setcancelstate(oldstate, 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 (len < 0)
{ {
if (errno == EINTR) switch (errno)
{ /* 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))
{ {
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); case XFRM_MSG_ACQUIRE:
reqid = tmpl->reqid; 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 hdr = NLMSG_NEXT(hdr, len);
{
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;
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; 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]; char request[BUFFER_SIZE];
struct nlmsghdr *out, *hdr; struct nlmsghdr *out, *hdr;
struct rtgenmsg *msg; struct rtgenmsg *msg;
size_t len; size_t len;
linked_list_t *list;
DBG2(DBG_IKE, "getting local address list"); DBG1(DBG_IKE, "listening on interfaces:");
list = linked_list_create();
memset(&request, 0, sizeof(request)); memset(&request, 0, sizeof(request));
@@ -729,61 +936,7 @@ static linked_list_t *create_address_list(private_kernel_interface_t *this)
{ {
case RTM_NEWADDR: case RTM_NEWADDR:
{ {
struct ifaddrmsg* msg = (struct ifaddrmsg*)(NLMSG_DATA(hdr)); process_newaddr(this, hdr, TRUE);
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);
}
hdr = NLMSG_NEXT(hdr, len); hdr = NLMSG_NEXT(hdr, len);
continue; 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"); 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; *out = in->host;
address_entry_t *entry; 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(); iterator = this->addrs->create_iterator_locked(this->addrs, &this->addrs_mutex);
list = create_address_list(this); iterator->set_iterator_hook(iterator,
while (list->remove_last(list, (void**)&entry) == SUCCESS) (iterator_hook_t*)address_iterator_hook, this);
{ return iterator;
result->insert_last(result, entry->host);
free(entry);
}
list->destroy(list);
return result;
} }
/** /**
@@ -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) static char *get_interface_name(private_kernel_interface_t *this, host_t* ip)
{ {
linked_list_t *list; iterator_t *iterator;
address_entry_t *entry; address_entry_t *entry;
char *name = NULL; char *name = NULL;
DBG2(DBG_IKE, "getting interface name for %H", ip); DBG2(DBG_IKE, "getting interface name for %H", ip);
list = create_address_list(this); iterator = this->addrs->create_iterator_locked(this->addrs, &this->addrs_mutex);
while (!name && list->remove_last(list, (void**)&entry) == SUCCESS) while (iterator->iterate(iterator, (void**)&entry))
{ {
if (ip->ip_equals(ip, entry->host)) if (ip->ip_equals(ip, entry->host))
{ {
name = strdup(entry->ifname); name = strdup(entry->ifname);
break;
} }
address_entry_destroy(entry);
} }
list->destroy_function(list, (void*)address_entry_destroy); iterator->destroy(iterator);
if (name) 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, static status_t get_address_by_ts(private_kernel_interface_t *this,
traffic_selector_t *ts, host_t **ip) traffic_selector_t *ts, host_t **ip)
{ {
iterator_t *iterator;
address_entry_t *entry; address_entry_t *entry;
host_t *host; host_t *host;
int family; int family;
linked_list_t *list;
bool found = FALSE; bool found = FALSE;
DBG2(DBG_IKE, "getting a local address in traffic selector %R", ts); 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); host->destroy(host);
list = create_address_list(this); iterator = this->addrs->create_iterator_locked(this->addrs, &this->addrs_mutex);
while (!found && list->remove_last(list, (void**)&entry) == SUCCESS) while (iterator->iterate(iterator, (void**)&entry))
{ {
if (ts->includes(ts, entry->host)) if (ts->includes(ts, entry->host))
{ {
found = TRUE; found = TRUE;
*ip = entry->host->clone(entry->host); *ip = entry->host->clone(entry->host);
break;
} }
address_entry_destroy(entry);
} }
list->destroy_function(list, (void*)address_entry_destroy); iterator->destroy(iterator);
if (!found) 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) static int get_interface_index(private_kernel_interface_t *this, host_t* ip)
{ {
linked_list_t *list; iterator_t *iterator;
address_entry_t *entry; address_entry_t *entry;
int ifindex = 0; int ifindex = 0;
DBG2(DBG_IKE, "getting iface for %H", ip); DBG2(DBG_IKE, "getting iface for %H", ip);
list = create_address_list(this); iterator = this->addrs->create_iterator_locked(this->addrs, &this->addrs_mutex);
while (!ifindex && list->remove_last(list, (void**)&entry) == SUCCESS) while (iterator->iterate(iterator, (void**)&entry))
{ {
if (ip->ip_equals(ip, entry->host)) if (ip->ip_equals(ip, entry->host))
{ {
ifindex = entry->ifindex; ifindex = entry->ifindex;
break;
} }
address_entry_destroy(entry);
} }
list->destroy_function(list, (void*)address_entry_destroy); iterator->destroy(iterator);
if (ifindex == 0) if (ifindex == 0)
{ {
@@ -1883,9 +2037,11 @@ static void destroy(private_kernel_interface_t *this)
this->job->cancel(this->job); this->job->cancel(this->job);
close(this->socket_xfrm_events); close(this->socket_xfrm_events);
close(this->socket_xfrm); close(this->socket_xfrm);
close(this->socket_rt_events);
close(this->socket_rt); close(this->socket_rt);
this->vips->destroy(this->vips); this->vips->destroy(this->vips);
this->policies->destroy(this->policies); this->policies->destroy(this->policies);
this->addrs->destroy_function(this->addrs, (void*)address_entry_destroy);
free(this); 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.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.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.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.del_ip = (status_t(*)(kernel_interface_t*,host_t*,host_t*)) del_ip;
this->public.destroy = (void(*)(kernel_interface_t*)) destroy; this->public.destroy = (void(*)(kernel_interface_t*)) destroy;
@@ -1916,24 +2072,13 @@ kernel_interface_t *kernel_interface_create()
/* private members */ /* private members */
this->vips = linked_list_create(); this->vips = linked_list_create();
this->policies = linked_list_create(); this->policies = linked_list_create();
this->addrs = linked_list_create();
pthread_mutex_init(&this->policies_mutex,NULL); pthread_mutex_init(&this->policies_mutex,NULL);
pthread_mutex_init(&this->vips_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_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 */ /* create and bind RT socket */
this->socket_rt = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 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"); charon->kill(charon, "unable to create RT netlink socket");
} }
addr.nl_groups = 0;
if (bind(this->socket_rt, (struct sockaddr*)&addr, sizeof(addr))) if (bind(this->socket_rt, (struct sockaddr*)&addr, sizeof(addr)))
{ {
charon->kill(charon, "unable to bind RT netlink socket"); 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 */ /* 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); this->socket_xfrm_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM);
if (this->socket_xfrm_events <= 0) if (this->socket_xfrm_events <= 0)
{ {
charon->kill(charon, "unable to create XFRM event socket"); 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))) if (bind(this->socket_xfrm_events, (struct sockaddr*)&addr, sizeof(addr)))
{ {
charon->kill(charon, "unable to bind XFRM event socket"); charon->kill(charon, "unable to bind XFRM event socket");
@@ -1964,6 +2132,8 @@ kernel_interface_t *kernel_interface_create()
this, NULL, NULL); this, NULL, NULL);
charon->processor->queue_job(charon->processor, (job_t*)this->job); charon->processor->queue_job(charon->processor, (job_t*)this->job);
init_address_list(this);
return &this->public; return &this->public;
} }
+7 -3
View File
@@ -277,12 +277,16 @@ struct kernel_interface_t {
char* (*get_interface) (kernel_interface_t *this, host_t *host); 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 * @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. * @brief Add a virtual IP to an interface.
+5 -6
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) static status_t build_i(private_ike_natd_t *this, message_t *message)
{ {
notify_payload_t *notify; notify_payload_t *notify;
linked_list_t *list; iterator_t *iterator;
host_t *host; host_t *host;
/* include one notify if our address is defined, all addresses otherwise */ /* include one notify if our address is defined, all addresses otherwise */
host = this->ike_sa->get_my_host(this->ike_sa); host = this->ike_sa->get_my_host(this->ike_sa);
if (host->is_anyaddr(host)) if (host->is_anyaddr(host))
{ {
/* TODO: we could get the src address from netlink!? */ iterator = charon->kernel_interface->create_address_iterator(
list = charon->kernel_interface->create_address_list(charon->kernel_interface); charon->kernel_interface);
while (list->remove_first(list, (void**)&host) == SUCCESS) while (iterator->iterate(iterator, (void**)&host))
{ {
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
host->destroy(host);
message->add_payload(message, (payload_t*)notify); message->add_payload(message, (payload_t*)notify);
} }
list->destroy(list); iterator->destroy(iterator);
} }
else else
{ {