From 969ae95f0979f29e75ff633a791e6400cab3a9a8 Mon Sep 17 00:00:00 2001 From: Glen Wiley Date: Mon, 4 Nov 2013 18:37:54 -0500 Subject: [PATCH 1/3] added extension validation to the primary entry point to catch bogus extension strings and perform simple type checking on extensions brief start on man pages, moving MIT license in source code files to BSD --- CodingStyle | 481 ++++++++++++++++++++++++++++++++++++++++ configure.ac | 6 +- doc/getdns_address.3.in | 46 ++++ doc/libgetdns.3.in | 70 ++++++ src/dict.c | 46 ++-- src/dict.h | 50 +++-- src/general.c | 68 +++--- src/general.h | 44 ++-- src/getdns/README | 1 + src/getdns/getdns.h | 57 ++--- src/list.c | 44 ++-- src/list.h | 2 +- src/request-internal.c | 46 ++-- src/sync.c | 46 ++-- src/types-internal.h | 64 ++++-- src/util-internal.c | 123 +++++++--- src/util-internal.h | 56 +++-- 17 files changed, 1000 insertions(+), 250 deletions(-) create mode 100644 CodingStyle create mode 100644 doc/getdns_address.3.in create mode 100644 doc/libgetdns.3.in create mode 100644 src/getdns/README diff --git a/CodingStyle b/CodingStyle new file mode 100644 index 00000000..5eedbc15 --- /dev/null +++ b/CodingStyle @@ -0,0 +1,481 @@ +/* $NetBSD: style,v 1.51 2013/03/08 16:50:02 christos Exp $ */ + +/* + * The revision control tag appears first, with a blank line after it. + * Copyright text appears after the revision control tag. + */ + +/* + * The NetBSD source code style guide. + * (Previously known as KNF - Kernel Normal Form). + * + * from: @(#)style 1.12 (Berkeley) 3/18/94 + */ +/* + * An indent(1) profile approximating the style outlined in + * this document lives in /usr/share/misc/indent.pro. It is a + * useful tool to assist in converting code to KNF, but indent(1) + * output generated using this profile must not be considered to + * be an authoritative reference. + */ + +/* + * Source code revision control identifiers appear after any copyright + * text. Use the appropriate macros from . Usually only one + * source file per program contains a __COPYRIGHT() section. + * Historic Berkeley code may also have an __SCCSID() section. + * Only one instance of each of these macros can occur in each file. + * Don't use newlines in the identifiers. + */ +#include +__COPYRIGHT("@(#) Copyright (c) 2008\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: style,v 1.51 2013/03/08 16:50:02 christos Exp $"); + +/* + * VERY important single-line comments look like this. + */ + +/* Most single-line comments look like this. */ + +/* + * Multi-line comments look like this. Make them real sentences. Fill + * them so they look like real paragraphs. + */ + +/* + * Attempt to wrap lines longer than 80 characters appropriately. + * Refer to the examples below for more information. + */ + +/* + * EXAMPLE HEADER FILE: + * + * A header file should protect itself against multiple inclusion. + * E.g, would contain something like: + */ +#ifndef _SYS_SOCKET_H_ +#define _SYS_SOCKET_H_ +/* + * Contents of #include file go between the #ifndef and the #endif at the end. + */ +#endif /* !_SYS_SOCKET_H_ */ +/* + * END OF EXAMPLE HEADER FILE. + */ + +/* + * If a header file requires structures, defines, typedefs, etc. from + * another header file it should include that header file and not depend + * on the including file for that header including both. If there are + * exceptions to this for specific headers it should be clearly documented + * in the headers and, if appropriate, the documentation. Nothing in this + * rule should suggest relaxation of the multiple inclusion rule and the + * application programmer should be free to include both regardless. + */ + +/* + * Kernel include files come first. + */ +#include /* first, */ +#include /* next, */ +#include /* and then the rest, */ +#include /* sorted lexicographically. */ +#include +#include /* Non-local includes in brackets. */ + +/* + * If it's a network program, put the network include files next. + * Group the includes files by subdirectory. + */ +#include +#include +#include +#include +#include + +/* + * Then there's a blank line, followed by the /usr include files. + * The /usr include files should be sorted lexicographically! + */ +#include +#include +#include +#include +#include + +/* + * Global pathnames are defined in /usr/include/paths.h. Pathnames local + * to the program go in pathnames.h in the local directory. + */ +#include + +/* Then, there's a blank line, and the user include files. */ +#include "pathnames.h" /* Local includes in double quotes. */ + +/* + * ANSI function declarations for private functions (i.e. functions not used + * elsewhere) and the main() function go at the top of the source module. + * Don't associate a name with the types. I.e. use: + * void function(int); + * Use your discretion on indenting between the return type and the name, and + * how to wrap a prototype too long for a single line. In the latter case, + * lining up under the initial left parenthesis may be more readable. + * In any case, consistency is important! + */ +static char *function(int, int, float, int); +static int dirinfo(const char *, struct stat *, struct dirent *, + struct statfs *, int *, char **[]); +static void usage(void) __dead; /* declare functions that don't return dead */ + +/* + * Macros are capitalized, parenthesized, and should avoid side-effects. + * Spacing before and after the macro name may be any whitespace, though + * use of TABs should be consistent through a file. + * If they are an inline expansion of a function, the function is defined + * all in lowercase, the macro has the same name all in uppercase. + * If the macro is an expression, wrap the expression in parenthesis. + * If the macro is more than a single statement, use ``do { ... } while (0)'', + * so that a trailing semicolon works. Right-justify the backslashes; it + * makes it easier to read. The CONSTCOND comment is to satisfy lint(1). + */ +#define MACRO(v, w, x, y) \ +do { \ + v = (x) + (y); \ + w = (y) + 2; \ +} while (/* CONSTCOND */ 0) + +#define DOUBLE(x) ((x) * 2) + +/* Enum types are capitalized. No comma on the last element. */ +enum enumtype { + ONE, + TWO +} et; + +/* + * When declaring variables in structures, declare them organized by use in + * a manner to attempt to minimize memory wastage because of compiler alignment + * issues, then by size, and then by alphabetical order. E.g, don't use + * ``int a; char *b; int c; char *d''; use ``int a; int b; char *c; char *d''. + * Each variable gets its own type and line, although an exception can be made + * when declaring bitfields (to clarify that it's part of the one bitfield). + * Note that the use of bitfields in general is discouraged. + * + * Major structures should be declared at the top of the file in which they + * are used, or in separate header files, if they are used in multiple + * source files. Use of the structures should be by separate declarations + * and should be "extern" if they are declared in a header file. + * + * It may be useful to use a meaningful prefix for each member name. + * E.g, for ``struct softc'' the prefix could be ``sc_''. + */ +struct foo { + struct foo *next; /* List of active foo */ + struct mumble amumble; /* Comment for mumble */ + int bar; + unsigned int baz:1, /* Bitfield; line up entries if desired */ + fuz:5, + zap:2; + uint8_t flag; +}; +struct foo *foohead; /* Head of global foo list */ + +/* Make the structure name match the typedef. */ +typedef struct BAR { + int level; +} BAR; + +/* C99 uintN_t is preferred over u_intN_t. */ +uint32_t zero; + +/* + * All major routines should have a comment briefly describing what + * they do. The comment before the "main" routine should describe + * what the program does. + */ +int +main(int argc, char *argv[]) +{ + long num; + int ch; + char *ep; + + /* + * At the start of main(), call setprogname() to set the program + * name. This does nothing on NetBSD, but increases portability + * to other systems. + */ + setprogname(argv[0]); + + /* + * For consistency, getopt should be used to parse options. + * Options should be sorted in the getopt call and the switch + * statement, unless parts of the switch cascade. For the + * sorting order, see the usage() example below. Don't forget + * to add option descriptions to the usage and the manpage. + * Elements in a switch statement that cascade should have a + * FALLTHROUGH comment. Numerical arguments should be checked + * for accuracy. Code that cannot be reached should have a + * NOTREACHED comment. + */ + while ((ch = getopt(argc, argv, "abn:")) != -1) { + switch (ch) { /* Indent the switch. */ + case 'a': /* Don't indent the case. */ + aflag = 1; + /* FALLTHROUGH */ + case 'b': + bflag = 1; + break; + case 'n': + errno = 0; + num = strtol(optarg, &ep, 10); + if (num <= 0 || *ep != '\0' || (errno == ERANGE && + (num == LONG_MAX || num == LONG_MIN)) ) + errx(1, "illegal number -- %s", optarg); + break; + case '?': + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + /* + * Space after keywords (while, for, return, switch). No braces are + * required for control statements with only a single statement, + * unless it's a long statement. + * + * Forever loops are done with for's, not while's. + */ + for (p = buf; *p != '\0'; ++p) + continue; /* Explicit no-op */ + for (;;) + stmt; + + /* + * Braces are required for control statements with a single statement + * that may expand to nothing. + */ +#ifdef DEBUG_FOO +#define DPRINTF(a) printf a +#else +#define DPRINTF(a) +#endif + if (broken) { + DPRINTF(("broken is %d\n", broken)); + } + + /* + * Parts of a for loop may be left empty. Don't put declarations + * inside blocks unless the routine is unusually complicated. + */ + for (; cnt < 15; cnt++) { + stmt1; + stmt2; + } + + /* Second level indents are four spaces. */ + while (cnt < 20) + z = a + really + long + statement + that + needs + two + lines + + gets + indented + four + spaces + on + the + second + + and + subsequent + lines; + + /* + * Closing and opening braces go on the same line as the else. + * Don't add braces that aren't necessary except in cases where + * there are ambiguity or readability issues. + */ + if (test) { + /* + * I have a long comment here. + */ +#ifdef zorro + z = 1; +#else + b = 3; +#endif + } else if (bar) { + stmt; + stmt; + } else + stmt; + + /* No spaces after function names. */ + if ((result = function(a1, a2, a3, a4)) == NULL) + exit(1); + + /* + * Unary operators don't require spaces, binary operators do. + * Don't excessively use parenthesis, but they should be used if + * statement is really confusing without them, such as: + * a = b->c[0] + ~d == (e || f) || g && h ? i : j >> 1; + */ + a = ((b->c[0] + ~d == (e || f)) || (g && h)) ? i : (j >> 1); + k = !(l & FLAGS); + + /* + * Exits should be EXIT_SUCCESS on success, and EXIT_FAILURE on + * failure. Don't denote all the possible exit points, using the + * integers 1 through 127. Avoid obvious comments such as "Exit + * 0 on success.". Since main is a function that returns an int, + * prefer returning from it, than calling exit. + */ + return EXIT_SUCCESS; +} + +/* + * The function type must be declared on a line by itself + * preceding the function. + */ +static char * +function(int a1, int a2, float fl, int a4) +{ + /* + * When declaring variables in functions declare them sorted by size, + * then in alphabetical order; multiple ones per line are okay. + * Function prototypes should go in the include file "extern.h". + * If a line overflows reuse the type keyword. + * + * DO NOT initialize variables in the declarations. + */ + extern u_char one; + extern char two; + struct foo three, *four; + double five; + int *six, seven; + char *eight, *nine, ten, eleven, twelve, thirteen; + char fourteen, fifteen, sixteen; + + /* + * Casts and sizeof's are not followed by a space. NULL is any + * pointer type, and doesn't need to be cast, so use NULL instead + * of (struct foo *)0 or (struct foo *)NULL. Also, test pointers + * against NULL. I.e. use: + * + * (p = f()) == NULL + * not: + * !(p = f()) + * + * The notable exception here is variadic functions. Since our + * code is designed to compile and work on different environments + * where we don't have control over the NULL definition (on NetBSD + * it is defined as ((void *)0), but on other systems it can be + * defined as (0) and both definitions are valid under ANSI C), it + * it advised to cast NULL to a pointer on varyadic functions, + * because on machines where sizeof(pointer) != sizeof(int) and in + * the absence of a prototype in scope, passing an un-casted NULL, + * will result in passing an int on the stack instead of a pointer. + * + * Don't use `!' for tests unless it's a boolean. + * E.g. use "if (*p == '\0')", not "if (!*p)". + * + * Routines returning ``void *'' should not have their return + * values cast to more specific pointer types. + * + * Prefer sizeof(*var) over sizeof(type) because if type changes, + * the change needs to be done in one place. + * + * Use err/warn(3), don't roll your own! + */ + if ((four = malloc(sizeof(*four))) == NULL) + err(1, NULL); + if ((six = (int *)overflow()) == NULL) + errx(1, "Number overflowed."); + + /* No parentheses are needed around the return value. */ + return eight; +} + +/* + * Use ANSI function declarations. ANSI function braces look like + * old-style (K&R) function braces. + * As per the wrapped prototypes, use your discretion on how to format + * the subsequent lines. + */ +static int +dirinfo(const char *p, struct stat *sb, struct dirent *de, struct statfs *sf, + int *rargc, char **rargv[]) +{ /* Insert an empty line if the function has no local variables. */ + + /* + * In system libraries, catch obviously invalid function arguments + * using _DIAGASSERT(3). + */ + _DIAGASSERT(p != NULL); + _DIAGASSERT(filedesc != -1); + + if (stat(p, sb) < 0) + err(1, "Unable to stat %s", p); + + /* + * To printf quantities that might be larger that "long", include + * , cast quantities to intmax_t or uintmax_t and use + * PRI?MAX constants. + */ + (void)printf("The size of %s is %" PRIdMAX " (%#" PRIxMAX ")\n", p, + (intmax_t)sb->st_size, (uintmax_t)sb->st_size); + + /* + * To printf quantities of known bit-width, use the corresponding + * defines (generally only done within NetBSD for quantities that + * exceed 32-bits). + */ + (void)printf("%s uses %" PRId64 " blocks and has flags %#" PRIx32 "\n", + p, sb->st_blocks, sb->st_flags); + + /* + * There are similar constants that should be used with the *scanf(3) + * family of functions: SCN?MAX, SCN?64, etc. + */ +} + +/* + * Functions that support variable numbers of arguments should look like this. + * (With the #include appearing at the top of the file with the + * other include files.) + */ +#include + +void +vaf(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + STUFF; + va_end(ap); + /* No return needed for void functions. */ +} + +static void +usage(void) +{ + + /* + * Use printf(3), not fputs/puts/putchar/whatever, it's faster and + * usually cleaner, not to mention avoiding stupid bugs. + * Use snprintf(3) or strlcpy(3)/strlcat(3) instead of sprintf(3); + * again to avoid stupid bugs. + * + * Usage statements should look like the manual pages. + * Options w/o operands come first, in alphabetical order + * inside a single set of braces, upper case before lower case + * (AaBbCc...). Next are options with operands, in the same + * order, each in braces. Then required arguments in the + * order they are specified, followed by optional arguments in + * the order they are specified. A bar (`|') separates + * either/or options/arguments, and multiple options/arguments + * which are specified together are placed in a single set of + * braces. + * + * Use getprogname() instead of hardcoding the program name. + * + * "usage: f [-aDde] [-b b_arg] [-m m_arg] req1 req2 [opt1 [opt2]]\n" + * "usage: f [-a | -b] [-c [-de] [-n number]]\n" + */ + (void)fprintf(stderr, "usage: %s [-ab]\n", getprogname()); + exit(EXIT_FAILURE); +} diff --git a/configure.ac b/configure.ac index b47e47eb..a1374f1e 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ # AC_PREREQ([2.68]) -AC_INIT([getdns], [0.320], [melinda.shore@nomountain.net]) +AC_INIT([getdns], [0.1.0], [melinda.shore@nomountain.net]) AC_CONFIG_SRCDIR([src/getdns/getdns.h]) # AM_INIT_AUTOMAKE # LT_INIT @@ -60,10 +60,10 @@ AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_UINT8_T -AC_CONFIG_FILES([Makefile src/Makefile src/getdns/Makefile src/example/Makefile src/test/Makefile]) +AC_CONFIG_FILES([Makefile src/Makefile src/getdns/Makefile src/example/Makefile src/test/Makefile doc/Makefile]) if [ test -n "$DOXYGEN" ] then AC_CONFIG_FILES([src/Doxyfile]) fi -AC_CONFIG_SUBDIRS([src/ src/getdns/ src/example/ src/test/]) +AC_CONFIG_SUBDIRS([src/ src/getdns/ src/example/ src/test/ doc/]) AC_OUTPUT diff --git a/doc/getdns_address.3.in b/doc/getdns_address.3.in new file mode 100644 index 00000000..33e41887 --- /dev/null +++ b/doc/getdns_address.3.in @@ -0,0 +1,46 @@ +.TH libgetdns 3 "November 2013" "getdns 0.0.0" getdns +.SH NAME +getdns_address +.SH LIBRARY +DNS Resolver library (libgetdns, -lgetdns) + +.SH SYNOPSIS +#include + +getdns_return_t +.br +.B getdns_address +(getdns_context_t context, const char *name, struct getdns_dict *extensions, void *userarg, getdns_transaction_t *transaction_id, getdns_callback_t callbackfn); + +.SH DESCRIPTION + +.LP +THIS IS A WORK IN PROGRESS - MUCH TO ADD + +.LP +The getdns_address(3) and getdns_address_sync functions provide public entry points into the getdns API library to retrieve the address given a host name. It always returns both IPv4 and IPv6 addresses. + +.SH FILES +.br +/etc/hosts +.br +/etc/resolv.conf + +.SH EXAMPLES + +TBD + +.SH DIAGNOSTICS + +TBD + +.SH SEE ALSO +.BR libgetdns (3), +.BR getdns_address_sync (3), +.BR getdns_general (3), +.BR getdns_general_sync (3), +.BR getdns_hostname (3), +.BR getdns_hostname_sync (3), +.BR getdns_service (3), +.BR getdns_service_sync (3). + diff --git a/doc/libgetdns.3.in b/doc/libgetdns.3.in new file mode 100644 index 00000000..64ddc54a --- /dev/null +++ b/doc/libgetdns.3.in @@ -0,0 +1,70 @@ +.TH libgetdns 3 "November 2013" "getdns 0.0.0" getdns +.SH NAME +libgetdns +.Sh LIBRARY +DNS Resolver library (libgetdns, -lgetdns) + +.SH SYNOPSIS +.Lb libgetdns +#include + +THe public entry points are captured in separate man pages. + +.SH DESCRIPTION + +.LP +THIS IS A WORK IN PROGRESS - LOTS TO ADD + +.LP +This document describes a modern asynchronous DNS API. This new API is intended to be useful to application developers and operating system distributors as a way of making all types of DNS information easily available in many types of programs. The major features of this new API are: + +.RS 3 + Full support for event-driven programming + Supports DNSSEC in multiple ways + Mirroring of the resolution in getaddrinfo() + Easily supports all RRtypes, even those yet to be defined +.RE + +.LP +This implementation of the getdns API is licensed under the BSD license. + +.SH FILES +.br /etc/hosts +.br /etc/resolv.conf + +.SH EXAMPLES +TBD + +.SH DIAGNOSTICS +TBD + +.SH "SEE ALSO" +.BR getdns_address (3), +.BR getdns_address_sync (3), +.BR getdns_general (3), +.BR getdns_general_sync (3), +.BR getdns_hostname (3), +.BR getdns_hostname_sync (3), +.BR getdns_service (3), +.BR getdns_service_sync (3). + +.SH REPORTING PROBLEMS +Bug reports should be sent to the getdns-bugs@getdns.net + +.SH AUTHORS + +The getdns API was documented by Paul Hoffman. This implementation of the getdns API was written by: +.LP +.RS 3 +.br +Neel Goyal, Verisign Inc. +.br +Melinda Shore, No Mountain Software, LLC +.br +Willem Toorop, NLNet Labs +.br +Wouter Wijngaards, NLNet Labs +.br +Glen Wiley, Verisign Inc. +.RE + diff --git a/src/dict.c b/src/dict.c index 2d78e5f8..5bc38758 100644 --- a/src/dict.c +++ b/src/dict.c @@ -7,26 +7,32 @@ * Interfaces originally taken from the getdns API description pseudo implementation. * */ -/* The MIT License (MIT) - * Copyright (c) 2013 Verisign, Inc. + +/* + * Copyright (c) 2013, Versign, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include @@ -673,4 +679,4 @@ getdns_pretty_print_dict(struct getdns_dict *dict) return ret; } /* getdns_pretty_print_dict */ -/* getdns_dict.c */ +/* dict.c */ diff --git a/src/dict.h b/src/dict.h index d184cba2..91ca0180 100644 --- a/src/dict.h +++ b/src/dict.h @@ -1,32 +1,37 @@ /** * - * /brief getdns contect management functions + * /brief getdns dict data type management functions * - * This is the meat of the API - * Originally taken from the getdns API description pseudo implementation. * */ -/* The MIT License (MIT) - * Copyright (c) 2013 Verisign, Inc. + +/* + * Copyright (c) 2013, NLNet Labs, Versign, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #ifndef _GETDNS_DICT_H_ #define _GETDNS_DICT_H_ @@ -63,3 +68,4 @@ struct getdns_dict { #endif +/* dict.h */ diff --git a/src/general.c b/src/general.c index 2e59af63..f1fe72ce 100644 --- a/src/general.c +++ b/src/general.c @@ -1,31 +1,37 @@ /** * - * /brief getdns core functions - * - * This is the meat of the API - * Originally taken from the getdns API description pseudo implementation. + * /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 + * file where they are directly logically related to the getdns_general implementation. */ -/* The MIT License (MIT) - * Copyright (c) 2013 Verisign, Inc. + +/* + * Copyright (c) 2013, Versign, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -195,7 +201,8 @@ getdns_general_ub(struct ub_ctx* unbound, struct getdns_dict *extensions, void *userarg, getdns_transaction_t *transaction_id, - getdns_callback_t callbackfn) { + getdns_callback_t callbackfn) +{ /* timeout */ struct timeval tv; getdns_return_t gr; @@ -241,9 +248,9 @@ getdns_general_ub(struct ub_ctx* unbound, return GETDNS_RETURN_GENERIC_ERROR; } return GETDNS_RETURN_GOOD; -} +} /* getdns_general_ub */ -/* +/** * getdns_general */ getdns_return_t @@ -253,7 +260,9 @@ getdns_general_ub(struct ub_ctx* unbound, struct getdns_dict *extensions, void *userarg, getdns_transaction_t *transaction_id, - getdns_callback_t callback) { + getdns_callback_t callback) +{ + int extcheck = GETDNS_RETURN_GOOD; if (!context || !context->event_base_async || callback == NULL) { @@ -263,6 +272,10 @@ getdns_general_ub(struct ub_ctx* unbound, return GETDNS_RETURN_BAD_CONTEXT; } + extcheck = validate_extensions(extensions); + if(extcheck != GETDNS_RETURN_GOOD) + return extcheck; + return getdns_general_ub(context->unbound_async, context->event_base_async, context, @@ -275,7 +288,6 @@ getdns_general_ub(struct ub_ctx* unbound, } /* getdns_general */ - /* * getdns_address * diff --git a/src/general.h b/src/general.h index 658131eb..7b4c98e8 100644 --- a/src/general.h +++ b/src/general.h @@ -6,27 +6,33 @@ * Originally taken from the getdns API description pseudo implementation. * */ -/* The MIT License (MIT) - * Copyright (c) 2013 Verisign, Inc. +/* + * Copyright (c) 2013, Versign, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #ifndef _GETDNS_GENERAL_H_ #define _GETDNS_GENERAL_H_ diff --git a/src/getdns/README b/src/getdns/README new file mode 100644 index 00000000..064d654c --- /dev/null +++ b/src/getdns/README @@ -0,0 +1 @@ +This directory contains the getdns API description that serves as the target of this implementation. diff --git a/src/getdns/getdns.h b/src/getdns/getdns.h index 6ec786c3..727741cb 100644 --- a/src/getdns/getdns.h +++ b/src/getdns/getdns.h @@ -1,30 +1,36 @@ /** * \file - * \brief Public interfaces to getdns - include this in your application to use getdns API. + * \brief Public interfaces to getdns, include in your application to use getdns API. * * This source was taken from the original pseudo-implementation by * Paul Hoffman. */ -/* The MIT License (MIT) - * Copyright (c) 2013 Verisign, Inc. + +/* + * Copyright (c) 2013, NLNet Labs, Versign, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef GETDNS_H @@ -64,7 +70,7 @@ struct event_base; #define GETDNS_RETURN_NO_SUCH_EXTENSION 307 #define GETDNS_RETURN_NO_SUCH_EXTENSION_TEXT A name in the extensions dict is not a valid extension. #define GETDNS_RETURN_EXTENSION_MISFORMAT 308 -#define GETDNS_RETURN_EXTENSION_MISFORMAT_TEXT One or more of the extensions is has a bad format. +#define GETDNS_RETURN_EXTENSION_MISFORMAT_TEXT One or more of the extensions has a bad format. #define GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED 309 #define GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED_TEXT A query was made with a context that is using stub resolution and a DNSSEC extension specified. @@ -278,12 +284,6 @@ struct event_base; #define GETDNS_STR_KEY_QTYPE "qtype" #define GETDNS_STR_KEY_QCLASS "qclass" #define GETDNS_STR_KEY_QNAME "qname" - - - - - - /** @} */ @@ -372,6 +372,9 @@ struct event_base; typedef struct getdns_context_t *getdns_context_t; typedef uint16_t getdns_return_t; typedef uint64_t getdns_transaction_t; +/** + * used to check data types within complex types (dict, list) + */ typedef enum getdns_data_type { t_dict, t_list, t_int, t_bindata, t_invalid } getdns_data_type; diff --git a/src/list.c b/src/list.c index 5c6ca170..e5398048 100644 --- a/src/list.c +++ b/src/list.c @@ -6,26 +6,32 @@ * Originally taken from the getdns API description pseudo implementation. * */ -/* The MIT License (MIT) - * Copyright (c) 2013 Verisign, Inc. + +/* + * Copyright (c) 2013, Versign, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include diff --git a/src/list.h b/src/list.h index a3c3cd58..2fb1b100 100644 --- a/src/list.h +++ b/src/list.h @@ -61,7 +61,7 @@ struct getdns_list { int numalloc; int numinuse; struct getdns_list_item *items; -} getdns_list; +}; #endif diff --git a/src/request-internal.c b/src/request-internal.c index 555a549e..b0e872cd 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -6,26 +6,31 @@ * Originally taken from the getdns API description pseudo implementation. * */ -/* The MIT License (MIT) - * Copyright (c) 2013 Verisign, Inc. +/* + * Copyright (c) 2013, Versign, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "types-internal.h" @@ -103,7 +108,8 @@ void dns_req_free(getdns_dns_req* req) { } /* create a new dns req to be submitted */ -getdns_dns_req* dns_req_new(getdns_context_t context, +getdns_dns_req* +dns_req_new(getdns_context_t context, struct ub_ctx* unbound, const char* name, uint16_t request_type, diff --git a/src/sync.c b/src/sync.c index 3aee6364..f47f7b39 100644 --- a/src/sync.c +++ b/src/sync.c @@ -5,26 +5,32 @@ * Originally taken from the getdns API description pseudo implementation. * */ -/* The MIT License (MIT) - * Copyright (c) 2013 Verisign, Inc. + +/* + * Copyright (c) 2013, Versign, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include @@ -148,4 +154,4 @@ getdns_free_sync_request_memory( ) { UNUSED_PARAM(response); } -/* getdns_core_sync.c */ +/* sync.c */ diff --git a/src/types-internal.h b/src/types-internal.h index 822e206b..90093464 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -1,31 +1,36 @@ /** * - * /brief getdns contect management functions - * - * This is the meat of the API - * Originally taken from the getdns API description pseudo implementation. + * /brief type declarations private to the getdns library * + * These type declarations are not meant to be used by applications calling + * the public library functions. */ -/* The MIT License (MIT) - * Copyright (c) 2013 Verisign, Inc. + +/* + * Copyright (c) 2013, Versign, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef TYPES_INTERNAL_H_ @@ -47,6 +52,14 @@ typedef enum network_req_state_enum { NET_REQ_CANCELED } network_req_state; +/** + * structure used by validate_extensions() to check extension formats + */ +typedef struct getdns_extension_format { + char *extstring; + getdns_data_type exttype; +} getdns_extension_format; + /** * Request data for unbound **/ @@ -71,7 +84,8 @@ typedef struct getdns_network_req { struct getdns_network_req* next; } getdns_network_req; -/* dns request - manages a number of network requests and +/** + * dns request - manages a number of network requests and * the initial data passed to getdns_general */ typedef struct getdns_dns_req { @@ -131,3 +145,5 @@ getdns_dns_req* dns_req_new(getdns_context_t context, void dns_req_free(getdns_dns_req* req); #endif + +/* types-internal.h */ diff --git a/src/util-internal.c b/src/util-internal.c index ef28fd73..f5ee94d9 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -1,36 +1,63 @@ /** * - * /brief getdns contect management functions + * /file + * /brief private library routines * - * This is the meat of the API - * Originally taken from the getdns API description pseudo implementation. + * These routines are not intended to be used by applications calling into + * the library. * */ -/* The MIT License (MIT) - * Copyright (c) 2013 Verisign, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ +/* + * Copyright (c) 2013, Versign, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "getdns/getdns.h" +#include +#include "dict.h" #include "util-internal.h" #include "types-internal.h" +/** + * this is a comprehensive list of extensions and their data types + * used by validate_extensions() + */ +getdns_extension_format extformats[] = { + {"dnssec_return_status", t_int}, + {"dnssec_return_only_secure", t_int}, + {"dnssec_return_supporting_responses", t_int}, + {"return_both_v4_and_v6", t_int}, + {"add_opt_parameters", t_dict}, + {"add_warning_for_bad_dns", t_int}, + {"specify_class", t_int}, + {"return_api_information", t_int}, + {"return_call_debugging", t_int}, + {"", t_invalid} +}; + getdns_return_t getdns_dict_util_set_string(getdns_dict* dict, char* name, const char* value) { /* account for the null term */ @@ -462,11 +489,12 @@ getdns_dict *create_getdns_response(struct getdns_dns_req* completed_request) { return result; } -/* - * reverse an IP address for PTR lookup +/** + * reverse an IP address for PTR lookup + * @param addr_str dotted notation of IP address to reverse + * @return NULL on allocation failure + * @return reversed string on success, caller must free storage via call to free() */ - - char * reverse_address(char *addr_str) { @@ -490,3 +518,42 @@ reverse_address(char *addr_str) ldns_rdf_deep_free(rev_rdf); return rev_str; } + +/*---------------------------------------- validate_extensions */ +getdns_return_t +validate_extensions(getdns_dict *extensions) +{ + int retval = GETDNS_RETURN_GOOD; + int i = 0; + ldns_rbnode_t *node; + + if(extensions == NULL) + return retval; + + node = ldns_rbtree_first(&(extensions->root)); + while(retval == GETDNS_RETURN_GOOD && node != NULL) + { + i = 0; + while(extformats[i].exttype != t_invalid) + { + if(strcmp(extformats[i].extstring, node->key) == 0) + { + if(((struct getdns_dict_item *) node->data)->dtype != extformats[i].exttype) + { + retval = GETDNS_RETURN_EXTENSION_MISFORMAT; + } + break; + } + i++; + } + + if(extformats[i].exttype == t_invalid) + retval = GETDNS_RETURN_NO_SUCH_EXTENSION; + else + node = ldns_rbtree_next(node); + } // while retval && node + + return retval; +} /* validate_extensions */ + +/* util-internal.c */ diff --git a/src/util-internal.h b/src/util-internal.h index 94b95bc3..ef0f89f9 100644 --- a/src/util-internal.h +++ b/src/util-internal.h @@ -6,26 +6,32 @@ * Originally taken from the getdns API description pseudo implementation. * */ -/* The MIT License (MIT) - * Copyright (c) 2013 Verisign, Inc. + +/* + * Copyright (c) 2013, Versign, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* @@ -52,3 +58,15 @@ getdns_return_t getdns_dict_util_set_string(getdns_dict* dict, char* name, getdns_return_t getdns_dict_util_get_string(getdns_dict* dict, char* name, char** result); char *reverse_address(char *addr_str); + +/** + * detect unrecognized extension strings or invalid extension formats + * TODO: this could be optimized by searching a sorted list + * @param extensions dictionary of valid extension strings and values + * @return GETDNS_RETURN_GOOD if each extension string is valid and the format matches the API specification + * @return GETDNS_RETURN_NO_SUCH_EXTENSION A name in the extensions dict is not a valid extension. + * @return GETDNS_RETURN_EXTENSION_MISFORMAT One or more of the extensions has a bad format. + */ +getdns_return_t validate_extensions(getdns_dict *extensions); + +/* util-internal.h */ From 89a7bdcae6c17ca79fd6b3fe6b5f1f84a7932619 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Mon, 4 Nov 2013 23:26:59 -0800 Subject: [PATCH 2/3] Fix validate_extensions --- src/sync.c | 14 ++++++---- src/util-internal.c | 62 ++++++++++++++++++++------------------------- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/src/sync.c b/src/sync.c index 45a66d3e..e3f75621 100644 --- a/src/sync.c +++ b/src/sync.c @@ -65,12 +65,16 @@ getdns_general_sync( { getdns_return_t response_status; - response_status = getdns_general_ub(context->unbound_sync, context->event_base_sync, - context, name, request_type, extensions, - (void *)response, NULL, sync_callback_func); - - event_base_dispatch(context->event_base_sync); + response_status = validate_extensions(extensions); + if (response_status == GETDNS_RETURN_GOOD) { + response_status = getdns_general_ub(context->unbound_sync, + context->event_base_sync, + context, name, request_type, + extensions, (void *)response, + NULL, sync_callback_func); + event_base_dispatch(context->event_base_sync); + } return response_status; } diff --git a/src/util-internal.c b/src/util-internal.c index 78d6c96e..d264c99a 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -44,18 +44,19 @@ /** * this is a comprehensive list of extensions and their data types * used by validate_extensions() + * The list has to be in sorted order for bsearch lookup in function + * validate_extensions. */ getdns_extension_format extformats[] = { - {"dnssec_return_status", t_int}, - {"dnssec_return_only_secure", t_int}, - {"dnssec_return_supporting_responses", t_int}, - {"return_both_v4_and_v6", t_int}, {"add_opt_parameters", t_dict}, {"add_warning_for_bad_dns", t_int}, - {"specify_class", t_int}, + {"dnssec_return_only_secure", t_int}, + {"dnssec_return_status", t_int}, + {"dnssec_return_supporting_responses", t_int}, {"return_api_information", t_int}, + {"return_both_v4_and_v6", t_int}, {"return_call_debugging", t_int}, - {"", t_invalid} + {"specify_class", t_int}, }; getdns_return_t getdns_dict_util_set_string(getdns_dict* dict, char* name, @@ -521,41 +522,34 @@ reverse_address(char *addr_str) return rev_str; } +static int extformatcmp(const void *a, const void *b) +{ + return strcmp(((getdns_extension_format *)a)->extstring, + ((getdns_extension_format *)b)->extstring); +} + /*---------------------------------------- validate_extensions */ getdns_return_t validate_extensions(getdns_dict *extensions) { - int retval = GETDNS_RETURN_GOOD; - int i = 0; - ldns_rbnode_t *node; + struct getdns_dict_item *item; + getdns_extension_format *extformat; - if(extensions == NULL) - return retval; + if(extensions) + LDNS_RBTREE_FOR(item, struct getdns_dict_item *, &(extensions->root)) { + getdns_extension_format key; + key.extstring = (char *)item->node.key; + extformat = bsearch(&key, extformats, + sizeof(extformats) / + sizeof(getdns_extension_format), + sizeof(getdns_extension_format), extformatcmp); + if (! extformat) + return GETDNS_RETURN_NO_SUCH_EXTENSION; - node = ldns_rbtree_first(&(extensions->root)); - while(retval == GETDNS_RETURN_GOOD && node != NULL) - { - i = 0; - while(extformats[i].exttype != t_invalid) - { - if(strcmp(extformats[i].extstring, node->key) == 0) - { - if(((struct getdns_dict_item *) node->data)->dtype != extformats[i].exttype) - { - retval = GETDNS_RETURN_EXTENSION_MISFORMAT; - } - break; - } - i++; + if (item->dtype != extformat->exttype) + return GETDNS_RETURN_EXTENSION_MISFORMAT; } - - if(extformats[i].exttype == t_invalid) - retval = GETDNS_RETURN_NO_SUCH_EXTENSION; - else - node = ldns_rbtree_next(node); - } // while retval && node - - return retval; + return GETDNS_RETURN_GOOD; } /* validate_extensions */ /* util-internal.c */ From b6df0b8c1ab4a997a69dda82d3d72ec4108779c3 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Tue, 5 Nov 2013 08:28:10 -0800 Subject: [PATCH 3/3] Add original getdns specification So we can fix its bugs in an orderly fashion --- spec/example-all-functions.c | 297 +++++ spec/example-simple-answers.c | 99 ++ spec/example-synchronous.c | 71 ++ spec/example-tree.c | 138 +++ spec/getdns_core_only.c | 403 ++++++ spec/getdns_core_only.h | 558 +++++++++ spec/getdns_libevent.h | 9 + spec/index.html | 2182 +++++++++++++++++++++++++++++++++ spec/make-examples-linux.sh | 22 + spec/make-examples-mac.sh | 22 + 10 files changed, 3801 insertions(+) create mode 100644 spec/example-all-functions.c create mode 100644 spec/example-simple-answers.c create mode 100644 spec/example-synchronous.c create mode 100644 spec/example-tree.c create mode 100644 spec/getdns_core_only.c create mode 100644 spec/getdns_core_only.h create mode 100644 spec/getdns_libevent.h create mode 100644 spec/index.html create mode 100755 spec/make-examples-linux.sh create mode 100755 spec/make-examples-mac.sh diff --git a/spec/example-all-functions.c b/spec/example-all-functions.c new file mode 100644 index 00000000..c4ad41c5 --- /dev/null +++ b/spec/example-all-functions.c @@ -0,0 +1,297 @@ +#include +#include +#include +#include +#include +#include +#include + +#define UNUSED_PARAM(x) ((void)(x)) + +/* The return values */ +getdns_return_t retregular; +char * retcharstar; + +/* The args */ +bool boolarg; +char * charstararg; +getdns_callback_t callbackarg; +uint16_t regulararg; +uint16_t *regularptrarg; +getdns_transaction_t txidarg; +getdns_transaction_t * txidptrarg; + +getdns_data_type * datatypeptrarg; +struct getdns_bindata ** bindataptrarg; +struct getdns_dict * dictarg; +struct getdns_bindata * bindataarg; +struct getdns_list * listarg; +struct getdns_dict ** dictptrarg; +struct getdns_list ** listptrarg; + +size_t sizetarg; +size_t * sizetptrarg; +getdns_context_t contextarg = NULL; +uint8_t uint8arg; +uint16_t uint16arg; +uint32_t uint32arg; +uint8_t * uint8ptrarg; +uint16_t * uint16ptrarg; +uint32_t * uint32ptrarg; +void * arrayarg; +void allocfunctionarg(size_t foo) {UNUSED_PARAM(foo);} +void deallocfunctionarg(void* foo) {UNUSED_PARAM(foo);} +void setcallbackfunctionarg(struct getdns_context_t *foo1, uint16_t foo2) + {UNUSED_PARAM(foo1);UNUSED_PARAM(foo2);} + +int main() +{ + +retregular = getdns_general( + contextarg, + charstararg, + uint16arg, + dictarg, + arrayarg, + txidptrarg, + callbackarg +); + +retregular = getdns_address( + contextarg, + charstararg, + dictarg, + arrayarg, + txidptrarg, + callbackarg +); + +retregular = getdns_hostname( + contextarg, + dictarg, + dictarg, + arrayarg, + txidptrarg, + callbackarg +); + +retregular = getdns_service( + contextarg, + charstararg, + dictarg, + arrayarg, + txidptrarg, + callbackarg +); + +retregular = getdns_context_create( + &contextarg, + boolarg +); + +getdns_context_destroy( + contextarg +); + +retregular = getdns_cancel_callback( + contextarg, + txidarg +); + +retregular = getdns_general_sync( + contextarg, + charstararg, + uint16arg, + dictarg, + uint32ptrarg, + dictarg +); + +retregular = getdns_address_sync( + contextarg, + charstararg, + dictarg, + uint32ptrarg, + dictarg +); + +retregular = getdns_hostname_sync( + contextarg, + dictarg, + dictarg, + uint32ptrarg, + dictarg +); + +retregular = getdns_service_sync( + contextarg, + charstararg, + dictarg, + uint32ptrarg, + dictarg +); + +getdns_free_sync_request_memory( + dictarg +); + +retregular = getdns_list_get_length(listarg, sizetptrarg); +retregular = getdns_list_get_data_type(listarg, sizetarg, datatypeptrarg); +retregular = getdns_list_get_dict(listarg, sizetarg, dictptrarg); +retregular = getdns_list_get_list(listarg, sizetarg, listptrarg); +retregular = getdns_list_get_bindata(listarg, sizetarg, bindataptrarg); +retregular = getdns_list_get_int(listarg, sizetarg, uint32ptrarg); + +retregular = getdns_dict_get_names(dictarg, listptrarg); +retregular = getdns_dict_get_data_type(dictarg, charstararg, datatypeptrarg); +retregular = getdns_dict_get_dict(dictarg, charstararg, dictptrarg); +retregular = getdns_dict_get_list(dictarg, charstararg, listptrarg); +retregular = getdns_dict_get_bindata(dictarg, charstararg, bindataptrarg); +retregular = getdns_dict_get_int(dictarg, charstararg, uint32ptrarg); + +listarg = getdns_list_create(); +getdns_list_destroy(listarg); +retregular = getdns_list_set_dict(listarg, sizetarg, dictarg); +retregular = getdns_list_set_list(listarg, sizetarg, listarg); +retregular = getdns_list_set_bindata(listarg, sizetarg, bindataarg); +retregular = getdns_list_set_int(listarg, sizetarg, uint32arg); + +dictarg = getdns_dict_create(); +getdns_dict_destroy(dictarg); +retregular = getdns_dict_set_dict(dictarg, charstararg, dictarg); +retregular = getdns_dict_set_list(dictarg, charstararg, listarg); +retregular = getdns_dict_set_bindata(dictarg, charstararg, bindataarg); +retregular = getdns_dict_set_int(dictarg, charstararg, uint32arg); + +retcharstar = getdns_convert_fqdn_to_dns_name( + charstararg +); + +retcharstar = getdns_convert_dns_name_to_fqdn( + charstararg +); + +retcharstar = getdns_convert_ulabel_to_alabel( + charstararg +); + +retcharstar = getdns_convert_alabel_to_ulabel( + charstararg +); + +retregular = getdns_validate_dnssec( + bindataarg, + listarg, + listarg +); + +retcharstar = getdns_pretty_print_dict( + dictarg +); + +retcharstar = getdns_display_ip_address( + bindataarg +); + +retregular = getdns_context_set_context_update_callback( + contextarg, + setcallbackfunctionarg +); + +retregular = getdns_context_set_resolution_type( + contextarg, + regulararg +); + +retregular = getdns_context_set_namespaces( + contextarg, + sizetarg, + regularptrarg +); + +retregular = getdns_context_set_dns_transport( + contextarg, + regulararg +); + +retregular = getdns_context_set_limit_outstanding_queries( + contextarg, + uint16arg +); + +retregular = getdns_context_set_timeout( + contextarg, + uint16arg +); + +retregular = getdns_context_set_follow_redirects( + contextarg, + regulararg +); + +retregular = getdns_context_set_dns_root_servers( + contextarg, + listarg +); + +retregular = getdns_context_set_append_name( + contextarg, + regulararg +); + +retregular = getdns_context_set_suffix( + contextarg, + listarg +); + +retregular = getdns_context_set_dnssec_trust_anchors( + contextarg, + listarg +); + +retregular = getdns_context_set_dnssec_allowed_skew( + contextarg, + uint16arg +); + +retregular = getdns_context_set_stub_resolution( + contextarg, + listarg +); + +retregular = getdns_context_set_edns_maximum_udp_payload_size( + contextarg, + uint16arg +); + +retregular = getdns_context_set_edns_extended_rcode( + contextarg, + uint8arg +); + +retregular = getdns_context_set_edns_version( + contextarg, + uint8arg +); + +retregular = getdns_context_set_edns_do_bit( + contextarg, + uint8arg +); + +retregular = getdns_context_set_memory_allocator( + contextarg, + allocfunctionarg +); + +retregular = getdns_context_set_memory_deallocator( + contextarg, + deallocfunctionarg +); + +retregular = getdns_context_set_memory_reallocator( + contextarg, + deallocfunctionarg +); + +return(0); } /* End of main() */ diff --git a/spec/example-simple-answers.c b/spec/example-simple-answers.c new file mode 100644 index 00000000..031af9e2 --- /dev/null +++ b/spec/example-simple-answers.c @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include +#include + +#define UNUSED_PARAM(x) ((void)(x)) + +/* Set up the callback function, which will also do the processing of the results */ +void this_callbackfn(struct getdns_context_t *this_context, + uint16_t this_callback_type, + struct getdns_dict *this_response, + void *this_userarg, + getdns_transaction_t this_transaction_id) +{ + UNUSED_PARAM(this_userarg); /* Not looking at the userarg for this example */ + UNUSED_PARAM(this_context); /* Not looking at the context for this example */ + getdns_return_t this_ret; /* Holder for all function returns */ + if (this_callback_type == GETDNS_CALLBACK_COMPLETE) /* This is a callback with data */ + { + /* Be sure the search returned something */ + uint32_t * this_error = NULL; + this_ret = getdns_dict_get_int(this_response, "status", this_error); // Ignore any error + if (*this_error != GETDNS_RESPSTATUS_GOOD) // If the search didn't return "good" + { + fprintf(stderr, "The search had no results, and a return value of %d. Exiting.", *this_error); + return; + } + struct getdns_list * just_the_addresses_ptr; + this_ret = getdns_dict_get_list(this_response, "just_address_answers", &just_the_addresses_ptr); + if (this_ret != GETDNS_RETURN_GOOD) // This check is really not needed, but prevents a compiler error under "pedantic" + { + fprintf(stderr, "Trying to get the answers failed: %d", this_ret); + return; + } + size_t * num_addresses_ptr = NULL; + this_ret = getdns_list_get_length(just_the_addresses_ptr, num_addresses_ptr); // Ignore any error + /* Go through each record */ + for ( size_t rec_count = 0; rec_count <= *num_addresses_ptr; ++rec_count ) + { + struct getdns_dict * this_address; + this_ret = getdns_list_get_dict(just_the_addresses_ptr, rec_count, &this_address); // Ignore any error + /* Just print the address */ + struct getdns_bindata * this_address_data; + this_ret = getdns_dict_get_bindata(this_address, "address_data", &this_address_data); // Ignore any error + printf("The address is %s", getdns_display_ip_address(this_address_data)); + } + } + else if (this_callback_type == GETDNS_CALLBACK_CANCEL) + fprintf(stderr, "The callback with ID %"PRIu64" was cancelled. Exiting.", this_transaction_id); + else + fprintf(stderr, "The callback got a callback_type of %d. Exiting.", this_callback_type); +} + +int main() +{ + /* Create the DNS context for this call */ + struct getdns_context_t *this_context = NULL; + getdns_return_t context_create_return = getdns_context_create(&this_context, true); + if (context_create_return != GETDNS_RETURN_GOOD) + { + fprintf(stderr, "Trying to create the context failed: %d", context_create_return); + return(GETDNS_RETURN_GENERIC_ERROR); + } + /* Create an event base and put it in the context using the unknown function name */ + struct event_base *this_event_base; + this_event_base = event_base_new(); + if (this_event_base == NULL) + { + fprintf(stderr, "Trying to create the event base failed."); + return(GETDNS_RETURN_GENERIC_ERROR); + } + (void)getdns_extension_set_libevent_base(this_context, this_event_base); + /* Set up the getdns call */ + const char * this_name = "www.example.com"; + char* this_userarg = "somestring"; // Could add things here to help identify this call + getdns_transaction_t this_transaction_id = 0; + + /* Make the call */ + getdns_return_t dns_request_return = getdns_address(this_context, this_name, + NULL, this_userarg, &this_transaction_id, this_callbackfn); + if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME) + { + fprintf(stderr, "A bad domain name was used: %s. Exiting.", this_name); + return(GETDNS_RETURN_GENERIC_ERROR); + } + else + { + /* Call the event loop */ + int dispatch_return = event_base_dispatch(this_event_base); + UNUSED_PARAM(dispatch_return); + // TODO: check the return value above + } + /* Clean up */ + getdns_context_destroy(this_context); + /* Assuming we get here, leave gracefully */ + exit(EXIT_SUCCESS); +} diff --git a/spec/example-synchronous.c b/spec/example-synchronous.c new file mode 100644 index 00000000..513a3112 --- /dev/null +++ b/spec/example-synchronous.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include + +int main() +{ + getdns_return_t this_ret; /* Holder for all function returns */ + /* Create the DNS context for this call */ + struct getdns_context_t *this_context = NULL; + getdns_return_t context_create_return = getdns_context_create(&this_context, true); + if (context_create_return != GETDNS_RETURN_GOOD) + { + fprintf(stderr, "Trying to create the context failed: %d", context_create_return); + return(GETDNS_RETURN_GENERIC_ERROR); + } + /* Set up the getdns_sync_request call */ + const char * this_name = "www.example.com"; + uint8_t this_request_type = GETDNS_RRTYPE_A; + /* Get the A and AAAA records */ + struct getdns_dict * this_extensions = getdns_dict_create(); + this_ret = getdns_dict_set_int(this_extensions, "return_both_v4_and_v6", GETDNS_EXTENSION_TRUE); + if (this_ret != GETDNS_RETURN_GOOD) + { + fprintf(stderr, "Trying to set an extension do both IPv4 and IPv6 failed: %d", this_ret); + return(GETDNS_RETURN_GENERIC_ERROR); + } + uint32_t this_response_length; + struct getdns_dict * this_response = NULL; + + /* Make the call */ + getdns_return_t dns_request_return = getdns_general_sync(this_context, this_name, this_request_type, + this_extensions, &this_response_length, this_response); + if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME) + { + fprintf(stderr, "A bad domain name was used: %s. Exiting.", this_name); + return(GETDNS_RETURN_GENERIC_ERROR); + } + else + { + /* Be sure the search returned something */ + uint32_t * this_error = NULL; + this_ret = getdns_dict_get_int(this_response, "status", this_error); // Ignore any error + if (*this_error != GETDNS_RESPSTATUS_GOOD) // If the search didn't return "good" + { + fprintf(stderr, "The search had no results, and a return value of %d. Exiting.", *this_error); + return(GETDNS_RETURN_GENERIC_ERROR); + } + struct getdns_list * just_the_addresses_ptr; + this_ret = getdns_dict_get_list(this_response, "just_address_answers", &just_the_addresses_ptr); // Ignore any error + size_t * num_addresses_ptr = NULL; + this_ret = getdns_list_get_length(just_the_addresses_ptr, num_addresses_ptr); // Ignore any error + /* Go through each record */ + for ( size_t rec_count = 0; rec_count <= *num_addresses_ptr; ++rec_count ) + { + struct getdns_dict * this_address; + this_ret = getdns_list_get_dict(just_the_addresses_ptr, rec_count, &this_address); // Ignore any error + /* Just print the address */ + struct getdns_bindata * this_address_data; + this_ret = getdns_dict_get_bindata(this_address, "address_data", &this_address_data); // Ignore any error + printf("The address is %s", getdns_display_ip_address(this_address_data)); + } + } + /* Clean up */ + getdns_context_destroy(this_context); + getdns_free_sync_request_memory(this_response); + /* Assuming we get here, leave gracefully */ + exit(EXIT_SUCCESS); +} diff --git a/spec/example-tree.c b/spec/example-tree.c new file mode 100644 index 00000000..9bda28ec --- /dev/null +++ b/spec/example-tree.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include +#include + +#define UNUSED_PARAM(x) ((void)(x)) + +/* Set up the callback function, which will also do the processing of the results */ +void this_callbackfn(struct getdns_context_t *this_context, + getdns_return_t this_callback_type, + struct getdns_dict *this_response, + void *this_userarg, + getdns_transaction_t this_transaction_id) +{ + UNUSED_PARAM(this_userarg); /* Not looking at the userarg for this example */ + UNUSED_PARAM(this_context); /* Not looking at the context for this example */ + getdns_return_t this_ret; /* Holder for all function returns */ + if (this_callback_type == GETDNS_CALLBACK_COMPLETE) /* This is a callback with data */ + { + /* Be sure the search returned something */ + uint32_t * this_error = NULL; + this_ret = getdns_dict_get_int(this_response, "status", this_error); // Ignore any error + if (*this_error != GETDNS_RESPSTATUS_GOOD) // If the search didn't return "good" + { + fprintf(stderr, "The search had no results, and a return value of %d. Exiting.", *this_error); + return; + } + /* Find all the answers returned */ + struct getdns_list * these_answers; + this_ret = getdns_dict_get_list(this_response, "replies-tree", &these_answers); + if (this_ret == GETDNS_RETURN_NO_SUCH_DICT_NAME) + { + fprintf(stderr, "Weird: the response had no error, but also no replies-tree. Exiting."); + return; + } + size_t * num_answers_ptr = NULL; + this_ret = getdns_list_get_length(these_answers, num_answers_ptr); + /* Go through each answer */ + for ( size_t rec_count = 0; rec_count <= *num_answers_ptr; ++rec_count ) + { + struct getdns_dict * this_record; + this_ret = getdns_list_get_dict(these_answers, rec_count, &this_record); // Ignore any error + /* Get the answer section */ + struct getdns_list * this_answer; + this_ret = getdns_dict_get_list(this_record, "answer", &this_answer); // Ignore any error + /* Get each RR in the answer section */ + size_t * num_rrs_ptr = NULL; + this_ret = getdns_list_get_length(this_answer, num_rrs_ptr); + for ( size_t rr_count = 0; rr_count <= *num_rrs_ptr; ++rr_count ) + { + struct getdns_dict * this_rr = NULL; + this_ret = getdns_list_get_dict(this_answer, rr_count, &this_rr); // Ignore any error + /* Get the RDATA */ + struct getdns_dict * this_rdata = NULL; + this_ret = getdns_dict_get_dict(this_rr, "rdata", &this_rdata); // Ignore any error + /* Get the RDATA type */ + uint32_t * this_type = NULL; + this_ret = getdns_dict_get_int(this_rdata, "type", this_type); // Ignore any error + /* If it is type A or AAAA, print the value */ + if (*this_type == GETDNS_RRTYPE_A) + { + struct getdns_bindata * this_a_record = NULL; + this_ret = getdns_dict_get_bindata(this_rdata, "ipv4_address", &this_a_record); + if (this_ret == GETDNS_RETURN_NO_SUCH_DICT_NAME) + { + fprintf(stderr, "Weird: the A record at %d in record at %d had no address. Exiting.", + (int) rr_count, (int) rec_count); + return; + } + printf("The IPv4 address is %s", getdns_display_ip_address(this_a_record)); + } + else if (*this_type == GETDNS_RRTYPE_AAAA) + { + struct getdns_bindata * this_aaaa_record = NULL; + this_ret = getdns_dict_get_bindata(this_rdata, "ipv6_address", &this_aaaa_record); + if (this_ret == GETDNS_RETURN_NO_SUCH_DICT_NAME) + { + fprintf(stderr, "Weird: the AAAA record at %d in record at %d had no address. Exiting.", + (int) rr_count, (int) rec_count); + return; + } + printf("The IPv6 address is %s", getdns_display_ip_address(this_aaaa_record)); + } + } + } + } + else if (this_callback_type == GETDNS_CALLBACK_CANCEL) + fprintf(stderr, "The callback with ID %"PRIu64" was cancelled. Exiting.", this_transaction_id); + else + fprintf(stderr, "The callback got a callback_type of %d. Exiting.", this_callback_type); +} + +int main() +{ + /* Create the DNS context for this call */ + struct getdns_context_t *this_context = NULL; + getdns_return_t context_create_return = getdns_context_create(&this_context, true); + if (context_create_return != GETDNS_RETURN_GOOD) + { + fprintf(stderr, "Trying to create the context failed: %d", context_create_return); + return(GETDNS_RETURN_GENERIC_ERROR); + } + /* Create an event base and put it in the context using the unknown function name */ + struct event_base *this_event_base; + this_event_base = event_base_new(); + if (this_event_base == NULL) + { + fprintf(stderr, "Trying to create the event base failed."); + return(GETDNS_RETURN_GENERIC_ERROR); + } + (void)getdns_extension_set_libevent_base(this_context, this_event_base); + /* Set up the getdns call */ + const char * this_name = "www.example.com"; + char* this_userarg = "somestring"; // Could add things here to help identify this call + getdns_transaction_t this_transaction_id = 0; + + /* Make the call */ + getdns_return_t dns_request_return = getdns_address(this_context, this_name, + NULL, this_userarg, &this_transaction_id, this_callbackfn); + if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME) + { + fprintf(stderr, "A bad domain name was used: %s. Exiting.", this_name); + return(GETDNS_RETURN_GENERIC_ERROR); + } + else + { + /* Call the event loop */ + int dispatch_return = event_base_dispatch(this_event_base); + UNUSED_PARAM(dispatch_return); + // TODO: check the return value above + } + /* Clean up */ + getdns_context_destroy(this_context); + /* Assuming we get here, leave gracefully */ + exit(EXIT_SUCCESS); +} diff --git a/spec/getdns_core_only.c b/spec/getdns_core_only.c new file mode 100644 index 00000000..60064440 --- /dev/null +++ b/spec/getdns_core_only.c @@ -0,0 +1,403 @@ +#include + +/* stuff to make it compile pedantically */ +#define UNUSED_PARAM(x) ((void)(x)) + +int main(){ return(0); } + +/* Function definitions */ + +getdns_return_t +getdns_general( + getdns_context_t context, + const char *name, + uint16_t request_type, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callback +) +{ UNUSED_PARAM(context); UNUSED_PARAM(name); UNUSED_PARAM(request_type); UNUSED_PARAM(extensions); UNUSED_PARAM(userarg); +UNUSED_PARAM(transaction_id); UNUSED_PARAM(callback); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_address( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callback +) +{ UNUSED_PARAM(context); UNUSED_PARAM(name); UNUSED_PARAM(extensions); UNUSED_PARAM(userarg); +UNUSED_PARAM(transaction_id); UNUSED_PARAM(callback); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_hostname( + getdns_context_t context, + struct getdns_dict *address, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callback +) +{ UNUSED_PARAM(context); UNUSED_PARAM(address); UNUSED_PARAM(extensions); UNUSED_PARAM(userarg); +UNUSED_PARAM(transaction_id); UNUSED_PARAM(callback); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_service( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callback +) +{ UNUSED_PARAM(context); UNUSED_PARAM(name); UNUSED_PARAM(extensions); UNUSED_PARAM(userarg); +UNUSED_PARAM(transaction_id); UNUSED_PARAM(callback); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_create( + getdns_context_t *context, + bool set_from_os +) +{ UNUSED_PARAM(context); UNUSED_PARAM(set_from_os); return GETDNS_RETURN_GOOD; } + +void +getdns_context_destroy( + getdns_context_t context +) +{ UNUSED_PARAM(context); } + +getdns_return_t +getdns_cancel_callback( + getdns_context_t context, + getdns_transaction_t transaction_id +) +{ UNUSED_PARAM(context); UNUSED_PARAM(transaction_id); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_general_sync( + getdns_context_t context, + const char *name, + uint16_t request_type, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +) +{ UNUSED_PARAM(context); UNUSED_PARAM(name); UNUSED_PARAM(request_type); UNUSED_PARAM(extensions); +UNUSED_PARAM(response_length); UNUSED_PARAM(response); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_address_sync( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +) +{ UNUSED_PARAM(context); UNUSED_PARAM(name); UNUSED_PARAM(extensions); +UNUSED_PARAM(response_length); UNUSED_PARAM(response); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_hostname_sync( + getdns_context_t context, + struct getdns_dict *address, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +) +{ UNUSED_PARAM(context); UNUSED_PARAM(address); UNUSED_PARAM(extensions); +UNUSED_PARAM(response_length); UNUSED_PARAM(response); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_service_sync( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +) +{ UNUSED_PARAM(context); UNUSED_PARAM(name); UNUSED_PARAM(extensions); +UNUSED_PARAM(response_length); UNUSED_PARAM(response); return GETDNS_RETURN_GOOD; } + +void +getdns_free_sync_request_memory( + struct getdns_dict *response +) +{ UNUSED_PARAM(response); } + +getdns_return_t getdns_list_get_length(struct getdns_list *this_list, size_t *answer) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_list_get_data_type(struct getdns_list *this_list, size_t index, getdns_data_type *answer) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_list_get_dict(struct getdns_list *this_list, size_t index, struct getdns_dict **answer) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_list_get_list(struct getdns_list *this_list, size_t index, struct getdns_list **answer) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_list_get_bindata(struct getdns_list *this_list, size_t index, struct getdns_bindata **answer) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_list_get_int(struct getdns_list *this_list, size_t index, uint32_t *answer) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_get_names(struct getdns_dict *this_dict, struct getdns_list **answer) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_get_data_type(struct getdns_dict *this_dict, char *name, getdns_data_type *answer) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_get_dict(struct getdns_dict *this_dict, char *name, struct getdns_dict **answer) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_get_list(struct getdns_dict *this_dict, char *name, struct getdns_list **answer) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_get_bindata(struct getdns_dict *this_dict, char *name, struct getdns_bindata **answer) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_get_int(struct getdns_dict *this_dict, char *name, uint32_t *answer) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(answer); return GETDNS_RETURN_GOOD; } + +struct getdns_list * getdns_list_create() +{ return NULL; } + +void getdns_list_destroy(struct getdns_list *this_list) +{ UNUSED_PARAM(this_list); } + +getdns_return_t getdns_list_set_dict(struct getdns_list *this_list, size_t index, struct getdns_dict *child_dict) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(child_dict); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_list_set_list(struct getdns_list *this_list, size_t index, struct getdns_list *child_list) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(child_list); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_list_set_bindata(struct getdns_list *this_list, size_t index, struct getdns_bindata *child_bindata) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(child_bindata); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_list_set_int(struct getdns_list *this_list, size_t index, uint32_t child_uint32) +{ UNUSED_PARAM(this_list); UNUSED_PARAM(index); UNUSED_PARAM(child_uint32); return GETDNS_RETURN_GOOD; } + +struct getdns_dict * getdns_dict_create() +{ return NULL; } + +void getdns_dict_destroy(struct getdns_dict *this_dict) +{ UNUSED_PARAM(this_dict); } + +getdns_return_t getdns_dict_set_dict(struct getdns_dict *this_dict, char *name, struct getdns_dict *child_dict) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(child_dict); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_set_list(struct getdns_dict *this_dict, char *name, struct getdns_list *child_list) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(child_list); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_set_bindata(struct getdns_dict *this_dict, char *name, struct getdns_bindata *child_bindata) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(child_bindata); return GETDNS_RETURN_GOOD; } + +getdns_return_t getdns_dict_set_int(struct getdns_dict *this_dict, char *name, uint32_t child_uint32) +{ UNUSED_PARAM(this_dict); UNUSED_PARAM(name); UNUSED_PARAM(child_uint32); return GETDNS_RETURN_GOOD; } + +char * +getdns_convert_dns_name_to_fqdn( + char *name_from_dns_response +) +{ UNUSED_PARAM(name_from_dns_response); return NULL; } + +char * +getdns_convert_fqdn_to_dns_name( + char *fqdn_as_string +) +{ UNUSED_PARAM(fqdn_as_string); return NULL; } + +char * +getdns_convert_ulabel_to_alabel( + char *ulabel +) +{ UNUSED_PARAM(ulabel); return NULL; } + +char * +getdns_convert_alabel_to_ulabel( + char *alabel +) +{ UNUSED_PARAM(alabel); return NULL; } + +getdns_return_t +getdns_validate_dnssec( + struct getdns_bindata *record_to_validate, + struct getdns_list *bundle_of_support_records, + struct getdns_list *trust_anchor_rdatas +) +{ UNUSED_PARAM(record_to_validate); UNUSED_PARAM(bundle_of_support_records); UNUSED_PARAM(trust_anchor_rdatas); +return GETDNS_RETURN_GOOD; } + + +char * +getdns_pretty_print_dict( + struct getdns_dict *some_dict +) +{ UNUSED_PARAM(some_dict); return NULL; } + +char * +getdns_display_ip_address( + struct getdns_bindata *bindata_of_ipv4_or_ipv6_address +) +{ UNUSED_PARAM(bindata_of_ipv4_or_ipv6_address); return NULL; } + +getdns_return_t +getdns_context_set_context_update_callback( + getdns_context_t context, + void (*value)(getdns_context_t context, uint16_t changed_item) +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_context_update( + getdns_context_t context, + uint16_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_resolution_type( + getdns_context_t context, + uint16_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_namespaces( + getdns_context_t context, + size_t namespace_count, + uint16_t *namespaces +) +{ UNUSED_PARAM(context); UNUSED_PARAM(namespace_count); UNUSED_PARAM(namespaces); +return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_dns_transport( + getdns_context_t context, + uint16_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_limit_outstanding_queries( + getdns_context_t context, + uint16_t limit +) +{ UNUSED_PARAM(context); UNUSED_PARAM(limit); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_timeout( + getdns_context_t context, + uint16_t timeout +) +{ UNUSED_PARAM(context); UNUSED_PARAM(timeout); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_follow_redirects( + getdns_context_t context, + uint16_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_dns_root_servers( + getdns_context_t context, + struct getdns_list *addresses +) +{ UNUSED_PARAM(context); UNUSED_PARAM(addresses); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_append_name( + getdns_context_t context, + uint16_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_suffix( + getdns_context_t context, + struct getdns_list *value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_dnssec_trust_anchors( + getdns_context_t context, + struct getdns_list *value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_dnssec_allowed_skew( + getdns_context_t context, + uint16_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_stub_resolution( + getdns_context_t context, + struct getdns_list *upstream_list +) +{ UNUSED_PARAM(context); UNUSED_PARAM(upstream_list); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_edns_maximum_udp_payload_size( + getdns_context_t context, + uint16_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_edns_extended_rcode( + getdns_context_t context, + uint8_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_edns_version( + getdns_context_t context, + uint8_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_edns_do_bit( + getdns_context_t context, + uint8_t value +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_memory_allocator( + getdns_context_t context, + void (*value)(size_t somesize) +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_memory_deallocator( + getdns_context_t context, + void (*value)(void*) +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_context_set_memory_reallocator( + getdns_context_t context, + void (*value)(void*) +) +{ UNUSED_PARAM(context); UNUSED_PARAM(value); return GETDNS_RETURN_GOOD; } + +getdns_return_t +getdns_extension_set_libevent_base( + getdns_context_t context, + struct event_base *this_event_base +) +{ UNUSED_PARAM(context); UNUSED_PARAM(this_event_base); return GETDNS_RETURN_GOOD; } + diff --git a/spec/getdns_core_only.h b/spec/getdns_core_only.h new file mode 100644 index 00000000..33d3bd32 --- /dev/null +++ b/spec/getdns_core_only.h @@ -0,0 +1,558 @@ +/* Created at 2013-04-02-16-59-04*/ +#ifndef GETDNS_H +#define GETDNS_H + +#include +#include +#include +#include + +#define GETDNS_COMPILATION_COMMENT The API implementation should fill in something here, such as a compilation version string and date, and change it each time the API is compiled. + +/* Return values */ +#define GETDNS_RETURN_GOOD 0 +#define GETDNS_RETURN_GOOD_TEXT Good +#define GETDNS_RETURN_GENERIC_ERROR 1 +#define GETDNS_RETURN_GENERIC_ERROR_TEXT Generic error +#define GETDNS_RETURN_BAD_DOMAIN_NAME 300 +#define GETDNS_RETURN_BAD_DOMAIN_NAME_TEXT Badly-formed domain name in first argument +#define GETDNS_RETURN_BAD_CONTEXT 301 +#define GETDNS_RETURN_BAD_CONTEXT_TEXT Bad value for a context type +#define GETDNS_RETURN_CONTEXT_UPDATE_FAIL 302 +#define GETDNS_RETURN_CONTEXT_UPDATE_FAIL_TEXT Did not update the context +#define GETDNS_RETURN_UNKNOWN_TRANSACTION 303 +#define GETDNS_RETURN_UNKNOWN_TRANSACTION_TEXT An attempt was made to cancel a callback with a transaction_id that is not recognized +#define GETDNS_RETURN_NO_SUCH_LIST_ITEM 304 +#define GETDNS_RETURN_NO_SUCH_LIST_ITEM_TEXT A helper function for lists had an index argument that was too high. +#define GETDNS_RETURN_NO_SUCH_DICT_NAME 305 +#define GETDNS_RETURN_NO_SUCH_DICT_NAME_TEXT A helper function for dicts had a name argument that for a name that is not in the dict. +#define GETDNS_RETURN_WRONG_TYPE_REQUESTED 306 +#define GETDNS_RETURN_WRONG_TYPE_REQUESTED_TEXT A helper function was supposed to return a certain type for an item, but the wrong type was given. +#define GETDNS_RETURN_NO_SUCH_EXTENSION 307 +#define GETDNS_RETURN_NO_SUCH_EXTENSION_TEXT A name in the extensions dict is not a valid extension. +#define GETDNS_RETURN_EXTENSION_MISFORMAT 308 +#define GETDNS_RETURN_EXTENSION_MISFORMAT_TEXT One or more of the extensions is has a bad format. +#define GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED 309 +#define GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED_TEXT A query was made with a context that is using stub resolution and a DNSSEC extension specified. + +/* DNSSEC values */ +#define GETDNS_DNSSEC_SECURE 400 +#define GETDNS_DNSSEC_SECURE_TEXT The record was determined to be secure in DNSSEC +#define GETDNS_DNSSEC_BOGUS 401 +#define GETDNS_DNSSEC_BOGUS_TEXT The record was determined to be bogus in DNSSEC +#define GETDNS_DNSSEC_INDETERMINATE 402 +#define GETDNS_DNSSEC_INDETERMINATE_TEXT The record was not determined to be any state in DNSSEC +#define GETDNS_DNSSEC_INSECURE 403 +#define GETDNS_DNSSEC_INSECURE_TEXT The record was determined to be insecure in DNSSEC +#define GETDNS_DNSSEC_NOT_PERFORMED 404 +#define GETDNS_DNSSEC_NOT_PERFORMED_TEXT DNSSEC validation was not performed (only used for debugging) + +/* Context Variables */ +#define GETDNS_CONTEXT_NAMESPACE_DNS 500 +#define GETDNS_CONTEXT_NAMESPACE_DNS_TEXT See getdns_context_set_namespaces() +#define GETDNS_CONTEXT_NAMESPACE_LOCALNAMES 501 +#define GETDNS_CONTEXT_NAMESPACE_LOCALNAMES_TEXT See getdns_context_set_namespaces() +#define GETDNS_CONTEXT_NAMESPACE_NETBIOS 502 +#define GETDNS_CONTEXT_NAMESPACE_NETBIOS_TEXT See getdns_context_set_namespaces() +#define GETDNS_CONTEXT_NAMESPACE_MDNS 503 +#define GETDNS_CONTEXT_NAMESPACE_MDNS_TEXT See getdns_context_set_namespaces() +#define GETDNS_CONTEXT_NAMESPACE_NIS 504 +#define GETDNS_CONTEXT_NAMESPACE_NIS_TEXT See getdns_context_set_namespaces() +#define GETDNS_CONTEXT_STUB 505 +#define GETDNS_CONTEXT_STUB_TEXT See getdns_context_set_resolution_type() +#define GETDNS_CONTEXT_RECURSING 506 +#define GETDNS_CONTEXT_RECURSING_TEXT See getdns_context_set_resolution_type() +#define GETDNS_CONTEXT_FOLLOW_REDIRECTS 507 +#define GETDNS_CONTEXT_FOLLOW_REDIRECTS_TEXT See getdns_context_set_follow_redirects() +#define GETDNS_CONTEXT_DO_NOT_FOLLOW_REDIRECTS 508 +#define GETDNS_CONTEXT_DO_NOT_FOLLOW_REDIRECTS_TEXT See getdns_context_set_follow_redirects() +#define GETDNS_CONTEXT_UDP_FIRST_AND_FALL_BACK_TO_TCP 509 +#define GETDNS_CONTEXT_UDP_FIRST_AND_FALL_BACK_TO_TCP_TEXT See getdns_context_set_use_udp_tcp() +#define GETDNS_CONTEXT_UDP_ONLY 510 +#define GETDNS_CONTEXT_UDP_ONLY_TEXT See getdns_context_set_use_udp_tcp() +#define GETDNS_CONTEXT_TCP_ONLY 511 +#define GETDNS_CONTEXT_TCP_ONLY_TEXT See getdns_context_set_use_udp_tcp() +#define GETDNS_CONTEXT_TCP_ONLY_KEEP_CONNECTIONS_OPEN 512 +#define GETDNS_CONTEXT_TCP_ONLY_KEEP_CONNECTIONS_OPEN_TEXT See getdns_context_set_use_udp_tcp() +#define GETDNS_CONTEXT_APPEND_NAME_ALWAYS 513 +#define GETDNS_CONTEXT_APPEND_NAME_ALWAYS_TEXT See getdns_context_set_append_name() +#define GETDNS_CONTEXT_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE 514 +#define GETDNS_CONTEXT_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE_TEXT See getdns_context_set_append_name() +#define GETDNS_CONTEXT_GETDNS_CONTEXT_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE 515 +#define GETDNS_CONTEXT_GETDNS_CONTEXT_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE_TEXT See getdns_context_set_append_name() +#define GETDNS_CONTEXT_DO_NOT_APPEND_NAMES 516 +#define GETDNS_CONTEXT_DO_NOT_APPEND_NAMES_TEXT See getdns_context_set_append_name() + +/* Context codes */ +#define GETDNS_CONTEXT_CODE_NAMESPACES 600 +#define GETDNS_CONTEXT_CODE_NAMESPACES_TEXT Change related to getdns_context_set_namespaces +#define GETDNS_CONTEXT_CODE_RESOLUTION_TYPE 601 +#define GETDNS_CONTEXT_CODE_RESOLUTION_TYPE_TEXT Change related to getdns_context_set_resolution_type +#define GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS 602 +#define GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS_TEXT Change related to getdns_context_set_follow_redirects +#define GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS 603 +#define GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS_TEXT Change related to getdns_context_set_upstream_recursive_servers +#define GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS 604 +#define GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS_TEXT Change related to getdns_context_set_dns_root_servers +#define GETDNS_CONTEXT_CODE_USE_UDP_TCP 605 +#define GETDNS_CONTEXT_CODE_USE_UDP_TCP_TEXT Change related to getdns_context_set_use_udp_tcp +#define GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES 606 +#define GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES_TEXT Change related to getdns_context_set_limit_outstanding_queries +#define GETDNS_CONTEXT_CODE_APPEND_NAME 607 +#define GETDNS_CONTEXT_CODE_APPEND_NAME_TEXT Change related to getdns_context_set_append_name +#define GETDNS_CONTEXT_CODE_SUFFIX 608 +#define GETDNS_CONTEXT_CODE_SUFFIX_TEXT Change related to getdns_context_set_suffix +#define GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS 609 +#define GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS_TEXT Change related to getdns_context_set_dnssec_trust_anchors +#define GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE 610 +#define GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE_TEXT Change related to getdns_context_set_edns_maximum_udp_payload_size +#define GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE 611 +#define GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE_TEXT Change related to getdns_context_set_edns_extended_rcode +#define GETDNS_CONTEXT_CODE_EDNS_VERSION 612 +#define GETDNS_CONTEXT_CODE_EDNS_VERSION_TEXT Change related to getdns_context_set_edns_version +#define GETDNS_CONTEXT_CODE_EDNS_DO_BIT 613 +#define GETDNS_CONTEXT_CODE_EDNS_DO_BIT_TEXT Change related to getdns_context_set_edns_do_bit +#define GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW 614 +#define GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW_TEXT Change related to getdns_context_set_dnssec_allowed_skew +#define GETDNS_CONTEXT_CODE_MEMORY_ALLOCATOR 615 +#define GETDNS_CONTEXT_CODE_MEMORY_ALLOCATOR_TEXT Change related to getdns_context_set_memory_allocator +#define GETDNS_CONTEXT_CODE_MEMORY_DEALLOCATOR 616 +#define GETDNS_CONTEXT_CODE_MEMORY_DEALLOCATOR_TEXT Change related to getdns_context_set_memory_deallocator +#define GETDNS_CONTEXT_CODE_MEMORY_REALLOCATOR 617 +#define GETDNS_CONTEXT_CODE_MEMORY_REALLOCATOR_TEXT Change related to getdns_context_set_memory_reallocator + +/* Callback Type Variables */ +#define GETDNS_CALLBACK_COMPLETE 700 +#define GETDNS_CALLBACK_COMPLETE_TEXT The response has the requested data in it +#define GETDNS_CALLBACK_CANCEL 701 +#define GETDNS_CALLBACK_CANCEL_TEXT The calling program cancelled the callback; response is NULL +#define GETDNS_CALLBACK_TIMEOUT 702 +#define GETDNS_CALLBACK_TIMEOUT_TEXT The requested action timed out; response is NULL +#define GETDNS_CALLBACK_ERROR 703 +#define GETDNS_CALLBACK_ERROR_TEXT The requested action had an error; response is NULL + +/* Type Of Name Services */ +#define GETDNS_NAMETYPE_DNS 800 +#define GETDNS_NAMETYPE_DNS_TEXT Normal DNS (RFC 1035) +#define GETDNS_NAMETYPE_WINS 801 +#define GETDNS_NAMETYPE_WINS_TEXT The WINS name service (some reference needed) + +/* Status Codes for Responses */ +#define GETDNS_RESPSTATUS_GOOD 900 +#define GETDNS_RESPSTATUS_GOOD_TEXT At least one response was returned +#define GETDNS_RESPSTATUS_NO_NAME 901 +#define GETDNS_RESPSTATUS_NO_NAME_TEXT Queries for the name yielded all negative responses +#define GETDNS_RESPSTATUS_ALL_TIMEOUT 902 +#define GETDNS_RESPSTATUS_ALL_TIMEOUT_TEXT All queries for the name timed out +#define GETDNS_RESPSTATUS_NO_SECURE_ANSWERS 903 +#define GETDNS_RESPSTATUS_NO_SECURE_ANSWERS_TEXT The context setting for getting only secure responses was specified, and at least one DNS response was received, but no DNS response was determined to be secure through DNSSEC. + +/* Values Associated With Extensions */ +#define GETDNS_EXTENSION_TRUE 1000 +#define GETDNS_EXTENSION_TRUE_TEXT Turn on the extension +#define GETDNS_EXTENSION_FALSE 1001 +#define GETDNS_EXTENSION_FALSE_TEXT Do not turn on the extension + +/* Values Associated With DNS Errors Found By The API */ +#define GETDNS_BAD_DNS_CNAME_IN_TARGET 1100 +#define GETDNS_BAD_DNS_CNAME_IN_TARGET_TEXT A DNS query type that does not allow a target to be a CNAME pointed to a CNAME +#define GETDNS_BAD_DNS_ALL_NUMERIC_LABEL 1101 +#define GETDNS_BAD_DNS_ALL_NUMERIC_LABEL_TEXT One or more labels in a returned domain name is all-numeric; this is not legal for a hostname +#define GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE 1102 +#define GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE_TEXT A DNS query for a type other than CNAME returned a CNAME response + +/* Defines for RRtypes (from 2012-12) */ + +#define GETDNS_RRTYPE_A 1 +#define GETDNS_RRTYPE_NS 2 +#define GETDNS_RRTYPE_MD 3 +#define GETDNS_RRTYPE_MF 4 +#define GETDNS_RRTYPE_CNAME 5 +#define GETDNS_RRTYPE_SOA 6 +#define GETDNS_RRTYPE_MB 7 +#define GETDNS_RRTYPE_MG 8 +#define GETDNS_RRTYPE_MR 9 +#define GETDNS_RRTYPE_NULL 10 +#define GETDNS_RRTYPE_WKS 11 +#define GETDNS_RRTYPE_PTR 12 +#define GETDNS_RRTYPE_HINFO 13 +#define GETDNS_RRTYPE_MINFO 14 +#define GETDNS_RRTYPE_MX 15 +#define GETDNS_RRTYPE_TXT 16 +#define GETDNS_RRTYPE_RP 17 +#define GETDNS_RRTYPE_AFSDB 18 +#define GETDNS_RRTYPE_X25 19 +#define GETDNS_RRTYPE_ISDN 20 +#define GETDNS_RRTYPE_RT 21 +#define GETDNS_RRTYPE_NSAP 22 +#define GETDNS_RRTYPE_SIG 24 +#define GETDNS_RRTYPE_KEY 25 +#define GETDNS_RRTYPE_PX 26 +#define GETDNS_RRTYPE_GPOS 27 +#define GETDNS_RRTYPE_AAAA 28 +#define GETDNS_RRTYPE_LOC 29 +#define GETDNS_RRTYPE_NXT 30 +#define GETDNS_RRTYPE_EID 31 +#define GETDNS_RRTYPE_NIMLOC 32 +#define GETDNS_RRTYPE_SRV 33 +#define GETDNS_RRTYPE_ATMA 34 +#define GETDNS_RRTYPE_NAPTR 35 +#define GETDNS_RRTYPE_KX 36 +#define GETDNS_RRTYPE_CERT 37 +#define GETDNS_RRTYPE_A6 38 +#define GETDNS_RRTYPE_DNAME 39 +#define GETDNS_RRTYPE_SINK 40 +#define GETDNS_RRTYPE_OPT 41 +#define GETDNS_RRTYPE_APL 42 +#define GETDNS_RRTYPE_DS 43 +#define GETDNS_RRTYPE_SSHFP 44 +#define GETDNS_RRTYPE_IPSECKEY 45 +#define GETDNS_RRTYPE_RRSIG 46 +#define GETDNS_RRTYPE_NSEC 47 +#define GETDNS_RRTYPE_DNSKEY 48 +#define GETDNS_RRTYPE_DHCID 49 +#define GETDNS_RRTYPE_NSEC3 50 +#define GETDNS_RRTYPE_NSEC3PARAM 51 +#define GETDNS_RRTYPE_TLSA 52 +#define GETDNS_RRTYPE_HIP 55 +#define GETDNS_RRTYPE_NINFO 56 +#define GETDNS_RRTYPE_RKEY 57 +#define GETDNS_RRTYPE_TALINK 58 +#define GETDNS_RRTYPE_CDS 59 +#define GETDNS_RRTYPE_SPF 99 +#define GETDNS_RRTYPE_UINFO 100 +#define GETDNS_RRTYPE_UID 101 +#define GETDNS_RRTYPE_GID 102 +#define GETDNS_RRTYPE_UNSPEC 103 +#define GETDNS_RRTYPE_NID 104 +#define GETDNS_RRTYPE_L32 105 +#define GETDNS_RRTYPE_L64 106 +#define GETDNS_RRTYPE_LP 107 +#define GETDNS_RRTYPE_TKEY 249 +#define GETDNS_RRTYPE_TSIG 250 +#define GETDNS_RRTYPE_IXFR 251 +#define GETDNS_RRTYPE_AXFR 252 +#define GETDNS_RRTYPE_MAILB 253 +#define GETDNS_RRTYPE_MAILA 254 +#define GETDNS_RRTYPE_URI 256 +#define GETDNS_RRTYPE_CAA 257 +#define GETDNS_RRTYPE_TA 32768 +#define GETDNS_RRTYPE_DLV 32769 + +/* Various typedefs */ +typedef struct getdns_context_t *getdns_context_t; +typedef uint16_t getdns_return_t; +typedef uint64_t getdns_transaction_t; +typedef enum some_data_type { + t_dict, t_list, t_int, t_bindata +} getdns_data_type; +typedef struct getdns_bindata { + size_t size; + uint8_t *binary_stuff; +} some_bindata; +typedef struct getdns_dict some_dict; +typedef struct getdns_list some_list; + +/* Helper functions for data structures */ + +/* Lists: get the length, get the data_type of the value at a given + position, and get the data at a given position */ +getdns_return_t getdns_list_get_length(struct getdns_list *this_list, size_t *answer); +getdns_return_t getdns_list_get_data_type(struct getdns_list *this_list, size_t index, getdns_data_type *answer); +getdns_return_t getdns_list_get_dict(struct getdns_list *this_list, size_t index, struct getdns_dict **answer); +getdns_return_t getdns_list_get_list(struct getdns_list *this_list, size_t index, struct getdns_list **answer); +getdns_return_t getdns_list_get_bindata(struct getdns_list *this_list, size_t index, struct getdns_bindata **answer); +getdns_return_t getdns_list_get_int(struct getdns_list *this_list, size_t index, uint32_t *answer); + +/* Dicts: get the list of names, get the data_type of the + value at a given name, and get the data at a given name */ +getdns_return_t getdns_dict_get_names(struct getdns_dict *this_dict, struct getdns_list **answer); +getdns_return_t getdns_dict_get_data_type(struct getdns_dict *this_dict, char *name, getdns_data_type *answer); +getdns_return_t getdns_dict_get_dict(struct getdns_dict *this_dict, char *name, struct getdns_dict **answer); +getdns_return_t getdns_dict_get_list(struct getdns_dict *this_dict, char *name, struct getdns_list **answer); +getdns_return_t getdns_dict_get_bindata(struct getdns_dict *this_dict, char *name, struct getdns_bindata **answer); +getdns_return_t getdns_dict_get_int(struct getdns_dict *this_dict, char *name, uint32_t *answer); + + +/* Lists: create, destroy, and set the data at a given position */ +struct getdns_list * getdns_list_create(); +void getdns_list_destroy(struct getdns_list *this_list); +getdns_return_t getdns_list_set_dict(struct getdns_list *this_list, size_t index, struct getdns_dict *child_dict); +getdns_return_t getdns_list_set_list(struct getdns_list *this_list, size_t index, struct getdns_list *child_list); +getdns_return_t getdns_list_set_bindata(struct getdns_list *this_list, size_t index, struct getdns_bindata *child_bindata); +getdns_return_t getdns_list_set_int(struct getdns_list *this_list, size_t index, uint32_t child_uint32); + +/* Dicts: create, destroy, and set the data at a given name */ +struct getdns_dict * getdns_dict_create(); +void getdns_dict_destroy(struct getdns_dict *this_dict); +getdns_return_t getdns_dict_set_dict(struct getdns_dict *this_dict, char *name, struct getdns_dict *child_dict); +getdns_return_t getdns_dict_set_list(struct getdns_dict *this_dict, char *name, struct getdns_list *child_list); +getdns_return_t getdns_dict_set_bindata(struct getdns_dict *this_dict, char *name, struct getdns_bindata *child_bindata); +getdns_return_t getdns_dict_set_int(struct getdns_dict *this_dict, char *name, uint32_t child_uint32); + +/* Callback arguments */ +typedef void (*getdns_callback_t)( + getdns_context_t context, + uint16_t callback_type, + struct getdns_dict *response, + void *userarg, + getdns_transaction_t transaction_id); + +/* Function definitions */ + +getdns_return_t +getdns_general( + getdns_context_t context, + const char *name, + uint16_t request_type, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn +); +getdns_return_t +getdns_address( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn +); +getdns_return_t +getdns_hostname( + getdns_context_t context, + struct getdns_dict *address, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn +); +getdns_return_t +getdns_service( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn +); + +getdns_return_t +getdns_context_create( + getdns_context_t *context, + bool set_from_os +); + +void +getdns_context_destroy( + getdns_context_t context +); + +getdns_return_t +getdns_cancel_callback( + getdns_context_t context, + getdns_transaction_t transaction_id +); + +getdns_return_t +getdns_general_sync( + getdns_context_t context, + const char *name, + uint16_t request_type, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +); + +getdns_return_t +getdns_address_sync( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +); + +getdns_return_t +getdns_hostname_sync( + getdns_context_t context, + struct getdns_dict *address, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +); + +getdns_return_t +getdns_service_sync( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +); + +void +getdns_free_sync_request_memory( + struct getdns_dict *response +); + +char * +getdns_convert_dns_name_to_fqdn( + char *name_from_dns_response +); + +char * +getdns_convert_fqdn_to_dns_name( + char *fqdn_as_string +); + +char * +getdns_convert_ulabel_to_alabel( + char *ulabel +); + +char * +getdns_convert_alabel_to_ulabel( + char *alabel +); + +getdns_return_t +getdns_validate_dnssec( + struct getdns_bindata *record_to_validate, + struct getdns_list *bundle_of_support_records, + struct getdns_list *trust_anchor_rdatas +); + +char * +getdns_pretty_print_dict( + struct getdns_dict *some_dict +); + +char * +getdns_display_ip_address( + struct getdns_bindata *bindata_of_ipv4_or_ipv6_address +); + +getdns_return_t +getdns_context_set_context_update_callback( + getdns_context_t context, + void (*value)(getdns_context_t context, uint16_t changed_item) +); + +getdns_return_t +getdns_context_set_resolution_type( + getdns_context_t context, + uint16_t value +); + +getdns_return_t +getdns_context_set_namespaces( + getdns_context_t context, + size_t namespace_count, + uint16_t *namespaces +); + +getdns_return_t +getdns_context_set_dns_transport( + getdns_context_t context, + uint16_t value +); + +getdns_return_t +getdns_context_set_limit_outstanding_queries( + getdns_context_t context, + uint16_t limit +); + +getdns_return_t +getdns_context_set_timeout( + getdns_context_t context, + uint16_t timeout +); + +getdns_return_t +getdns_context_set_follow_redirects( + getdns_context_t context, + uint16_t value +); + +getdns_return_t +getdns_context_set_dns_root_servers( + getdns_context_t context, + struct getdns_list *addresses +); + +getdns_return_t +getdns_context_set_append_name( + getdns_context_t context, + uint16_t value +); + +getdns_return_t +getdns_context_set_suffix( + getdns_context_t context, + struct getdns_list *value +); + +getdns_return_t +getdns_context_set_dnssec_trust_anchors( + getdns_context_t context, + struct getdns_list *value +); + +getdns_return_t +getdns_context_set_dnssec_allowed_skew( + getdns_context_t context, + uint16_t value +); + +getdns_return_t +getdns_context_set_stub_resolution( + getdns_context_t context, + struct getdns_list *upstream_list +); + +getdns_return_t +getdns_context_set_edns_maximum_udp_payload_size( + getdns_context_t context, + uint16_t value +); + +getdns_return_t +getdns_context_set_edns_extended_rcode( + getdns_context_t context, + uint8_t value +); + +getdns_return_t +getdns_context_set_edns_version( + getdns_context_t context, + uint8_t value +); + +getdns_return_t +getdns_context_set_edns_do_bit( + getdns_context_t context, + uint8_t value +); + +getdns_return_t +getdns_context_set_memory_allocator( + getdns_context_t context, + void (*value)(size_t somesize) +); + +getdns_return_t +getdns_context_set_memory_deallocator( + getdns_context_t context, + void (*value)(void*) +); + +getdns_return_t +getdns_context_set_memory_reallocator( + getdns_context_t context, + void (*value)(void*) +); + +#endif /* GETDNS_H */ diff --git a/spec/getdns_libevent.h b/spec/getdns_libevent.h new file mode 100644 index 00000000..fd9effce --- /dev/null +++ b/spec/getdns_libevent.h @@ -0,0 +1,9 @@ +#include +#include + +/* For libevent, which we are using for these examples */ +getdns_return_t +getdns_extension_set_libevent_base( + getdns_context_t context, + struct event_base *this_event_base +); diff --git a/spec/index.html b/spec/index.html new file mode 100644 index 00000000..99c6218c --- /dev/null +++ b/spec/index.html @@ -0,0 +1,2182 @@ + +DNS API Description + + + + + +

