Merge branch 'android-mobility'
This brings support for MOBIKE to the Android app. The app also tries to keep the connection up as long as possible. DNS queries are now handled by a new class that uses independent threads to resolve them, this allows to cancel them e.g. if no network connectivity is available (otherwise the app would block until the DNS query returns).
This commit is contained in:
@@ -696,6 +696,12 @@ strength
|
||||
.BR libstrongswan.ecp_x_coordinate_only " [yes]"
|
||||
Compliance with the errata for RFC 4753
|
||||
.TP
|
||||
.BR libstrongswan.host_resolver.max_threads " [3]"
|
||||
Maximum number of concurrent resolver threads (they are terminated if unused)
|
||||
.TP
|
||||
.BR libstrongswan.host_resolver.min_threads " [0]"
|
||||
Minimum number of resolver threads to keep around
|
||||
.TP
|
||||
.BR libstrongswan.integrity_test " [no]"
|
||||
Check daemon, libstrongswan and plugin integrity at startup
|
||||
.TP
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<uses-sdk android:minSdkVersion="14" />
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<application
|
||||
android:icon="@drawable/ic_launcher"
|
||||
|
||||
@@ -16,11 +16,14 @@ openssl_PATH := $(LOCAL_PATH)/openssl/include
|
||||
|
||||
# CFLAGS (partially from a configure run using droid-gcc)
|
||||
strongswan_CFLAGS := \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wno-format \
|
||||
-Wno-pointer-sign \
|
||||
-Wno-pointer-arith \
|
||||
-Wno-sign-compare \
|
||||
-Wno-strict-aliasing \
|
||||
-Wno-unused-parameter \
|
||||
-DHAVE___BOOL \
|
||||
-DHAVE_STDBOOL_H \
|
||||
-DHAVE_ALLOCA_H \
|
||||
|
||||
@@ -11,6 +11,7 @@ backend/android_service.c backend/android_service.h \
|
||||
charonservice.c charonservice.h \
|
||||
kernel/android_ipsec.c kernel/android_ipsec.h \
|
||||
kernel/android_net.c kernel/android_net.h \
|
||||
kernel/network_manager.c kernel/network_manager.h \
|
||||
vpnservice_builder.c vpnservice_builder.h
|
||||
|
||||
# build libandroidbridge -------------------------------------------------------
|
||||
|
||||
@@ -58,11 +58,6 @@ struct private_android_service_t {
|
||||
*/
|
||||
char *type;
|
||||
|
||||
/**
|
||||
* local ipv4 address
|
||||
*/
|
||||
char *local_address;
|
||||
|
||||
/**
|
||||
* gateway
|
||||
*/
|
||||
@@ -362,7 +357,6 @@ METHOD(listener_t, child_updown, bool,
|
||||
{
|
||||
/* disable the hooks registered to catch initiation failures */
|
||||
this->public.listener.ike_updown = NULL;
|
||||
this->public.listener.ike_state_change = NULL;
|
||||
if (!setup_tun_device(this, ike_sa, child_sa))
|
||||
{
|
||||
DBG1(DBG_DMN, "failed to setup TUN device");
|
||||
@@ -403,19 +397,6 @@ METHOD(listener_t, ike_updown, bool,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(listener_t, ike_state_change, bool,
|
||||
private_android_service_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
|
||||
{
|
||||
/* this call back is only registered during initiation */
|
||||
if (this->ike_sa == ike_sa && state == IKE_DESTROYING)
|
||||
{
|
||||
charonservice->update_status(charonservice,
|
||||
CHARONSERVICE_UNREACHABLE_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(listener_t, alert, bool,
|
||||
private_android_service_t *this, ike_sa_t *ike_sa, alert_t alert,
|
||||
va_list args)
|
||||
@@ -432,6 +413,15 @@ METHOD(listener_t, alert, bool,
|
||||
charonservice->update_status(charonservice,
|
||||
CHARONSERVICE_PEER_AUTH_ERROR);
|
||||
break;
|
||||
case ALERT_PEER_INIT_UNREACHABLE:
|
||||
this->lock->read_lock(this->lock);
|
||||
if (this->tunfd < 0)
|
||||
{ /* only handle this if we are not reestablishing the SA */
|
||||
charonservice->update_status(charonservice,
|
||||
CHARONSERVICE_UNREACHABLE_ERROR);
|
||||
}
|
||||
this->lock->unlock(this->lock);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -455,9 +445,8 @@ METHOD(listener_t, ike_reestablish, bool,
|
||||
if (this->ike_sa == old)
|
||||
{
|
||||
this->ike_sa = new;
|
||||
/* re-register hooks to detect initiation failures */
|
||||
/* re-register hook to detect initiation failures */
|
||||
this->public.listener.ike_updown = _ike_updown;
|
||||
this->public.listener.ike_state_change = _ike_state_change;
|
||||
/* the TUN device will be closed when the new CHILD_SA is established */
|
||||
}
|
||||
return TRUE;
|
||||
@@ -480,13 +469,13 @@ static job_requeue_t initiate(private_android_service_t *this)
|
||||
}
|
||||
};
|
||||
|
||||
ike_cfg = ike_cfg_create(TRUE, TRUE, this->local_address, FALSE,
|
||||
ike_cfg = ike_cfg_create(TRUE, TRUE, "0.0.0.0", FALSE,
|
||||
charon->socket->get_port(charon->socket, FALSE),
|
||||
this->gateway, FALSE, IKEV2_UDP_PORT);
|
||||
ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
|
||||
|
||||
peer_cfg = peer_cfg_create("android", IKEV2, ike_cfg, CERT_SEND_IF_ASKED,
|
||||
UNIQUE_REPLACE, 1, /* keyingtries */
|
||||
UNIQUE_REPLACE, 0, /* keyingtries */
|
||||
36000, 0, /* rekey 10h, reauth none */
|
||||
600, 600, /* jitter, over 10min */
|
||||
TRUE, FALSE, /* mobike, aggressive */
|
||||
@@ -538,10 +527,14 @@ static job_requeue_t initiate(private_android_service_t *this)
|
||||
peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
|
||||
|
||||
child_cfg = child_cfg_create("android", &lifetime, NULL, TRUE, MODE_TUNNEL,
|
||||
ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE,
|
||||
0, 0, NULL, NULL, 0);
|
||||
child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
|
||||
ts = traffic_selector_create_dynamic(0, 0, 65535);
|
||||
ACTION_NONE, ACTION_RESTART, ACTION_RESTART,
|
||||
FALSE, 0, 0, NULL, NULL, 0);
|
||||
/* create an ESP proposal with the algorithms currently supported by
|
||||
* libipsec, no PFS for now */
|
||||
child_cfg->add_proposal(child_cfg, proposal_create_from_string(PROTO_ESP,
|
||||
"aes128-aes192-aes256-sha1-sha256-sha384-sha512"));
|
||||
ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "0.0.0.0",
|
||||
0, "255.255.255.255", 65535);
|
||||
child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
|
||||
ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "0.0.0.0",
|
||||
0, "255.255.255.255", 65535);
|
||||
@@ -588,7 +581,6 @@ METHOD(android_service_t, destroy, void,
|
||||
close_tun_device(this);
|
||||
this->lock->destroy(this->lock);
|
||||
free(this->type);
|
||||
free(this->local_address);
|
||||
free(this->gateway);
|
||||
free(this->username);
|
||||
if (this->password)
|
||||
@@ -603,8 +595,8 @@ METHOD(android_service_t, destroy, void,
|
||||
* See header
|
||||
*/
|
||||
android_service_t *android_service_create(android_creds_t *creds, char *type,
|
||||
char *local_address, char *gateway,
|
||||
char *username, char *password)
|
||||
char *gateway, char *username,
|
||||
char *password)
|
||||
{
|
||||
private_android_service_t *this;
|
||||
|
||||
@@ -614,14 +606,12 @@ android_service_t *android_service_create(android_creds_t *creds, char *type,
|
||||
.ike_rekey = _ike_rekey,
|
||||
.ike_reestablish = _ike_reestablish,
|
||||
.ike_updown = _ike_updown,
|
||||
.ike_state_change = _ike_state_change,
|
||||
.child_updown = _child_updown,
|
||||
.alert = _alert,
|
||||
},
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
|
||||
.local_address = local_address,
|
||||
.username = username,
|
||||
.password = password,
|
||||
.gateway = gateway,
|
||||
|
||||
@@ -53,13 +53,12 @@ struct android_service_t {
|
||||
*
|
||||
* @param creds Android specific credential set
|
||||
* @param type VPN type (see VpnType.java)
|
||||
* @param local_address local ip address
|
||||
* @param gateway gateway address
|
||||
* @param username user name (local identity)
|
||||
* @param password password (if any)
|
||||
*/
|
||||
android_service_t *android_service_create(android_creds_t *creds, char *type,
|
||||
char *local_address, char *gateway,
|
||||
char *username, char *password);
|
||||
char *gateway, char *username,
|
||||
char *password);
|
||||
|
||||
#endif /** ANDROID_SERVICE_H_ @}*/
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
#define ANDROID_DEBUG_LEVEL 1
|
||||
#define ANDROID_RETRASNMIT_TRIES 3
|
||||
#define ANDROID_RETRANSMIT_TIMEOUT 3.0
|
||||
#define ANDROID_RETRANSMIT_TIMEOUT 2.0
|
||||
#define ANDROID_RETRANSMIT_BASE 1.4
|
||||
|
||||
typedef struct private_charonservice_t private_charonservice_t;
|
||||
@@ -73,10 +73,20 @@ struct private_charonservice_t {
|
||||
*/
|
||||
vpnservice_builder_t *builder;
|
||||
|
||||
/**
|
||||
* NetworkManager instance (accessed via JNI)
|
||||
*/
|
||||
network_manager_t *network_manager;
|
||||
|
||||
/**
|
||||
* CharonVpnService reference
|
||||
*/
|
||||
jobject vpn_service;
|
||||
|
||||
/**
|
||||
* Sockets that were bypassed and we keep track for
|
||||
*/
|
||||
linked_list_t *sockets;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -172,8 +182,10 @@ failed:
|
||||
return success;
|
||||
}
|
||||
|
||||
METHOD(charonservice_t, bypass_socket, bool,
|
||||
private_charonservice_t *this, int fd, int family)
|
||||
/**
|
||||
* Bypass a single socket
|
||||
*/
|
||||
static bool bypass_single_socket(intptr_t fd, private_charonservice_t *this)
|
||||
{
|
||||
JNIEnv *env;
|
||||
jmethodID method_id;
|
||||
@@ -188,7 +200,7 @@ METHOD(charonservice_t, bypass_socket, bool,
|
||||
}
|
||||
if (!(*env)->CallBooleanMethod(env, this->vpn_service, method_id, fd))
|
||||
{
|
||||
DBG1(DBG_CFG, "VpnService.protect() failed");
|
||||
DBG2(DBG_KNL, "VpnService.protect() failed");
|
||||
goto failed;
|
||||
}
|
||||
androidjni_detach_thread();
|
||||
@@ -200,6 +212,19 @@ failed:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
METHOD(charonservice_t, bypass_socket, bool,
|
||||
private_charonservice_t *this, int fd, int family)
|
||||
{
|
||||
if (fd >= 0)
|
||||
{
|
||||
this->sockets->insert_last(this->sockets, (void*)(intptr_t)fd);
|
||||
return bypass_single_socket((intptr_t)fd, this);
|
||||
}
|
||||
this->sockets->invoke_function(this->sockets, (void*)bypass_single_socket,
|
||||
this);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given Java array of byte arrays (byte[][]) to a linked list
|
||||
* of chunk_t objects.
|
||||
@@ -330,22 +355,26 @@ METHOD(charonservice_t, get_vpnservice_builder, vpnservice_builder_t*,
|
||||
return this->builder;
|
||||
}
|
||||
|
||||
METHOD(charonservice_t, get_network_manager, network_manager_t*,
|
||||
private_charonservice_t *this)
|
||||
{
|
||||
return this->network_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate a new connection
|
||||
*
|
||||
* @param local local ip address (gets owned)
|
||||
* @param gateway gateway address (gets owned)
|
||||
* @param username username (gets owned)
|
||||
* @param password password (gets owned)
|
||||
*/
|
||||
static void initiate(char *type, char *local, char *gateway,
|
||||
char *username, char *password)
|
||||
static void initiate(char *type, char *gateway, char *username, char *password)
|
||||
{
|
||||
private_charonservice_t *this = (private_charonservice_t*)charonservice;
|
||||
|
||||
this->creds->clear(this->creds);
|
||||
DESTROY_IF(this->service);
|
||||
this->service = android_service_create(this->creds, type, local, gateway,
|
||||
this->service = android_service_create(this->creds, type, gateway,
|
||||
username, password);
|
||||
}
|
||||
|
||||
@@ -400,10 +429,13 @@ static void charonservice_init(JNIEnv *env, jobject service, jobject builder)
|
||||
.get_user_certificate = _get_user_certificate,
|
||||
.get_user_key = _get_user_key,
|
||||
.get_vpnservice_builder = _get_vpnservice_builder,
|
||||
.get_network_manager = _get_network_manager,
|
||||
},
|
||||
.attr = android_attr_create(),
|
||||
.creds = android_creds_create(),
|
||||
.builder = vpnservice_builder_create(builder),
|
||||
.network_manager = network_manager_create(service),
|
||||
.sockets = linked_list_create(),
|
||||
.vpn_service = (*env)->NewGlobalRef(env, service),
|
||||
);
|
||||
charonservice = &this->public;
|
||||
@@ -439,6 +471,8 @@ static void charonservice_deinit(JNIEnv *env)
|
||||
{
|
||||
private_charonservice_t *this = (private_charonservice_t*)charonservice;
|
||||
|
||||
this->network_manager->destroy(this->network_manager);
|
||||
this->sockets->destroy(this->sockets);
|
||||
this->builder->destroy(this->builder);
|
||||
this->creds->destroy(this->creds);
|
||||
this->attr->destroy(this->attr);
|
||||
@@ -555,16 +589,14 @@ JNI_METHOD(CharonVpnService, deinitializeCharon, void)
|
||||
* Initiate SA
|
||||
*/
|
||||
JNI_METHOD(CharonVpnService, initiate, void,
|
||||
jstring jtype, jstring jlocal_address, jstring jgateway, jstring jusername,
|
||||
jstring jpassword)
|
||||
jstring jtype, jstring jgateway, jstring jusername, jstring jpassword)
|
||||
{
|
||||
char *type, *local_address, *gateway, *username, *password;
|
||||
char *type, *gateway, *username, *password;
|
||||
|
||||
type = androidjni_convert_jstring(env, jtype);
|
||||
local_address = androidjni_convert_jstring(env, jlocal_address);
|
||||
gateway = androidjni_convert_jstring(env, jgateway);
|
||||
username = androidjni_convert_jstring(env, jusername);
|
||||
password = androidjni_convert_jstring(env, jpassword);
|
||||
|
||||
initiate(type, local_address, gateway, username, password);
|
||||
initiate(type, gateway, username, password);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#define CHARONSERVICE_H_
|
||||
|
||||
#include "vpnservice_builder.h"
|
||||
#include "kernel/network_manager.h"
|
||||
|
||||
#include <library.h>
|
||||
#include <utils/linked_list.h>
|
||||
@@ -69,7 +70,9 @@ struct charonservice_t {
|
||||
|
||||
/**
|
||||
* Install a bypass policy for the given socket using the protect() Method
|
||||
* of the Android VpnService interface
|
||||
* of the Android VpnService interface.
|
||||
*
|
||||
* Use -1 as fd to re-bypass previously bypassed sockets.
|
||||
*
|
||||
* @param fd socket file descriptor
|
||||
* @param family socket protocol family
|
||||
@@ -111,6 +114,12 @@ struct charonservice_t {
|
||||
*/
|
||||
vpnservice_builder_t *(*get_vpnservice_builder)(charonservice_t *this);
|
||||
|
||||
/**
|
||||
* Get the current network_manager_t object
|
||||
*
|
||||
* @return NetworkManager instance
|
||||
*/
|
||||
network_manager_t *(*get_network_manager)(charonservice_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -79,7 +79,8 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
|
||||
u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
|
||||
bool encap, bool new_encap, mark_t mark)
|
||||
{
|
||||
return NOT_SUPPORTED;
|
||||
return ipsec->sas->update_sa(ipsec->sas, spi, protocol, cpi, src, dst,
|
||||
new_src, new_dst, encap, new_encap, mark);
|
||||
}
|
||||
|
||||
METHOD(kernel_ipsec_t, query_sa, status_t,
|
||||
|
||||
@@ -14,6 +14,15 @@
|
||||
|
||||
#include "android_net.h"
|
||||
|
||||
#include "../charonservice.h"
|
||||
#include <hydra.h>
|
||||
#include <debug.h>
|
||||
#include <processing/jobs/callback_job.h>
|
||||
#include <threading/mutex.h>
|
||||
|
||||
/** delay before firing roam events (ms) */
|
||||
#define ROAM_DELAY 100
|
||||
|
||||
typedef struct private_kernel_android_net_t private_kernel_android_net_t;
|
||||
|
||||
struct private_kernel_android_net_t {
|
||||
@@ -22,8 +31,66 @@ struct private_kernel_android_net_t {
|
||||
* Public kernel interface
|
||||
*/
|
||||
kernel_android_net_t public;
|
||||
|
||||
/**
|
||||
* Reference to NetworkManager object
|
||||
*/
|
||||
network_manager_t *network_manager;
|
||||
|
||||
/**
|
||||
* earliest time of the next roam event
|
||||
*/
|
||||
timeval_t next_roam;
|
||||
|
||||
/**
|
||||
* mutex to check and update roam event time
|
||||
*/
|
||||
mutex_t *mutex;
|
||||
};
|
||||
|
||||
/**
|
||||
* callback function that raises the delayed roam event
|
||||
*/
|
||||
static job_requeue_t roam_event()
|
||||
{
|
||||
/* this will fail if no connection is up */
|
||||
charonservice->bypass_socket(charonservice, -1, 0);
|
||||
hydra->kernel_interface->roam(hydra->kernel_interface, TRUE);
|
||||
return JOB_REQUEUE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen for connectivity change events and queue a roam event
|
||||
*/
|
||||
static void connectivity_cb(private_kernel_android_net_t *this,
|
||||
bool disconnected)
|
||||
{
|
||||
timeval_t now;
|
||||
job_t *job;
|
||||
|
||||
time_monotonic(&now);
|
||||
this->mutex->lock(this->mutex);
|
||||
if (!timercmp(&now, &this->next_roam, >))
|
||||
{
|
||||
this->mutex->unlock(this->mutex);
|
||||
return;
|
||||
}
|
||||
timeval_add_ms(&now, ROAM_DELAY);
|
||||
this->next_roam = now;
|
||||
this->mutex->unlock(this->mutex);
|
||||
|
||||
job = (job_t*)callback_job_create((callback_job_cb_t)roam_event, NULL,
|
||||
NULL, NULL);
|
||||
lib->scheduler->schedule_job_ms(lib->scheduler, job, ROAM_DELAY);
|
||||
}
|
||||
|
||||
METHOD(kernel_net_t, get_source_addr, host_t*,
|
||||
private_kernel_android_net_t *this, host_t *dest, host_t *src)
|
||||
{
|
||||
return this->network_manager->get_local_address(this->network_manager,
|
||||
dest->get_family(dest) == AF_INET);
|
||||
}
|
||||
|
||||
METHOD(kernel_net_t, add_ip, status_t,
|
||||
private_kernel_android_net_t *this, host_t *virtual_ip, host_t *iface_ip)
|
||||
{
|
||||
@@ -34,6 +101,9 @@ METHOD(kernel_net_t, add_ip, status_t,
|
||||
METHOD(kernel_net_t, destroy, void,
|
||||
private_kernel_android_net_t *this)
|
||||
{
|
||||
this->network_manager->remove_connectivity_cb(this->network_manager,
|
||||
(void*)connectivity_cb);
|
||||
this->mutex->destroy(this->mutex);
|
||||
free(this);
|
||||
}
|
||||
|
||||
@@ -47,7 +117,7 @@ kernel_android_net_t *kernel_android_net_create()
|
||||
INIT(this,
|
||||
.public = {
|
||||
.interface = {
|
||||
.get_source_addr = (void*)return_null,
|
||||
.get_source_addr = _get_source_addr,
|
||||
.get_nexthop = (void*)return_null,
|
||||
.get_interface = (void*)return_null,
|
||||
.create_address_enumerator = (void*)enumerator_create_empty,
|
||||
@@ -58,7 +128,12 @@ kernel_android_net_t *kernel_android_net_create()
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
|
||||
.network_manager = charonservice->get_network_manager(charonservice),
|
||||
);
|
||||
timerclear(&this->next_roam);
|
||||
|
||||
this->network_manager->add_connectivity_cb(this->network_manager,
|
||||
(void*)connectivity_cb, this);
|
||||
return &this->public;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 "network_manager.h"
|
||||
|
||||
#include "../android_jni.h"
|
||||
#include "../charonservice.h"
|
||||
#include <debug.h>
|
||||
#include <threading/mutex.h>
|
||||
|
||||
typedef struct private_network_manager_t private_network_manager_t;
|
||||
|
||||
struct private_network_manager_t {
|
||||
|
||||
/**
|
||||
* Public interface
|
||||
*/
|
||||
network_manager_t public;
|
||||
|
||||
/**
|
||||
* Reference to NetworkManager object
|
||||
*/
|
||||
jobject obj;
|
||||
|
||||
/**
|
||||
* Java class for NetworkManager
|
||||
*/
|
||||
jclass cls;
|
||||
|
||||
/**
|
||||
* Registered callback
|
||||
*/
|
||||
struct {
|
||||
connectivity_cb_t cb;
|
||||
void *data;
|
||||
} connectivity_cb;
|
||||
|
||||
/**
|
||||
* Mutex to access callback
|
||||
*/
|
||||
mutex_t *mutex;
|
||||
};
|
||||
|
||||
METHOD(network_manager_t, get_local_address, host_t*,
|
||||
private_network_manager_t *this, bool ipv4)
|
||||
{
|
||||
JNIEnv *env;
|
||||
jmethodID method_id;
|
||||
jstring jaddr;
|
||||
char *addr;
|
||||
host_t *host;
|
||||
|
||||
androidjni_attach_thread(&env);
|
||||
method_id = (*env)->GetMethodID(env, this->cls, "getLocalAddress",
|
||||
"(Z)Ljava/lang/String;");
|
||||
if (!method_id)
|
||||
{
|
||||
goto failed;
|
||||
}
|
||||
jaddr = (*env)->CallObjectMethod(env, this->obj, method_id, ipv4);
|
||||
if (!jaddr)
|
||||
{
|
||||
goto failed;
|
||||
}
|
||||
addr = androidjni_convert_jstring(env, jaddr);
|
||||
androidjni_detach_thread();
|
||||
host = host_create_from_string(addr, 0);
|
||||
free(addr);
|
||||
return host;
|
||||
|
||||
failed:
|
||||
androidjni_exception_occurred(env);
|
||||
androidjni_detach_thread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JNI_METHOD(NetworkManager, networkChanged, void,
|
||||
bool disconnected)
|
||||
{
|
||||
private_network_manager_t *nm;
|
||||
|
||||
nm = (private_network_manager_t*)charonservice->get_network_manager(
|
||||
charonservice);
|
||||
nm->mutex->lock(nm->mutex);
|
||||
if (nm->connectivity_cb.cb)
|
||||
{
|
||||
nm->connectivity_cb.cb(nm->connectivity_cb.data, disconnected);
|
||||
}
|
||||
nm->mutex->unlock(nm->mutex);
|
||||
}
|
||||
|
||||
METHOD(network_manager_t, add_connectivity_cb, void,
|
||||
private_network_manager_t *this, connectivity_cb_t cb, void *data)
|
||||
{
|
||||
this->mutex->lock(this->mutex);
|
||||
if (!this->connectivity_cb.cb)
|
||||
{
|
||||
JNIEnv *env;
|
||||
jmethodID method_id;
|
||||
|
||||
androidjni_attach_thread(&env);
|
||||
method_id = (*env)->GetMethodID(env, this->cls, "Register", "()V");
|
||||
if (!method_id)
|
||||
{
|
||||
androidjni_exception_occurred(env);
|
||||
}
|
||||
else
|
||||
{
|
||||
(*env)->CallVoidMethod(env, this->obj, method_id);
|
||||
if (!androidjni_exception_occurred(env))
|
||||
{
|
||||
this->connectivity_cb.cb = cb;
|
||||
this->connectivity_cb.data = data;
|
||||
}
|
||||
androidjni_detach_thread();
|
||||
}
|
||||
}
|
||||
this->mutex->unlock(this->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister the NetworkManager via JNI.
|
||||
*
|
||||
* this->mutex has to be locked
|
||||
*/
|
||||
static void unregister_network_manager(private_network_manager_t *this)
|
||||
{
|
||||
JNIEnv *env;
|
||||
jmethodID method_id;
|
||||
|
||||
androidjni_attach_thread(&env);
|
||||
method_id = (*env)->GetMethodID(env, this->cls, "Unregister", "()V");
|
||||
if (!method_id)
|
||||
{
|
||||
androidjni_exception_occurred(env);
|
||||
}
|
||||
else
|
||||
{
|
||||
(*env)->CallVoidMethod(env, this->obj, method_id);
|
||||
androidjni_exception_occurred(env);
|
||||
}
|
||||
androidjni_detach_thread();
|
||||
}
|
||||
|
||||
METHOD(network_manager_t, remove_connectivity_cb, void,
|
||||
private_network_manager_t *this, connectivity_cb_t cb)
|
||||
{
|
||||
this->mutex->lock(this->mutex);
|
||||
if (this->connectivity_cb.cb == cb)
|
||||
{
|
||||
this->connectivity_cb.cb = NULL;
|
||||
unregister_network_manager(this);
|
||||
}
|
||||
this->mutex->unlock(this->mutex);
|
||||
}
|
||||
|
||||
METHOD(network_manager_t, destroy, void,
|
||||
private_network_manager_t *this)
|
||||
{
|
||||
JNIEnv *env;
|
||||
|
||||
this->mutex->lock(this->mutex);
|
||||
if (this->connectivity_cb.cb)
|
||||
{
|
||||
this->connectivity_cb.cb = NULL;
|
||||
unregister_network_manager(this);
|
||||
}
|
||||
this->mutex->unlock(this->mutex);
|
||||
|
||||
androidjni_attach_thread(&env);
|
||||
if (this->obj)
|
||||
{
|
||||
(*env)->DeleteGlobalRef(env, this->obj);
|
||||
}
|
||||
if (this->cls)
|
||||
{
|
||||
(*env)->DeleteGlobalRef(env, this->cls);
|
||||
}
|
||||
androidjni_detach_thread();
|
||||
this->mutex->destroy(this->mutex);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
network_manager_t *network_manager_create(jobject context)
|
||||
{
|
||||
private_network_manager_t *this;
|
||||
JNIEnv *env;
|
||||
jmethodID method_id;
|
||||
jobject obj;
|
||||
jclass cls;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.get_local_address = _get_local_address,
|
||||
.add_connectivity_cb = _add_connectivity_cb,
|
||||
.remove_connectivity_cb = _remove_connectivity_cb,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
|
||||
);
|
||||
|
||||
androidjni_attach_thread(&env);
|
||||
cls = (*env)->FindClass(env, JNI_PACKAGE_STRING "/NetworkManager");
|
||||
if (!cls)
|
||||
{
|
||||
goto failed;
|
||||
}
|
||||
this->cls = (*env)->NewGlobalRef(env, cls);
|
||||
method_id = (*env)->GetMethodID(env, cls, "<init>",
|
||||
"(Landroid/content/Context;)V");
|
||||
if (!method_id)
|
||||
{
|
||||
goto failed;
|
||||
}
|
||||
obj = (*env)->NewObject(env, cls, method_id, context);
|
||||
if (!obj)
|
||||
{
|
||||
goto failed;
|
||||
}
|
||||
this->obj = (*env)->NewGlobalRef(env, obj);
|
||||
androidjni_detach_thread();
|
||||
return &this->public;
|
||||
|
||||
failed:
|
||||
DBG1(DBG_KNL, "failed to build NetworkManager object");
|
||||
androidjni_exception_occurred(env);
|
||||
androidjni_detach_thread();
|
||||
destroy(this);
|
||||
return NULL;
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup network_manager network_manager
|
||||
* @{ @ingroup kernel_android
|
||||
*/
|
||||
|
||||
#ifndef NETWORK_MANAGER_H_
|
||||
#define NETWORK_MANAGER_H_
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <library.h>
|
||||
#include <utils/host.h>
|
||||
|
||||
typedef struct network_manager_t network_manager_t;
|
||||
|
||||
/**
|
||||
* Callback called if connectivity changes somehow.
|
||||
*
|
||||
* Implementation should be quick as the call is made by the Java apps main
|
||||
* thread.
|
||||
*
|
||||
* @param data data supplied during registration
|
||||
* @param disconnected TRUE if currently disconnected
|
||||
*/
|
||||
typedef void (*connectivity_cb_t)(void *data, bool disconnected);
|
||||
|
||||
/**
|
||||
* NetworkManager, used to listen for network changes and retrieve local IP
|
||||
* addresses.
|
||||
*
|
||||
* Communicates with NetworkManager via JNI
|
||||
*/
|
||||
struct network_manager_t {
|
||||
|
||||
/**
|
||||
* Get a local address
|
||||
*
|
||||
* @param ipv4 TRUE to get an IPv4 address
|
||||
* @return the address or NULL if none available
|
||||
*/
|
||||
host_t *(*get_local_address)(network_manager_t *this, bool ipv4);
|
||||
|
||||
/**
|
||||
* Register a callback that is called if connectivity changes
|
||||
*
|
||||
* @note Only the first registered callback is currently used
|
||||
*
|
||||
* @param cb callback to register
|
||||
* @param data data provided to callback
|
||||
*/
|
||||
void (*add_connectivity_cb)(network_manager_t *this, connectivity_cb_t cb,
|
||||
void *data);
|
||||
|
||||
/**
|
||||
* Unregister a previously registered callback for connectivity changes
|
||||
*
|
||||
* @param cb previously registered callback
|
||||
*/
|
||||
void (*remove_connectivity_cb)(network_manager_t *this,
|
||||
connectivity_cb_t cb);
|
||||
|
||||
/**
|
||||
* Destroy a network_manager_t instance
|
||||
*/
|
||||
void (*destroy)(network_manager_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a network_manager_t instance
|
||||
*
|
||||
* @param context Context object
|
||||
* @return network_manager_t instance
|
||||
*/
|
||||
network_manager_t *network_manager_create(jobject context);
|
||||
|
||||
#endif /** NETWORK_MANAGER_H_ @}*/
|
||||
@@ -18,14 +18,10 @@
|
||||
package org.strongswan.android.logic;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import org.strongswan.android.data.VpnProfile;
|
||||
import org.strongswan.android.data.VpnProfileDataSource;
|
||||
@@ -218,9 +214,7 @@ public class CharonVpnService extends VpnService implements Runnable
|
||||
initializeCharon(builder, mLogFile);
|
||||
Log.i(TAG, "charon started");
|
||||
|
||||
String local_address = getLocalIPv4Address();
|
||||
initiate(mCurrentProfile.getVpnType().getIdentifier(),
|
||||
local_address != null ? local_address : "0.0.0.0",
|
||||
mCurrentProfile.getGateway(), mCurrentProfile.getUsername(),
|
||||
mCurrentProfile.getPassword());
|
||||
}
|
||||
@@ -335,15 +329,7 @@ public class CharonVpnService extends VpnService implements Runnable
|
||||
switch (status)
|
||||
{
|
||||
case STATE_CHILD_SA_DOWN:
|
||||
synchronized (mServiceLock)
|
||||
{
|
||||
/* if we are not actively disconnecting we assume the remote terminated
|
||||
* the connection and call disconnect() to deinitialize charon properly */
|
||||
if (mService != null && !mIsDisconnecting)
|
||||
{
|
||||
mService.disconnect();
|
||||
}
|
||||
}
|
||||
/* we ignore this as we use closeaction=restart */
|
||||
break;
|
||||
case STATE_CHILD_SA_UP:
|
||||
setState(State.CONNECTED);
|
||||
@@ -486,41 +472,7 @@ public class CharonVpnService extends VpnService implements Runnable
|
||||
/**
|
||||
* Initiate VPN, provided by libandroidbridge.so
|
||||
*/
|
||||
public native void initiate(String type, String local_address, String gateway,
|
||||
String username, String password);
|
||||
|
||||
/**
|
||||
* Helper function that retrieves a local IPv4 address.
|
||||
*
|
||||
* @return string representation of an IPv4 address, or null if none found
|
||||
*/
|
||||
private static String getLocalIPv4Address()
|
||||
{
|
||||
try
|
||||
{
|
||||
Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
|
||||
while (en.hasMoreElements())
|
||||
{
|
||||
NetworkInterface intf = en.nextElement();
|
||||
|
||||
Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses();
|
||||
while (enumIpAddr.hasMoreElements())
|
||||
{
|
||||
InetAddress inetAddress = enumIpAddr.nextElement();
|
||||
if (!inetAddress.isLoopbackAddress() && inetAddress.getAddress().length == 4)
|
||||
{
|
||||
return inetAddress.getHostAddress().toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public native void initiate(String type, String gateway, String username, String password);
|
||||
|
||||
/**
|
||||
* Adapter for VpnService.Builder which is used to access it safely via JNI.
|
||||
@@ -547,7 +499,7 @@ public class CharonVpnService extends VpnService implements Runnable
|
||||
Context context = getApplicationContext();
|
||||
Intent intent = new Intent(context, MainActivity.class);
|
||||
PendingIntent pending = PendingIntent.getActivity(context, 0, intent,
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
builder.setConfigureIntent(pending);
|
||||
return builder;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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.
|
||||
*/
|
||||
|
||||
package org.strongswan.android.logic;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
|
||||
public class NetworkManager extends BroadcastReceiver
|
||||
{
|
||||
private final Context mContext;
|
||||
private boolean mRegistered;
|
||||
|
||||
public NetworkManager(Context context)
|
||||
{
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public void Register()
|
||||
{
|
||||
mContext.registerReceiver(this, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
|
||||
}
|
||||
|
||||
public void Unregister()
|
||||
{
|
||||
mContext.unregisterReceiver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo info = cm.getActiveNetworkInfo();
|
||||
networkChanged(info == null || !info.isConnected());
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the native parts about a network change
|
||||
*
|
||||
* @param disconnected true if no connection is available at the moment
|
||||
*/
|
||||
public native void networkChanged(boolean disconnected);
|
||||
|
||||
/**
|
||||
* Function that retrieves a local address of the given family.
|
||||
*
|
||||
* @param ipv4 true to return an IPv4 address, false for IPv6
|
||||
* @return string representation of an IPv4 address, or null if none found
|
||||
*/
|
||||
public String getLocalAddress(boolean ipv4)
|
||||
{
|
||||
try
|
||||
{
|
||||
Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
|
||||
if (en == null)
|
||||
{ /* no interfaces at all */
|
||||
return null;
|
||||
}
|
||||
while (en.hasMoreElements())
|
||||
{
|
||||
NetworkInterface intf = en.nextElement();
|
||||
if (intf.isLoopback() || !intf.isUp() ||
|
||||
intf.getName().startsWith("tun"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses();
|
||||
while (enumIpAddr.hasMoreElements())
|
||||
{
|
||||
InetAddress inetAddress = enumIpAddr.nextElement();
|
||||
if (inetAddress.isLoopbackAddress())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ((ipv4 && inetAddress instanceof Inet4Address) ||
|
||||
(!ipv4 && inetAddress instanceof Inet6Address))
|
||||
{
|
||||
return inetAddress.getHostAddress();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -90,6 +90,8 @@ enum alert_t {
|
||||
ALERT_PEER_AUTH_FAILED,
|
||||
/** failed to resolve peer address, no arguments */
|
||||
ALERT_PEER_ADDR_FAILED,
|
||||
/** peer did not respond to initial message, current try (int, 0-based) */
|
||||
ALERT_PEER_INIT_UNREACHABLE,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -84,7 +84,8 @@ static void destroy(private_daemon_t *this)
|
||||
{
|
||||
/* terminate all idle threads */
|
||||
lib->processor->set_threads(lib->processor, 0);
|
||||
|
||||
/* make sure nobody waits for a DNS query */
|
||||
lib->hosts->flush(lib->hosts);
|
||||
/* close all IKE_SAs */
|
||||
if (this->public.ike_sa_manager)
|
||||
{
|
||||
|
||||
@@ -1690,6 +1690,8 @@ METHOD(ike_sa_t, retransmit, status_t,
|
||||
{
|
||||
/* retry IKE_SA_INIT/Main Mode if we have multiple keyingtries */
|
||||
u_int32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg);
|
||||
charon->bus->alert(charon->bus, ALERT_PEER_INIT_UNREACHABLE,
|
||||
this->keyingtry);
|
||||
this->keyingtry++;
|
||||
if (tries == 0 || tries > this->keyingtry)
|
||||
{
|
||||
|
||||
@@ -543,12 +543,7 @@ static void queue_route_reinstall(private_kernel_netlink_net_t *this,
|
||||
time_monotonic(&now);
|
||||
if (timercmp(&now, &this->last_route_reinstall, >))
|
||||
{
|
||||
now.tv_usec += ROUTE_DELAY * 1000;
|
||||
while (now.tv_usec > 1000000)
|
||||
{
|
||||
now.tv_sec++;
|
||||
now.tv_usec -= 1000000;
|
||||
}
|
||||
timeval_add_ms(&now, ROUTE_DELAY);
|
||||
this->last_route_reinstall = now;
|
||||
|
||||
job = (job_t*)callback_job_create((callback_job_cb_t)reinstall_routes,
|
||||
@@ -704,12 +699,7 @@ static void fire_roam_event(private_kernel_netlink_net_t *this, bool address)
|
||||
this->roam_lock->unlock(this->roam_lock);
|
||||
return;
|
||||
}
|
||||
now.tv_usec += ROAM_DELAY * 1000;
|
||||
while (now.tv_usec > 1000000)
|
||||
{
|
||||
now.tv_sec++;
|
||||
now.tv_usec -= 1000000;
|
||||
}
|
||||
timeval_add_ms(&now, ROAM_DELAY);
|
||||
this->next_roam = now;
|
||||
this->roam_lock->unlock(this->roam_lock);
|
||||
|
||||
|
||||
@@ -285,12 +285,7 @@ static void fire_roam_event(private_kernel_pfroute_net_t *this, bool address)
|
||||
time_monotonic(&now);
|
||||
if (timercmp(&now, &this->last_roam, >))
|
||||
{
|
||||
now.tv_usec += ROAM_DELAY * 1000;
|
||||
while (now.tv_usec > 1000000)
|
||||
{
|
||||
now.tv_sec++;
|
||||
now.tv_usec -= 1000000;
|
||||
}
|
||||
timeval_add_ms(&now, ROAM_DELAY);
|
||||
this->last_roam = now;
|
||||
|
||||
job = (job_t*)callback_job_create((callback_job_cb_t)roam_event,
|
||||
|
||||
@@ -146,7 +146,9 @@ static job_requeue_t process_inbound(private_ipsec_processor_t *this)
|
||||
policy->destroy(policy);
|
||||
break;
|
||||
}
|
||||
DBG1(DBG_ESP, "discarding inbound IP packet due to policy");
|
||||
DBG1(DBG_ESP, "discarding inbound IP packet %H == %H due to "
|
||||
"policy", ip_packet->get_source(ip_packet),
|
||||
ip_packet->get_destination(ip_packet));
|
||||
/* no matching policy found, fall-through */
|
||||
}
|
||||
case IPPROTO_NONE:
|
||||
|
||||
@@ -95,6 +95,20 @@ METHOD(ipsec_sa_t, get_destination, host_t*,
|
||||
return this->dst;
|
||||
}
|
||||
|
||||
METHOD(ipsec_sa_t, set_source, void,
|
||||
private_ipsec_sa_t *this, host_t *addr)
|
||||
{
|
||||
this->src->destroy(this->src);
|
||||
this->src = addr->clone(addr);
|
||||
}
|
||||
|
||||
METHOD(ipsec_sa_t, set_destination, void,
|
||||
private_ipsec_sa_t *this, host_t *addr)
|
||||
{
|
||||
this->dst->destroy(this->dst);
|
||||
this->dst = addr->clone(addr);
|
||||
}
|
||||
|
||||
METHOD(ipsec_sa_t, get_spi, u_int32_t,
|
||||
private_ipsec_sa_t *this)
|
||||
{
|
||||
@@ -202,6 +216,8 @@ ipsec_sa_t *ipsec_sa_create(u_int32_t spi, host_t *src, host_t *dst,
|
||||
.destroy = _destroy,
|
||||
.get_source = _get_source,
|
||||
.get_destination = _get_destination,
|
||||
.set_source = _set_source,
|
||||
.set_destination = _set_destination,
|
||||
.get_spi = _get_spi,
|
||||
.get_reqid = _get_reqid,
|
||||
.get_protocol = _get_protocol,
|
||||
|
||||
@@ -51,6 +51,20 @@ struct ipsec_sa_t {
|
||||
*/
|
||||
host_t *(*get_destination)(ipsec_sa_t *this);
|
||||
|
||||
/**
|
||||
* Set the source address for this SA
|
||||
*
|
||||
* @param addr source address of this SA (gets cloned)
|
||||
*/
|
||||
void (*set_source)(ipsec_sa_t *this, host_t *addr);
|
||||
|
||||
/**
|
||||
* Set the destination address for this SA
|
||||
*
|
||||
* @param addr destination address of this SA (gets cloned)
|
||||
*/
|
||||
void (*set_destination)(ipsec_sa_t *this, host_t *addr);
|
||||
|
||||
/**
|
||||
* Get the SPI for this SA
|
||||
*
|
||||
|
||||
+54
-15
@@ -237,29 +237,29 @@ static bool match_entry_by_sa_ptr(ipsec_sa_entry_t *item, ipsec_sa_t *sa)
|
||||
return item->sa == sa;
|
||||
}
|
||||
|
||||
static bool match_entry_by_spi_inbound(ipsec_sa_entry_t *item, u_int32_t spi,
|
||||
bool inbound)
|
||||
static bool match_entry_by_spi_inbound(ipsec_sa_entry_t *item, u_int32_t *spi,
|
||||
bool *inbound)
|
||||
{
|
||||
return item->sa->get_spi(item->sa) == spi &&
|
||||
item->sa->is_inbound(item->sa) == inbound;
|
||||
return item->sa->get_spi(item->sa) == *spi &&
|
||||
item->sa->is_inbound(item->sa) == *inbound;
|
||||
}
|
||||
|
||||
static bool match_entry_by_spi_src_dst(ipsec_sa_entry_t *item, u_int32_t spi,
|
||||
static bool match_entry_by_spi_src_dst(ipsec_sa_entry_t *item, u_int32_t *spi,
|
||||
host_t *src, host_t *dst)
|
||||
{
|
||||
return item->sa->match_by_spi_src_dst(item->sa, spi, src, dst);
|
||||
return item->sa->match_by_spi_src_dst(item->sa, *spi, src, dst);
|
||||
}
|
||||
|
||||
static bool match_entry_by_reqid_inbound(ipsec_sa_entry_t *item,
|
||||
u_int32_t reqid, bool inbound)
|
||||
u_int32_t *reqid, bool *inbound)
|
||||
{
|
||||
return item->sa->match_by_reqid(item->sa, reqid, inbound);
|
||||
return item->sa->match_by_reqid(item->sa, *reqid, *inbound);
|
||||
}
|
||||
|
||||
static bool match_entry_by_spi_dst(ipsec_sa_entry_t *item, u_int32_t spi,
|
||||
static bool match_entry_by_spi_dst(ipsec_sa_entry_t *item, u_int32_t *spi,
|
||||
host_t *dst)
|
||||
{
|
||||
return item->sa->match_by_spi_dst(item->sa, spi, dst);
|
||||
return item->sa->match_by_spi_dst(item->sa, *spi, dst);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -381,7 +381,7 @@ static bool allocate_spi(private_ipsec_sa_mgr_t *this, u_int32_t spi)
|
||||
|
||||
if (this->allocated_spis->get(this->allocated_spis, &spi) ||
|
||||
this->sas->find_first(this->sas, (void*)match_entry_by_spi_inbound,
|
||||
NULL, spi, TRUE) == SUCCESS)
|
||||
NULL, &spi, TRUE) == SUCCESS)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@@ -471,7 +471,7 @@ METHOD(ipsec_sa_mgr_t, add_sa, status_t,
|
||||
}
|
||||
|
||||
if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_src_dst,
|
||||
NULL, spi, src, dst) == SUCCESS)
|
||||
NULL, &spi, src, dst) == SUCCESS)
|
||||
{
|
||||
this->mutex->unlock(this->mutex);
|
||||
DBG1(DBG_ESP, "failed to install SAD entry: already installed");
|
||||
@@ -487,6 +487,44 @@ METHOD(ipsec_sa_mgr_t, add_sa, status_t,
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(ipsec_sa_mgr_t, update_sa, status_t,
|
||||
private_ipsec_sa_mgr_t *this, u_int32_t spi, u_int8_t protocol,
|
||||
u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
|
||||
bool encap, bool new_encap, mark_t mark)
|
||||
{
|
||||
ipsec_sa_entry_t *entry = NULL;
|
||||
|
||||
DBG2(DBG_ESP, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H",
|
||||
ntohl(spi), src, dst, new_src, new_dst);
|
||||
|
||||
if (!new_encap)
|
||||
{
|
||||
DBG1(DBG_ESP, "failed to update SAD entry: can't deactivate UDP "
|
||||
"encapsulation");
|
||||
return NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
this->mutex->lock(this->mutex);
|
||||
if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_src_dst,
|
||||
(void**)&entry, &spi, src, dst) == SUCCESS &&
|
||||
wait_for_entry(this, entry))
|
||||
{
|
||||
entry->sa->set_source(entry->sa, new_src);
|
||||
entry->sa->set_destination(entry->sa, new_dst);
|
||||
/* checkin the entry */
|
||||
entry->locked = FALSE;
|
||||
entry->condvar->signal(entry->condvar);
|
||||
}
|
||||
this->mutex->unlock(this->mutex);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
DBG1(DBG_ESP, "failed to update SAD entry: not found");
|
||||
return FAILED;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(ipsec_sa_mgr_t, del_sa, status_t,
|
||||
private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, u_int32_t spi,
|
||||
u_int8_t protocol, u_int16_t cpi, mark_t mark)
|
||||
@@ -498,7 +536,7 @@ METHOD(ipsec_sa_mgr_t, del_sa, status_t,
|
||||
enumerator = this->sas->create_enumerator(this->sas);
|
||||
while (enumerator->enumerate(enumerator, (void**)¤t))
|
||||
{
|
||||
if (match_entry_by_spi_src_dst(current, spi, src, dst))
|
||||
if (match_entry_by_spi_src_dst(current, &spi, src, dst))
|
||||
{
|
||||
if (wait_remove_entry(this, current))
|
||||
{
|
||||
@@ -529,7 +567,7 @@ METHOD(ipsec_sa_mgr_t, checkout_by_reqid, ipsec_sa_t*,
|
||||
|
||||
this->mutex->lock(this->mutex);
|
||||
if (this->sas->find_first(this->sas, (void*)match_entry_by_reqid_inbound,
|
||||
(void**)&entry, reqid, inbound) == SUCCESS &&
|
||||
(void**)&entry, &reqid, &inbound) == SUCCESS &&
|
||||
wait_for_entry(this, entry))
|
||||
{
|
||||
sa = entry->sa;
|
||||
@@ -546,7 +584,7 @@ METHOD(ipsec_sa_mgr_t, checkout_by_spi, ipsec_sa_t*,
|
||||
|
||||
this->mutex->lock(this->mutex);
|
||||
if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_dst,
|
||||
(void**)&entry, spi, dst) == SUCCESS &&
|
||||
(void**)&entry, &spi, dst) == SUCCESS &&
|
||||
wait_for_entry(this, entry))
|
||||
{
|
||||
sa = entry->sa;
|
||||
@@ -609,6 +647,7 @@ ipsec_sa_mgr_t *ipsec_sa_mgr_create()
|
||||
.public = {
|
||||
.get_spi = _get_spi,
|
||||
.add_sa = _add_sa,
|
||||
.update_sa = _update_sa,
|
||||
.del_sa = _del_sa,
|
||||
.checkout_by_spi = _checkout_by_spi,
|
||||
.checkout_by_reqid = _checkout_by_reqid,
|
||||
|
||||
@@ -85,6 +85,27 @@ struct ipsec_sa_mgr_t {
|
||||
u_int16_t cpi, bool encap, bool esn, bool inbound,
|
||||
traffic_selector_t *src_ts, traffic_selector_t *dst_ts);
|
||||
|
||||
/**
|
||||
* Update the hosts on an installed SA.
|
||||
*
|
||||
* @param spi SPI of the SA
|
||||
* @param protocol protocol for this SA (ESP/AH)
|
||||
* @param cpi CPI for IPComp, 0 if no IPComp is used
|
||||
* @param src current source address
|
||||
* @param dst current destination address
|
||||
* @param new_src new source address
|
||||
* @param new_dst new destination address
|
||||
* @param encap current use of UDP encapsulation
|
||||
* @param new_encap new use of UDP encapsulation
|
||||
* @param mark optional mark for this SA
|
||||
* @return SUCCESS if operation completed
|
||||
*/
|
||||
status_t (*update_sa)(ipsec_sa_mgr_t *this,
|
||||
u_int32_t spi, u_int8_t protocol, u_int16_t cpi,
|
||||
host_t *src, host_t *dst,
|
||||
host_t *new_src, host_t *new_dst,
|
||||
bool encap, bool new_encap, mark_t mark);
|
||||
|
||||
/**
|
||||
* Delete a previously added SA
|
||||
*
|
||||
|
||||
@@ -3,8 +3,8 @@ include $(CLEAR_VARS)
|
||||
|
||||
# copy-n-paste from Makefile.am
|
||||
LOCAL_SRC_FILES := \
|
||||
library.c chunk.c debug.c enum.c settings.c printf_hook.c asn1/asn1.c \
|
||||
asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \
|
||||
library.c chunk.c debug.c enum.c host_resolver.c settings.c printf_hook.c \
|
||||
asn1/asn1.c asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \
|
||||
crypto/crypters/crypter.c crypto/hashers/hasher.c crypto/pkcs7.c crypto/pkcs9.c \
|
||||
crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \
|
||||
crypto/prfs/prf.c crypto/prfs/mac_prf.c \
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
ipseclib_LTLIBRARIES = libstrongswan.la
|
||||
|
||||
libstrongswan_la_SOURCES = \
|
||||
library.c chunk.c debug.c enum.c settings.c printf_hook.c asn1/asn1.c \
|
||||
asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \
|
||||
library.c chunk.c debug.c enum.c host_resolver.c settings.c printf_hook.c \
|
||||
asn1/asn1.c asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \
|
||||
crypto/crypters/crypter.c crypto/hashers/hasher.c crypto/pkcs7.c crypto/pkcs9.c \
|
||||
crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \
|
||||
crypto/prfs/prf.c crypto/prfs/mac_prf.c \
|
||||
@@ -31,7 +31,7 @@ utils/optionsfrom.c utils/capabilities.c utils/backtrace.c utils/tun_device.c
|
||||
if USE_DEV_HEADERS
|
||||
strongswan_includedir = ${dev_headers}
|
||||
nobase_strongswan_include_HEADERS = \
|
||||
library.h chunk.h debug.h enum.h settings.h printf_hook.h \
|
||||
library.h chunk.h debug.h enum.h host_resolver.h settings.h printf_hook.h \
|
||||
asn1/asn1.h asn1/asn1_parser.h asn1/oid.h bio/bio_reader.h bio/bio_writer.h \
|
||||
crypto/crypters/crypter.h crypto/hashers/hasher.h crypto/mac.h \
|
||||
crypto/pkcs7.h crypto/pkcs9.h crypto/proposal/proposal_keywords.h \
|
||||
|
||||
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "host_resolver.h"
|
||||
|
||||
#include <debug.h>
|
||||
#include <library.h>
|
||||
#include <threading/condvar.h>
|
||||
#include <threading/mutex.h>
|
||||
#include <threading/thread.h>
|
||||
#include <utils/hashtable.h>
|
||||
#include <utils/linked_list.h>
|
||||
|
||||
/**
|
||||
* Default minimum and maximum number of threads
|
||||
*/
|
||||
#define MIN_THREADS_DEFAULT 0
|
||||
#define MAX_THREADS_DEFAULT 3
|
||||
|
||||
/**
|
||||
* Timeout in seconds to wait for new queries until a thread may be stopped
|
||||
*/
|
||||
#define NEW_QUERY_WAIT_TIMEOUT 30
|
||||
|
||||
typedef struct private_host_resolver_t private_host_resolver_t;
|
||||
|
||||
/**
|
||||
* Private data of host_resolver_t
|
||||
*/
|
||||
struct private_host_resolver_t {
|
||||
|
||||
/**
|
||||
* Public interface
|
||||
*/
|
||||
host_resolver_t public;
|
||||
|
||||
/**
|
||||
* Hashtable to check for queued queries, query_t*
|
||||
*/
|
||||
hashtable_t *queries;
|
||||
|
||||
/**
|
||||
* Queue for queries, query_t*
|
||||
*/
|
||||
linked_list_t *queue;
|
||||
|
||||
/**
|
||||
* Mutex to safely access private data
|
||||
*/
|
||||
mutex_t *mutex;
|
||||
|
||||
/**
|
||||
* Condvar to signal arrival of new queries
|
||||
*/
|
||||
condvar_t *new_query;
|
||||
|
||||
/**
|
||||
* Minimum number of resolver threads
|
||||
*/
|
||||
u_int min_threads;
|
||||
|
||||
/**
|
||||
* Maximum number of resolver threads
|
||||
*/
|
||||
u_int max_threads;
|
||||
|
||||
/**
|
||||
* Current number of threads
|
||||
*/
|
||||
u_int threads;
|
||||
|
||||
/**
|
||||
* Current number of busy threads
|
||||
*/
|
||||
u_int busy_threads;
|
||||
|
||||
/**
|
||||
* Pool of threads, thread_t*
|
||||
*/
|
||||
linked_list_t *pool;
|
||||
|
||||
/**
|
||||
* TRUE if no new queries are accepted
|
||||
*/
|
||||
bool disabled;
|
||||
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
/** DNS name we are looking for */
|
||||
char *name;
|
||||
/** address family we request */
|
||||
int family;
|
||||
/** Condvar to signal completion of a query */
|
||||
condvar_t *done;
|
||||
/** refcount */
|
||||
refcount_t refcount;
|
||||
/** the result if successful */
|
||||
host_t *result;
|
||||
} query_t;
|
||||
|
||||
/**
|
||||
* Destroy the given query_t object if refcount is zero
|
||||
*/
|
||||
static void query_destroy(query_t *this)
|
||||
{
|
||||
if (ref_put(&this->refcount))
|
||||
{
|
||||
DESTROY_IF(this->result);
|
||||
this->done->destroy(this->done);
|
||||
free(this->name);
|
||||
free(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals all waiting threads and destroys the query
|
||||
*/
|
||||
static void query_signal_and_destroy(query_t *this)
|
||||
{
|
||||
this->done->broadcast(this->done);
|
||||
query_destroy(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash a queued query
|
||||
*/
|
||||
static u_int query_hash(query_t *this)
|
||||
{
|
||||
return chunk_hash_inc(chunk_create(this->name, strlen(this->name)),
|
||||
chunk_hash(chunk_from_thing(this->family)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two queued queries
|
||||
*/
|
||||
static bool query_equals(query_t *this, query_t *other)
|
||||
{
|
||||
return this->family == other->family && streq(this->name, other->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function of resolver threads
|
||||
*/
|
||||
static void *resolve_hosts(private_host_resolver_t *this)
|
||||
{
|
||||
struct addrinfo hints, *result;
|
||||
query_t *query;
|
||||
int error;
|
||||
bool old, timed_out;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
this->mutex->lock(this->mutex);
|
||||
thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex);
|
||||
while (this->queue->remove_first(this->queue,
|
||||
(void**)&query) != SUCCESS)
|
||||
{
|
||||
old = thread_cancelability(TRUE);
|
||||
timed_out = this->new_query->timed_wait(this->new_query,
|
||||
this->mutex, NEW_QUERY_WAIT_TIMEOUT * 1000);
|
||||
thread_cancelability(old);
|
||||
if (this->disabled)
|
||||
{
|
||||
thread_cleanup_pop(TRUE);
|
||||
return NULL;
|
||||
}
|
||||
else if (timed_out && (this->threads > this->min_threads))
|
||||
{ /* terminate this thread by detaching it */
|
||||
thread_t *thread = thread_current();
|
||||
|
||||
this->threads--;
|
||||
this->pool->remove(this->pool, thread, NULL);
|
||||
thread_cleanup_pop(TRUE);
|
||||
thread->detach(thread);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
this->busy_threads++;
|
||||
thread_cleanup_pop(TRUE);
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = query->family;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
thread_cleanup_push((thread_cleanup_t)query_signal_and_destroy, query);
|
||||
old = thread_cancelability(TRUE);
|
||||
error = getaddrinfo(query->name, NULL, &hints, &result);
|
||||
thread_cancelability(old);
|
||||
thread_cleanup_pop(FALSE);
|
||||
|
||||
this->mutex->lock(this->mutex);
|
||||
this->busy_threads--;
|
||||
if (error != 0)
|
||||
{
|
||||
DBG1(DBG_LIB, "resolving '%s' failed: %s", query->name,
|
||||
gai_strerror(error));
|
||||
}
|
||||
else
|
||||
{ /* result is a linked list, but we use only the first address */
|
||||
query->result = host_create_from_sockaddr(result->ai_addr);
|
||||
freeaddrinfo(result);
|
||||
}
|
||||
this->queries->remove(this->queries, query);
|
||||
query->done->broadcast(query->done);
|
||||
this->mutex->unlock(this->mutex);
|
||||
query_destroy(query);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to convert IP addresses directly
|
||||
*/
|
||||
static host_t *try_numeric_lookup(char *name, int family)
|
||||
{
|
||||
struct addrinfo hints, *result;
|
||||
int error;
|
||||
host_t *host;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = family;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
|
||||
error = getaddrinfo(name, NULL, &hints, &result);
|
||||
if (error != 0)
|
||||
{ /* not an IP address */
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{ /* result is a linked list, but we use only the first address */
|
||||
host = host_create_from_sockaddr(result->ai_addr);
|
||||
freeaddrinfo(result);
|
||||
}
|
||||
return host;
|
||||
}
|
||||
|
||||
METHOD(host_resolver_t, resolve, host_t*,
|
||||
private_host_resolver_t *this, char *name, int family)
|
||||
{
|
||||
query_t *query, lookup = {
|
||||
.name = name,
|
||||
.family = family,
|
||||
};
|
||||
host_t *result;
|
||||
|
||||
if (streq(name, "%any") || streq(name, "0.0.0.0"))
|
||||
{
|
||||
return host_create_any(family ? family : AF_INET);
|
||||
}
|
||||
if (streq(name, "%any6") || streq(name, "::"))
|
||||
{
|
||||
return host_create_any(family ? family : AF_INET6);
|
||||
}
|
||||
if (family == AF_INET && strchr(name, ':'))
|
||||
{ /* do not try to convert v6 addresses for v4 family */
|
||||
return NULL;
|
||||
}
|
||||
result = try_numeric_lookup(name, family);
|
||||
if (result)
|
||||
{ /* shortcut for numeric IP addresses */
|
||||
return result;
|
||||
}
|
||||
this->mutex->lock(this->mutex);
|
||||
if (this->disabled)
|
||||
{
|
||||
this->mutex->unlock(this->mutex);
|
||||
return NULL;
|
||||
}
|
||||
query = this->queries->get(this->queries, &lookup);
|
||||
if (!query)
|
||||
{
|
||||
INIT(query,
|
||||
.name = strdup(name),
|
||||
.family = family,
|
||||
.done = condvar_create(CONDVAR_TYPE_DEFAULT),
|
||||
.refcount = 1,
|
||||
);
|
||||
this->queries->put(this->queries, query, query);
|
||||
this->queue->insert_last(this->queue, query);
|
||||
this->new_query->signal(this->new_query);
|
||||
}
|
||||
ref_get(&query->refcount);
|
||||
if (this->busy_threads == this->threads &&
|
||||
this->threads < this->max_threads)
|
||||
{
|
||||
thread_t *thread;
|
||||
|
||||
thread = thread_create((thread_main_t)resolve_hosts, this);
|
||||
if (thread)
|
||||
{
|
||||
this->threads++;
|
||||
this->pool->insert_last(this->pool, thread);
|
||||
}
|
||||
}
|
||||
query->done->wait(query->done, this->mutex);
|
||||
this->mutex->unlock(this->mutex);
|
||||
|
||||
result = query->result ? query->result->clone(query->result) : NULL;
|
||||
query_destroy(query);
|
||||
return result;
|
||||
}
|
||||
|
||||
METHOD(host_resolver_t, flush, void,
|
||||
private_host_resolver_t *this)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
query_t *query;
|
||||
|
||||
this->mutex->lock(this->mutex);
|
||||
enumerator = this->queries->create_enumerator(this->queries);
|
||||
while (enumerator->enumerate(enumerator, &query, NULL))
|
||||
{ /* use the hashtable here as we also want to signal dequeued queries */
|
||||
this->queries->remove_at(this->queries, enumerator);
|
||||
query->done->broadcast(query->done);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
this->queue->destroy_function(this->queue, (void*)query_destroy);
|
||||
this->queue = linked_list_create();
|
||||
this->disabled = TRUE;
|
||||
/* this will already terminate most idle threads */
|
||||
this->new_query->broadcast(this->new_query);
|
||||
this->mutex->unlock(this->mutex);
|
||||
}
|
||||
|
||||
METHOD(host_resolver_t, destroy, void,
|
||||
private_host_resolver_t *this)
|
||||
{
|
||||
thread_t *thread;
|
||||
|
||||
flush(this);
|
||||
this->pool->invoke_offset(this->pool, offsetof(thread_t, cancel));
|
||||
while (this->pool->remove_first(this->pool, (void**)&thread) == SUCCESS)
|
||||
{
|
||||
thread->join(thread);
|
||||
}
|
||||
this->pool->destroy(this->pool);
|
||||
this->queue->destroy(this->queue);
|
||||
this->queries->destroy(this->queries);
|
||||
this->new_query->destroy(this->new_query);
|
||||
this->mutex->destroy(this->mutex);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
host_resolver_t *host_resolver_create()
|
||||
{
|
||||
private_host_resolver_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.resolve = _resolve,
|
||||
.flush = _flush,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.queries = hashtable_create((hashtable_hash_t)query_hash,
|
||||
(hashtable_equals_t)query_equals, 8),
|
||||
.queue = linked_list_create(),
|
||||
.pool = linked_list_create(),
|
||||
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
|
||||
.new_query = condvar_create(CONDVAR_TYPE_DEFAULT),
|
||||
);
|
||||
|
||||
this->min_threads = max(0, lib->settings->get_int(lib->settings,
|
||||
"libstrongswan.host_resolver.min_threads",
|
||||
MIN_THREADS_DEFAULT));
|
||||
this->max_threads = max(this->min_threads ?: 1,
|
||||
lib->settings->get_int(lib->settings,
|
||||
"libstrongswan.host_resolver.max_threads",
|
||||
MAX_THREADS_DEFAULT));
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup host_resolver host_resolver
|
||||
* @{ @ingroup libstrongswan
|
||||
*/
|
||||
|
||||
#ifndef HOST_RESOLVER_H_
|
||||
#define HOST_RESOLVER_H_
|
||||
|
||||
#include "utils/host.h"
|
||||
|
||||
typedef struct host_resolver_t host_resolver_t;
|
||||
|
||||
/**
|
||||
* Resolve hosts by DNS name but do so in a separate thread (calling
|
||||
* getaddrinfo(3) directly might block indefinitely, or at least a very long
|
||||
* time if no DNS servers are reachable).
|
||||
*/
|
||||
struct host_resolver_t {
|
||||
|
||||
/**
|
||||
* Resolve host from the given DNS name.
|
||||
*
|
||||
* @param name name to lookup
|
||||
* @param family requested address family
|
||||
* @return resolved host or NULL if failed or canceled
|
||||
*/
|
||||
host_t *(*resolve)(host_resolver_t *this, char *name, int family);
|
||||
|
||||
/**
|
||||
* Flush the queue of queries. No new queries will be accepted afterwards.
|
||||
*/
|
||||
void (*flush)(host_resolver_t *this);
|
||||
|
||||
/**
|
||||
* Destroy a host_resolver_t.
|
||||
*/
|
||||
void (*destroy)(host_resolver_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a host_resolver_t instance.
|
||||
*/
|
||||
host_resolver_t *host_resolver_create();
|
||||
|
||||
#endif /** HOST_RESOLVER_H_ @}*/
|
||||
@@ -68,6 +68,7 @@ void library_deinit()
|
||||
this->public.scheduler->destroy(this->public.scheduler);
|
||||
this->public.processor->destroy(this->public.processor);
|
||||
this->public.plugins->destroy(this->public.plugins);
|
||||
this->public.hosts->destroy(this->public.hosts);
|
||||
this->public.settings->destroy(this->public.settings);
|
||||
this->public.credmgr->destroy(this->public.credmgr);
|
||||
this->public.creds->destroy(this->public.creds);
|
||||
@@ -183,6 +184,7 @@ bool library_init(char *settings)
|
||||
this->objects = hashtable_create((hashtable_hash_t)hash,
|
||||
(hashtable_equals_t)equals, 4);
|
||||
this->public.settings = settings_create(settings);
|
||||
this->public.hosts = host_resolver_create();
|
||||
this->public.proposal = proposal_keywords_create();
|
||||
this->public.crypto = crypto_factory_create();
|
||||
this->public.creds = credential_factory_create();
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
#include "printf_hook.h"
|
||||
#include "utils.h"
|
||||
#include "chunk.h"
|
||||
#include "host_resolver.h"
|
||||
#include "settings.h"
|
||||
#include "integrity_checker.h"
|
||||
#include "processing/processor.h"
|
||||
@@ -170,6 +171,11 @@ struct library_t {
|
||||
*/
|
||||
scheduler_t *scheduler;
|
||||
|
||||
/**
|
||||
* resolve hosts by DNS name
|
||||
*/
|
||||
host_resolver_t *hosts;
|
||||
|
||||
/**
|
||||
* various settings loaded from settings file
|
||||
*/
|
||||
|
||||
@@ -282,13 +282,7 @@ METHOD(condvar_t, timed_wait, bool,
|
||||
ms = timeout % 1000;
|
||||
|
||||
tv.tv_sec += s;
|
||||
tv.tv_usec += ms * 1000;
|
||||
|
||||
if (tv.tv_usec > 1000000 /* 1s */)
|
||||
{
|
||||
tv.tv_usec -= 1000000;
|
||||
tv.tv_sec++;
|
||||
}
|
||||
timeval_add_ms(&tv, ms);
|
||||
return timed_wait_abs(this, mutex, tv);
|
||||
}
|
||||
|
||||
|
||||
@@ -433,13 +433,8 @@ METHOD(rwlock_condvar_t, timed_wait, bool,
|
||||
ms = timeout % 1000;
|
||||
|
||||
tv.tv_sec += s;
|
||||
tv.tv_usec += ms * 1000;
|
||||
timeval_add_ms(&tv, ms);
|
||||
|
||||
if (tv.tv_usec > 1000000 /* 1s */)
|
||||
{
|
||||
tv.tv_usec -= 1000000;
|
||||
tv.tv_sec++;
|
||||
}
|
||||
return timed_wait_abs(this, lock, tv);
|
||||
}
|
||||
|
||||
|
||||
@@ -454,6 +454,22 @@ void closefrom(int lowfd);
|
||||
*/
|
||||
time_t time_monotonic(timeval_t *tv);
|
||||
|
||||
/**
|
||||
* Add the given number of milliseconds to the given timeval struct
|
||||
*
|
||||
* @param tv timeval struct to modify
|
||||
* @param ms number of milliseconds
|
||||
*/
|
||||
static inline void timeval_add_ms(timeval_t *tv, u_int ms)
|
||||
{
|
||||
tv->tv_usec += ms * 1000;
|
||||
while (tv->tv_usec > 1000000 /* 1s */)
|
||||
{
|
||||
tv->tv_usec -= 1000000;
|
||||
tv->tv_sec++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns null
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2009 Tobias Brunner
|
||||
* Copyright (C) 2006-2012 Tobias Brunner
|
||||
* Copyright (C) 2006 Daniel Roethlisberger
|
||||
* Copyright (C) 2005-2006 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
@@ -16,14 +16,10 @@
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "host.h"
|
||||
|
||||
#include <debug.h>
|
||||
#include <library.h>
|
||||
|
||||
#define IPV4_LEN 4
|
||||
#define IPV6_LEN 16
|
||||
@@ -450,48 +446,14 @@ host_t *host_create_from_sockaddr(sockaddr_t *sockaddr)
|
||||
*/
|
||||
host_t *host_create_from_dns(char *string, int af, u_int16_t port)
|
||||
{
|
||||
private_host_t *this;
|
||||
struct addrinfo hints, *result;
|
||||
int error;
|
||||
host_t *this;
|
||||
|
||||
if (streq(string, "%any"))
|
||||
{
|
||||
return host_create_any_port(af ? af : AF_INET, port);
|
||||
}
|
||||
if (streq(string, "%any6"))
|
||||
{
|
||||
return host_create_any_port(af ? af : AF_INET6, port);
|
||||
}
|
||||
if (af == AF_INET && strchr(string, ':'))
|
||||
{ /* do not try to convert v6 addresses for v4 family */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = af;
|
||||
error = getaddrinfo(string, NULL, &hints, &result);
|
||||
if (error != 0)
|
||||
{
|
||||
DBG1(DBG_LIB, "resolving '%s' failed: %s", string, gai_strerror(error));
|
||||
return NULL;
|
||||
}
|
||||
/* result is a linked list, but we use only the first address */
|
||||
this = (private_host_t*)host_create_from_sockaddr(result->ai_addr);
|
||||
freeaddrinfo(result);
|
||||
this = lib->hosts->resolve(lib->hosts, string, af);
|
||||
if (this)
|
||||
{
|
||||
switch (this->address.sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
this->address4.sin_port = htons(port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
this->address6.sin6_port = htons(port);
|
||||
break;
|
||||
}
|
||||
return &this->public;
|
||||
this->set_port(this, port);
|
||||
}
|
||||
return NULL;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user