aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2013-04-19 15:53:45 +0200
committerMartin Willi <martin@revosec.ch>2013-05-06 16:10:13 +0200
commit2a2d7a4dc8d11cc5695ed6c0f25bc20830282eaf (patch)
tree51c4a356680d0e033e0985dfbe8497fe9c1eaaf0 /src
parentca4a14ae83a1b00b792530dc328eae164d3f66e6 (diff)
downloadstrongswan-2a2d7a4dc8d11cc5695ed6c0f25bc20830282eaf.tar.bz2
strongswan-2a2d7a4dc8d11cc5695ed6c0f25bc20830282eaf.tar.xz
kernel-pfroute: install virtual IPs using dedicated tun devices
Diffstat (limited to 'src')
-rw-r--r--src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c96
1 files changed, 91 insertions, 5 deletions
diff --git a/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c b/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c
index 2aeb840b2..44f31080d 100644
--- a/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c
+++ b/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c
@@ -27,6 +27,7 @@
#include <hydra.h>
#include <utils/debug.h>
#include <networking/host.h>
+#include <networking/tun_device.h>
#include <threading/thread.h>
#include <threading/mutex.h>
#include <threading/condvar.h>
@@ -196,6 +197,11 @@ struct private_kernel_pfroute_net_t
hashtable_t *addrs;
/**
+ * List of tun devices we installed for virtual IPs
+ */
+ linked_list_t *tuns;
+
+ /**
* mutex to communicate exclusively with PF_KEY
*/
mutex_t *mutex;
@@ -669,8 +675,9 @@ static job_requeue_t receive_events(private_kernel_pfroute_net_t *this)
/* seems like the message someone is waiting for, deliver */
this->reply = realloc(this->reply, msg.rtm.rtm_msglen);
memcpy(this->reply, &msg, msg.rtm.rtm_msglen);
- this->condvar->signal(this->condvar);
}
+ /* signal on any event, add_ip()/del_ip() might wait for it */
+ this->condvar->signal(this->condvar);
this->mutex->unlock(this->mutex);
return JOB_REQUEUE_DIRECT;
@@ -815,17 +822,94 @@ METHOD(kernel_net_t, get_source_addr, host_t*,
}
METHOD(kernel_net_t, add_ip, status_t,
- private_kernel_pfroute_net_t *this, host_t *virtual_ip, int prefix,
+ private_kernel_pfroute_net_t *this, host_t *vip, int prefix,
char *iface)
{
- return FAILED;
+ tun_device_t *tun;
+ bool timeout = FALSE;
+
+ tun = tun_device_create(NULL);
+ if (!tun)
+ {
+ return FAILED;
+ }
+ if (prefix == -1)
+ {
+ prefix = vip->get_address(vip).len * 8;
+ }
+ if (!tun->set_address(tun, vip, prefix) || !tun->up(tun))
+ {
+ tun->destroy(tun);
+ return FAILED;
+ }
+
+ /* wait until address appears */
+ this->mutex->lock(this->mutex);
+ while (!timeout && !get_interface_name(this, vip, NULL))
+ {
+ timeout = this->condvar->timed_wait(this->condvar, this->mutex, 1000);
+ }
+ this->mutex->unlock(this->mutex);
+ if (timeout)
+ {
+ DBG1(DBG_KNL, "virtual IP %H did not appear on %s",
+ vip, tun->get_name(tun));
+ tun->destroy(tun);
+ return FAILED;
+ }
+
+ this->lock->write_lock(this->lock);
+ this->tuns->insert_last(this->tuns, tun);
+ this->lock->unlock(this->lock);
+
+ return SUCCESS;
}
METHOD(kernel_net_t, del_ip, status_t,
- private_kernel_pfroute_net_t *this, host_t *virtual_ip, int prefix,
+ private_kernel_pfroute_net_t *this, host_t *vip, int prefix,
bool wait)
{
- return FAILED;
+ enumerator_t *enumerator;
+ tun_device_t *tun;
+ host_t *addr;
+ bool timeout = FALSE, found = FALSE;
+
+ this->lock->write_lock(this->lock);
+ enumerator = this->tuns->create_enumerator(this->tuns);
+ while (enumerator->enumerate(enumerator, &tun))
+ {
+ addr = tun->get_address(tun, NULL);
+ if (addr && addr->ip_equals(addr, vip))
+ {
+ this->tuns->remove_at(this->tuns, enumerator);
+ tun->destroy(tun);
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+
+ if (!found)
+ {
+ return NOT_FOUND;
+ }
+ /* wait until address disappears */
+ if (wait)
+ {
+ this->mutex->lock(this->mutex);
+ while (!timeout && get_interface_name(this, vip, NULL))
+ {
+ timeout = this->condvar->timed_wait(this->condvar, this->mutex, 1000);
+ }
+ this->mutex->unlock(this->mutex);
+ if (timeout)
+ {
+ DBG1(DBG_KNL, "virtual IP %H did not disappear from tun", vip);
+ return FAILED;
+ }
+ }
+ return SUCCESS;
}
/**
@@ -1162,6 +1246,7 @@ METHOD(kernel_net_t, destroy, void,
enumerator->destroy(enumerator);
this->addrs->destroy(this->addrs);
this->ifaces->destroy_function(this->ifaces, (void*)iface_entry_destroy);
+ this->tuns->destroy(this->tuns);
this->lock->destroy(this->lock);
this->mutex->destroy(this->mutex);
this->condvar->destroy(this->condvar);
@@ -1195,6 +1280,7 @@ kernel_pfroute_net_t *kernel_pfroute_net_create()
.addrs = hashtable_create(
(hashtable_hash_t)addr_map_entry_hash,
(hashtable_equals_t)addr_map_entry_equals, 16),
+ .tuns = linked_list_create(),
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
.condvar = condvar_create(CONDVAR_TYPE_DEFAULT),