Description of the getdns API

+

Paul Hoffman, Editor

+

Document version: "getdns April 2013"

+ +

This document describes a modern asynchronous DNS API. This new API is intended to be useful to +application developers and operating system distributors as a way of making +all types of DNS information easily available in many types of programs. The major features +of this new API are:

+ +
    +
  • Full support for event-driven programming
  • +
  • Supports DNSSEC in multiple ways
  • +
  • Mirroring of the resolution in getaddrinfo()
  • +
  • Easily supports all RRtypes, even those yet to be defined
  • +
+ +

There is more background into the design and future goals of this API +later in this document.

+ +

This document was discussed on the +getdns-api mailing list; future versions of the API might be discussed there as well. +(If you +want to contact the editor off-list, please send mail to paul.hoffman@vpnc.org.)

+ +

1. The getdns Async Functions

+ +

The API has four async functions:

+ +
    + +
  • getdns_address for doing getaddrinfo()-like address lookups
  • + +
  • getdns_hostname for doing getnameinfo()-like name lookups
  • + +
  • getdns_service for getting results from SRV lookups
  • + +
  • getdns_general for looking up any type of DNS record
  • + +
+ +

1.1 getdns_general()

+ +
getdns_return_t +getdns_general( + getdns_context_t context, + const char *name, + uint16_t request_type, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn +); +
+ +

