steps toward proper support of namespaces and system files

This commit is contained in:
Glen Wiley 2014-02-10 19:59:45 -05:00
parent b9bc90a986
commit bdff98ffb3
10 changed files with 388 additions and 142 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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_ */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 *);

View File

@ -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 */

View File

@ -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 */

View File

@ -1,5 +1,6 @@
/**
*
* \file util-internal.h
* /brief getdns contect management functions
*
* This is the meat of the API