mirror of https://github.com/getdnsapi/getdns.git
steps toward proper support of namespaces and system files
This commit is contained in:
parent
b9bc90a986
commit
bdff98ffb3
51
README.md
51
README.md
|
@ -1,19 +1,23 @@
|
|||
getdns API {#mainpage}
|
||||
==========
|
||||
|
||||
* Date: 2013-11-03
|
||||
* Date: 2014-02-10
|
||||
* GitHub: <https://github.com/verisign/getdns>
|
||||
|
||||
getdns is a [modern asynchronous DNS API](http://www.vpnc.org/getdns-api/) intended to make all types of DNS information easily available as described by Paul Hoffman. This implementation is licensed under the New BSD License (BSD-new).
|
||||
|
||||
The [getdns-api mailing list](http://www.vpnc.org/mailman/listinfo/getdns-api) is a good place to engage in discussions regarding the design of the API.
|
||||
|
||||
If you are just getting started with the library take a look at the section below that
|
||||
describes building and handling external dependencies for the library. Once it is
|
||||
built you should take a look at src/examples to see how the library is used.
|
||||
|
||||
This file captures the goals and direction of the project and the current state of the implementation.
|
||||
|
||||
The goals of this implementation of the getdns API are:
|
||||
|
||||
* Provide an open source implementation, in C, of the formally described getdns API by Paul Hoffman at <http://www.vpnc.org/getdns-api/>
|
||||
* Initial support for FreeBSD x.y, MS-Windows Ver. X, OSX 10.x, Linux (CentOS/RHEL R6uX, Ubuntu Ver X) via functional "configure" script
|
||||
* Initial support for FreeBSD, MS-Windows, OSX, Linux (CentOS/RHEL, Ubuntu) via functional "configure" script
|
||||
* Initial support to include the Android platform
|
||||
* Include examples and tests as part of the build
|
||||
* Document code using doxygen
|
||||
|
@ -24,9 +28,10 @@ The goals of this implementation of the getdns API are:
|
|||
** the develop branch contains the latest development changes which are merged from develop into master once they are considered production ready
|
||||
* Both synchronous and asynchronous entry points with an early focus on the asynchronous model
|
||||
|
||||
Non-goals (things we will not be doing) include:
|
||||
Non-goals (things we will not be doing at least initially) include:
|
||||
* implementation of the traditional DNS related routines (gethostbyname, etc.)
|
||||
|
||||
|
||||
Releases
|
||||
========
|
||||
Release numbering follows the [Semantic Versioning](http://semver.org/) approach. We are currently in the early stages of building the API so the code should be considered incomplete.
|
||||
|
@ -37,6 +42,7 @@ The 0.1.0 release will be issued when the repository is opened to the public, ou
|
|||
* examples must compile and be clean
|
||||
* clearly document supported/unsupported elements of the API
|
||||
|
||||
|
||||
Tickets/Bug Reports
|
||||
===================
|
||||
Tickets and bug reports from external contacts are received via a mailing list and managed in the git issues list.
|
||||
|
@ -44,8 +50,7 @@ Tickets and bug reports from external contacts are received via a mailing list a
|
|||
TBD: mailing list address
|
||||
|
||||
|
||||
External Dependencies
|
||||
=====================
|
||||
#Building/External Dependencies
|
||||
External dependencies are linked outside the getdns API build tree (we rely on configure to find them). We would like to keep the dependency tree short.
|
||||
|
||||
* [libevent](http://libevent.org) version 2.0.21 stable
|
||||
|
@ -72,8 +77,14 @@ Assuming that the getdns sources are in a diretory named getdns in your home dir
|
|||
# make install
|
||||
```
|
||||
|
||||
Unsupported Features
|
||||
====================
|
||||
##Regression Tests
|
||||
|
||||
A suite of regression tests are included with the library, if you make changes or just
|
||||
want to sanity check things on your system take a look at src/test. You will need
|
||||
to install [libcheck](http://check.sourceforge.net/). Check is also available from
|
||||
many of the package repositories for the more popular operating systems.
|
||||
|
||||
#Unsupported Features
|
||||
|
||||
The following API calls are documented in getDNS but *not supported* by the implementation at this time:
|
||||
|
||||
|
@ -92,6 +103,12 @@ The following API calls are documented in getDNS but *not supported* by the impl
|
|||
* `getdns_context_set_dnssec_trust_anchors`
|
||||
* `getdns_validate_dnssec`
|
||||
* Detecting changes to resolv.conf and hosts
|
||||
* MDNS and NetBIOS namespaces (only DNS and LOCALFILES are supported)
|
||||
|
||||
Some platform specific features are not implemented in the first public release of getdns, however they are on the radar. These include:
|
||||
|
||||
* Respecting settings in /etc/nsswitch.conf (linux and some other OSes), for the first release we simply check local files (/etc/hosts) before checking the DNS.
|
||||
* Search suffixes specified in /etc/resolv.conf
|
||||
|
||||
Spec Differences
|
||||
================
|
||||
|
@ -107,21 +124,20 @@ The primary platforms targeted are Linux and FreeBSD, other platform are support
|
|||
|
||||
Where at all possible we need to make sure that both 32 and 64 bit implementations work.
|
||||
|
||||
* Android, Neel
|
||||
* FreeBSD 9.2, gcc/clang Melinda
|
||||
* FreeBSD 10.0 (not yet released), gcc/clang Melinda
|
||||
* Linux RHEL/CentOS 6.x, Glen
|
||||
* MS-Windows 8, cygwin, Neel
|
||||
* NetBSD x.x, Wouter
|
||||
* OpenBSD 5.3, Wouter
|
||||
* OSX 10.8, Glen
|
||||
* OSX 10.9, Allison
|
||||
* Ubuntu 12.x, Melinda
|
||||
* Debian 7.0, 7.3
|
||||
* FreeBSD 8.4, 9.2, 10.0
|
||||
* RHEL/CentOS 6.4, 6.5
|
||||
* OSX 10.8, 10.9
|
||||
* Ubuntu 12.04, 13.10
|
||||
|
||||
The NLNet folks offered to build on a number of legacy platforms as well to help ensure that the code is clean. These include some big endian hardware and a few more obscure operating systems which will not be publicly supported but might work if someone wants to try them.
|
||||
|
||||
We intend to add MS-Windows, Android and other platforms to the releases as we have time to port it.
|
||||
|
||||
|
||||
##Build Reports
|
||||
|
||||
|
||||
TBD
|
||||
|
||||
Contributors
|
||||
|
@ -132,6 +148,7 @@ Contributors
|
|||
* Willem Toorop, NLNet Labs
|
||||
* Glen Wiley, Verisign, Inc.
|
||||
* Wouter Wijngaards, NLNet Labs
|
||||
* Craig Despeaux, Verisign, Inc.
|
||||
|
||||
--
|
||||
end README
|
||||
|
|
|
@ -21,7 +21,7 @@ VPATH = @srcdir@
|
|||
EDITS=-e 's/@''version@/$(version)/g'
|
||||
|
||||
DOCDIRS = html latex man
|
||||
MANPAGES3 = libgetdns.3 getdns_address.3 getdns_dict.3 getdns_general.3 getdns_hostname.3 getdns_service.3
|
||||
MANPAGES3 = libgetdns.3 getdns_address.3 getdns_context.3 getdns_context_set.3 getdns_dict.3 getdns_general.3 getdns_hostname.3 getdns_service.3
|
||||
|
||||
default: all
|
||||
|
||||
|
|
215
src/context.c
215
src/context.c
|
@ -40,6 +40,7 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <unbound.h>
|
||||
|
||||
|
@ -50,8 +51,7 @@
|
|||
void *plain_mem_funcs_user_arg = MF_PLAIN;
|
||||
|
||||
/* Private functions */
|
||||
static getdns_namespace_t *create_default_namespaces(
|
||||
struct getdns_context *context);
|
||||
getdns_return_t create_default_namespaces(struct getdns_context *context);
|
||||
static struct getdns_list *create_default_root_servers();
|
||||
static getdns_return_t add_ip_str(struct getdns_dict *);
|
||||
static struct getdns_dict *create_ipaddr_dict_from_rdf(struct getdns_context *,
|
||||
|
@ -69,21 +69,24 @@ static void cancel_dns_req(getdns_dns_req *);
|
|||
static void cancel_outstanding_requests(struct getdns_context*, int);
|
||||
|
||||
/* Stuff to make it compile pedantically */
|
||||
#define UNUSED_PARAM(x) ((void)(x))
|
||||
#define RETURN_IF_NULL(ptr, code) if(ptr == NULL) return code;
|
||||
|
||||
/**
|
||||
* Helper to get default lookup namespaces.
|
||||
* TODO: Determine from OS
|
||||
*/
|
||||
static getdns_namespace_t*
|
||||
getdns_return_t
|
||||
create_default_namespaces(struct getdns_context *context)
|
||||
{
|
||||
getdns_namespace_t *result = GETDNS_XMALLOC(
|
||||
context->my_mf, getdns_namespace_t, 2);
|
||||
result[0] = GETDNS_NAMESPACE_LOCALNAMES;
|
||||
result[1] = GETDNS_NAMESPACE_DNS;
|
||||
return result;
|
||||
context->namespaces = GETDNS_XMALLOC(context->my_mf, getdns_namespace_t, 2);
|
||||
if(context->namespaces == NULL)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
|
||||
context->namespaces[0] = GETDNS_NAMESPACE_LOCALNAMES;
|
||||
context->namespaces[1] = GETDNS_NAMESPACE_DNS;
|
||||
context->namespace_count = 2;
|
||||
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -151,6 +154,57 @@ add_ip_str(struct getdns_dict * ip)
|
|||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
||||
/**
|
||||
* check a file for changes since the last check
|
||||
* and refresh the current data if changes are detected
|
||||
* @param file to check
|
||||
* @returns changes as OR'd list of GETDNS_FCHG_* values
|
||||
* @returns GETDNS_FCHG_NONE if no changes
|
||||
* @returns GETDNS_FCHG_ERRORS if problems (see fchg->errors for details)
|
||||
*/
|
||||
int
|
||||
filechg_check(struct getdns_context *context, struct filechg *fchg)
|
||||
{
|
||||
struct stat *finfo;
|
||||
|
||||
if(fchg == NULL)
|
||||
return 0;
|
||||
|
||||
fchg->errors = GETDNS_FCHG_NOERROR;
|
||||
fchg->changes = GETDNS_FCHG_NOCHANGES;
|
||||
|
||||
finfo = GETDNS_MALLOC(context->my_mf, struct stat);
|
||||
if(finfo == NULL)
|
||||
{
|
||||
fchg->errors = errno;
|
||||
return GETDNS_FCHG_ERRORS;
|
||||
}
|
||||
|
||||
if(stat(fchg->fn, finfo) != 0)
|
||||
{
|
||||
GETDNS_FREE(context->my_mf, finfo);
|
||||
fchg->errors = errno;
|
||||
return GETDNS_FCHG_ERRORS;
|
||||
}
|
||||
|
||||
/* we want to consider a file that previously returned error for stat() as a
|
||||
change */
|
||||
|
||||
if(fchg->prevstat == NULL)
|
||||
fchg->changes = GETDNS_FCHG_MTIME | GETDNS_FCHG_CTIME;
|
||||
else
|
||||
{
|
||||
if(fchg->prevstat->st_mtimespec.tv_sec != finfo->st_mtimespec.tv_sec)
|
||||
fchg->changes |= GETDNS_FCHG_MTIME;
|
||||
if(fchg->prevstat->st_ctimespec.tv_sec != finfo->st_ctimespec.tv_sec)
|
||||
fchg->changes |= GETDNS_FCHG_CTIME;
|
||||
GETDNS_FREE(context->my_mf, fchg->prevstat);
|
||||
}
|
||||
fchg->prevstat = finfo;
|
||||
|
||||
return fchg->changes;
|
||||
} /* filechg */
|
||||
|
||||
static struct getdns_dict *
|
||||
create_ipaddr_dict_from_rdf(struct getdns_context *context, ldns_rdf * rdf)
|
||||
{
|
||||
|
@ -212,27 +266,45 @@ create_from_ldns_list(struct getdns_context *context, ldns_rdf ** ldns_list,
|
|||
return result;
|
||||
}
|
||||
|
||||
/*---------------------------------------- set_os_defaults */
|
||||
/*---------------------------------------- set_os_defaults
|
||||
we use ldns to read the resolv.conf file - the ldns resolver is
|
||||
destroyed once the file is read
|
||||
*/
|
||||
static getdns_return_t
|
||||
set_os_defaults(struct getdns_context *context)
|
||||
{
|
||||
ldns_resolver *lr = NULL;
|
||||
if (ldns_resolver_new_frm_file(&lr, NULL) != LDNS_STATUS_OK) {
|
||||
ldns_rdf **rdf_list;
|
||||
size_t rdf_list_sz;
|
||||
|
||||
if (ldns_resolver_new_frm_file(&lr, NULL) != LDNS_STATUS_OK)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
ldns_rdf **rdf_list = ldns_resolver_nameservers(lr);
|
||||
size_t rdf_list_sz = ldns_resolver_nameserver_count(lr);
|
||||
|
||||
if(context->fchg_resolvconf == NULL)
|
||||
{
|
||||
context->fchg_resolvconf = (struct filechg *) malloc(sizeof(struct filechg));
|
||||
if(context->fchg_resolvconf == NULL)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
context->fchg_resolvconf->fn = "/etc/resolv.conf";
|
||||
context->fchg_resolvconf->prevstat = NULL;
|
||||
context->fchg_resolvconf->changes = GETDNS_FCHG_NOCHANGES;
|
||||
context->fchg_resolvconf->errors = GETDNS_FCHG_NOERROR;
|
||||
}
|
||||
filechg_check(context, context->fchg_resolvconf);
|
||||
|
||||
rdf_list = ldns_resolver_nameservers(lr);
|
||||
rdf_list_sz = ldns_resolver_nameserver_count(lr);
|
||||
if (rdf_list_sz > 0) {
|
||||
context->upstream_list =
|
||||
create_from_ldns_list(context, rdf_list, rdf_list_sz);
|
||||
}
|
||||
|
||||
rdf_list = ldns_resolver_searchlist(lr);
|
||||
rdf_list_sz = ldns_resolver_searchlist_count(lr);
|
||||
if (rdf_list_sz > 0) {
|
||||
context->suffix = create_from_ldns_list(context, rdf_list,
|
||||
rdf_list_sz);
|
||||
}
|
||||
/** cleanup **/
|
||||
ldns_resolver_deep_free(lr);
|
||||
|
||||
return GETDNS_RETURN_GOOD;
|
||||
|
@ -265,7 +337,9 @@ transaction_id_cmp(const void *id1, const void *id2)
|
|||
}
|
||||
}
|
||||
|
||||
static int timeout_cmp(const void *to1, const void *to2) {
|
||||
static int
|
||||
timeout_cmp(const void *to1, const void *to2)
|
||||
{
|
||||
if (to1 == NULL && to2 == NULL) {
|
||||
return 0;
|
||||
} else if (to1 == NULL && to2 != NULL) {
|
||||
|
@ -340,7 +414,8 @@ getdns_context_create_with_extended_memory_functions(
|
|||
result->outbound_requests = ldns_rbtree_create(transaction_id_cmp);
|
||||
|
||||
result->resolution_type = GETDNS_RESOLUTION_RECURSING;
|
||||
result->namespaces = create_default_namespaces(result);
|
||||
if(create_default_namespaces(result) != GETDNS_RETURN_GOOD)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
|
||||
result->timeout = 5000;
|
||||
result->follow_redirects = GETDNS_REDIRECTS_FOLLOW;
|
||||
|
@ -360,6 +435,8 @@ getdns_context_create_with_extended_memory_functions(
|
|||
result->timeouts_by_time = ldns_rbtree_create(timeout_cmp);
|
||||
result->timeouts_by_id = ldns_rbtree_create(transaction_id_cmp);
|
||||
|
||||
result->fchg_resolvconf = NULL;
|
||||
result->fchg_hosts = NULL;
|
||||
if (set_from_os) {
|
||||
if (GETDNS_RETURN_GOOD != set_os_defaults(result)) {
|
||||
getdns_context_destroy(result);
|
||||
|
@ -376,7 +453,7 @@ getdns_context_create_with_extended_memory_functions(
|
|||
GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP);
|
||||
|
||||
return GETDNS_RETURN_GOOD;
|
||||
} /* getdns_context_create */
|
||||
} /* getdns_context_create_with_extended_memory_functions */
|
||||
|
||||
/*
|
||||
* getdns_context_create
|
||||
|
@ -427,6 +504,18 @@ getdns_context_destroy(struct getdns_context *context)
|
|||
}
|
||||
if (context->namespaces)
|
||||
GETDNS_FREE(context->my_mf, context->namespaces);
|
||||
if(context->fchg_resolvconf)
|
||||
{
|
||||
if(context->fchg_resolvconf->prevstat)
|
||||
GETDNS_FREE(context->my_mf, context->fchg_resolvconf->prevstat);
|
||||
GETDNS_FREE(context->my_mf, context->fchg_resolvconf);
|
||||
}
|
||||
if(context->fchg_hosts)
|
||||
{
|
||||
if(context->fchg_hosts->prevstat)
|
||||
GETDNS_FREE(context->my_mf, context->fchg_hosts->prevstat);
|
||||
GETDNS_FREE(context->my_mf, context->fchg_hosts);
|
||||
}
|
||||
|
||||
cancel_outstanding_requests(context, 0);
|
||||
getdns_extension_detach_eventloop(context);
|
||||
|
@ -529,12 +618,23 @@ getdns_return_t
|
|||
getdns_context_set_namespaces(struct getdns_context *context,
|
||||
size_t namespace_count, getdns_namespace_t *namespaces)
|
||||
{
|
||||
int i;
|
||||
|
||||
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
if (namespace_count == 0 || namespaces == NULL) {
|
||||
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
|
||||
}
|
||||
|
||||
/** clean up old namespaces **/
|
||||
for(i=0; i<namespace_count; i++)
|
||||
{
|
||||
if( namespaces[i] != GETDNS_NAMESPACE_DNS
|
||||
&& namespaces[i] != GETDNS_NAMESPACE_LOCALNAMES
|
||||
&& namespaces[i] != GETDNS_NAMESPACE_NETBIOS
|
||||
&& namespaces[i] != GETDNS_NAMESPACE_MDNS
|
||||
&& namespaces[i] != GETDNS_NAMESPACE_NIS)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
GETDNS_FREE(context->my_mf, context->namespaces);
|
||||
|
||||
/** duplicate **/
|
||||
|
@ -542,7 +642,7 @@ getdns_context_set_namespaces(struct getdns_context *context,
|
|||
namespace_count);
|
||||
memcpy(context->namespaces, namespaces,
|
||||
namespace_count * sizeof(getdns_namespace_t));
|
||||
|
||||
context->namespace_count = namespace_count;
|
||||
dispatch_updated(context, GETDNS_CONTEXT_CODE_NAMESPACES);
|
||||
|
||||
return GETDNS_RETURN_GOOD;
|
||||
|
@ -1079,41 +1179,58 @@ ub_setup_stub(struct ub_ctx *ctx, struct getdns_list * upstreams, size_t count)
|
|||
}
|
||||
|
||||
getdns_return_t
|
||||
getdns_context_prepare_for_resolution(struct getdns_context *context)
|
||||
getdns_context_prepare_for_resolution(struct getdns_context *context, int usenamespaces)
|
||||
{
|
||||
int i;
|
||||
size_t upstream_len = 0;
|
||||
|
||||
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
if (context->resolution_type_set == context->resolution_type) {
|
||||
/* already set and no config changes have caused this to be
|
||||
* bad.
|
||||
*/
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
if (context->resolution_type == GETDNS_RESOLUTION_STUB) {
|
||||
size_t upstream_len = 0;
|
||||
getdns_return_t r =
|
||||
getdns_list_get_length(context->upstream_list,
|
||||
&upstream_len);
|
||||
if (r != GETDNS_RETURN_GOOD || upstream_len == 0) {
|
||||
return GETDNS_RETURN_BAD_CONTEXT;
|
||||
}
|
||||
/* set upstreams */
|
||||
ub_setup_stub(context->unbound_ctx, context->upstream_list,
|
||||
upstream_len);
|
||||
/* use /etc/hosts */
|
||||
ub_ctx_hosts(context->unbound_ctx, NULL);
|
||||
|
||||
} else if (context->resolution_type == GETDNS_RESOLUTION_RECURSING) {
|
||||
/* set recursive */
|
||||
/* TODO: use the root servers via root hints file */
|
||||
ub_ctx_set_fwd(context->unbound_ctx, NULL);
|
||||
|
||||
} else {
|
||||
/* bogus? */
|
||||
if (context->resolution_type_set == context->resolution_type)
|
||||
{
|
||||
/* already set and no config changes have caused this to be bad. */
|
||||
return GETDNS_RETURN_BAD_CONTEXT;
|
||||
}
|
||||
|
||||
/* TODO: respect namespace order (unbound always uses local first if cfg
|
||||
* the spec calls for us to treat the namespace list as ordered
|
||||
* so we need to respect that order
|
||||
*/
|
||||
|
||||
if(usenamespaces == 0)
|
||||
{
|
||||
ub_setup_stub(context->unbound_ctx, context->upstream_list,
|
||||
upstream_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(i=0; i<context->namespace_count; i++)
|
||||
{
|
||||
if(context->namespaces[i] == GETDNS_NAMESPACE_LOCALNAMES)
|
||||
{
|
||||
ub_ctx_hosts(context->unbound_ctx, NULL);
|
||||
}
|
||||
else if(context->namespaces[i] == GETDNS_NAMESPACE_DNS)
|
||||
{
|
||||
if (context->resolution_type == GETDNS_RESOLUTION_STUB)
|
||||
{
|
||||
getdns_return_t r =
|
||||
getdns_list_get_length(context->upstream_list, &upstream_len);
|
||||
if (r != GETDNS_RETURN_GOOD || upstream_len == 0)
|
||||
return GETDNS_RETURN_BAD_CONTEXT;
|
||||
} else if (context->resolution_type == GETDNS_RESOLUTION_RECURSING)
|
||||
{
|
||||
/* TODO: use the root servers via root hints file */
|
||||
ub_ctx_set_fwd(context->unbound_ctx, NULL);
|
||||
} else
|
||||
return GETDNS_RETURN_BAD_CONTEXT;
|
||||
} /* DNS */
|
||||
} /* for i */
|
||||
} /* if usenamespaces = 0 else */
|
||||
|
||||
context->resolution_type_set = context->resolution_type;
|
||||
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
} /* getdns_context_prepare_for_resolution */
|
||||
|
||||
getdns_return_t
|
||||
getdns_context_track_outbound_request(getdns_dns_req * req)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
*
|
||||
* /file
|
||||
* /brief getdns context management functions
|
||||
* \file context.h
|
||||
* @brief getdns context management functions
|
||||
*
|
||||
* Originally taken from the getdns API description pseudo implementation.
|
||||
*
|
||||
|
@ -44,22 +44,40 @@ struct getdns_dns_req;
|
|||
struct ldns_rbtree_t;
|
||||
struct ub_ctx;
|
||||
|
||||
#define GETDNS_FN_RESOLVCONF "/etc/resolv.conf"
|
||||
#define GETDNS_FN_HOSTS "/etc/hosts"
|
||||
|
||||
enum filechgs { GETDNS_FCHG_ERRORS = -1
|
||||
, GETDNS_FCHG_NOERROR = 0
|
||||
, GETDNS_FCHG_NOCHANGES = 0
|
||||
, GETDNS_FCHG_MTIME = 1
|
||||
, GETDNS_FCHG_CTIME = 2};
|
||||
|
||||
/** function pointer typedefs */
|
||||
typedef void (*getdns_update_callback) (struct getdns_context *,
|
||||
getdns_context_code_t);
|
||||
|
||||
/* internal use only for detecting changes to system files */
|
||||
struct filechg {
|
||||
char *fn;
|
||||
int changes;
|
||||
int errors;
|
||||
struct stat *prevstat;
|
||||
};
|
||||
|
||||
struct getdns_context {
|
||||
|
||||
/* Context values */
|
||||
getdns_resolution_t resolution_type;
|
||||
getdns_namespace_t *namespaces;
|
||||
uint64_t timeout;
|
||||
getdns_redirects_t follow_redirects;
|
||||
struct getdns_list *dns_root_servers;
|
||||
getdns_resolution_t resolution_type;
|
||||
getdns_namespace_t *namespaces;
|
||||
int namespace_count;
|
||||
uint64_t timeout;
|
||||
getdns_redirects_t follow_redirects;
|
||||
struct getdns_list *dns_root_servers;
|
||||
getdns_append_name_t append_name;
|
||||
struct getdns_list *suffix;
|
||||
struct getdns_list *dnssec_trust_anchors;
|
||||
struct getdns_list *upstream_list;
|
||||
struct getdns_list *suffix;
|
||||
struct getdns_list *dnssec_trust_anchors;
|
||||
struct getdns_list *upstream_list;
|
||||
|
||||
uint8_t edns_extended_rcode;
|
||||
uint8_t edns_version;
|
||||
|
@ -103,14 +121,25 @@ struct getdns_context {
|
|||
*/
|
||||
struct ldns_rbtree_t *timeouts_by_id;
|
||||
struct ldns_rbtree_t *timeouts_by_time;
|
||||
};
|
||||
|
||||
/*
|
||||
* state data used to detect changes to the system config files
|
||||
*/
|
||||
struct filechg *fchg_resolvconf;
|
||||
struct filechg *fchg_hosts;
|
||||
|
||||
}; /* getdns_context */
|
||||
|
||||
/** internal functions **/
|
||||
/**
|
||||
* Sets up the unbound contexts with stub or recursive behavior
|
||||
* if needed.
|
||||
* @param context previously initialized getdns_context
|
||||
* @param usenamespaces if 0 then only use the DNS, else use context namespace list
|
||||
* @return GETDNS_RETURN_GOOD on success
|
||||
*/
|
||||
getdns_return_t getdns_context_prepare_for_resolution(struct getdns_context *context);
|
||||
getdns_return_t getdns_context_prepare_for_resolution(struct getdns_context *context,
|
||||
int usenamespaces);
|
||||
|
||||
/* track an outbound request */
|
||||
getdns_return_t getdns_context_track_outbound_request(struct getdns_dns_req
|
||||
|
@ -148,4 +177,6 @@ getdns_return_t getdns_context_schedule_timeout(struct getdns_context* context,
|
|||
getdns_return_t getdns_context_clear_timeout(struct getdns_context* context,
|
||||
getdns_transaction_t id);
|
||||
|
||||
int filechg_check(struct getdns_context *context, struct filechg *fchg);
|
||||
|
||||
#endif /* _GETDNS_CONTEXT_H_ */
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* @brief example using getdns to resolve a simple query
|
||||
*
|
||||
* Originally taken from the getdns API description pseudo implementation.
|
||||
* Modified to more clearly demonstrate some of the API features.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -34,16 +35,11 @@
|
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#ifdef HAVE_EVENT2_EVENT_H
|
||||
# include <event2/event.h>
|
||||
#else
|
||||
# include <event.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <getdns_libevent.h>
|
||||
|
||||
|
@ -51,10 +47,10 @@
|
|||
|
||||
/* Set up the callback function, which will also do the processing of the results */
|
||||
void this_callbackfn(struct getdns_context *this_context,
|
||||
getdns_callback_type_t this_callback_type,
|
||||
struct getdns_dict *this_response,
|
||||
void *this_userarg,
|
||||
getdns_transaction_t this_transaction_id)
|
||||
uint16_t this_callback_type,
|
||||
struct getdns_dict *this_response,
|
||||
void *this_userarg,
|
||||
getdns_transaction_t this_transaction_id)
|
||||
{
|
||||
getdns_return_t this_ret;
|
||||
uint32_t this_error;
|
||||
|
@ -62,8 +58,8 @@ void this_callbackfn(struct getdns_context *this_context,
|
|||
struct getdns_list *just_the_addresses_ptr;
|
||||
struct getdns_dict *this_address;
|
||||
struct getdns_bindata *this_address_data;
|
||||
size_t rec_count;
|
||||
char *this_address_str;
|
||||
size_t rec_count;
|
||||
char *this_address_str;
|
||||
|
||||
UNUSED_PARAM(this_userarg);
|
||||
UNUSED_PARAM(this_context);
|
||||
|
@ -73,12 +69,12 @@ void this_callbackfn(struct getdns_context *this_context,
|
|||
/* Be sure the search returned something */
|
||||
|
||||
this_ret = getdns_dict_get_int(this_response, "status", &this_error);
|
||||
if (this_ret != GETDNS_RETURN_GOOD)
|
||||
if (this_ret != GETDNS_RETURN_GOOD)
|
||||
{
|
||||
fprintf(stderr, "The dictionary does not contain \"status\" (this shouldn't have happened). Exiting\n");
|
||||
getdns_dict_destroy(this_response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this_error != GETDNS_RESPSTATUS_GOOD)
|
||||
{
|
||||
|
@ -96,39 +92,39 @@ void this_callbackfn(struct getdns_context *this_context,
|
|||
}
|
||||
|
||||
this_ret = getdns_list_get_length(just_the_addresses_ptr, &num_addresses);
|
||||
if (this_ret != GETDNS_RETURN_GOOD)
|
||||
if (this_ret != GETDNS_RETURN_GOOD)
|
||||
{
|
||||
fprintf(stderr, "The address list is invalid (this shouldn't have happened). Exiting\n");
|
||||
getdns_dict_destroy(this_response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_addresses == 0)
|
||||
if (num_addresses == 0)
|
||||
fprintf(stderr, "The address list has 0 records. Exiting\n");
|
||||
|
||||
/* Go through each record */
|
||||
for (rec_count = 0; rec_count < num_addresses; ++rec_count)
|
||||
{
|
||||
this_ret = getdns_list_get_dict(just_the_addresses_ptr, rec_count, &this_address);
|
||||
if(this_ret != GETDNS_RETURN_GOOD)
|
||||
{
|
||||
fprintf(stderr, "Record %d is invalid (this shouldn't have happened). skipping.\n", (int) rec_count);
|
||||
continue;
|
||||
}
|
||||
if(this_ret != GETDNS_RETURN_GOOD)
|
||||
{
|
||||
fprintf(stderr, "Record %d is invalid (this shouldn't have happened). skipping.\n", (int) rec_count);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Just print the address */
|
||||
this_ret = getdns_dict_get_bindata(this_address, "address_data", &this_address_data);
|
||||
if(this_ret != GETDNS_RETURN_GOOD)
|
||||
{
|
||||
fprintf(stderr, "Record %d does not contain \"address_data\" (this shouldn't happen), skipping\n", (int) rec_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
this_address_str = getdns_display_ip_address(this_address_data);
|
||||
printf("The address is %s\n", this_address_str);
|
||||
free(this_address_str);
|
||||
}
|
||||
}
|
||||
if(this_ret != GETDNS_RETURN_GOOD)
|
||||
{
|
||||
fprintf(stderr, "Record %d does not contain \"address_data\" (this shouldn't happen), skipping\n", (int) rec_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
this_address_str = getdns_display_ip_address(this_address_data);
|
||||
printf("The address is %s\n", this_address_str);
|
||||
free(this_address_str);
|
||||
}
|
||||
} // for rec_count
|
||||
}
|
||||
else if (this_callback_type == GETDNS_CALLBACK_CANCEL)
|
||||
fprintf(stderr, "The callback with ID %"PRIu64" was cancelled. Exiting.\n", this_transaction_id);
|
||||
|
@ -138,24 +134,57 @@ void this_callbackfn(struct getdns_context *this_context,
|
|||
getdns_dict_destroy(this_response);
|
||||
} /* this_callbackfn */
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
printf(
|
||||
"USAGE: example-simple-answers [-s] [hostname]\n"
|
||||
"\n"
|
||||
"-s act as stub resolver (default is to act as a recursive resolver)\n"
|
||||
"\n"
|
||||
"The example program demonstrates the simplest use of the getdns API to\n"
|
||||
"resolve a hostname to an IP address\n"
|
||||
"\n");
|
||||
|
||||
return;
|
||||
} /* usage */
|
||||
|
||||
/*---------------------------------------- main */
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *this_name = "www.example.com";
|
||||
char *this_name = "www.example.com";
|
||||
char *this_userarg = "somestring";
|
||||
int dispatch_return;
|
||||
int exitval = EXIT_SUCCESS;
|
||||
char opt;
|
||||
int stubonly = 0;
|
||||
int dispatch_return;
|
||||
int exitval = EXIT_SUCCESS;
|
||||
struct getdns_context *this_context = NULL;
|
||||
struct event_base *this_event_base;
|
||||
getdns_return_t dns_request_return;
|
||||
getdns_return_t dns_request_return;
|
||||
getdns_transaction_t this_transaction_id;
|
||||
getdns_return_t context_create_return;
|
||||
getdns_return_t context_create_return;
|
||||
|
||||
if(argc > 1)
|
||||
this_name = argv[1];
|
||||
while((opt = getopt(argc, argv, "?s")) != -1)
|
||||
{
|
||||
switch(opt)
|
||||
{
|
||||
case 's':
|
||||
stubonly = 1;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
printf("resolving %s\n", this_name);
|
||||
if(argc > 0)
|
||||
this_name = argv[0];
|
||||
|
||||
printf("resolving %s\n", this_name);
|
||||
|
||||
/* Create the DNS context for this call, use OS configs such as resolv.conf */
|
||||
|
||||
|
@ -166,6 +195,16 @@ main(int argc, char *argv[])
|
|||
return(GETDNS_RETURN_GENERIC_ERROR);
|
||||
}
|
||||
|
||||
if(stubonly == 1)
|
||||
{
|
||||
if(getdns_context_set_resolution_type(this_context, GETDNS_RESOLUTION_STUB)
|
||||
!= GETDNS_RETURN_GOOD)
|
||||
{
|
||||
fprintf(stderr, "Failed to set stub resolver in context (this should never fail). Exiting.\n");
|
||||
return(GETDNS_RETURN_GENERIC_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create an event base and put it in the context using the unknown function name */
|
||||
|
||||
this_event_base = event_base_new();
|
||||
|
@ -188,16 +227,15 @@ main(int argc, char *argv[])
|
|||
if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME)
|
||||
{
|
||||
fprintf(stderr, "A bad domain name was used: %s. Exiting.\n", this_name);
|
||||
exitval = GETDNS_RETURN_GENERIC_ERROR;
|
||||
exitval = GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Call the event loop */
|
||||
|
||||
dispatch_return = event_base_dispatch(this_event_base);
|
||||
|
||||
if(dispatch_return < 0)
|
||||
fprintf(stderr, "event_base_dispatch() failed, returned %d\n", dispatch_return);
|
||||
if(dispatch_return < 0)
|
||||
fprintf(stderr, "event_base_dispatch() failed, returned %d\n", dispatch_return);
|
||||
}
|
||||
|
||||
/* Clean up */
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/**
|
||||
*
|
||||
* /brief getdns_general and related support functions
|
||||
* \file general.c
|
||||
* @brief getdns_general and related support functions
|
||||
*
|
||||
* The getdns_general function is called by most of the other public entry
|
||||
* points to the library. Private support functions are also included in this
|
||||
|
@ -209,7 +210,7 @@ ub_resolve_callback(void* arg, int err, struct ub_result* ub_res)
|
|||
submit_network_request(netreq->next);
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* ub_resolve_callback */
|
||||
|
||||
getdns_return_t
|
||||
getdns_general_ub(struct getdns_context *context,
|
||||
|
@ -218,7 +219,8 @@ getdns_general_ub(struct getdns_context *context,
|
|||
struct getdns_dict *extensions,
|
||||
void *userarg,
|
||||
getdns_transaction_t * transaction_id,
|
||||
getdns_callback_t callbackfn)
|
||||
getdns_callback_t callbackfn,
|
||||
int usenamespaces)
|
||||
{
|
||||
getdns_return_t gr;
|
||||
int r;
|
||||
|
@ -227,7 +229,7 @@ getdns_general_ub(struct getdns_context *context,
|
|||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
gr = getdns_context_prepare_for_resolution(context);
|
||||
gr = getdns_context_prepare_for_resolution(context, usenamespaces);
|
||||
if (gr != GETDNS_RETURN_GOOD) {
|
||||
return gr;
|
||||
}
|
||||
|
@ -305,7 +307,7 @@ getdns_general(struct getdns_context *context,
|
|||
return extcheck;
|
||||
|
||||
return getdns_general_ub(context,
|
||||
name, request_type, extensions, userarg, transaction_id, callback);
|
||||
name, request_type, extensions, userarg, transaction_id, callback, 0);
|
||||
|
||||
} /* getdns_general */
|
||||
|
||||
|
@ -321,20 +323,37 @@ getdns_address(struct getdns_context *context,
|
|||
getdns_transaction_t * transaction_id, getdns_callback_t callback)
|
||||
{
|
||||
int cleanup_extensions = 0;
|
||||
if (!extensions) {
|
||||
int extcheck;
|
||||
getdns_return_t result;
|
||||
|
||||
if (!context)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
if (!callback || !name)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
extcheck = validate_dname(name);
|
||||
if (extcheck != GETDNS_RETURN_GOOD)
|
||||
return extcheck;
|
||||
|
||||
/* we set the extensions that make general behave like getdns_address */
|
||||
if (!extensions)
|
||||
{
|
||||
extensions = getdns_dict_create_with_context(context);
|
||||
cleanup_extensions = 1;
|
||||
}
|
||||
getdns_dict_set_int(extensions,
|
||||
GETDNS_STR_EXTENSION_RETURN_BOTH_V4_AND_V6, GETDNS_EXTENSION_TRUE);
|
||||
extcheck = validate_extensions(extensions);
|
||||
if (extcheck != GETDNS_RETURN_GOOD)
|
||||
return extcheck;
|
||||
|
||||
getdns_return_t result = getdns_general(context, name, GETDNS_RRTYPE_A,
|
||||
extensions, userarg, transaction_id,
|
||||
callback);
|
||||
if (cleanup_extensions) {
|
||||
result = getdns_general_ub(context,
|
||||
name, GETDNS_RRTYPE_A, extensions, userarg, transaction_id, callback, 1);
|
||||
|
||||
if (cleanup_extensions)
|
||||
getdns_dict_destroy(extensions);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
} /* getdns_address */
|
||||
|
||||
/* getdns_general.c */
|
||||
|
|
|
@ -46,7 +46,9 @@ getdns_general_ub(struct getdns_context *context,
|
|||
uint16_t request_type,
|
||||
struct getdns_dict *extensions,
|
||||
void *userarg,
|
||||
getdns_transaction_t * transaction_id, getdns_callback_t callbackfn);
|
||||
getdns_transaction_t * transaction_id,
|
||||
getdns_callback_t callbackfn,
|
||||
int usenamespaces);
|
||||
|
||||
void priv_getdns_call_user_callback(getdns_dns_req *, struct getdns_dict *);
|
||||
|
||||
|
|
|
@ -47,8 +47,29 @@ getdns_service(struct getdns_context *context,
|
|||
void *userarg,
|
||||
getdns_transaction_t * transaction_id, getdns_callback_t callback)
|
||||
{
|
||||
return getdns_general(context, name, GETDNS_RRTYPE_SRV,
|
||||
extensions, userarg, transaction_id, callback);
|
||||
int parmcheck;
|
||||
getdns_return_t result;
|
||||
|
||||
if (!context)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
if (!callback || !name)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
parmcheck = validate_dname(name);
|
||||
if (parmcheck != GETDNS_RETURN_GOOD)
|
||||
return parmcheck;
|
||||
|
||||
if(extensions)
|
||||
{
|
||||
parmcheck = validate_extensions(extensions);
|
||||
if (parmcheck != GETDNS_RETURN_GOOD)
|
||||
return parmcheck;
|
||||
}
|
||||
|
||||
result = getdns_general_ub(context,
|
||||
name, GETDNS_RRTYPE_SRV, extensions, userarg, transaction_id, callback, 1);
|
||||
|
||||
return result;
|
||||
} /* getdns_service */
|
||||
|
||||
/* service.c */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
*
|
||||
* /file
|
||||
* /brief private library routines
|
||||
* \file util-internal.c
|
||||
* @brief private library routines
|
||||
*
|
||||
* These routines are not intended to be used by applications calling into
|
||||
* the library.
|
||||
|
@ -768,6 +768,6 @@ validate_dname(const char* dname) {
|
|||
return GETDNS_RETURN_BAD_DOMAIN_NAME;
|
||||
}
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
} /* validate_dname */
|
||||
|
||||
/* util-internal.c */
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* \file util-internal.h
|
||||
* /brief getdns contect management functions
|
||||
*
|
||||
* This is the meat of the API
|
||||
|
|
Loading…
Reference in New Issue