context

+

A pointer to the DNS context that is to be used with this call. DNS contexts are +described later in this document. Note that a context must be created +before calling the function.

+ +

*name

+

The ASCII-based domain name to be looked up as a string. This can also be +an IPv4 or IPv6 address for request types that take addresses instead of domain names, +such as PTR. The values here follow the rules in section 2.1 of RFC 4343 +to allow non-ASCII octets and special characters in labels.

+ +

request_type

+

Specifies the RRtype for the query; the RRtype numbers are listed in the IANA +registry. For example, to get the NS records, request_type would be 2. The API also has +defined macros for most of the RRtypes by name; the definition names all start with +"GETDNS_RRTYPE_". For example, to get the NS records, you can also set the +request_type to GETDNS_RRTYPE_NS. +(The full list of request types is always +here.)

+ +

*extensions

+

Specifies the extensions for this request; the value may be NULL if there are no +extensions. See the section below for information on how to specify +the extensions used for a request.

+ +

*userarg

+

A void* that is passed to the function, which the funciton +returns to the callback function untouched. userarg can be used by the callback +function for any user-specific data needed. This can be NULL.

+ +

*transaction_id

+

A pointer to a value that is filled in by the +function to identify the callback being made. +This pointer can be NULL, in which case it is ignored and no value is assigned. +The getdns_cancel_callback() function uses the +transaction_id to determine which callback is to be cancelled. +If the function fails, +transaction_id is set to 0.

