network_manager_t *network_manager;
/**
- * Handle network events
- */
- android_net_t *net_handler;
-
- /**
* CharonVpnService reference
*/
jobject vpn_service;
private_charonservice_t *this = (private_charonservice_t*)charonservice;
if (reg)
{
- this->net_handler = android_net_create();
lib->credmgr->add_set(lib->credmgr, &this->creds->set);
charon->attributes->add_handler(charon->attributes,
&this->attr->handler);
}
else
{
- this->net_handler->destroy(this->net_handler);
lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
charon->attributes->remove_handler(charon->attributes,
&this->attr->handler);
* so lets disable IPv6 for now to avoid issues with dual-stack gateways */
lib->settings->set_bool(lib->settings,
"charon.plugins.socket-default.use_ipv6", FALSE);
- /* don't install virtual IPs via kernel-netlink */
- lib->settings->set_bool(lib->settings,
- "charon.install_virtual_ip", FALSE);
- /* kernel-netlink should not trigger roam events, we use Android's
- * ConnectivityManager for that, much less noise */
- lib->settings->set_bool(lib->settings,
- "charon.plugins.kernel-netlink.roam_events", FALSE);
- /* ignore tun devices (it's mostly tun0 but it may already be taken, ignore
- * some others too), also ignore lo as a default route points to it when
- * no connectivity is available */
- lib->settings->set_str(lib->settings,
- "charon.interfaces_ignore", "lo, tun0, tun1, tun2, tun3, "
- "tun4");
#ifdef USE_BYOD
lib->settings->set_str(lib->settings,
static plugin_feature_t features[] = {
PLUGIN_CALLBACK(kernel_ipsec_register, kernel_android_ipsec_create),
PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"),
+ PLUGIN_CALLBACK(kernel_net_register, kernel_android_net_create),
+ PLUGIN_PROVIDE(CUSTOM, "kernel-net"),
PLUGIN_CALLBACK(charonservice_register, NULL),
PLUGIN_PROVIDE(CUSTOM, "android-backend"),
PLUGIN_DEPENDS(CUSTOM, "libcharon"),
/*
- * Copyright (C) 2012-2013 Tobias Brunner
+ * Copyright (C) 2012-2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
#include "android_net.h"
/**
* Public kernel interface
*/
- android_net_t public;
+ kernel_net_t public;
/**
* Reference to NetworkManager object
network_manager_t *network_manager;
/**
- * earliest time of the next roam event
+ * Earliest time of the next roam event
*/
timeval_t next_roam;
/**
- * mutex to check and update roam event time
+ * Mutex to check and update roam event time, and other private members
*/
mutex_t *mutex;
+
+ /**
+ * List of virtual IPs
+ */
+ linked_list_t *vips;
+
+ /**
+ * Socket used to determine source address
+ */
+ int socket_v4;
};
/**
lib->scheduler->schedule_job_ms(lib->scheduler, job, ROAM_DELAY);
}
-METHOD(android_net_t, destroy, void,
+METHOD(kernel_net_t, get_source_addr, host_t*,
+ private_android_net_t *this, host_t *dest, host_t *src)
+{
+ union {
+ struct sockaddr sockaddr;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } addr;
+ socklen_t addrlen;
+
+ addrlen = *dest->get_sockaddr_len(dest);
+ addr.sockaddr.sa_family = AF_UNSPEC;
+ if (connect(this->socket_v4, &addr.sockaddr, addrlen) < 0)
+ {
+ DBG1(DBG_KNL, "failed to disconnect socket: %s", strerror(errno));
+ return NULL;
+ }
+ if (connect(this->socket_v4, dest->get_sockaddr(dest), addrlen) < 0)
+ {
+ /* don't report an error if we are not connected (ENETUNREACH) */
+ if (errno != ENETUNREACH)
+ {
+ DBG1(DBG_KNL, "failed to connect socket: %s", strerror(errno));
+ }
+ return NULL;
+ }
+ if (getsockname(this->socket_v4, &addr.sockaddr, &addrlen) < 0)
+ {
+ DBG1(DBG_KNL, "failed to determine src address: %s", strerror(errno));
+ return NULL;
+ }
+ return host_create_from_sockaddr((sockaddr_t*)&addr);
+}
+
+METHOD(kernel_net_t, get_nexthop, host_t*,
+ private_android_net_t *this, host_t *dest, int prefix, host_t *src)
+{
+ return NULL;
+}
+
+METHOD(kernel_net_t, get_interface, bool,
+ private_android_net_t *this, host_t *host, char **name)
+{
+ if (name)
+ { /* the actual name does not matter in our case */
+ *name = strdup("strongswan");
+ }
+ return TRUE;
+}
+
+METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
+ private_android_net_t *this, kernel_address_type_t which)
+{
+ /* return virtual IPs if requested, nothing otherwise */
+ if (which & ADDR_TYPE_VIRTUAL)
+ {
+ this->mutex->lock(this->mutex);
+ return enumerator_create_cleaner(
+ this->vips->create_enumerator(this->vips),
+ (void*)this->mutex->unlock, this->mutex);
+ }
+ return enumerator_create_empty();
+}
+
+METHOD(kernel_net_t, add_ip, status_t,
+ private_android_net_t *this, host_t *virtual_ip, int prefix, char *iface)
+{
+ this->mutex->lock(this->mutex);
+ this->vips->insert_last(this->vips, virtual_ip->clone(virtual_ip));
+ this->mutex->unlock(this->mutex);
+ return SUCCESS;
+}
+
+METHOD(kernel_net_t, del_ip, status_t,
+ private_android_net_t *this, host_t *virtual_ip, int prefix, bool wait)
+{
+ host_t *vip;
+
+ this->mutex->lock(this->mutex);
+ if (this->vips->find_first(this->vips, (void*)virtual_ip->ip_equals,
+ (void**)&vip, virtual_ip) == SUCCESS)
+ {
+ this->vips->remove(this->vips, vip, NULL);
+ vip->destroy(vip);
+ }
+ this->mutex->unlock(this->mutex);
+ return SUCCESS;
+}
+
+METHOD(kernel_net_t, add_route, status_t,
+ private_android_net_t *this, chunk_t dst_net, u_int8_t prefixlen,
+ host_t *gateway, host_t *src_ip, char *if_name)
+{
+ return NOT_SUPPORTED;
+}
+
+METHOD(kernel_net_t, del_route, status_t,
+ private_android_net_t *this, chunk_t dst_net, u_int8_t prefixlen,
+ host_t *gateway, host_t *src_ip, char *if_name)
+{
+ return NOT_SUPPORTED;
+}
+
+METHOD(kernel_net_t, destroy, void,
private_android_net_t *this)
{
this->network_manager->remove_connectivity_cb(this->network_manager,
(void*)connectivity_cb);
this->mutex->destroy(this->mutex);
+ this->vips->destroy(this->vips);
+ close(this->socket_v4);
free(this);
}
-/*
- * Described in header.
- */
-android_net_t *android_net_create()
+kernel_net_t *kernel_android_net_create()
{
private_android_net_t *this;
INIT(this,
.public = {
+ .get_source_addr = _get_source_addr,
+ .get_nexthop = _get_nexthop,
+ .get_interface = _get_interface,
+ .create_address_enumerator = _create_address_enumerator,
+ .add_ip = _add_ip,
+ .del_ip = _del_ip,
+ .add_route = _add_route,
+ .del_route = _del_route,
.destroy = _destroy,
},
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .vips = linked_list_create(),
.network_manager = charonservice->get_network_manager(charonservice),
);
timerclear(&this->next_roam);
+ this->socket_v4 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (this->socket_v4 < 0)
+ {
+ DBG1(DBG_KNL, "failed to create socket to lookup src addresses: %s",
+ strerror(errno));
+ }
+ charonservice->bypass_socket(charonservice, this->socket_v4, AF_INET);
+
this->network_manager->add_connectivity_cb(this->network_manager,
(void*)connectivity_cb, this);
return &this->public;
-};
+}