strongswan/src/libcharon/plugins/stroke/stroke_handler.c

235 lines
5.1 KiB
C

/*
* Copyright (C) 2012 Martin Willi
* Copyright (C) 2012 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "stroke_handler.h"
#include <daemon.h>
#include <collections/linked_list.h>
#include <threading/rwlock.h>
typedef struct private_stroke_handler_t private_stroke_handler_t;
/**
* Private data of an stroke_handler_t object.
*/
struct private_stroke_handler_t {
/**
* Public stroke_handler_t interface.
*/
stroke_handler_t public;
/**
* List of connection specific attributes, as attributes_t
*/
linked_list_t *attrs;
/**
* rwlock to lock access to pools
*/
rwlock_t *lock;
};
/**
* Attributes assigned to a connection
*/
typedef struct {
/** name of the connection */
char *name;
/** list of DNS attributes, as host_t */
linked_list_t *dns;
} attributes_t;
/**
* Destroy an attributes_t entry
*/
static void attributes_destroy(attributes_t *this)
{
this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
free(this->name);
free(this);
}
CALLBACK(attr_filter, bool,
void *lock, enumerator_t *orig, va_list args)
{
configuration_attribute_type_t *type;
chunk_t *data;
host_t *host;
VA_ARGS_VGET(args, type, data);
while (orig->enumerate(orig, &host))
{
switch (host->get_family(host))
{
case AF_INET:
*type = INTERNAL_IP4_DNS;
break;
case AF_INET6:
*type = INTERNAL_IP6_DNS;
break;
default:
continue;
}
if (host->is_anyaddr(host))
{
*data = chunk_empty;
}
else
{
*data = host->get_address(host);
}
return TRUE;
}
return FALSE;
}
METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
private_stroke_handler_t *this, ike_sa_t *ike_sa,
linked_list_t *vips)
{
peer_cfg_t *peer_cfg;
enumerator_t *enumerator;
attributes_t *attr;
ike_sa = charon->bus->get_sa(charon->bus);
if (ike_sa)
{
peer_cfg = ike_sa->get_peer_cfg(ike_sa);
this->lock->read_lock(this->lock);
enumerator = this->attrs->create_enumerator(this->attrs);
while (enumerator->enumerate(enumerator, &attr))
{
if (streq(attr->name, peer_cfg->get_name(peer_cfg)))
{
enumerator->destroy(enumerator);
return enumerator_create_filter(
attr->dns->create_enumerator(attr->dns),
attr_filter, this->lock,
(void*)this->lock->unlock);
}
}
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
}
return enumerator_create_empty();
}
METHOD(stroke_handler_t, add_attributes, void,
private_stroke_handler_t *this, stroke_msg_t *msg)
{
if (msg->add_conn.me.dns)
{
enumerator_t *enumerator;
attributes_t *attr = NULL;
host_t *host;
char *token;
enumerator = enumerator_create_token(msg->add_conn.me.dns, ",", " ");
while (enumerator->enumerate(enumerator, &token))
{
if (streq(token, "%config") || streq(token, "%config4"))
{
host = host_create_any(AF_INET);
}
else if (streq(token, "%config6"))
{
host = host_create_any(AF_INET6);
}
else
{
host = host_create_from_string(token, 0);
}
if (host)
{
if (!attr)
{
INIT(attr,
.name = strdup(msg->add_conn.name),
.dns = linked_list_create(),
);
}
attr->dns->insert_last(attr->dns, host);
}
else
{
DBG1(DBG_CFG, "ignoring invalid DNS address '%s'", token);
}
}
enumerator->destroy(enumerator);
if (attr)
{
this->lock->write_lock(this->lock);
this->attrs->insert_last(this->attrs, attr);
this->lock->unlock(this->lock);
}
}
}
METHOD(stroke_handler_t, del_attributes, void,
private_stroke_handler_t *this, stroke_msg_t *msg)
{
enumerator_t *enumerator;
attributes_t *attr;
this->lock->write_lock(this->lock);
enumerator = this->attrs->create_enumerator(this->attrs);
while (enumerator->enumerate(enumerator, &attr))
{
if (streq(msg->del_conn.name, attr->name))
{
this->attrs->remove_at(this->attrs, enumerator);
attributes_destroy(attr);
break;
}
}
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
}
METHOD(stroke_handler_t, destroy, void,
private_stroke_handler_t *this)
{
this->lock->destroy(this->lock);
this->attrs->destroy_function(this->attrs, (void*)attributes_destroy);
free(this);
}
/**
* See header
*/
stroke_handler_t *stroke_handler_create()
{
private_stroke_handler_t *this;
INIT(this,
.public = {
.handler = {
.handle = (void*)return_false,
.release = (void*)return_false,
.create_attribute_enumerator = _create_attribute_enumerator,
},
.add_attributes = _add_attributes,
.del_attributes = _del_attributes,
.destroy = _destroy,
},
.attrs = linked_list_create(),
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
);
return &this->public;
}