+ +

*callbackfn

+

A pointer to a callback function that is defined by the application. +Typically, the callback function will do all the processing on the results from +the API. The parameters of the callback are defined below. This really needs +to be a pointer to a function (and not something like NULL); otherwise, the +results are unpredictable.

+ +

The async getdns functions return GETDNS_RETURN_GOOD if the call was properly formatted. +It returns GETDNS_RETURN_BAD_DOMAIN_NAME if the API determines that the name passed to +the function was bad, GETDNS_RETURN_BAD_CONTEXT if the context pointer is bad, +GETDNS_RETURN_NO_SUCH_EXTENSION if one or more extensions do not exist, or +GETDNS_RETURN_EXTENSION_MISFORMAT if the contents of one or more of the +extensions is incorrect. All of the return values are given later in this document.

+ +

1.2 getdns_address()

+ +
getdns_return_t +getdns_address( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn +); +
+ +

There are three critical differences between getdns_address() and +getdns_general() beyond the missing request_type argument:

+ +
    + +
  • In getdns_address(), the name argument can only take a host name.
  • + +
  • You do not need to include a return_both_v4_and_v6 extension with the call in +getdns_address(): it will always return both IPv4 and IPv6 addresses.
  • + +
  • getdns_address() always uses all of namespaces from the context (to better emulate +getaddrinfo()), while getdns_general() only uses the DNS namespace.
  • + +
