Resolve hosts by DNS name in separate threads so we can cancel them
getaddrinfo(3) may block a long time so proper termination of the daemon may block if DNS servers are not reachable. getaddrinfo(3) is an optional cancellation point in posix threads so it might still block a shutdown but at least on Android (with the signal based pthread_cancel implementation) it works, on Linux starter will kill charon anyway after a while.
This commit is contained in:
@@ -84,7 +84,8 @@ static void destroy(private_daemon_t *this)
|
|||||||
{
|
{
|
||||||
/* terminate all idle threads */
|
/* terminate all idle threads */
|
||||||
lib->processor->set_threads(lib->processor, 0);
|
lib->processor->set_threads(lib->processor, 0);
|
||||||
|
/* make sure nobody waits for a DNS query */
|
||||||
|
lib->hosts->flush(lib->hosts);
|
||||||
/* close all IKE_SAs */
|
/* close all IKE_SAs */
|
||||||
if (this->public.ike_sa_manager)
|
if (this->public.ike_sa_manager)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ include $(CLEAR_VARS)
|
|||||||
|
|
||||||
# copy-n-paste from Makefile.am
|
# copy-n-paste from Makefile.am
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
library.c chunk.c debug.c enum.c settings.c printf_hook.c asn1/asn1.c \
|
library.c chunk.c debug.c enum.c host_resolver.c settings.c printf_hook.c \
|
||||||
asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.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/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/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \
|
||||||
crypto/prfs/prf.c crypto/prfs/mac_prf.c \
|
crypto/prfs/prf.c crypto/prfs/mac_prf.c \
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
ipseclib_LTLIBRARIES = libstrongswan.la
|
ipseclib_LTLIBRARIES = libstrongswan.la
|
||||||
|
|
||||||
libstrongswan_la_SOURCES = \
|
libstrongswan_la_SOURCES = \
|
||||||
library.c chunk.c debug.c enum.c settings.c printf_hook.c asn1/asn1.c \
|
library.c chunk.c debug.c enum.c host_resolver.c settings.c printf_hook.c \
|
||||||
asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.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/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/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \
|
||||||
crypto/prfs/prf.c crypto/prfs/mac_prf.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
|
if USE_DEV_HEADERS
|
||||||
strongswan_includedir = ${dev_headers}
|
strongswan_includedir = ${dev_headers}
|
||||||
nobase_strongswan_include_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 \
|
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/crypters/crypter.h crypto/hashers/hasher.h crypto/mac.h \
|
||||||
crypto/pkcs7.h crypto/pkcs9.h crypto/proposal/proposal_keywords.h \
|
crypto/pkcs7.h crypto/pkcs9.h crypto/proposal/proposal_keywords.h \
|
||||||
|
|||||||
@@ -0,0 +1,289 @@
|
|||||||
|
/*
|
||||||
|
* 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 <processing/jobs/callback_job.h>
|
||||||
|
#include <threading/condvar.h>
|
||||||
|
#include <threading/mutex.h>
|
||||||
|
#include <threading/thread.h>
|
||||||
|
#include <utils/hashtable.h>
|
||||||
|
#include <utils/linked_list.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum number of resolver threads
|
||||||
|
*/
|
||||||
|
u_int max_threads;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current number of threads
|
||||||
|
*/
|
||||||
|
u_int threads;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 job_requeue_t resolve_hosts(private_host_resolver_t *this)
|
||||||
|
{
|
||||||
|
struct addrinfo hints, *result;
|
||||||
|
query_t *query;
|
||||||
|
int error;
|
||||||
|
bool old;
|
||||||
|
|
||||||
|
this->mutex->lock(this->mutex);
|
||||||
|
while (this->queue->remove_first(this->queue, (void**)&query) != SUCCESS)
|
||||||
|
{
|
||||||
|
thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex);
|
||||||
|
old = thread_cancelability(TRUE);
|
||||||
|
this->new_query->wait(this->new_query, this->mutex);
|
||||||
|
thread_cancelability(old);
|
||||||
|
thread_cleanup_pop(FALSE);
|
||||||
|
}
|
||||||
|
this->mutex->unlock(this->mutex);
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = query->family;
|
||||||
|
|
||||||
|
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);
|
||||||
|
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 JOB_REQUEUE_DIRECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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->threads < this->max_threads)
|
||||||
|
{
|
||||||
|
this->threads++;
|
||||||
|
lib->processor->queue_job(lib->processor,
|
||||||
|
(job_t*)callback_job_create_with_prio(
|
||||||
|
(callback_job_cb_t)resolve_hosts, this, NULL,
|
||||||
|
(callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL));
|
||||||
|
}
|
||||||
|
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->mutex->unlock(this->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(host_resolver_t, destroy, void,
|
||||||
|
private_host_resolver_t *this)
|
||||||
|
{
|
||||||
|
this->queue->destroy_function(this->queue, (void*)query_signal_and_destroy);
|
||||||
|
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(u_int max_threads)
|
||||||
|
{
|
||||||
|
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(),
|
||||||
|
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
|
||||||
|
.new_query = condvar_create(CONDVAR_TYPE_DEFAULT),
|
||||||
|
.max_threads = max_threads,
|
||||||
|
);
|
||||||
|
|
||||||
|
return &this->public;
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @param max_threads maximum number of resolver threads to use
|
||||||
|
*/
|
||||||
|
host_resolver_t *host_resolver_create(u_int max_threads);
|
||||||
|
|
||||||
|
#endif /** HOST_RESOLVER_H_ @}*/
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
#include <selectors/traffic_selector.h>
|
#include <selectors/traffic_selector.h>
|
||||||
|
|
||||||
#define CHECKSUM_LIBRARY IPSEC_LIB_DIR"/libchecksum.so"
|
#define CHECKSUM_LIBRARY IPSEC_LIB_DIR"/libchecksum.so"
|
||||||
|
#define HOST_RESOLVER_MAX_THREADS 2
|
||||||
|
|
||||||
typedef struct private_library_t private_library_t;
|
typedef struct private_library_t private_library_t;
|
||||||
|
|
||||||
@@ -68,6 +69,7 @@ void library_deinit()
|
|||||||
this->public.scheduler->destroy(this->public.scheduler);
|
this->public.scheduler->destroy(this->public.scheduler);
|
||||||
this->public.processor->destroy(this->public.processor);
|
this->public.processor->destroy(this->public.processor);
|
||||||
this->public.plugins->destroy(this->public.plugins);
|
this->public.plugins->destroy(this->public.plugins);
|
||||||
|
this->public.hosts->destroy(this->public.hosts);
|
||||||
this->public.settings->destroy(this->public.settings);
|
this->public.settings->destroy(this->public.settings);
|
||||||
this->public.credmgr->destroy(this->public.credmgr);
|
this->public.credmgr->destroy(this->public.credmgr);
|
||||||
this->public.creds->destroy(this->public.creds);
|
this->public.creds->destroy(this->public.creds);
|
||||||
@@ -182,6 +184,7 @@ bool library_init(char *settings)
|
|||||||
|
|
||||||
this->objects = hashtable_create((hashtable_hash_t)hash,
|
this->objects = hashtable_create((hashtable_hash_t)hash,
|
||||||
(hashtable_equals_t)equals, 4);
|
(hashtable_equals_t)equals, 4);
|
||||||
|
this->public.hosts = host_resolver_create(HOST_RESOLVER_MAX_THREADS);
|
||||||
this->public.settings = settings_create(settings);
|
this->public.settings = settings_create(settings);
|
||||||
this->public.proposal = proposal_keywords_create();
|
this->public.proposal = proposal_keywords_create();
|
||||||
this->public.crypto = crypto_factory_create();
|
this->public.crypto = crypto_factory_create();
|
||||||
|
|||||||
@@ -77,6 +77,7 @@
|
|||||||
#include "printf_hook.h"
|
#include "printf_hook.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "chunk.h"
|
#include "chunk.h"
|
||||||
|
#include "host_resolver.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "integrity_checker.h"
|
#include "integrity_checker.h"
|
||||||
#include "processing/processor.h"
|
#include "processing/processor.h"
|
||||||
@@ -170,6 +171,11 @@ struct library_t {
|
|||||||
*/
|
*/
|
||||||
scheduler_t *scheduler;
|
scheduler_t *scheduler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resolve hosts by DNS name
|
||||||
|
*/
|
||||||
|
host_resolver_t *hosts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* various settings loaded from settings file
|
* various settings loaded from settings file
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2006-2009 Tobias Brunner
|
* Copyright (C) 2006-2012 Tobias Brunner
|
||||||
* Copyright (C) 2006 Daniel Roethlisberger
|
* Copyright (C) 2006 Daniel Roethlisberger
|
||||||
* Copyright (C) 2005-2006 Martin Willi
|
* Copyright (C) 2005-2006 Martin Willi
|
||||||
* Copyright (C) 2005 Jan Hutter
|
* Copyright (C) 2005 Jan Hutter
|
||||||
@@ -16,14 +16,10 @@
|
|||||||
* for more details.
|
* for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
|
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
#include <library.h>
|
||||||
|
|
||||||
#define IPV4_LEN 4
|
#define IPV4_LEN 4
|
||||||
#define IPV6_LEN 16
|
#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)
|
host_t *host_create_from_dns(char *string, int af, u_int16_t port)
|
||||||
{
|
{
|
||||||
private_host_t *this;
|
host_t *this;
|
||||||
struct addrinfo hints, *result;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
if (streq(string, "%any"))
|
this = lib->hosts->resolve(lib->hosts, string, af);
|
||||||
{
|
|
||||||
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);
|
|
||||||
if (this)
|
if (this)
|
||||||
{
|
{
|
||||||
switch (this->address.sa_family)
|
this->set_port(this, port);
|
||||||
{
|
|
||||||
case AF_INET:
|
|
||||||
this->address4.sin_port = htons(port);
|
|
||||||
break;
|
|
||||||
case AF_INET6:
|
|
||||||
this->address6.sin6_port = htons(port);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return &this->public;
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user