diff options
Diffstat (limited to 'src/libcharon/plugins/android/android_handler.c')
| -rw-r--r-- | src/libcharon/plugins/android/android_handler.c | 225 | 
1 files changed, 225 insertions, 0 deletions
| diff --git a/src/libcharon/plugins/android/android_handler.c b/src/libcharon/plugins/android/android_handler.c new file mode 100644 index 000000000..a475eeaab --- /dev/null +++ b/src/libcharon/plugins/android/android_handler.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2010 Martin Willi + * Copyright (C) 2010 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 "android_handler.h" + +#include <utils/linked_list.h> + +#include <cutils/properties.h> + +typedef struct private_android_handler_t private_android_handler_t; + +/** + * Private data of an android_handler_t object. + */ +struct private_android_handler_t { + +	/** +	 * Public android_handler_t interface. +	 */ +	android_handler_t public; + +	/** +	 * List of registered DNS servers +	 */ +	linked_list_t *dns; +}; + +/** + * Struct to store a pair of old and installed DNS servers + */ +typedef struct { +	/** installed dns server */ +	host_t *dns; +	/** old dns server */ +	host_t *old; +} dns_pair_t; + +/** + * Destroy a pair of old and installed DNS servers + */ +void destroy_dns_pair(dns_pair_t *this) +{ +	DESTROY_IF(this->dns); +	DESTROY_IF(this->old); +	free(this); +} + +/** + * Filter pairs of DNS servers + */ +bool filter_dns_pair(void *data, dns_pair_t **in, host_t **out) +{ +	*out = (*in)->dns; +	return TRUE; +} + +/** + * Read DNS server property with a given index + */ +host_t *get_dns_server(int index) +{ +	host_t *dns = NULL; +	char key[10], value[PROPERTY_VALUE_MAX]; + +	if (snprintf(key, sizeof(key), "net.dns%d", index) >= sizeof(key)) +	{ +		return NULL; +	} + +	if (property_get(key, value, NULL) > 0) +	{ +		dns = host_create_from_string(value, 0); +	} +	return dns; +} + +/** + * Set DNS server property with a given index + */ +bool set_dns_server(int index, host_t *dns) +{ +	char key[10], value[PROPERTY_VALUE_MAX]; + +	if (snprintf(key, sizeof(key), "net.dns%d", index) >= sizeof(key)) +	{ +		return FALSE; +	} + +	if (dns) +	{ +		if (snprintf(value, sizeof(value), "%H", dns) >= sizeof(value)) +		{ +			return FALSE; +		} +	} +	else +	{ +		value[0] = '\0'; +	} + +	if (property_set(key, value) != 0) +	{ +		return FALSE; +	} +	return TRUE; +} + +METHOD(attribute_handler_t, handle, bool, +	private_android_handler_t *this, identification_t *id, +	configuration_attribute_type_t type, chunk_t data) +{ +	switch (type) +	{ +		case INTERNAL_IP4_DNS: +		{ +			host_t *dns; +			dns_pair_t *pair; +			int index; + +			dns = host_create_from_chunk(AF_INET, data, 0); +			if (dns) +			{ +				pair = malloc_thing(dns_pair_t); +				pair->dns = dns; +				index = this->dns->get_count(this->dns) + 1; +				pair->old = get_dns_server(index); +				set_dns_server(index, dns); +				this->dns->insert_last(this->dns, pair); +				return TRUE; +			} +			return FALSE; +		} +		default: +			return FALSE; +	} +} + +METHOD(attribute_handler_t, release, void, +	private_android_handler_t *this, identification_t *server, +	configuration_attribute_type_t type, chunk_t data) +{ +	if (type == INTERNAL_IP4_DNS) +	{ +		enumerator_t *enumerator; +		dns_pair_t *pair; +		int index; + +		enumerator = this->dns->create_enumerator(this->dns); +		for (index = 1; enumerator->enumerate(enumerator, &pair); index++) +		{ +			if (chunk_equals(pair->dns->get_address(pair->dns), data)) +			{ +				this->dns->remove_at(this->dns, enumerator); +				set_dns_server(index, pair->old); +				destroy_dns_pair(pair); +			} +		} +		enumerator->destroy(enumerator); +	} +} + +METHOD(enumerator_t, enumerate_dns, bool, +	enumerator_t *this, configuration_attribute_type_t *type, chunk_t *data) +{ +	*type = INTERNAL_IP4_DNS; +	*data = chunk_empty; +	/* stop enumeration */ +	this->enumerate = (void*)return_false; +	return TRUE; +} + +METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *, +	android_handler_t *this, identification_t *id, host_t *vip) +{ +	enumerator_t *enumerator; + +	INIT(enumerator, +		.enumerate = (void*)_enumerate_dns, +		.destroy = (void*)free, +	); +	return enumerator; +} + +METHOD(android_handler_t, destroy, void, +	private_android_handler_t *this) +{ +	this->dns->destroy_function(this->dns, (void*)destroy_dns_pair); +	free(this); +} + +/** + * See header + */ +android_handler_t *android_handler_create() +{ +	private_android_handler_t *this; + +	INIT(this, +		.public = { +			.handler = { +				.handle = _handle, +				.release = _release, +				.create_attribute_enumerator = _create_attribute_enumerator, +			}, +			.destroy = _destroy, +		}, +		.dns = linked_list_create(), +	); + +	return &this->public; +} + | 