+ +

1.3 getdns_hostname()

+ +
getdns_return_t +getdns_hostname( + getdns_context_t context, + struct getdns_dict *address, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn +); +
+ +

The address is given as a getdns_dict data structure (defined below). The list must +have two names: address_type (whose value is a bindata; it is currently either "IPv4" +or "IPv6") and address_data (whose value is a bindata).

+ +

1.4 getdns_service()

+ +
getdns_return_t +getdns_service( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + void *userarg, + getdns_transaction_t *transaction_id, + getdns_callback_t callbackfn +); +
+ +

name must be a domain name for an SRV lookup; the call returns the +relevant SRV information for the name.

+ +

1.5 Callback Functions for getdns

+ +

A call to the async getdns functions typically returns before any network or file I/O occurs. After +the API marshalls all the needed information, it calls the callback function that was passed by the +application. The callback function might be called at any time, even before the calling function +has returned. The API guarantees that the callback will be called exactly once unless the calling function +returned an error, in which case the callback function is never called.

+ +

The getdns calling function calls the callback with the parameters defined +as follows:

+
+typedef void (*getdns_callback_t)( + getdns_context_t context, + uint16_t callback_type, + struct getdns_dict *response, + void *userarg, + getdns_transaction_t transaction_id); +
+ +

context

+

The DNS context that was used in the calling function. See below for a description of the basic use of contexts, and later for more advanced use.

+ +

callback_type

+

Supplies the reason for the callback. See below for the codes and reasons.

+ +

*response

+

A response object with the response data. This is described below. The response +object is part of the API's memory space, and will be freed by the API with the callback returns.

+ +

*userarg

+

Identical to the *userarg passed to the calling function.

+ +

transaction_id

+

The transaction identifier that was assigned by the calling function.

+ +

The following are the values for callback_type.

+ +

GETDNS_CALLBACK_COMPLETE

+

The response has the requested data in it

+

GETDNS_CALLBACK_CANCEL

+

The calling program cancelled the callback; response is NULL

+

GETDNS_CALLBACK_TIMEOUT

+

The requested action timed out; response is NULL

+

GETDNS_CALLBACK_ERROR

+

The requested action had an error; response is NULL

+ + +

1.6 Setting Up The DNS Context

+ +

Calls to getdns functions require a DNS context, which is a group of API settings +that affect how DNS calls are made. For most applications, a default context is sufficient.

+ +

To create a new DNS context, use the function:

+ +
getdns_return_t +getdns_context_create( + getdns_context_t *context, + bool set_from_os +); +
+ +

The call to getdns_context_create immediately returns a context that can +be used with other API calls; that context contains the API's default values. Most applications will +want set_from_os set to true.

+ +

To clean up the context, including cleaning up all outstanding transactions that were called +using this context, use the function:

+ +
void +getdns_context_destroy( + getdns_context_t context +); +
+ +

When getdns_context_destroy() returns, the +application knows that all outstanding transactions associated with this +context will have been called; callbacks that had not been called before +getdns_context_destroy() was called will be called with a callback_type of +GETDNS_CALLBACK_CANCEL. getdns_context_destroy() returns after +all of the needed cleanup is done and callbacks are made.

+ +

1.7 Canceling a Callback

+ +

To cancel an outstanding callback, use the following function.

+ +
getdns_return_t +getdns_cancel_callback( + getdns_context_t context, + getdns_transaction_t transaction_id +); +
+ +

This causes the API to call the callback with a callback_type of +GETDNS_CALLBACK_CANCEL if the callback for this transaction_id has not +already been called. The callback code for cancellation should clean up any memory related to the +identified call, such as to deallocate the memory for the userarg. +getdns_cancel_callback() may return immediately, even before the callback finishes its +work and returns. Calling getdns_cancel_callback() with a transaction_id +of a callback that has already been called or an unknown transaction_id returns +GETDNS_RETURN_UNKNOWN_TRANSACTION; otherwise, getdns_cancel_callback() +returns GETDNS_RETURN_GOOD.

+ +

1.8 Event-driven Programs

+ +

Event-driven programs (sometimes called "async programs") require an event +base and event loop (among other things). Different event libraries have +different structures or the event base. Because of this, there is no standard +method to set the event base in the DNS API: those are all added as +extensions. The API is distributed as a core package and one or more sets of +extensions to align with event libraries. It is mandatory to use one of the extension +functions to set the event base in the DNS context; this is required before +calling any event-driven calls like the getdns functions.

+ +

Each implementation of the DNS API will specify an extension function that +tells the DNS context which event base is being used. For example, one +implementation of this API that uses the libevent event library might name +this function "getdns_extension_set_libevent_base()" while +another might name it +"getdns_extension_set_eventbase_for_libevent()"; the two +extension functions could have very different calling patterns and return +values. Thus, the application developer must read the API documentation +(not just this design document) in order to determine what extension function +to use to tell the API the event base to use.

+ +

The structure of a typical event-driven application might look like the following pseudocode. +The code in italics is specific to the event mechanism.

+ +
+Includes for one or more regular C libraries
+An include for the getdns library specific to the event library you use
+Definition of your callback function
+    Get the DNS data from the allocated pointer
+    Process that data
+    Check for errors
+Definition of main()
+    Create context
+    Set up your event base
+    Point the context to your event base
+    Set up the getdns call arguments
+    Make the getdns call
+    Check if the getdns return is good
+    Destroy the context
+    Exit
+
+ +

The API does not have direct support for a polling interface. Instead, the callback interface is +specifically designed to allow an application that wants to process results in polling instead of in +callbacks to be able to create its own polling interface fairly trivially. Such a program would +create a data structure for the calls, including their transaction_id and +userag. The userarg could be the polling data structure or have a pointer to it. +The application would have just +one callback function for all requests, and that function would copy the response into +application memory, update the data structure based on the transaction_id index, +and return from the callback. The polling code could then check the data structure for any updates +at its leisure.

+ +

1.9 Calling the API Synchronously (Without Events)

+ +

Thare are functions parallel to the four getdns async functions, +except that there is no callback. That is, when an application calls one of these +synchronous functions, the +API gathers all the required information and then returns the result. The value returned is exactly the +same as the response returned in the callback if you had used the async version of the function.

+ +
getdns_return_t +getdns_general_sync( + getdns_context_t context, + const char *name, + uint16_t request_type, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +); +
+ +
getdns_return_t +getdns_address_sync( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +); +
+ +
getdns_return_t +getdns_hostname_sync( + getdns_context_t context, + struct getdns_dict *address, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +); +
+ +
getdns_return_t +getdns_service_sync( + getdns_context_t context, + const char *name, + struct getdns_dict *extensions, + uint32_t *response_length, + struct getdns_dict *response +); +
+ +

When you are done with the data in the response, use the following function so that the API can +free the memory from its internal pool.

+ +
void +getdns_free_sync_request_memory( + struct getdns_dict *response +); +
+ +

2. Data structures in the API

+ +

The API returns data structures. The data structure is not a representational language like JSON: +it is really just a data structure. Data structures can have four types of members:

+ +
    + +
  • list is an ordered list, like JSON and Python lists. +The members of the list can be any of the four data types.
  • + +
  • dict is a name-value pair, like a JSON object or Python dict. The +name is a string literal, and the value can be any of the four data types. The order of the +name-value pairs in a dict is not important.
  • + +
  • int is an integer compatible with uint32_t.
  • + +
  • bindata is a struct to hold binary data. It is defined as +{ size_t size; uint8_t *binary_stuff; }.
  • + +
+ +

The API comes with helper functions to get data from the list and dict data types:

+ +
+/* Lists: get the length, get the data_type of the value at a given + position, and get the data at a given position */ +getdns_return_t getdns_list_get_length(struct getdns_list *this_list, size_t *answer); +getdns_return_t getdns_list_get_data_type(struct getdns_list *this_list, size_t index, getdns_data_type *answer); +getdns_return_t getdns_list_get_dict(struct getdns_list *this_list, size_t index, struct getdns_dict **answer); +getdns_return_t getdns_list_get_list(struct getdns_list *this_list, size_t index, struct getdns_list **answer); +getdns_return_t getdns_list_get_bindata(struct getdns_list *this_list, size_t index, struct getdns_bindata **answer); +getdns_return_t getdns_list_get_int(struct getdns_list *this_list, size_t index, uint32_t *answer); + +/* Dicts: get the list of names, get the data_type of the + value at a given name, and get the data at a given name */ +getdns_return_t getdns_dict_get_names(struct getdns_dict *this_dict, struct getdns_list **answer); +getdns_return_t getdns_dict_get_data_type(struct getdns_dict *this_dict, char *name, getdns_data_type *answer); +getdns_return_t getdns_dict_get_dict(struct getdns_dict *this_dict, char *name, struct getdns_dict **answer); +getdns_return_t getdns_dict_get_list(struct getdns_dict *this_dict, char *name, struct getdns_list **answer); +getdns_return_t getdns_dict_get_bindata(struct getdns_dict *this_dict, char *name, struct getdns_bindata **answer); +getdns_return_t getdns_dict_get_int(struct getdns_dict *this_dict, char *name, uint32_t *answer); +
+ +

All of these helper getter functions return GETDNS_RETURN_GOOD if the call is successful. +The list functions will return GETDNS_RETURN_NO_SUCH_LIST_ITEM if the index argument is +out of range; the dict functions will return GETDNS_RETURN_NO_SUCH_DICT_NAME if the name +argument doesn't exist in the dict. The functions also return GETDNS_RETURN_WRONG_TYPE_REQUESTED +if the requested data type doesn't match the contents of the indexed argument or name.

+ +

This document uses graphical representations of data structures. It is important to note that +this is only a graphical representation; the brackets, commas, quotation marks, comments, and so on +are not part of the data. Also, this document uses macro names instead of some of the int +arguments; of course, the data structures have the actual int in them.

+ +

2.1 Creating Data Structures

+ +

Some of the features of the API require that you create your own data structures to be used in +arguments passed to the API. For example, if you want to use any extensions for the calling functions, +you need to create a dict. The requisite functions are:

+ +
+/* Lists: create, destroy, and set the data at a given position */ +struct getdns_list * getdns_list_create(); +void getdns_list_destroy(struct getdns_list *this_list); +getdns_return_t getdns_list_set_dict(struct getdns_list *this_list, size_t index, struct getdns_dict *child_dict); +getdns_return_t getdns_list_set_list(struct getdns_list *this_list, size_t index, struct getdns_list *child_list); +getdns_return_t getdns_list_set_bindata(struct getdns_list *this_list, size_t index, struct getdns_bindata *child_bindata); +getdns_return_t getdns_list_set_int(struct getdns_list *this_list, size_t index, uint32_t child_uint32); + +/* Dicts: create, destroy, and set the data at a given name */ +struct getdns_dict * getdns_dict_create(); +void getdns_dict_destroy(struct getdns_dict *this_dict); +getdns_return_t getdns_dict_set_dict(struct getdns_dict *this_dict, char *name, struct getdns_dict *child_dict); +getdns_return_t getdns_dict_set_list(struct getdns_dict *this_dict, char *name, struct getdns_list *child_list); +getdns_return_t getdns_dict_set_bindata(struct getdns_dict *this_dict, char *name, struct getdns_bindata *child_bindata); +getdns_return_t getdns_dict_set_int(struct getdns_dict *this_dict, char *name, uint32_t child_uint32); +
+ +

These helper setter functions return GETDNS_RETURN_GOOD if the call is successful. +The list functions will return GETDNS_RETURN_NO_SUCH_LIST_ITEM if the index argument is +out of range; the dict functions will return GETDNS_RETURN_NO_SUCH_DICT_NAME if the name +argument doesn't exist in the dict. The functions also return GETDNS_RETURN_WRONG_TYPE_REQUESTED +if the requested data type doesn't match the contents of the indexed argument or name.

+ +

3. Extensions

+ +

Extensions are dict data structures. The names in the dict are the names of the extensions. +The definition of each extension describes the value associated with the name. For most extensions, +it is an on-off boolean, and the value is GETDNS_EXTENSION_TRUE. (There is +not currently a good reason to specify an extension name and give it a value of GETDNS_EXTENSION_FALSE, +but that is allowed by the API.)

+ +

For example, to create a dict for extensions and specify the extension to only return +results that have been validated with DNSSEC, you might use:

+ +
+/* . . . */
+struct getdns_dict * this_extensions = getdns_dict_create();
+this_ret = getdns_dict_set_int(this_extensions, "dnssec_return_only_secure", GETDNS_EXTENSION_TRUE);
+/* . . . Do some processing with the extensions and results . . . */
+/* Remember to clean up memory*/
+getdns_dict_destroy(this_extensions);
+
+ +

The extensions described in this section are are: + +

    + +
  • dnssec_return_status
  • + +
  • dnssec_return_only_secure
  • + +
  • dnssec_return_supporting_responses
  • + +
  • return_both_v4_and_v6
  • + +
  • add_opt_parameters
  • + +
  • add_warning_for_bad_dns
  • + +
  • specify_class
  • + +
  • return_api_information
  • + +
  • return_call_debugging
  • + +
+ +

3.1 Extensions for DNSSEC

+ +

If an application wants the API to do DNSSEC validation for a request, it must set one or more +DNSSEC-related extensions. Note that the default is for none of these extensions to be set and +the API will not perform DNSSEC, and thus will return results sooner.

+ +

To return the DNSSEC status for each DNS record in the replies_tree list, use the +dnssec_return_status extension. The extension's value (an int) is set to +GETDNS_EXTENSION_TRUE to cause the returned status to have the name +dnssec_status (an int) added to the other names in the record's dict ("header", +"question", and so on). The values for that name are GETDNS_DNSSEC_SECURE, +GETDNS_DNSSEC_BOGUS, GETDNS_DNSSEC_INDETERMINATE, and +GETDNS_DNSSEC_INSECURE. Thus, a reply might look like:

+ +
+    {     # This is the first reply
+      "dnssec_status": GETDNS_DNSSEC_INDETERMINATE,
+      "header": { "id": 23456, "qr": 1, "opcode": 0, ... },
+      . . .
+
+ +

If instead of returning the status, you want to only see secure results, use the +dnssec_return_only_secure extension. The extension's value (an int) is set to +GETDNS_EXTENSION_TRUE to cause only records that the API can validate as secure with +DNSSEC to be returned in the replies_tree and replies_full lists. No +additional names are added to the dict of the record; the change is that some records might not +appear in the results. When this context option is set, if the API receives DNS replies but none +are determined to be secure, the error code at the top level of the response object is +GETDNS_RESPSTATUS_NO_SECURE_ANSWERS.

+ +

Applications that want to do their own validation will want to have the DNSSEC-related records +for a particular response. Use the dnssec_return_supporting_responses extension. The +extension's value (an int) is set to GETDNS_EXTENSION_TRUE to cause a set +of additional DNSSEC-related records needed for validation to be returned in the response object. +This set comes as additional_dnssec (a list) at the top level of the response object. +This list includes any trust anchors needed for the validation. Thus, a reply might look like:

+ +
+{     # This is the response object
+  "additional_dnssec": [ <bindata of the first DNSSEC record>, <bindata of the second DNSSEC record> ... ],
+  "replies_tree":
+  [
+  . . .
+
+ +

If a request is using a context in which stub resolution is set, and that request also has +any of the dnssec_return_status, dnssec_return_only_secure, or +dnssec_return_supporting_responses extensions specified, the API will not perform +the request and will instead return an error of GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED.

+ +

3.2 Returning Both IPv4 and IPv6 Responses

+ +

Many applications want to get both IPv4 and IPv6 addresses in a single call so that the results +can be processed together. The getdns_address and getdns_address_sync +functions are able to do this automatically. If you are using the getdns_general or +getdns_general_sync function, you can enable this with the +return_both_v4_and_v6 extension. The extension's value (an int) is set to +GETDNS_EXTENSION_TRUE to cause the results to be the lookup of either A or AAAA records +to include any A and AAAA records for the queried name (otherwise, the extension does nothing). +These results are expected to be used with Happy Eyeballs systems that will find the best socket for +an application.

+ +

3.3 Setting Up OPT Resource Records

+ +

For lookups that need an OPT resource record in the Additional Data section, use the +add_opt_parameters extension. The extension's value (a dict) contains the +parameters; these are described in more detail in RFC 2671. They are:

+ +
    + +
  • maximum_udp_payload_size (an int), a value between 512 and 65535; if not specified, +this defaults to those from the DNS context
  • + +
  • extended_rcode (an int), a value between 0 and 255; if not specified, +this defaults to those from the DNS context
  • + +
  • version (an int), a value between 0 and 255; if not specified, this +defaults to 0
  • + +
  • do_bit (an int), a value between 0 and 1; if not specified, this defaults +to those from the DNS context
  • + +
  • options (a list) contains dicts for each option to be specified. +Each list time contains two names: option_code (an int) and option_data +(a bindata). The API marshalls the entire set of options into a properly-formatted RDATA +for the resource record.
  • + +
+ +

It is very important to note that the OPT resource record specified in the +add_opt_parameters extension might not be the same the one that the API sends in the +query. For example, if the application also includes any of the DNSSEC extensions, the API will make +sure that the OPT resource record sets the resource record appropriately, making the needed changes +to the settings from the add_opt_parameters extension.

+ +

The use of this extension can conflict with the values in the DNS context. For example, +the default for an OS might be a maximum payload size of 65535, but the extension might specify +1550. In such a case, the API will honor the values stated in the extension, but will honor the +values from the DNS context if values are not given in the extension.

+ +

3.4 Getting Warnings for Responses that Violate the DNS Standard

+ +

To receive a warning if a particular response violates some parts of the DNS standard, use +the add_warning_for_bad_dns extension. The extension's value (an int) is set to +GETDNS_EXTENSION_TRUE to cause each reply in the replies_tree +to contain an additional name, bad_dns (a list). The list is zero or more +ints that indicate types of bad DNS found in that reply. The list of values is: + +

GETDNS_BAD_DNS_CNAME_IN_TARGET

+

A DNS query type that does not allow a target to be a CNAME pointed to a CNAME

+

GETDNS_BAD_DNS_ALL_NUMERIC_LABEL

+

One or more labels in a returned domain name is all-numeric; this is not legal for a hostname

+

GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE

+

A DNS query for a type other than CNAME returned a CNAME response

+ + +

3.5 Using Other Class Types

+ +

The vast majority of DNS requests are made with the Internet (IN) class. To make a request in a +different DNS class, use, the specify_class extension. The extension's value (an int) +contains the class number. Few applications will ever use this extension.

+ +

3.6 Extensions Relating to the API

+ +

An application might want to see information about the API itself. Use the +return_api_information extension. An application that wants to get this information +before a "real" query is issued can add this extension to a PTR query for 127.0.0.1. +The extension's value (an int) is set to +GETDNS_EXTENSION_TRUE to add the following to the top level of the response object:

+ +
    + +
  • version_string (a bindata) represents the version string for this version of the DNS +API.
  • + +
  • implementation_string (a bindata) is a string set by the API implementer. It might +be human-readable, and it might have information in it useful to an application developer (but it doesn't +have to).
  • + +
  • resolver_type (an int) is the type of resolver that the API is acting as in this context: +GETDNS_CONTEXT_RECURSING or GETDNS_CONTEXT_STUB (it will be +a recursing resolver unless the application changed this in a context.
  • + +
  • all_context (a dict) with names for all the types of context. This can be used with +getdns_pretty_print_dict() for debugging.
  • + +
+ +

An application might want to see debugging information for queries such as the length of time it +takes for each query to return to the API. Use the return_call_debugging extension. The +extension's value (an int) is set to GETDNS_EXTENSION_TRUE to add the name +call_debugging (a list) to the top level of the response object. Each member of the +list is a dict that represents one call made for the call to the API. Each member has the following +names:

+ +
    +
  • query_name (a bindata) is the name that was sent
  • +
  • query_type (an int) is the type that was queried for
  • +
  • query_to (a bindata) is the address to which the query was sent
  • +
  • start_time (a bindata) is the time the query started in milliseconds since the epoch, +represented as a uint64_t
  • +
  • end_time (a bindata) is the time the query was received in milliseconds since the epoch, +represented as a uint64_t
  • +
  • entire_reply (a bindata) is the entire response received
  • +
  • dnssec_result (an int) is the DNSSEC status, or GETDNS_DNSSEC_NOT_PERFORMED +if DNSSEC validation was not performed
  • +
+ +

4. Response Data from Queries

+ +

The callback function contains a pointer to a response object. +A response object is always a dict. The response +object always contains at least three names: replies_full (a list) and +replies_tree (a list), and status (an int). +replies_full is a list of DNS replies (each is bindata) as they appear on the wire. +replies_tree is a list of DNS replies (each is a dict) with the various part of the +reply parsed out. status is a status code for the query.

+ +

Because the API might be extended in the future, a response object might also contain names other +than replies_full, replies_tree, and status. Similarly, any +of the dicts described here might be extended in later versions of the API. Thus, an application +using the API must not assume that it knows all possible names in a dict.

+ +

The following lists the status codes for response objects. Note that, if the status is that there +are no responses for the query, the lists in replies_full and replies_tree +will have zero length.

+ +

GETDNS_RESPSTATUS_GOOD

+

At least one response was returned

+

GETDNS_RESPSTATUS_NO_NAME

+

Queries for the name yielded all negative responses

+

GETDNS_RESPSTATUS_ALL_TIMEOUT

+

All queries for the name timed out

+

GETDNS_RESPSTATUS_NO_SECURE_ANSWERS

+

The context setting for getting only secure responses was specified, and at least one DNS response was received, but no DNS response was determined to be secure through DNSSEC.

+ + +

The top level of replies_tree can optionally have the following names: canonical_name (a +bindata), intermediate_aliases (a list), answer_ipv4_address (a bindata), +answer_ipv6_address (a bindata), and answer_type (an int).

+ +
    + +
  • The value of canonical_name is the name that the API used for its lookup. It is in +FQDN presentation format.
  • + +
  • The values in the intermediate_aliases list are domain names from any CNAME or +unsynthesized DNAME found when resolving the original query. The list might have zero entries +if there were no CNAMEs in the path. These may be useful, for example, for name comparisons +when following the rules in RFC 6125.
  • + +
  • The value of answer_ipv4_address and answer_ipv6_address are +the addresses of the server from which the answer was received.
  • + +
  • The value of answer_type is the type of name service that generated the response. +The values are:
  • + +
+ +

GETDNS_NAMETYPE_DNS

+

Normal DNS (RFC 1035)

+

GETDNS_NAMETYPE_WINS

+

The WINS name service (some reference needed)

+ + +

If the call was getdns_address or getdns_address_sync, the top level +of replies_tree has an additional name, just_address_answers (a list). +The value of just_address_answers is a list that contains all of the A and AAAA +records from the answer sections of any of the replies, in the order they appear in the replies. +Each item in the list is a dict with at least two names: address_type (whose value is +a bindata; it is currently either "IPv4" or "IPv6") and address_data (whose value is a bindata). +Note that the dnssec_return_only_secure extension affects +what will appear in the just_address_answers list. Also note if later versions of the +DNS return other address types, those types will appear in this list as well.

+ +

The API can make service discovery through SRV records easier. If +the call was getdns_service or getdns_service_sync, +the top level of replies_tree has an additional name, +srv_addresses (a list). +The list is ordered by priority and weight based on the weighting +algorithm in RFC 2782, lowest priority value first. Each element +of the list is dict has at least two names: port and domain_name. If the +API was able to determine the address of the target domain name (such as from its cache or from the +Additional section of responses), the dict for an element will also contain +address_type (whose value is a bindata; it is currently either "IPv4" or "IPv6") and +address_data (whose value is a bindata). Note that the +dnssec_return_only_secure extension affects what will appear in the +srv_addresses list.

+ +

4.1 Structure of DNS replies_tree

+ +

The names in each entry in the the replies_tree list for DNS responses include +header (a dict), question (a dict), answer (a list), +authority (a list), and additional (a list), corresponding to the sections +in the DNS message format. The answer, authority, and additional lists each contain zero or more +dicts, with each dict in each list representing a resource record.

+ +

The names in the header dict are all the fields from Section 4.1.1. of RFC 1035. +They are: id, qr, opcode, aa, tc, +rd, ra, z, rcode, qdcount, +ancount, nscount, and arcount. All are ints.

+ +

The names in the question dict are the three fields from Section 4.1.2. of RFC 1035: +qname (a bindata), qtype (an int), and qclass (an int).

+ +

Resource records are a bit different than headers and question sections in that the RDATA portion +often has its own structure. The other names in the resource record dicts are name (a +bindata), type (an int), class (an int), ttl (an int) and +rdata (a dict); there is no name equivalent to the RDLENGTH field.

+ +

The rdata dict has different names for each response type. There is a complete list of the types defined in the API. For names that end in +"-obsolete" or "-unknown", the bindata is the entire RDATA field. For example, the +rdata for an A record has a name ipv4_address (a bindata); the +rdata for an SRV record has the names priority (an int), +weight (an int), port (an int), and target (a bindata).

+ +

Each rdata dict also has a rdata_raw field (a bindata). This is useful +for types not defined in this version of the API. It also might be of value if a later version of +the API allows for additional parsers. Thus, doing a query for types not known by the API still will +return a result: an rdata with just a rdata_raw.

+ +

It is expected that later extensions to the API will give some DNS types different names. It is +also possible that later extensions will change the names for some of the DNS types listed above.

+ +

For example, a response to a getdns_address() call for www.example.com would +look something like this:

+ +
+{     # This is the response object
+  "replies_full": [ <bindata of the first response>, <bindata of the second response> ],
+  "just_address_answers": [ <bindata of 0x0a0b0c01>, <bindata of 0x33445566334455663344556633445566> ],
+  "canonical_name": <bindata for "www.example.com">,
+  "answer_type": GETDNS_NAMETYPE_DNS,
+  "intermediate_aliases": [],
+  "replies_tree":
+  [
+    {     # This is the first reply
+      "header": { "id": 23456, "qr": 1, "opcode": 0, ... },
+      "question": { "qname": <bindata for "www.example.com">, "qtype": 1, "qclass": 1 },
+      "answer":
+      [
+        {
+          "name": <bindata for "www.example.com">,
+          "type": 1,
+          "class": 1,
+          "ttl": 33000,
+          "rdata":
+          {
+            "ipv4_address": <bindata of 0x0a0b0c01>
+            "rdata_raw": <bindata of 0x0a0b0c01>
+          }
+        }
+      ],
+      "authority":
+      [
+        {
+          "name": <bindata for "ns1.example.com">,
+          "type": 1,
+          "class": 1,
+          "ttl": 600,
+          "rdata":
+          {
+            "ipv4_address": <bindata of 0x65439876>
+            "rdata_raw": <bindata of 0x65439876>
+          }
+        }
+      ]
+      "additional": [],
+      "canonical_name": <bindata for "www.example.com">,
+      "answer_type": GETDNS_NAMETYPE_DNS
+    },
+    {     # This is the second reply
+      "header": { "id": 47809, "qr": 1, "opcode": 0, ... },
+      "question": { "qname": <bindata for "www.example.com">, "qtype": 28, "qclass": 1 },
+      "answer":
+      [
+        {
+          "name": <bindata for "www.example.com">,
+          "type": 28,
+          "class": 1,
+          "ttl": 1000,
+          "rdata":
+          {
+            "ipv6_address": <bindata of 0x33445566334455663344556633445566>
+            "rdata_raw": <bindata of 0x33445566334455663344556633445566>
+          }
+       }
+      ],
+      "authority": [  # Same as for other record... ]
+      "additional": [],
+    },
+  ]
+}
+
+ +

In DNS responses, domain names are treated special. RFC 1035 describes a form of name compression +that requires that the entire record be available for analysis. The API deals with this by +converting compressed names into full names when returning names in the replies_tree. +This conversion happens for qname in question; name in the +answer, authority, and additional; and in domain names in the +data in names under rdata where the response type is AFSDB, CNAME, MX, NS, PTR, RP, RT, and SOA.

+ +

4.2 Converting Domain Names

+ +

Names in DNS fields are stored in a fashion very different from the normal presentation format +normally used in applications. The DNS format is described in the first paragraph in Section 3.1 of +RFC 1035; the presentation format here is a null-terminated string with interior dots. These helper +functions only work with names in the DNS format that are not compressed. They are useful for +converting domain names in the replies_tree to and from the FQDN presentation +format.

+ +

getdns_convert_dns_name_to_fqdn() converts a domain name in DNS format to the +presentation format. For example, the hex sequence 03 77 77 77 07 65 78 61 6d 70 6c 65 03 63 +6f 6d 00 would be converted to "www.example.com". +getdns_convert_fqdn_to_dns_name() does the reverse: it converts a null-terminated +string in FQDN format to bytes in DNS format.

+ +
+char * +getdns_convert_dns_name_to_fqdn( + char *name_from_dns_response +); + +char * +getdns_convert_fqdn_to_dns_name( + char *fqdn_as_string +); +
+ +

5. Additional Definitions and Descriptions

+ +

5.1 A Few Needed Definitions

+ +
typedef struct getdns_context_t *getdns_context_t; +typedef uint16_t getdns_return_t; +typedef uint64_t getdns_transaction_t; +typedef enum some_data_type { + t_dict, t_list, t_int, t_bindata +} getdns_data_type; +typedef struct getdns_bindata { + size_t size; + uint8_t *binary_stuff; +} some_bindata; +typedef struct getdns_dict some_dict; +typedef struct getdns_list some_list; +
+ +

5.2 Return Codes

+ +

The return codes for all the functions are:

+ +

GETDNS_RETURN_GOOD

+

Good

+

GETDNS_RETURN_GENERIC_ERROR

+

Generic error

+

GETDNS_RETURN_BAD_DOMAIN_NAME

+

Badly-formed domain name in first argument

+

GETDNS_RETURN_BAD_CONTEXT

+

Bad value for a context type

+

GETDNS_RETURN_CONTEXT_UPDATE_FAIL

+

Did not update the context

+

GETDNS_RETURN_UNKNOWN_TRANSACTION

+

An attempt was made to cancel a callback with a transaction_id that is not recognized

+

GETDNS_RETURN_NO_SUCH_LIST_ITEM

+

A helper function for lists had an index argument that was too high.

+

GETDNS_RETURN_NO_SUCH_DICT_NAME

+

A helper function for dicts had a name argument that for a name that is not in the dict.

+

GETDNS_RETURN_WRONG_TYPE_REQUESTED

+

A helper function was supposed to return a certain type for an item, but the wrong type was given.

+

GETDNS_RETURN_NO_SUCH_EXTENSION

+

A name in the extensions dict is not a valid extension.

+

GETDNS_RETURN_EXTENSION_MISFORMAT

+

One or more of the extensions is has a bad format.

+

GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED

+

A query was made with a context that is using stub resolution and a DNSSEC extension specified.

+ + +

5.3 Types of RDATA Returned in the API

+ +

The names in the rdata dicts in replies are:

+ + +

A (1)

+

ipv4_address (a bindata)

+ +

NS (2)

+

nsdname (a bindata)

+ +

MD (3)

+

madname (a bindata)

+ +

MF (4)

+

madname (a bindata)

+ +

CNAME (5)

+

cname (a bindata)

+ +

SOA (6)

+

mname (a bindata), rname (a bindata), +serial (an int), refresh (an int), refresh (an int), +retry (an int), and expire (an int)

+ +

MB (7)

+

madname (a bindata)

+ +

MG (8)

+

mgmname (a bindata)

+ +

MR (9)

+

newname (a bindata)

+ +

NULL (10)

+

anything (a bindata)

+ +

WKS (11)

+

address (a bindata), protocol (an int), +and bitmap (a bindata)

+ +

PTR (12)

+

ptrdname (a bindata)

+ +

HINFO (13)

+

cpu (a bindata) and os (a bindata)

+ +

MINFO (14)

+

rmailbx (a bindata) and emailbx (a bindata)

+ +

MX (15)

+

preference (an int) and exchange (a bindata)

+ +

TXT (16)

+

txt_strings (a list) which contains zero or more bindata elements +that are text strings

+ +

RP (17)

+

mbox_dname (a bindata) and txt_dname (a bindata)

+ +

AFSDB (18)

+

subtype (an int) and hostname (a bindata)

+ +

X25 (19)

+

psdn_address (a bindata)

+ +

ISDN (20)

+

isdn_address (a bindata) and sa (a bindata)

+ +

RT (21)

+

preference (an int) and intermediate_host (a bindata)

+ +

NSAP (22)

+

nsap (a bindata)

+ +

SIG (24)

+

sig_obsolete (a bindata)

+ +

KEY (25)

+

key_obsolete (a bindata)

+ +

PX (26)

+

preference (an int), map822 (a bindata), and mapx400 (a bindata)

+ +

GPOS (27)

+

longitude (a bindata), latitude (a bindata), and altitude (a bindata)

+ +

AAAA (28)

+

ipv6_address (a bindata)

+ +

LOC (29)

+

loc_obsolete (a bindata)

+ +

NXT (30)

+

nxt_obsolete (a bindata)

+ +

EID (31)

+

eid_unknown (a bindata)

+ +

NIMLOC (32)

+

nimloc_unknown (a bindata)

+ +

SRV (33)

+

priority (an int), weight (an int), +port (an int), and target (a bindata)

+ +

ATMA (34)

+

format (an int) and address (a bindata)

+ +

NAPTR (35)

+

order (an int), preference (an int), flags +(a bindata), service (a bindata), regexp (a bindata), and +replacement (a bindata).

+ +

KX (36)

+

preference (an int) and exchanger (a bindata)

+ +

CERT (37)

+

type (an int), key_tag (an int), algorithm (an int), +and certificate_or_crl (a bindata)

+ +

A6 (38)

+

a6_obsolete (a bindata)

+ +

DNAME (39)

+

target (a bindata)

+ +

SINK (40)

+

sink_unknown (a bindata)

+ +

OPT (41)

+

options (a list). Each element of the options list is a +dict with two names: option_code (an int) and option_data (a bindata).

+ +

APL (42)

+

address_family (an int), prefix (an int), +n (an int), and afdpart (a bindata)

+ +

DS (43)

+

key_tag (an int), algorithm (an int), digest_type (an int), +and digest (a bindata)

+ +

SSHFP (44)

+

algorithm (an int), fp_type (an int), +and fingerprint (a bindata)

+ +

IPSECKEY (45)

+

algorithm (an int), gateway_type (an int), precedence (an int), +gateway, and public_key (a bindata)

+ +

RRSIG (46)

+

type_covered (an int), algorithm (an int), +labels (an int), original_ttl (an int), signature_expiration +(an int), signature_inception (an int), key_tag (an int), +signers_name (a bindata), and signature (a bindata)

+ +

NSEC (47)

+

next_domain_name (a bindata) and type_bit_maps (a bindata)

+ +

DNSKEY (48)

+

flags (an int), protocol (an int), algorithm (an int), +and public_key (a bindata)

+ +

DHCID (49)

+

dhcid_opaque (a bindata)

+ +

NSEC3 (50)

+

hash_algorithm (an int), flags (an int), +iterations (an int), salt_length (an int), salt (a bindata), +hash_length (an int), next_hashed_owner_name (a bindata), and +type_bit_maps (a bindata)

+ +

NSEC3PARAM (51)

+

hash_algorithm (an int), flags (an int), +iterations (an int), salt_length (an int), and +salt (a bindata)

+ +

TLSA (52)

+

certificate_usage (an int), selector (an int), +matching_type (an int), and certificate_association_data (a +bindata).

+ +

HIP (55)

+

hit_length (an int), pk_algorithm (an int), +pk_length (an int), hit (a bindata), public_key +(a bindata), and rendezvous_servers (a bindata)

+ +

NINFO (56)

+

ninfo_unknown (a bindata)

+ +

RKEY (57)

+

rkey_unknown (a bindata)

+ +

TALINK (58)

+

talink_unknown (a bindata)

+ +

CDS (59)

+

cds_unknown (a bindata)

+ +

SPF (99)

+

text (a bindata)

+ +

UINFO (100)

+

uinfo_unknown (a bindata)

+ +

UID (101)

+

uid_unknown (a bindata)

+ +

GID (102)

+

gid_unknown (a bindata)

+ +

UNSPEC (103)

+

unspec_unknown (a bindata)

+ +

NID (104)

+

preference (an int) and +node_id (a bindata)

+ +

L32 (105)

+

preference (an int), locator32_msbs (a bindata), +and locator64_lsbs (a bindata)

+ +

L64 (106)

+

preference (an int) and locator64 (a bindata)

+ +

LP (107)

+

preference (an int) and fqdn (a bindata)

+ +

TKEY (249)

+

algorithm (a bindata), inception (an int), +expiration (an int), mode (an int), error (an int), +key_data (a bindata), and other_data (a bindata)

+ +

TSIG (250)

+

algorithm (a bindata), time_signed (a bindata), +fudge (an int), mac (a bindata), original_id (an int), +error (an int), and other_data (a bindata)

+ +

IXFR (251)

+

zones (a bindata)

+ +

AXFR (252)

+

zones (a bindata)

+ +

MAILB (253)

+

mailb-unknown (a bindata)

+ +

MAILA (254)

+

maila-unknown (a bindata)

+ +

URI (256)

+

priority (an int), weight (an int), +and target (a bindata)

+ +

CAA (257)

+

flags (an int), tag (a bindata), and value (a bindata)

+ +

TA (32768)

+

ta_unknown (a bindata)

+ +

DLV (32769)

+

Identical to DS (43)

+ + +

6. Examples

+ +

This section gives examples of code that calls the API to do many common tasks. +The purpose of the code here is to give application developers a quick hands-on +demo of using the API.

+ +

Note that the examples here all use getdns_libevent.h as the include that will call in the API +code as well as calling in libevent as the event library. They also use +getdns_context_set_libevent_base() as the name of the function to set the event base in +the DNS context. If you are using a different event library, you will of course use a different +#include at the beginning of your code, and a different name for the event base +function.

+ +

6.1 Get Both IPv4 and IPv6 Addresses for a Domain Name Using Quick Results

+ +

This is an example of a common call to getdns_address().

+ +
#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <getdns_libevent.h>
+
+#define UNUSED_PARAM(x) ((void)(x))
+
+/* Set up the callback function, which will also do the processing of the results */
+void this_callbackfn(struct getdns_context_t *this_context,
+                     uint16_t     this_callback_type,
+                     struct getdns_dict *this_response, 
+                     void *this_userarg,
+                     getdns_transaction_t this_transaction_id)
+{
+    UNUSED_PARAM(this_userarg);  /* Not looking at the userarg for this example */
+    UNUSED_PARAM(this_context);  /* Not looking at the context for this example */
+    getdns_return_t this_ret;  /* Holder for all function returns */
+    if (this_callback_type == GETDNS_CALLBACK_COMPLETE)  /* This is a callback with data */
+    {
+        /* Be sure the search returned something */
+        uint32_t * this_error = NULL;
+        this_ret = getdns_dict_get_int(this_response, "status", this_error);  // Ignore any error
+        if (*this_error != GETDNS_RESPSTATUS_GOOD)  // If the search didn't return "good"
+        {
+            fprintf(stderr, "The search had no results, and a return value of %d. Exiting.", *this_error);
+            return;
+        }
+        struct getdns_list * just_the_addresses_ptr;
+        this_ret = getdns_dict_get_list(this_response, "just_address_answers", &just_the_addresses_ptr);
+        if (this_ret != GETDNS_RETURN_GOOD)  // This check is really not needed, but prevents a compiler error under "pedantic"
+        {
+            fprintf(stderr, "Trying to get the answers failed: %d", this_ret);
+            return;
+        }
+        size_t * num_addresses_ptr = NULL;
+        this_ret = getdns_list_get_length(just_the_addresses_ptr, num_addresses_ptr);  // Ignore any error
+        /* Go through each record */
+        for ( size_t rec_count = 0; rec_count <= *num_addresses_ptr; ++rec_count )
+        {
+            struct getdns_dict * this_address;
+            this_ret = getdns_list_get_dict(just_the_addresses_ptr, rec_count, &this_address);  // Ignore any error
+            /* Just print the address */
+            struct getdns_bindata * this_address_data;
+            this_ret = getdns_dict_get_bindata(this_address, "address_data", &this_address_data); // Ignore any error
+            printf("The address is %s", getdns_display_ip_address(this_address_data));
+        }
+    }
+    else if (this_callback_type == GETDNS_CALLBACK_CANCEL)
+        fprintf(stderr, "The callback with ID %"PRIu64" was cancelled. Exiting.", this_transaction_id);
+    else
+        fprintf(stderr, "The callback got a callback_type of %d. Exiting.", this_callback_type);
+}
+
+int main()
+{
+    /* Create the DNS context for this call */
+    struct getdns_context_t *this_context = NULL;
+    getdns_return_t context_create_return = getdns_context_create(&this_context, true);
+    if (context_create_return != GETDNS_RETURN_GOOD)
+    {
+        fprintf(stderr, "Trying to create the context failed: %d", context_create_return);
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    /* Create an event base and put it in the context using the unknown function name */
+    struct event_base *this_event_base;
+    this_event_base = event_base_new();
+    if (this_event_base == NULL)
+    {
+        fprintf(stderr, "Trying to create the event base failed.");
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    (void)getdns_extension_set_libevent_base(this_context, this_event_base);
+    /* Set up the getdns call */
+    const char * this_name  = "www.example.com";
+    char* this_userarg = "somestring"; // Could add things here to help identify this call
+    getdns_transaction_t this_transaction_id = 0;
+
+    /* Make the call */
+    getdns_return_t dns_request_return = getdns_address(this_context, this_name,
+        NULL, this_userarg, &this_transaction_id, this_callbackfn);
+    if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME)
+    {
+        fprintf(stderr, "A bad domain name was used: %s. Exiting.", this_name);
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    else
+    {
+        /* Call the event loop */
+        int dispatch_return = event_base_dispatch(this_event_base);
+        UNUSED_PARAM(dispatch_return);
+        // TODO: check the return value above
+    }
+    /* Clean up */
+    getdns_context_destroy(this_context);
+    /* Assuming we get here, leave gracefully */
+    exit(EXIT_SUCCESS);
+}
+
+ + + +

6.2 Get IPv4 and IPv6 Addresses for a Domain Name

+ +

This example is similar to the previous one, except that it retrieves more information than just +the addresses, so it traverses the replies_tree. In this case, it gets both the addresses and +their TTLs.

+ +
#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <getdns_libevent.h>
+
+#define UNUSED_PARAM(x) ((void)(x))
+
+/* Set up the callback function, which will also do the processing of the results */
+void this_callbackfn(struct getdns_context_t *this_context,
+                     getdns_return_t this_callback_type,
+                     struct getdns_dict *this_response, 
+                     void *this_userarg,
+                     getdns_transaction_t this_transaction_id)
+{
+    UNUSED_PARAM(this_userarg);  /* Not looking at the userarg for this example */
+    UNUSED_PARAM(this_context);  /* Not looking at the context for this example */
+    getdns_return_t this_ret;  /* Holder for all function returns */
+    if (this_callback_type == GETDNS_CALLBACK_COMPLETE)  /* This is a callback with data */
+    {
+        /* Be sure the search returned something */
+        uint32_t * this_error = NULL;
+        this_ret = getdns_dict_get_int(this_response, "status", this_error);  // Ignore any error
+        if (*this_error != GETDNS_RESPSTATUS_GOOD)  // If the search didn't return "good"
+        {
+            fprintf(stderr, "The search had no results, and a return value of %d. Exiting.", *this_error);
+            return;
+        }
+        /* Find all the answers returned */
+        struct getdns_list * these_answers;
+        this_ret = getdns_dict_get_list(this_response, "replies-tree", &these_answers);
+        if (this_ret == GETDNS_RETURN_NO_SUCH_DICT_NAME)
+        {
+            fprintf(stderr, "Weird: the response had no error, but also no replies-tree. Exiting.");
+            return;
+        }
+        size_t * num_answers_ptr = NULL;
+        this_ret = getdns_list_get_length(these_answers, num_answers_ptr);
+        /* Go through each answer */
+        for ( size_t rec_count = 0; rec_count <= *num_answers_ptr; ++rec_count )
+        {
+            struct getdns_dict * this_record;
+            this_ret = getdns_list_get_dict(these_answers, rec_count, &this_record);  // Ignore any error
+            /* Get the answer section */
+            struct getdns_list * this_answer;
+            this_ret = getdns_dict_get_list(this_record, "answer", &this_answer);  // Ignore any error
+            /* Get each RR in the answer section */
+            size_t * num_rrs_ptr = NULL;
+            this_ret = getdns_list_get_length(this_answer, num_rrs_ptr);
+            for ( size_t rr_count = 0; rr_count <= *num_rrs_ptr; ++rr_count )
+            {
+                struct getdns_dict * this_rr = NULL;
+                this_ret = getdns_list_get_dict(this_answer, rr_count, &this_rr);  // Ignore any error
+                /* Get the RDATA */
+                struct getdns_dict * this_rdata = NULL;
+                this_ret = getdns_dict_get_dict(this_rr, "rdata", &this_rdata);  // Ignore any error
+                /* Get the RDATA type */
+                uint32_t * this_type = NULL;
+                this_ret = getdns_dict_get_int(this_rdata, "type", this_type);  // Ignore any error
+                /* If it is type A or AAAA, print the value */
+                if (*this_type == GETDNS_RRTYPE_A)
+                {
+                    struct getdns_bindata * this_a_record = NULL;
+                    this_ret = getdns_dict_get_bindata(this_rdata, "ipv4_address", &this_a_record);
+                    if (this_ret == GETDNS_RETURN_NO_SUCH_DICT_NAME)
+                    {
+                        fprintf(stderr, "Weird: the A record at %d in record at %d had no address. Exiting.",
+                            (int) rr_count, (int) rec_count);
+                        return;
+                    }
+                    printf("The IPv4 address is %s", getdns_display_ip_address(this_a_record));
+                }
+                else if (*this_type == GETDNS_RRTYPE_AAAA)
+                {
+                    struct getdns_bindata * this_aaaa_record = NULL;
+                    this_ret = getdns_dict_get_bindata(this_rdata, "ipv6_address", &this_aaaa_record);
+                    if (this_ret == GETDNS_RETURN_NO_SUCH_DICT_NAME)
+                    {
+                        fprintf(stderr, "Weird: the AAAA record at %d in record at %d had no address. Exiting.",
+                            (int) rr_count, (int) rec_count);
+                        return;
+                    }
+                    printf("The IPv6 address is %s", getdns_display_ip_address(this_aaaa_record));
+                }
+            }
+        }
+    }
+    else if (this_callback_type == GETDNS_CALLBACK_CANCEL)
+        fprintf(stderr, "The callback with ID %"PRIu64" was cancelled. Exiting.", this_transaction_id);
+    else
+        fprintf(stderr, "The callback got a callback_type of %d. Exiting.", this_callback_type);
+}
+
+int main()
+{
+    /* Create the DNS context for this call */
+    struct getdns_context_t *this_context = NULL;
+    getdns_return_t context_create_return = getdns_context_create(&this_context, true);
+    if (context_create_return != GETDNS_RETURN_GOOD)
+    {
+        fprintf(stderr, "Trying to create the context failed: %d", context_create_return);
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    /* Create an event base and put it in the context using the unknown function name */
+    struct event_base *this_event_base;
+    this_event_base = event_base_new();
+    if (this_event_base == NULL)
+    {
+        fprintf(stderr, "Trying to create the event base failed.");
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    (void)getdns_extension_set_libevent_base(this_context, this_event_base);
+    /* Set up the getdns call */
+    const char * this_name  = "www.example.com";
+    char* this_userarg = "somestring"; // Could add things here to help identify this call
+    getdns_transaction_t this_transaction_id = 0;
+
+    /* Make the call */
+    getdns_return_t dns_request_return = getdns_address(this_context, this_name,
+        NULL, this_userarg, &this_transaction_id, this_callbackfn);
+    if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME)
+    {
+        fprintf(stderr, "A bad domain name was used: %s. Exiting.", this_name);
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    else
+    {
+        /* Call the event loop */
+        int dispatch_return = event_base_dispatch(this_event_base);
+        UNUSED_PARAM(dispatch_return);
+        // TODO: check the return value above
+    }
+    /* Clean up */
+    getdns_context_destroy(this_context);
+    /* Assuming we get here, leave gracefully */
+    exit(EXIT_SUCCESS);
+}
+
+ + + +

6.3 Get Addresses for a Domain Name And Their Associated DNSSEC Validation Status

+ +

This example shows how to check for secure DNSSEC results using the +dnssec_return_status extension. In the innermost loop of the +callback function, add a check for the DNSSEC status. It shows how to add two +extensions to the extensions argument of the call.

+ +
+struct getdns_dict * this_extensions = getdns_dict_create();
+this_ret = getdns_dict_set_int(this_extensions, "return_both_v4_and_v6", GETDNS_EXTENSION_TRUE);
+this_ret = getdns_dict_set_int(this_extensions, "dnssec_return_status", GETDNS_EXTENSION_TRUE);
+. . .
+if (*this_type == GETDNS_RRTYPE_A)
+{
+    uint32_t * this_dnssec_status;
+    this_ret = getdns_dict_get_int(this_rdata, "dnssec_status", this_dnssec_status);
+    if (&this_dnssec_status != GETDNS_DNSSEC_SECURE)
+    {
+        // Log the DNSSEC status somewhere
+    }
+    else
+    {
+        // Deal with the record however you were going to
+    }
+}
+. . .
+
+ +

You can put the DNSSEC status check outside the check for the particular type of record you care about, but +you will then get log messages for bad status on records you might not care about as well.

+ +

6.4 Using the API Synchronously with getdns_sync_request()

+ +

This example is the same as the earlier examples, but uses getdns_general_sync() +and thus does not use the async code. Note that the processing of the answers is essentially the same +as it is for the synchronous example, it is just done in main().

+ +
#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <getdns_core_only.h>
+
+int main()
+{
+    getdns_return_t this_ret;  /* Holder for all function returns */
+    /* Create the DNS context for this call */
+    struct getdns_context_t *this_context = NULL;
+    getdns_return_t context_create_return = getdns_context_create(&this_context, true);
+    if (context_create_return != GETDNS_RETURN_GOOD)
+    {
+        fprintf(stderr, "Trying to create the context failed: %d", context_create_return);
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    /* Set up the getdns_sync_request call */
+    const char * this_name  = "www.example.com";
+    uint8_t this_request_type = GETDNS_RRTYPE_A;
+    /* Get the A and AAAA records */
+    struct getdns_dict * this_extensions = getdns_dict_create();
+    this_ret = getdns_dict_set_int(this_extensions, "return_both_v4_and_v6", GETDNS_EXTENSION_TRUE);
+    if (this_ret != GETDNS_RETURN_GOOD)
+    {
+        fprintf(stderr, "Trying to set an extension do both IPv4 and IPv6 failed: %d", this_ret);
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    uint32_t this_response_length;
+    struct getdns_dict * this_response = NULL;
+
+    /* Make the call */
+    getdns_return_t dns_request_return = getdns_general_sync(this_context, this_name, this_request_type,
+        this_extensions, &this_response_length, this_response);
+    if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME)
+    {
+        fprintf(stderr, "A bad domain name was used: %s. Exiting.", this_name);
+        return(GETDNS_RETURN_GENERIC_ERROR);
+    }
+    else
+    {
+        /* Be sure the search returned something */
+        uint32_t * this_error = NULL;
+        this_ret = getdns_dict_get_int(this_response, "status", this_error);  // Ignore any error
+        if (*this_error != GETDNS_RESPSTATUS_GOOD)  // If the search didn't return "good"
+        {
+            fprintf(stderr, "The search had no results, and a return value of %d. Exiting.", *this_error);
+            return(GETDNS_RETURN_GENERIC_ERROR);
+        }
+        struct getdns_list * just_the_addresses_ptr;
+        this_ret = getdns_dict_get_list(this_response, "just_address_answers", &just_the_addresses_ptr);  // Ignore any error
+        size_t * num_addresses_ptr = NULL;
+        this_ret = getdns_list_get_length(just_the_addresses_ptr, num_addresses_ptr);  // Ignore any error
+        /* Go through each record */
+        for ( size_t rec_count = 0; rec_count <= *num_addresses_ptr; ++rec_count )
+        {
+            struct getdns_dict * this_address;
+            this_ret = getdns_list_get_dict(just_the_addresses_ptr, rec_count, &this_address);  // Ignore any error
+            /* Just print the address */
+            struct getdns_bindata * this_address_data;
+            this_ret = getdns_dict_get_bindata(this_address, "address_data", &this_address_data); // Ignore any error
+            printf("The address is %s", getdns_display_ip_address(this_address_data));
+        }
+    }
+    /* Clean up */
+    getdns_context_destroy(this_context);
+    getdns_free_sync_request_memory(this_response); 
+    /* Assuming we get here, leave gracefully */
+    exit(EXIT_SUCCESS);
+}
+
+ + + +

7. More Helper Functions

+ +

The following two functions convert individual labels of IDNs between their Unicode +encoding and their ASCII encoding. They follow the rules for IDNA 2008 described in +RFC 5890-5892.

+
char * +getdns_convert_ulabel_to_alabel( + char *ulabel +); +
+
char * +getdns_convert_alabel_to_ulabel( + char *alabel +); +
+ +

If an application wants the API do perform DNSSEC validation without using the extensions, it +can use the getdns_validate_dnssec() helper function.

+
getdns_return_t +getdns_validate_dnssec( + struct getdns_bindata *record_to_validate, + struct getdns_list *bundle_of_support_records, + struct getdns_list *trust_anchor_rdatas +); +
+

The record_to_validate is the resource record being validated. The API +will use the resource records in bundle_of_support_records and the RDATAs in the +trust_ancor_rdatas as trust anchors. The function returns one of +GETDNS_DNSSEC_SECURE, GETDNS_DNSSEC_BOGUS, +GETDNS_DNSSEC_INDETERMINATE, or GETDNS_DNSSEC_INSECURE.

+ +

There are two functions that help process data:

+ +
+char * +getdns_pretty_print_dict( + struct getdns_dict *some_dict +); +
+

This returns a string that is the nicely-formatted version +of the dict and all of the named elements in it.

+ +
+char * +getdns_display_ip_address( + struct getdns_bindata *bindata_of_ipv4_or_ipv6_address +); +
+

This returns a string that is the nicely-formatted version +of the IPv4 or IPv6 address in it. The API determines they type of address +by the length given in the bindata.

+ +

8. DNS Contexts

+ +

Many calls in the DNS API require a DNS context. A DNS +context contains the information that the API needs in order to process DNS calls, such as the +locations of upstream DNS servers, DNSSEC trust anchors, and so on. The internal structure of the +DNS context is opaque, and might be different on each OS. When a context is passed to any function, +it must be an allocated context; the context must not be NULL.

+ +

A typical application using this API doesn't need to know anything about contexts. Basically, +the application creates a default context, uses it in the functions that require a context, and +then deallocates it when done. Context manipulation is available for more DNS-aware programs, +but is unlikely to be of interest to applications that just want the results of lookups for +A, AAAA, SRV, and PTR records.

+ +

It is expected that contexts in implementations of the API will not necessarily be thread-safe, +but they will not be thread-hostile. A context should not be used by multiple threads: create a new +context for use on a different thread. It is just fine for an application to have many contexts, +and some DNS-heavy applications will certainly want to have many even if the application uses +a single thread.

+ +

See above for the method for creating and destroying +contexts. When the context is used in the API for the first time and set_from_os is +true, the API starts replacing some of the values with values from the OS, such as +those that would be found in res_query(3), /etc/resolv.conf, and so on, then proceeds with the new +function. Some advanced users will not want the API to change the values to the OS's defaults; if +set_from_os is false, the API will not do any updates to the initial +values based on changes in the OS. For example, this might be useful if the API is acting +as a stub resolver that is using a specific upstream recursive resolver chosen by the +application, not the one that might come back from DHCP.

+ +

8.1 Updating the Context Automatically

+ +

The context returned by getdns_context_create() is updated by the API by default, +such as when changes are made to /etc/resolv.conf. When there is a change, the callback function +that is set in getdns_context_set_context_update_callback() (described below) is +called.

+ +

Many of the defaults for a context come from the operating system under which the API is running. +In specific, it is important that the implementation should try to replicate as best as possible the +logic of a local getaddrinfo() when creating a new context. This includes making +lookups in WINS for NetBIOS, mDNS lookups, nis names, and any other name lookup that +getaddrinfo() normally does automatically. The API should look at nsswitch, the Windows +resolver, and so on.

+ +

In the function definitions below, the choice listed in bold is the one used +for the API default context.

+ +

8.2 Updating the Context Manually

+ +

Setting specific values in a context are done with value-specific +functions shown here. The setting functions all return either GETDNS_RETURN_GOOD for +success, GETDNS_RETURN_BAD_CONTEXT for trying to set a type with a value that +is not allowed, or GETDNS_RETURN_CONTEXT_UPDATE_FAIL for a failure to update the context.

+ +

An application can be notified when the context is changed.

+ +
+getdns_return_t +getdns_context_set_context_update_callback( + getdns_context_t context, + void (*value)(getdns_context_t context, uint16_t changed_item) +);
+

The value is a pointer to the callback function that will be +called when any context is changed. Such changes might be from automatic +changes from the API (such as changes to /etc/resolv.conf), or might be from any of the +API functions in this section being called. The second argument to the callback function +specifies which of the context changed; the context codes are listed +later in this document.

+ +

8.3 Contexts for Basic Resolution

+ +
+getdns_return_t +getdns_context_set_resolution_type( + getdns_context_t context, + uint16_t value +);
+

Specifies whether DNS queries are performed with nonrecurive lookups or +as a stub resolver. The value is GETDNS_CONTEXT_RECURSING or +GETDNS_CONTEXT_STUB.

+ +

All implementations of this API can act as recursive resolvers, and that must be the +default mode of the default context. +Some implementations of this API are expected to also be able to act as stub resolvers. +If an +implementation of this API is only able to act as a recursive resolver, a call to +getdns_context_set_resolution_type(somecontext, GETDNS_CONTEXT_STUB) will +return GETDNS_RETURN_CONTEXT_UPDATE_FAIL.

+ +
+getdns_return_t +getdns_context_set_namespaces( + getdns_context_t context, + size_t namespace_count, + uint16_t *namespaces +);
+

The namespaces array contains an ordered list +of namespaces that will be queried. +Important: this context setting is ignored for the getdns_general and +getdns_general_sync functions; it is used for the other funtions. +The values +are GETDNS_CONTEXT_NAMESPACE_DNS, +GETDNS_CONTEXT_NAMESPACE_LOCALNAMES, +GETDNS_CONTEXT_NAMESPACE_NETBIOS, +GETDNS_CONTEXT_NAMESPACE_MDNS, and +GETDNS_CONTEXT_NAMESPACE_NIS. When a normal lookup is done, +the API does the lookups in the order given and stops when it gets the +first result; a different method with the same result would be to run +the queries in parallel and return when it gets the first result. +Because lookups might be done over different mechanisms because of the +different namespaces, there can be information leakage that is similar +to that seen with getaddrinfo(). The +default is determined by the OS.

+ +
+getdns_return_t +getdns_context_set_dns_transport( + getdns_context_t context, + uint16_t value +);
+

Specifies what transport is used for DNS lookups. +The value is +GETDNS_CONTEXT_UDP_FIRST_AND_FALL_BACK_TO_TCP, +GETDNS_CONTEXT_UDP_ONLY, +GETDNS_CONTEXT_TCP_ONLY, or +GETDNS_CONTEXT_TCP_ONLY_KEEP_CONNECTIONS_OPEN.

+ +
+getdns_return_t +getdns_context_set_limit_outstanding_queries( + getdns_context_t context, + uint16_t limit +);
+

Specifies limit the number of outstanding DNS queries. +The API will block itself from sending more queries if it is about to exceed +this value, and instead keep those queries in an internal queue. +The a value of 0 indicates that +the number of outstanding DNS queries is unlimited.

+ +
+getdns_return_t +getdns_context_set_timeout( + getdns_context_t context, + uint16_t timeout +);
+

Specifies number of seconds the API will wait for request to return. +The default is not specified.

+ +

8.4 Context for Recursive Resolvers

+ +
+getdns_return_t +getdns_context_set_follow_redirects( + getdns_context_t context, + uint16_t value +);
+

Specifies whether or not DNS queries follow redirects. +The value is GETDNS_CONTEXT_FOLLOW_REDIRECTS for normal +following of redirects though CNAME and DNAME; or +GETDNS_CONTEXT_DO_NOT_FOLLOW_REDIRECTS to cause any lookups that would have gone +through CNAME and DNAME to return the CNAME or DNAME, not the eventual target.

+ +
+getdns_return_t +getdns_context_set_dns_root_servers( + getdns_context_t context, + struct getdns_list *addresses +);
+

The list contains dicts that are addresses to be used for looking up top-level +domains; the default is the list of "normal" IANA root servers. Each dict in the list +contains at least two names: address_type (whose value is a bindata; it is currently +either "IPv4" or "IPv6") and address_data (whose value is a bindata).

+ +

8.5 Context for Local Naming

+ +
+getdns_return_t +getdns_context_set_append_name( + getdns_context_t context, + uint16_t value +);
+

Specifies whether to append a suffix to the query string +before the API starts resolving a name. +The value is +GETDNS_CONTEXT_APPEND_NAME_ALWAYS, +GETDNS_CONTEXT_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE, +GETDNS_CONTEXT_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE, +or GETDNS_CONTEXT_DO_NOT_APPEND_NAMES. This controls +whether or not to append the suffix given by getdns_context_set_suffix

+ +
+getdns_return_t +getdns_context_set_suffix( + getdns_context_t context, + struct getdns_list *value +);
+

The value is a list of bindatas that are strings that are +to be appended based on getdns_context_set_append_name; the default is an empty list. The values here follow the rules in section 2.1 of RFC 4343 +to allow non-ASCII octets and special characters in labels.

+ +

8.6 Context for DNSSEC

+ +

These context settings affect queries that have extensions that specify the use of DNSSEC.

+ +

Applications that need to specify the DNSSEC trust anchors can use:

+
+getdns_return_t +getdns_context_set_dnssec_trust_anchors( + getdns_context_t context, + struct getdns_list *value +);
+

The value is a list of bindatas that are the DNSSEC trust anchors. The default +is the trust anchors from the IANA root. The trust anchors +are expressed as RDATAs from DNSKEY resource records.

+ +

In the rare case that an application needs to set the DNSSEC skew, it can:

+
+getdns_return_t +getdns_context_set_dnssec_allowed_skew( + getdns_context_t context, + uint16_t value +);
+

The value is the number of seconds of skew that is allowed in either direction when +checking an RRSIG's Expiration and Inception fields. The default +is 0.

+ +

8.7 Context Specific to Stub Resolvers

+ +

An application can change the quering mechanism of a context to be to act as a stub +resolver. Such an application might first get the default information to make this change +from the operating system, probably through DHCP.

+ +

Note that if a context is changed to being a stub resolver, this automatically prevents the application +from using the extenstions for DNSSEC. An application that wants to both do DNSSEC and stub resolution +must do its own DNSSEC processing, possibly with the getdns_validate_dnssec() function.

+ +
+getdns_return_t +getdns_context_set_stub_resolution( + getdns_context_t context, + struct getdns_list *upstream_list +);
+

The list of dicts define where a stub resolver will send queries. Each dict contains +at least two names: address_type (whose value is a bindata; it is currently either +"IPv4" or "IPv6") and address_data (whose value is a bindata). It might also contain +port to specify which port to use to contact these DNS servers; the default is 53. If +the stub and a recursive resolver both support TSIG (RFC 2845), the upstream_list entry +can also contain tsig_algorithm (a bindata) that is the name of the TSIG hash +algorithm, and tsig_secret (a bindata) that is the TSIG key.

+ +

8.8 Context for EDNS

+ +

These context settings affect queries that have extensions that specify the use of OPT resource records. +These come from RFC 2671.

+ +
+getdns_return_t +getdns_context_set_edns_maximum_udp_payload_size( + getdns_context_t context, + uint16_t value +);
+

The value is between 512 and 65535; the default +is 512.

+ +
+getdns_return_t +getdns_context_set_edns_extended_rcode( + getdns_context_t context, + uint8_t value +);
+

The value is between 0 and 256; the default +is 0.

+ +
+getdns_return_t +getdns_context_set_edns_version( + getdns_context_t context, + uint8_t value +);
+

The value is between 0 and 256; the default +is 0.

+ +
+getdns_return_t +getdns_context_set_edns_do_bit( + getdns_context_t context, + uint8_t value +);
+

The value is between 0 and 1; the default +is 0.

+ +

8.9 Context Use of C Functions

+ +
+getdns_return_t +getdns_context_set_memory_allocator( + getdns_context_t context, + void (*value)(size_t somesize) +);
+

The value is a function pointer to the memory allocator; the +default is the malloc function.

+ +
+getdns_return_t +getdns_context_set_memory_deallocator( + getdns_context_t context, + void (*value)(void*) +);
+

The value is a function pointer to the memory deallocator; the +default is the free function.

+ +
+getdns_return_t +getdns_context_set_memory_reallocator( + getdns_context_t context, + void (*value)(void*) +);
+

The value is a function pointer to the memory reallocator; the +default is the realloc function.

+ +

8.10 Context Codes

+ +

The context codes for getdns_context_set_context_update_callback() are:

+ +

GETDNS_CONTEXT_CODE_NAMESPACES

+

Change related to getdns_context_set_namespaces

+

GETDNS_CONTEXT_CODE_RESOLUTION_TYPE

+

Change related to getdns_context_set_resolution_type

+

GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS

+

Change related to getdns_context_set_follow_redirects

+

GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS

+

Change related to getdns_context_set_upstream_recursive_servers

+

GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS

+

Change related to getdns_context_set_dns_root_servers

+

GETDNS_CONTEXT_CODE_USE_UDP_TCP

+

Change related to getdns_context_set_use_udp_tcp

+

GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES

+

Change related to getdns_context_set_limit_outstanding_queries

+

GETDNS_CONTEXT_CODE_APPEND_NAME

+

Change related to getdns_context_set_append_name

+

GETDNS_CONTEXT_CODE_SUFFIX

+

Change related to getdns_context_set_suffix

+

GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS

+

Change related to getdns_context_set_dnssec_trust_anchors

+

GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE

+

Change related to getdns_context_set_edns_maximum_udp_payload_size

+

GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE

+

Change related to getdns_context_set_edns_extended_rcode

+

GETDNS_CONTEXT_CODE_EDNS_VERSION

+

Change related to getdns_context_set_edns_version

+

GETDNS_CONTEXT_CODE_EDNS_DO_BIT

+

Change related to getdns_context_set_edns_do_bit

+

GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW

+

Change related to getdns_context_set_dnssec_allowed_skew

+

GETDNS_CONTEXT_CODE_MEMORY_ALLOCATOR

+

Change related to getdns_context_set_memory_allocator

+

GETDNS_CONTEXT_CODE_MEMORY_DEALLOCATOR

+

Change related to getdns_context_set_memory_deallocator

+

GETDNS_CONTEXT_CODE_MEMORY_REALLOCATOR

+

Change related to getdns_context_set_memory_reallocator

+ + +

9. The Generated Files

+ +

There is a tarball that includes the .h files, +the examples, and so on. The examples all make, even though there is no API implementation, based +on a pseudo-implementation in the tarball; see make-examples-PLATFORM.sh. Note that this currently builds fine +on the Macintosh and Ubuntu; help is definitely appreciated on making the build process +work on more platforms if it fails there.

+ +

10. Commentary

+ +

The following description of the API may be of value to those who might implement the design, and +those who are using an implementation of the design.

+ +

10.1 API Design Considerations

+ +

The genesis of this DNS API design was seeing other DNS API designs flounder. There are other +DNS APIs already available (such as draft-hayatnagarkar-dnsext-validator-api, as well +as DNSSEC APIs in BIND and Unbound), but there has been very little uptake of them. In talking to +application developers, there was a consistent story: that they felt that the APIs were developed by and +for DNS people, not applications developers.

+ +

This API design comes from talking to a small handful of applications developers about what they +would want to see in a modern DNS API. Now that the API is public, it would be great to hear from many +more application developers about whether it would meet their needs if it was implemented. My goal +is to create a design that is a natural follow-on to getaddrinfo() that has all the +capabilities that most application developers might want now or in the next few years: access to all +types of DNS records (including those which are yet to be defined), full DNSSEC awareness, IDN +handling, and parity for IPv4 and IPv6 addresses.

+ +

Note that this is just a design for a new API: there is no implementation of the design yet, but +at least one is being worked on. The process of designing the API without implementing it at the +same time has the huge advantage that major design changes could be made without any worry about +"but we already coded it the other way". In the early revisions of this document, many fundamental +design choices changed over and over, and even bike-shedding-like changes were allowed because they +didn't involve any programming effort.

+ +

This work was done independently, not through the IETF because the IETF generally doesn't take on +API work, and has explicitly avoided DNS API work in the past.

+ +

This API design has a Creative Commons license so that it can be +used widely by potential API implementers. This also allows other people who want to fork the design +to do so cleanly. Of course, any implementation of this API can choose whatever kind of license the +API implementer wishes, but it would be fabulous if one or more such implementations had Creative +Commons or BSD-ish licenses.

+ +

The API relies heavily on C macros and hopefully has no magic numbers.

+ +

10.2 API Implementation Considerations

+ +

All implementations of this API must act as recursive resolvers, and some might choose not to be +able to act as stub resolvers. Note that all implementations of this API must be DNSSEC validators.

+ +

Because there are many C event libraries available, and they have different calling routines, +it is the implementation of an API that determines which event library is used. This is certainly +not optimal for C programmers, but they appear to have gotten used to is so far. All implementations +of this API must support synchronous calls with getdns_sync_request().

+ +

Versions are differentiated by version strings instead of version numbers. The version string for +this API is "getdns April 2013". Each implementation is free to set the implementation string as it +feels fit.

+ +

The API's .h file contains a macro called GETDNS_COMPILATION_COMMENT. This can be useful +to an application which will use the API because it can check the string without calling any +functions. Each time the API implementation is compiled, this string should be updated with unique +information about the implementation build.

+ +

The implementation of both the async and sync getdns functions will +copy all the values of the parameters into local memory, in case the application changes or +deallocates them.

+ +
+ +

Creative
+Commons License
This work is licensed under a Creative Commons Attribution 3.0 +Unported License.

+ + diff --git a/spec/make-examples-linux.sh b/spec/make-examples-linux.sh new file mode 100755 index 00000000..ca56726d --- /dev/null +++ b/spec/make-examples-linux.sh @@ -0,0 +1,22 @@ +rm -rf *.o *.dylib +gcc -std=c89 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c getdns_core_only.c +gcc -std=c89 -shared -fPIC -levent_core -o libgetdns.so getdns_core_only.o +gcc -std=c89 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-all-functions.c +gcc -std=c89 -fPIC -L./ example-all-functions.o -levent_core -lgetdns -o example-all-functions +gcc -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-simple-answers.c +gcc -std=c99 -fPIC -L./ example-simple-answers.o -levent_core -lgetdns -o example-simple-answers +gcc -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-tree.c +gcc -std=c99 -fPIC -L./ example-tree.o -levent_core -lgetdns -o example-tree +gcc -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-synchronous.c +gcc -std=c99 -fPIC -L./ example-synchronous.o -levent_core -lgetdns -o example-synchronous +rm -rf *.o *.dylib +clang -std=c89 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c getdns_core_only.c +clang -std=c89 -shared -fPIC -levent_core -o libgetdns.so getdns_core_only.o +clang -std=c89 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-all-functions.c +clang -std=c89 -fPIC -L./ example-all-functions.o -levent_core -lgetdns -o example-all-functions +clang -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-simple-answers.c +clang -std=c99 -fPIC -L./ example-simple-answers.o -levent_core -lgetdns -o example-simple-answers +clang -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-tree.c +clang -std=c99 -fPIC -L./ example-tree.o -levent_core -lgetdns -o example-tree +clang -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-synchronous.c +clang -std=c99 -fPIC -L./ example-synchronous.o -levent_core -lgetdns -o example-synchronous diff --git a/spec/make-examples-mac.sh b/spec/make-examples-mac.sh new file mode 100755 index 00000000..02c91eb0 --- /dev/null +++ b/spec/make-examples-mac.sh @@ -0,0 +1,22 @@ +rm -rf *.o *.dylib +gcc -std=c89 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c getdns_core_only.c +gcc -std=c89 -dynamiclib -fPIC -levent_core -o libgetdns.dylib getdns_core_only.o +gcc -std=c89 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-all-functions.c +gcc -std=c89 -fPIC -L./ example-all-functions.o -levent_core -lgetdns -o example-all-functions +gcc -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-simple-answers.c +gcc -std=c99 -fPIC -L./ example-simple-answers.o -levent_core -lgetdns -o example-simple-answers +gcc -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-tree.c +gcc -std=c99 -fPIC -L./ example-tree.o -levent_core -lgetdns -o example-tree +gcc -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-synchronous.c +gcc -std=c99 -fPIC -L./ example-synchronous.o -levent_core -lgetdns -o example-synchronous +rm -rf *.o *.dylib +clang -std=c89 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c getdns_core_only.c +clang -std=c89 -dynamiclib -fPIC -levent_core -o libgetdns.dylib getdns_core_only.o +clang -std=c89 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-all-functions.c +clang -std=c89 -fPIC -L./ example-all-functions.o -levent_core -lgetdns -o example-all-functions +clang -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-simple-answers.c +clang -std=c99 -fPIC -L./ example-simple-answers.o -levent_core -lgetdns -o example-simple-answers +clang -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-tree.c +clang -std=c99 -fPIC -L./ example-tree.o -levent_core -lgetdns -o example-tree +clang -std=c99 -c -fPIC -pedantic -g -I./ -Werror -Wall -Wextra -c example-synchronous.c +clang -std=c99 -fPIC -L./ example-synchronous.o -levent_core -lgetdns -o example-synchronous