From df540ad5ca454116d886a032d659f47bd40ce74c Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Mon, 4 Jul 2016 16:13:30 +0200 Subject: [PATCH 01/61] Bumb version --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index da1dccd3..468178ce 100644 --- a/configure.ac +++ b/configure.ac @@ -36,8 +36,8 @@ sinclude(./m4/acx_getaddrinfo.m4) sinclude(./m4/ax_check_compile_flag.m4) sinclude(./m4/pkg.m4) -AC_INIT([getdns], [1.0.0], [users@getdnsapi.net], [], [https://getdnsapi.net]) -AC_SUBST(RELEASE_CANDIDATE, [b2]) +AC_INIT([getdns], [1.1.0], [users@getdnsapi.net], [], [https://getdnsapi.net]) +AC_SUBST(RELEASE_CANDIDATE, [a1]) # Set current date from system if not set AC_ARG_WITH([current-date], @@ -47,7 +47,7 @@ AC_ARG_WITH([current-date], [CURRENT_DATE="`date -u +%Y-%m-%dT%H:%M:%SZ`"]) AC_SUBST(GETDNS_VERSION, ["AC_PACKAGE_VERSION$RELEASE_CANDIDATE"]) -AC_SUBST(GETDNS_NUMERIC_VERSION, [0x00100200]) +AC_SUBST(GETDNS_NUMERIC_VERSION, [0x0100A100]) AC_SUBST(API_VERSION, ["December 2015"]) AC_SUBST(API_NUMERIC_VERSION, [0x07df0c00]) GETDNS_COMPILATION_COMMENT="AC_PACKAGE_NAME $GETDNS_VERSION configured on $CURRENT_DATE for the $API_VERSION version of the API" From e0eb39a295fada487de58fe0890ab19bdba9843e Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Mon, 4 Jul 2016 16:57:27 +0200 Subject: [PATCH 02/61] Move str2getdns type functions in the library --- .gitmodules | 2 +- src/Makefile.in | 16 +- src/const-info.c | 209 ++++++++ src/const-info.h | 7 + src/convert.c | 644 +++++++++++++++++++++++- src/getdns/getdns_extra.h.in | 4 + src/{test => }/jsmn | 0 src/libgetdns.symbols | 4 + src/mk-const-info.c.sh | 13 +- src/test/Makefile.in | 21 +- src/test/getdns_query.c | 1 - src/test/getdns_str2dict.c | 951 ----------------------------------- src/test/getdns_str2dict.h | 37 -- 13 files changed, 893 insertions(+), 1016 deletions(-) rename src/{test => }/jsmn (100%) delete mode 100644 src/test/getdns_str2dict.c delete mode 100644 src/test/getdns_str2dict.h diff --git a/.gitmodules b/.gitmodules index 06b16b93..a79d3846 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "src/test/jsmn"] - path = src/test/jsmn + path = src/jsmn url = https://github.com/getdnsapi/jsmn.git branch = getdns diff --git a/src/Makefile.in b/src/Makefile.in index 3766b318..1c66530c 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -76,6 +76,8 @@ COMPAT_OBJ=$(LIBOBJS:.o=.lo) UTIL_OBJ=rbtree.lo val_secalgo.lo +JSMN_OBJ=jsmn.lo + EXTENSION_OBJ=default_eventloop.lo libevent.lo libev.lo NON_C99_OBJS=context.lo libuv.lo @@ -104,6 +106,9 @@ $(COMPAT_OBJ): $(UTIL_OBJ): $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $(srcdir)/util/$(@:.lo=.c) -o $@ +$(JSMN_OBJ): + $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -DJSMN_GETDNS -c $(srcdir)/jsmn/$(@:.lo=.c) -o $@ + $(EXTENSION_OBJ): $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $(srcdir)/extension/$(@:.lo=.c) -o $@ @@ -144,8 +149,8 @@ libgetdns_ext_ev.la: libgetdns.la libev.lo $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ libev.lo libgetdns.la $(LDFLAGS) $(EXTENSION_LIBEV_LDFLAGS) $(EXTENSION_LIBEV_EXT_LIBS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/extension/libev.symbols -libgetdns.la: $(GETDNS_OBJ) version.lo context.lo default_eventloop.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) - $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ $(GETDNS_OBJ) version.lo context.lo default_eventloop.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols +libgetdns.la: $(GETDNS_OBJ) version.lo context.lo default_eventloop.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ) + $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ $(GETDNS_OBJ) version.lo context.lo default_eventloop.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols test: all @@ -203,11 +208,12 @@ configure.status: configure depend: (cd $(srcdir) ; awk 'BEGIN{P=1}{if(P)print}/^# Dependencies/{P=0}' Makefile.in > Makefile.in.new ) - (blddir=`pwd`; cd $(srcdir) ; gcc -MM -I. -I"$$blddir" *.c gldns/*.c compat/*.c util/*.c extension/*.c| \ + (blddir=`pwd`; cd $(srcdir) ; gcc -MM -I. -I"$$blddir" *.c gldns/*.c compat/*.c util/*.c jsmn/*.c extension/*.c| \ sed -e "s? $$blddir/? ?g" \ -e 's?gldns/?$$(srcdir)/gldns/?g' \ -e 's?compat/?$$(srcdir)/compat/?g' \ -e 's?util/?$$(srcdir)/util/?g' \ + -e 's?jsmn/?$$(srcdir)/jsmn/?g' \ -e 's?extension/?$$(srcdir)/extension/?g' \ -e 's? \([a-z_-]*\)\.\([ch]\)? $$(srcdir)/\1.\2?g' \ -e 's? \$$(srcdir)/config\.h? config.h?g' \ @@ -237,7 +243,8 @@ convert.lo convert.o: $(srcdir)/convert.c config.h getdns/getdns.h getdns/getdns getdns/getdns.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ - $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/convert.h + $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/const-info.h $(srcdir)/dict.h \ + $(srcdir)/list.h $(srcdir)/jsmn/jsmn.h $(srcdir)/convert.h dict.lo dict.o: $(srcdir)/dict.c config.h $(srcdir)/types-internal.h getdns/getdns.h \ getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/util-internal.h \ $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h \ @@ -324,6 +331,7 @@ rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c config.h $(srcdir)/util/log.h $(srcd $(srcdir)/util/fptr_wlist.h $(srcdir)/util/rbtree.h val_secalgo.lo val_secalgo.o: $(srcdir)/util/val_secalgo.c config.h $(srcdir)/util/val_secalgo.h $(srcdir)/util/log.h \ $(srcdir)/debug.h config.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/gbuffer.h +jsmn.lo jsmn.o: $(srcdir)/jsmn/jsmn.c $(srcdir)/jsmn/jsmn.h default_eventloop.lo default_eventloop.o: $(srcdir)/extension/default_eventloop.c \ $(srcdir)/extension/default_eventloop.h config.h getdns/getdns.h \ getdns/getdns_extra.h $(srcdir)/debug.h config.h diff --git a/src/const-info.c b/src/const-info.c index 200100c2..0294e281 100644 --- a/src/const-info.c +++ b/src/const-info.c @@ -123,3 +123,212 @@ getdns_get_errorstr_by_id(uint16_t err) else return NULL; } + +static struct const_name_info consts_name_info[] = { + { "GETDNS_APPEND_NAME_ALWAYS", 550 }, + { "GETDNS_APPEND_NAME_NEVER", 553 }, + { "GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE", 552 }, + { "GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE", 551 }, + { "GETDNS_APPEND_NAME_TO_SINGLE_LABEL_FIRST", 554 }, + { "GETDNS_AUTHENTICATION_NONE", 1300 }, + { "GETDNS_AUTHENTICATION_REQUIRED", 1301 }, + { "GETDNS_BAD_DNS_ALL_NUMERIC_LABEL", 1101 }, + { "GETDNS_BAD_DNS_CNAME_IN_TARGET", 1100 }, + { "GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE", 1102 }, + { "GETDNS_CALLBACK_CANCEL", 701 }, + { "GETDNS_CALLBACK_COMPLETE", 700 }, + { "GETDNS_CALLBACK_ERROR", 703 }, + { "GETDNS_CALLBACK_TIMEOUT", 702 }, + { "GETDNS_CONTEXT_CODE_APPEND_NAME", 607 }, + { "GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW", 614 }, + { "GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS", 609 }, + { "GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS", 604 }, + { "GETDNS_CONTEXT_CODE_DNS_TRANSPORT", 605 }, + { "GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE", 619 }, + { "GETDNS_CONTEXT_CODE_EDNS_DO_BIT", 613 }, + { "GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE", 611 }, + { "GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE", 610 }, + { "GETDNS_CONTEXT_CODE_EDNS_VERSION", 612 }, + { "GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS", 602 }, + { "GETDNS_CONTEXT_CODE_IDLE_TIMEOUT", 617 }, + { "GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES", 606 }, + { "GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS", 615 }, + { "GETDNS_CONTEXT_CODE_NAMESPACES", 600 }, + { "GETDNS_CONTEXT_CODE_PUBKEY_PINSET", 621 }, + { "GETDNS_CONTEXT_CODE_RESOLUTION_TYPE", 601 }, + { "GETDNS_CONTEXT_CODE_SUFFIX", 608 }, + { "GETDNS_CONTEXT_CODE_TIMEOUT", 616 }, + { "GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION", 618 }, + { "GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE", 620 }, + { "GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS", 603 }, + { "GETDNS_DNSSEC_BOGUS", 401 }, + { "GETDNS_DNSSEC_INDETERMINATE", 402 }, + { "GETDNS_DNSSEC_INSECURE", 403 }, + { "GETDNS_DNSSEC_NOT_PERFORMED", 404 }, + { "GETDNS_DNSSEC_SECURE", 400 }, + { "GETDNS_EXTENSION_FALSE", 1001 }, + { "GETDNS_EXTENSION_TRUE", 1000 }, + { "GETDNS_NAMESPACE_DNS", 500 }, + { "GETDNS_NAMESPACE_LOCALNAMES", 501 }, + { "GETDNS_NAMESPACE_MDNS", 503 }, + { "GETDNS_NAMESPACE_NETBIOS", 502 }, + { "GETDNS_NAMESPACE_NIS", 504 }, + { "GETDNS_NAMETYPE_DNS", 800 }, + { "GETDNS_NAMETYPE_WINS", 801 }, + { "GETDNS_OPCODE_IQUERY", 1 }, + { "GETDNS_OPCODE_NOTIFY", 4 }, + { "GETDNS_OPCODE_QUERY", 0 }, + { "GETDNS_OPCODE_STATUS", 2 }, + { "GETDNS_OPCODE_UPDATE", 5 }, + { "GETDNS_RCODE_BADALG", 21 }, + { "GETDNS_RCODE_BADKEY", 17 }, + { "GETDNS_RCODE_BADMODE", 19 }, + { "GETDNS_RCODE_BADNAME", 20 }, + { "GETDNS_RCODE_BADSIG", 16 }, + { "GETDNS_RCODE_BADTIME", 18 }, + { "GETDNS_RCODE_BADTRUNC", 22 }, + { "GETDNS_RCODE_BADVERS", 16 }, + { "GETDNS_RCODE_FORMERR", 1 }, + { "GETDNS_RCODE_NOERROR", 0 }, + { "GETDNS_RCODE_NOTAUTH", 9 }, + { "GETDNS_RCODE_NOTIMP", 4 }, + { "GETDNS_RCODE_NOTZONE", 10 }, + { "GETDNS_RCODE_NXDOMAIN", 3 }, + { "GETDNS_RCODE_NXRRSET", 8 }, + { "GETDNS_RCODE_REFUSED", 5 }, + { "GETDNS_RCODE_SERVFAIL", 2 }, + { "GETDNS_RCODE_YXDOMAIN", 6 }, + { "GETDNS_RCODE_YXRRSET", 7 }, + { "GETDNS_REDIRECTS_DO_NOT_FOLLOW", 531 }, + { "GETDNS_REDIRECTS_FOLLOW", 530 }, + { "GETDNS_RESOLUTION_RECURSING", 521 }, + { "GETDNS_RESOLUTION_STUB", 520 }, + { "GETDNS_RESPSTATUS_ALL_BOGUS_ANSWERS", 904 }, + { "GETDNS_RESPSTATUS_ALL_TIMEOUT", 902 }, + { "GETDNS_RESPSTATUS_GOOD", 900 }, + { "GETDNS_RESPSTATUS_NO_NAME", 901 }, + { "GETDNS_RESPSTATUS_NO_SECURE_ANSWERS", 903 }, + { "GETDNS_RETURN_BAD_CONTEXT", 301 }, + { "GETDNS_RETURN_BAD_DOMAIN_NAME", 300 }, + { "GETDNS_RETURN_CONTEXT_UPDATE_FAIL", 302 }, + { "GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED", 309 }, + { "GETDNS_RETURN_EXTENSION_MISFORMAT", 308 }, + { "GETDNS_RETURN_GENERIC_ERROR", 1 }, + { "GETDNS_RETURN_GOOD", 0 }, + { "GETDNS_RETURN_INVALID_PARAMETER", 311 }, + { "GETDNS_RETURN_MEMORY_ERROR", 310 }, + { "GETDNS_RETURN_NEED_MORE_SPACE", 399 }, + { "GETDNS_RETURN_NOT_IMPLEMENTED", 312 }, + { "GETDNS_RETURN_NO_SUCH_DICT_NAME", 305 }, + { "GETDNS_RETURN_NO_SUCH_EXTENSION", 307 }, + { "GETDNS_RETURN_NO_SUCH_LIST_ITEM", 304 }, + { "GETDNS_RETURN_UNKNOWN_TRANSACTION", 303 }, + { "GETDNS_RETURN_WRONG_TYPE_REQUESTED", 306 }, + { "GETDNS_RRCLASS_ANY", 255 }, + { "GETDNS_RRCLASS_CH", 3 }, + { "GETDNS_RRCLASS_HS", 4 }, + { "GETDNS_RRCLASS_IN", 1 }, + { "GETDNS_RRCLASS_NONE", 254 }, + { "GETDNS_RRTYPE_A", 1 }, + { "GETDNS_RRTYPE_AAAA", 28 }, + { "GETDNS_RRTYPE_AFSDB", 18 }, + { "GETDNS_RRTYPE_ANY", 255 }, + { "GETDNS_RRTYPE_APL", 42 }, + { "GETDNS_RRTYPE_ATMA", 34 }, + { "GETDNS_RRTYPE_AXFR", 252 }, + { "GETDNS_RRTYPE_CAA", 257 }, + { "GETDNS_RRTYPE_CDNSKEY", 60 }, + { "GETDNS_RRTYPE_CDS", 59 }, + { "GETDNS_RRTYPE_CERT", 37 }, + { "GETDNS_RRTYPE_CNAME", 5 }, + { "GETDNS_RRTYPE_CSYNC", 62 }, + { "GETDNS_RRTYPE_DHCID", 49 }, + { "GETDNS_RRTYPE_DLV", 32769 }, + { "GETDNS_RRTYPE_DNAME", 39 }, + { "GETDNS_RRTYPE_DNSKEY", 48 }, + { "GETDNS_RRTYPE_DS", 43 }, + { "GETDNS_RRTYPE_EID", 31 }, + { "GETDNS_RRTYPE_GID", 102 }, + { "GETDNS_RRTYPE_GPOS", 27 }, + { "GETDNS_RRTYPE_HINFO", 13 }, + { "GETDNS_RRTYPE_HIP", 55 }, + { "GETDNS_RRTYPE_IPSECKEY", 45 }, + { "GETDNS_RRTYPE_ISDN", 20 }, + { "GETDNS_RRTYPE_IXFR", 251 }, + { "GETDNS_RRTYPE_KEY", 25 }, + { "GETDNS_RRTYPE_KX", 36 }, + { "GETDNS_RRTYPE_LOC", 29 }, + { "GETDNS_RRTYPE_LP", 107 }, + { "GETDNS_RRTYPE_MAILA", 254 }, + { "GETDNS_RRTYPE_MAILB", 253 }, + { "GETDNS_RRTYPE_MB", 7 }, + { "GETDNS_RRTYPE_MD", 3 }, + { "GETDNS_RRTYPE_MF", 4 }, + { "GETDNS_RRTYPE_MG", 8 }, + { "GETDNS_RRTYPE_MINFO", 14 }, + { "GETDNS_RRTYPE_MR", 9 }, + { "GETDNS_RRTYPE_MX", 15 }, + { "GETDNS_RRTYPE_NAPTR", 35 }, + { "GETDNS_RRTYPE_NID", 104 }, + { "GETDNS_RRTYPE_NIMLOC", 32 }, + { "GETDNS_RRTYPE_NINFO", 56 }, + { "GETDNS_RRTYPE_NS", 2 }, + { "GETDNS_RRTYPE_NSAP", 22 }, + { "GETDNS_RRTYPE_NSEC", 47 }, + { "GETDNS_RRTYPE_NULL", 10 }, + { "GETDNS_RRTYPE_NXT", 30 }, + { "GETDNS_RRTYPE_OPENPGPKEY", 61 }, + { "GETDNS_RRTYPE_OPT", 41 }, + { "GETDNS_RRTYPE_PTR", 12 }, + { "GETDNS_RRTYPE_PX", 26 }, + { "GETDNS_RRTYPE_RKEY", 57 }, + { "GETDNS_RRTYPE_RP", 17 }, + { "GETDNS_RRTYPE_RRSIG", 46 }, + { "GETDNS_RRTYPE_RT", 21 }, + { "GETDNS_RRTYPE_SIG", 24 }, + { "GETDNS_RRTYPE_SINK", 40 }, + { "GETDNS_RRTYPE_SOA", 6 }, + { "GETDNS_RRTYPE_SPF", 99 }, + { "GETDNS_RRTYPE_SRV", 33 }, + { "GETDNS_RRTYPE_SSHFP", 44 }, + { "GETDNS_RRTYPE_TA", 32768 }, + { "GETDNS_RRTYPE_TALINK", 58 }, + { "GETDNS_RRTYPE_TKEY", 249 }, + { "GETDNS_RRTYPE_TLSA", 52 }, + { "GETDNS_RRTYPE_TSIG", 250 }, + { "GETDNS_RRTYPE_TXT", 16 }, + { "GETDNS_RRTYPE_UID", 101 }, + { "GETDNS_RRTYPE_UINFO", 100 }, + { "GETDNS_RRTYPE_UNSPEC", 103 }, + { "GETDNS_RRTYPE_URI", 256 }, + { "GETDNS_RRTYPE_WKS", 11 }, + { "GETDNS_TRANSPORT_TCP", 1201 }, + { "GETDNS_TRANSPORT_TCP_ONLY", 542 }, + { "GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN", 543 }, + { "GETDNS_TRANSPORT_TLS", 1202 }, + { "GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN", 545 }, + { "GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN", 544 }, + { "GETDNS_TRANSPORT_UDP", 1200 }, + { "GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP", 540 }, + { "GETDNS_TRANSPORT_UDP_ONLY", 541 }, +}; + +static int const_name_info_cmp(const void *a, const void *b) +{ + return strcmp( ((struct const_name_info *) a)->name + , ((struct const_name_info *) b)->name ); +} + +int +_getdns_get_const_name_info(const char *name, uint32_t *code) +{ + struct const_name_info key = { name, 0 }; + struct const_name_info *i = bsearch(&key, consts_name_info, + sizeof(consts_name_info) / sizeof(struct const_name_info), + sizeof(struct const_name_info), const_name_info_cmp); + if (!i) + return 0; + if (code) + *code = i->code; + return 1; +} diff --git a/src/const-info.h b/src/const-info.h index 39d7c98e..379e2512 100644 --- a/src/const-info.h +++ b/src/const-info.h @@ -47,6 +47,13 @@ struct const_info { struct const_info *_getdns_get_const_info(int value); +struct const_name_info { + const char *name; + uint32_t code; +}; + +int _getdns_get_const_name_info(const char *name, uint32_t *code); + #endif /* const-info.h */ diff --git a/src/convert.c b/src/convert.c index 2539d7bd..c5bc98c4 100644 --- a/src/convert.c +++ b/src/convert.c @@ -48,9 +48,15 @@ #include "util-internal.h" #include "gldns/wire2str.h" #include "gldns/str2wire.h" +#include "gldns/parseutil.h" +#include "const-info.h" +#include "types-internal.h" /* For getdns_item */ #include "dict.h" #include "list.h" +#include "jsmn/jsmn.h" #include "convert.h" +#include /* For bsearch */ + /* stuff to make it compile pedantically */ #define UNUSED_PARAM(x) ((void)(x)) @@ -1031,5 +1037,641 @@ getdns_msg_dict2str_scan( return r; } +static getdns_dict * +_getdns_ipaddr_dict_mf(struct mem_funcs *mf, char *ipstr) +{ + getdns_dict *r = _getdns_dict_create_with_mf(mf); + char *s = strchr(ipstr, '%'), *scope_id_str = ""; + char *p = strchr(ipstr, '@'), *portstr = ""; + char *t = strchr(ipstr, '#'), *tls_portstr = ""; + char *n = strchr(ipstr, '~'), *tls_namestr = ""; + /* ^[alg:]name:key */ + char *T = strchr(ipstr, '^'), *tsig_name_str = "" + , *tsig_secret_str = "" + , *tsig_algorithm_str = ""; + char *br, *c; + int tsig_secret_size; + uint8_t tsig_secret_buf[256]; /* 4 times SHA512 */ + getdns_bindata tsig_secret; + uint8_t buf[sizeof(struct in6_addr)]; + getdns_bindata addr; + + addr.data = buf; + + if (!r) return NULL; + + if (*ipstr == '[') { + char *br = strchr(ipstr, ']'); + if (br) { + ipstr += 1; + *br = 0; + if ((c = strchr(br + 1, ':'))) { + p = c; + } + } + } else if ((br = strchr(ipstr, '.')) && (c = strchr(br + 1, ':')) + && (T == NULL || c < T)) + p = c; + + else if ((*ipstr == '*') && (c = strchr(ipstr+1, ':'))) + p = c; + + if (s) { + *s = 0; + scope_id_str = s + 1; + } + if (p) { + *p = 0; + portstr = p + 1; + } + if (t) { + *t = 0; + tls_portstr = t + 1; + } + if (n) { + *n = 0; + tls_namestr = n + 1; + } + if (T) { + *T = 0; + tsig_name_str = T + 1; + if ((T = strchr(tsig_name_str, ':'))) { + *T = 0; + tsig_secret_str = T + 1; + if ((T = strchr(tsig_secret_str, ':'))) { + *T = 0; + tsig_algorithm_str = tsig_name_str; + tsig_name_str = tsig_secret_str; + tsig_secret_str = T + 1; + } + } else { + tsig_name_str = ""; + } + } + if (*ipstr == '*') { + getdns_dict_util_set_string(r, "address_type", "IPv6"); + addr.size = 16; + (void) memset(buf, 0, 16); + } else if (strchr(ipstr, ':')) { + getdns_dict_util_set_string(r, "address_type", "IPv6"); + addr.size = 16; + if (inet_pton(AF_INET6, ipstr, buf) <= 0) { + getdns_dict_destroy(r); + return NULL; + } + } else { + getdns_dict_util_set_string(r, "address_type", "IPv4"); + addr.size = 4; + if (inet_pton(AF_INET, ipstr, buf) <= 0) { + getdns_dict_destroy(r); + return NULL; + } + } + getdns_dict_set_bindata(r, "address_data", &addr); + if (*portstr) + getdns_dict_set_int(r, "port", (int32_t)atoi(portstr)); + if (*tls_portstr) + getdns_dict_set_int(r, "tls_port", (int32_t)atoi(tls_portstr)); + if (*tls_namestr) { + getdns_dict_util_set_string(r, "tls_auth_name", tls_namestr); + } + if (*scope_id_str) + getdns_dict_util_set_string(r, "scope_id", scope_id_str); + if (*tsig_name_str) + getdns_dict_util_set_string(r, "tsig_name", tsig_name_str); + if (*tsig_algorithm_str) + getdns_dict_util_set_string(r, "tsig_algorithm", tsig_algorithm_str); + if (*tsig_secret_str) { + tsig_secret_size = gldns_b64_pton( + tsig_secret_str, tsig_secret_buf, sizeof(tsig_secret_buf)); + if (tsig_secret_size > 0) { + tsig_secret.size = tsig_secret_size; + tsig_secret.data = tsig_secret_buf; + getdns_dict_set_bindata(r, "tsig_secret", &tsig_secret); + } + } + return r; +} + +static int _jsmn_get_ipdict(struct mem_funcs *mf, const char *js, jsmntok_t *t, + getdns_dict **value) +{ + char value_str[3072]; + int size = t->end - t->start; + + if (size <= 0 || size >= sizeof(value_str)) + return 0; + + (void) memcpy(value_str, js + t->start, size); + value_str[size] = '\0'; + + *value = _getdns_ipaddr_dict_mf(mf, value_str); + return *value != NULL; +} + +static int _jsmn_get_data(struct mem_funcs *mf, const char *js, jsmntok_t *t, + getdns_bindata **value) +{ + size_t i, j; + uint8_t h, l; + + if ((t->end - t->start) < 4 || (t->end - t->start) % 2 == 1 || + js[t->start] != '0' || js[t->start + 1] != 'x') + return 0; + + for (i = t->start + 2; i < t->end; i++) + if (!((js[i] >= '0' && js[i] <= '9') + ||(js[i] >= 'a' && js[i] <= 'f') + ||(js[i] >= 'A' && js[i] <= 'F'))) + return 0; + + if (!(*value = GETDNS_MALLOC(*mf, getdns_bindata))) + return 0; + + else if (!((*value)->data = GETDNS_XMALLOC( + *mf, uint8_t, (t->end - t->start) / 2 - 1))) { + GETDNS_FREE(*mf, *value); + return 0; + } + for (i = t->start + 2, j = 0; i < t->end; i++, j++) { + h = js[i] >= '0' && js[i] <= '9' ? js[i] - '0' + : js[i] >= 'A' && js[i] <= 'F' ? js[i] + 10 - 'A' + : js[i] + 10 - 'a'; + h <<= 4; + i++; + l = js[i] >= '0' && js[i] <= '9' ? js[i] - '0' + : js[i] >= 'A' && js[i] <= 'F' ? js[i] + 10 - 'A' + : js[i] + 10 - 'a'; + (*value)->data[j] = h | l; + } + (*value)->size = j; + return 1; +} + +static int _jsmn_get_dname(struct mem_funcs *mf, const char *js, jsmntok_t *t, + getdns_bindata **value) +{ + char value_str[1025]; + int size = t->end - t->start; + + if (size <= 0 || size >= sizeof(value_str) || js[t->end - 1] != '.') + return 0; + + (void) memcpy(value_str, js + t->start, size); + value_str[size] = '\0'; + + return !getdns_convert_fqdn_to_dns_name(value_str, value); +} + +static int _jsmn_get_ipv4(struct mem_funcs *mf, const char *js, jsmntok_t *t, + getdns_bindata **value) +{ + char value_str[16]; + int size = t->end - t->start; + uint8_t buf[4]; + + if (size <= 0 || size >= sizeof(value_str)) + return 0; + + (void) memcpy(value_str, js + t->start, size); + value_str[size] = '\0'; + + if (inet_pton(AF_INET, value_str, buf) <= 0) + ; /* pass */ + + else if (!(*value = GETDNS_MALLOC(*mf, getdns_bindata))) + ; /* pass */ + + else if (!((*value)->data = GETDNS_XMALLOC(*mf, uint8_t, 4))) + GETDNS_FREE(*mf, *value); + + else { + (*value)->size = 4; + (void) memcpy((*value)->data, buf, 4); + return 1; + } + return 0; +} + +static int _jsmn_get_ipv6(struct mem_funcs *mf, const char *js, jsmntok_t *t, + getdns_bindata **value) +{ + char value_str[40]; + int size = t->end - t->start; + uint8_t buf[16]; + + if (size <= 0 || size >= sizeof(value_str)) + return 0; + + (void) memcpy(value_str, js + t->start, size); + value_str[size] = '\0'; + + if (inet_pton(AF_INET6, value_str, buf) <= 0) + ; /* pass */ + + else if (!(*value = GETDNS_MALLOC(*mf, getdns_bindata))) + ; /* pass */ + + else if (!((*value)->data = GETDNS_XMALLOC(*mf, uint8_t, 16))) + GETDNS_FREE(*mf, *value); + + else { + (*value)->size = 16; + (void) memcpy((*value)->data, buf, 16); + return 1; + } + return 0; +} + +static int _jsmn_get_int(struct mem_funcs *mf, const char *js, jsmntok_t *t, + uint32_t *value) +{ + char value_str[11]; + int size = t->end - t->start; + char *endptr; + + if (size <= 0 || size >= sizeof(value_str)) + return 0; + + (void) memcpy(value_str, js + t->start, size); + value_str[size] = '\0'; + + *value = (uint32_t)strtoul(value_str, &endptr, 10); + return *value_str != '\0' && *endptr == '\0'; +} + +static int _jsmn_get_const(struct mem_funcs *mf, const char *js, jsmntok_t *t, + uint32_t *value) +{ + char value_str[80]; + int size = t->end - t->start; + + if (size <= 0 || size >= sizeof(value_str)) + return 0; + + (void) memcpy(value_str, js + t->start, size); + value_str[size] = '\0'; + + return _getdns_get_const_name_info(value_str, value); +} + +static void +_getdns_destroy_item_data(struct mem_funcs *mf, getdns_item *item) +{ + switch (item->dtype) { + case t_dict: + getdns_dict_destroy(item->data.dict); + break; + + case t_list: + getdns_list_destroy(item->data.list); + break; + + case t_bindata: + GETDNS_FREE(*mf, item->data.bindata->data); + GETDNS_FREE(*mf, item->data.bindata); + default: + break; + } +} +static int _jsmn_get_item(struct mem_funcs *mf, const char *js, jsmntok_t *t, + size_t count, getdns_item *item, getdns_return_t *r); + +static int _jsmn_get_dict(struct mem_funcs *mf, const char *js, jsmntok_t *t, + size_t count, getdns_dict *dict, getdns_return_t *r) +{ + size_t i, j = 1; + char key_spc[1024], *key = NULL; + getdns_item child_item; + + for (i = 0; i < t->size; i++) { + if (t[j].type != JSMN_STRING && + t[j].type != JSMN_PRIMITIVE) { + + /* Key must be string or primitive */ + *r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; + break; + } + if (t[j].end <= t[j].start) { + /* Key must be at least 1 character */ + *r = GETDNS_RETURN_GENERIC_ERROR; /* range error */ + break; + } + if (t[j].end - t[j].start < sizeof(key_spc)) + key = key_spc; + + else if (!(key = GETDNS_XMALLOC( + *mf, char, t[j].end - t[j].start + 1))) { + + *r = GETDNS_RETURN_MEMORY_ERROR; + break; + } + (void) memcpy(key, js + t[j].start, t[j].end - t[j].start); + key[t[j].end - t[j].start] = '\0'; + j += 1; + + j += _jsmn_get_item(mf, js, t + j, count - j, &child_item, r); + if (*r) break; + + switch (child_item.dtype) { + case t_int: + *r = getdns_dict_set_int(dict, key, + child_item.data.n); + break; + case t_bindata: + *r = getdns_dict_set_bindata(dict, key, + child_item.data.bindata); + break; + case t_list: + *r = getdns_dict_set_list(dict, key, + child_item.data.list); + break; + case t_dict: + *r = getdns_dict_set_dict(dict, key, + child_item.data.dict); + break; + default: + *r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; + break; + + } + _getdns_destroy_item_data(mf, &child_item); + if (*r) break; + if (key && key != key_spc) { + GETDNS_FREE(*mf, key); + key = NULL; + } + } + if (key && key != key_spc) + GETDNS_FREE(*mf, key); + + if (*r) { + getdns_dict_destroy(dict); + return 0; + } + return j; +} + +static int _jsmn_get_list(struct mem_funcs *mf, const char *js, jsmntok_t *t, + size_t count, getdns_list *list, getdns_return_t *r) +{ + size_t i, j = 1, index = 0; + getdns_item child_item; + + for (i = 0; i < t->size; i++) { + j += _jsmn_get_item(mf, js, t + j, count - j, &child_item, r); + if (*r) break; + + switch (child_item.dtype) { + case t_int: + *r = getdns_list_set_int(list, index++, + child_item.data.n); + break; + case t_bindata: + *r = getdns_list_set_bindata(list, index++, + child_item.data.bindata); + break; + case t_list: + *r = getdns_list_set_list(list, index++, + child_item.data.list); + break; + case t_dict: + *r = getdns_list_set_dict(list, index++, + child_item.data.dict); + break; + default: + *r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; + break; + + } + _getdns_destroy_item_data(mf, &child_item); + if (*r) break; + } + if (*r) { + getdns_list_destroy(list); + return 0; + } + return j; +} + +static int _jsmn_get_item(struct mem_funcs *mf, const char *js, jsmntok_t *t, + size_t count, getdns_item *item, getdns_return_t *r) +{ + assert(item); + + switch (t->type) { + case JSMN_STRING: + if (t->end < t->start) + *r = GETDNS_RETURN_GENERIC_ERROR; + + else if (!(item->data.bindata = + GETDNS_MALLOC(*mf, getdns_bindata))) + *r = GETDNS_RETURN_MEMORY_ERROR; + + else if (!(item->data.bindata->data = GETDNS_XMALLOC( + *mf, uint8_t, t->end - t->start + 1))) { + GETDNS_FREE(*mf, item->data.bindata); + *r = GETDNS_RETURN_MEMORY_ERROR; + } else { + item->dtype = t_bindata; + if (t->end - t->start) { + (void) memcpy(item->data.bindata->data, + js + t->start, t->end - t->start); + } + item->data.bindata->data[t->end - t->start] = '\0'; + item->data.bindata->size = t->end - t->start; + *r = GETDNS_RETURN_GOOD; + return 1; + } + break; + + case JSMN_PRIMITIVE: + /* There is no such thing as an empty primitive */ + if (t->end <= t->start) { + *r = GETDNS_RETURN_GENERIC_ERROR; + break; + + } else if (_jsmn_get_int(mf, js, t, &item->data.n) + || _jsmn_get_const(mf, js, t, &item->data.n)) { + + item->dtype = t_int; + } + else if (_jsmn_get_data(mf, js, t, &item->data.bindata) + || _jsmn_get_dname(mf, js, t, &item->data.bindata) + || _jsmn_get_ipv4(mf, js, t, &item->data.bindata) + || _jsmn_get_ipv6(mf, js, t, &item->data.bindata)) + + item->dtype = t_bindata; + + else if (_jsmn_get_ipdict(mf, js, t, &item->data.dict)) + + item->dtype = t_dict; + else { + *r = GETDNS_RETURN_GENERIC_ERROR; + break; + } + *r = GETDNS_RETURN_GOOD; + return 1; + + case JSMN_OBJECT: + if (!(item->data.dict = _getdns_dict_create_with_mf(mf))) { + *r = GETDNS_RETURN_MEMORY_ERROR; + break; + } + item->dtype = t_dict; + return _jsmn_get_dict(mf, js, t, count, item->data.dict, r); + + case JSMN_ARRAY: + if (!(item->data.list = _getdns_list_create_with_mf(mf))) { + *r = GETDNS_RETURN_MEMORY_ERROR; + break; + } + item->dtype = t_list; + return _jsmn_get_list(mf, js, t, count, item->data.list, r); + + default: + *r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; + break; + } + return 0; +} + +static getdns_return_t +_getdns_str2item_mf(struct mem_funcs *mf, const char *str, getdns_item *item) +{ + jsmn_parser p; + jsmntok_t *tok = NULL, *new_tok; + size_t tokcount = 100; + int r; + getdns_return_t gr; + + jsmn_init(&p); + tok = GETDNS_XMALLOC(*mf, jsmntok_t, tokcount); + do { + r = jsmn_parse(&p, str, strlen(str), tok, tokcount); + if (r == JSMN_ERROR_NOMEM) { + tokcount *= 2; + if (!(new_tok = GETDNS_XREALLOC( + *mf, tok, jsmntok_t, tokcount))) { + GETDNS_FREE(*mf, tok); + return GETDNS_RETURN_MEMORY_ERROR; + } + tok = new_tok; + } + } while (r == JSMN_ERROR_NOMEM); + if (r < 0) + gr = GETDNS_RETURN_GENERIC_ERROR; + else + (void) _jsmn_get_item(mf, str, tok, p.toknext, item, &gr); + GETDNS_FREE(*mf, tok); + return gr; +} + +getdns_return_t +getdns_str2dict(const char *str, getdns_dict **dict) +{ + getdns_item item; + getdns_return_t r; + + if ((r = _getdns_str2item_mf(&_getdns_plain_mem_funcs, str, &item))) + return r; + + else if (item.dtype != t_dict) { + uint8_t buf[16]; + getdns_dict *dict_r; + + if (item.dtype != t_bindata) + r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; + + else if (item.data.bindata->size == 4 && + inet_pton(AF_INET, str, buf) == 1) { + + if (!(dict_r = getdns_dict_create())) + r = GETDNS_RETURN_MEMORY_ERROR; + + else if ((r = getdns_dict_util_set_string( + dict_r, "address_type", "IPv4"))) + getdns_dict_destroy(dict_r); + + else if ((r = getdns_dict_set_bindata( + dict_r, "address_data", item.data.bindata))) + getdns_dict_destroy(dict_r); + else + *dict = dict_r; + + } else if (item.data.bindata->size == 16 && + inet_pton(AF_INET6, str, buf) == 1) { + + if (!(dict_r = getdns_dict_create())) + r = GETDNS_RETURN_MEMORY_ERROR; + + else if ((r = getdns_dict_util_set_string( + dict_r, "address_type", "IPv6"))) + getdns_dict_destroy(dict_r); + + else if ((r = getdns_dict_set_bindata( + dict_r, "address_data", item.data.bindata))) + getdns_dict_destroy(dict_r); + else + *dict = dict_r; + } else + r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; + + _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); + return r; + } + *dict = item.data.dict; + return GETDNS_RETURN_GOOD; +} + +getdns_return_t +getdns_str2list(const char *str, getdns_list **list) +{ + getdns_item item; + getdns_return_t r; + + if ((r = _getdns_str2item_mf(&_getdns_plain_mem_funcs, str, &item))) + return r; + + else if (item.dtype != t_list) { + _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); + return GETDNS_RETURN_WRONG_TYPE_REQUESTED; + } + *list = item.data.list; + return GETDNS_RETURN_GOOD; +} + +getdns_return_t +getdns_str2bindata(const char *str, getdns_bindata **bindata) +{ + getdns_item item; + getdns_return_t r; + + if ((r = _getdns_str2item_mf(&_getdns_plain_mem_funcs, str, &item))) + return r; + + else if (item.dtype != t_bindata) { + _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); + return GETDNS_RETURN_WRONG_TYPE_REQUESTED; + } + *bindata = item.data.bindata; + return GETDNS_RETURN_GOOD; +} + +getdns_return_t +getdns_str2int(const char *str, uint32_t *value) +{ + getdns_item item; + getdns_return_t r; + + if ((r = _getdns_str2item_mf(&_getdns_plain_mem_funcs, str, &item))) + return r; + + else if (item.dtype != t_int) { + _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); + return GETDNS_RETURN_WRONG_TYPE_REQUESTED; + } + *value = item.data.n; + return GETDNS_RETURN_GOOD; +} -/* convert.c */ diff --git a/src/getdns/getdns_extra.h.in b/src/getdns/getdns_extra.h.in index c8a3713f..a8d9740b 100644 --- a/src/getdns/getdns_extra.h.in +++ b/src/getdns/getdns_extra.h.in @@ -822,6 +822,10 @@ getdns_validate_dnssec2(getdns_list *to_validate, #define GETDNS_APPEND_NAME_TO_SINGLE_LABEL_FIRST ((getdns_append_name_t) 554 ) #define GETDNS_APPEND_NAME_TO_SINGLE_LABEL_FIRST_TEXT "See getdns_context_set_append_name()" +getdns_return_t getdns_str2dict(const char *str, getdns_dict **dict); +getdns_return_t getdns_str2list(const char *str, getdns_list **list); +getdns_return_t getdns_str2bindata(const char *str, getdns_bindata **bindata); +getdns_return_t getdns_str2int(const char *str, uint32_t *value); #ifdef __cplusplus } diff --git a/src/test/jsmn b/src/jsmn similarity index 100% rename from src/test/jsmn rename to src/jsmn diff --git a/src/libgetdns.symbols b/src/libgetdns.symbols index 2eb8e381..88d1cebe 100644 --- a/src/libgetdns.symbols +++ b/src/libgetdns.symbols @@ -134,6 +134,10 @@ getdns_service getdns_service_sync getdns_snprint_json_dict getdns_snprint_json_list +getdns_str2bindata +getdns_str2dict +getdns_str2int +getdns_str2list getdns_str2rr_dict getdns_strerror getdns_validate_dnssec diff --git a/src/mk-const-info.c.sh b/src/mk-const-info.c.sh index 9e8b2826..f9c54323 100755 --- a/src/mk-const-info.c.sh +++ b/src/mk-const-info.c.sh @@ -46,18 +46,20 @@ getdns_get_errorstr_by_id(uint16_t err) else return NULL; } -END_OF_TAIL -gawk 'BEGIN{p=1}{if(p)print}/^static struct const_name_info consts_name_info\[\] = {$/{p=0}' test/getdns_str2dict.c > test/new-getdns_str2dict.c -gawk '/^[ ]+GETDNS_[A-Z_]+[ ]+=[ ]+[0-9]+/{ key = sprintf("%d", $3); consts[$1] = key; }/^#define GETDNS_[A-Z_]+[ ]+[0-9]+/ && !/_TEXT/{ key = sprintf("%d", $3); consts[$2] = key; }/^#define GETDNS_[A-Z_]+[ ]+\(\(getdns_(return|append_name)_t) [0-9]+ \)/{ key = sprintf("%d", $4); consts[$2] = key; }END{ n = asorti(consts, const_vals); for ( i = 1; i <= n; i++) { val = const_vals[i]; name = consts[val]; print "\t{ \""val"\", "name" },"}}' getdns/getdns.h.in getdns/getdns_extra.h.in | sed 's/,,/,/g' >> test/new-getdns_str2dict.c -cat >> test/new-getdns_str2dict.c << END_OF_TAIL +static struct const_name_info consts_name_info[] = { +END_OF_TAIL +gawk '/^[ ]+GETDNS_[A-Z_]+[ ]+=[ ]+[0-9]+/{ key = sprintf("%d", $3); consts[$1] = key; }/^#define GETDNS_[A-Z_]+[ ]+[0-9]+/ && !/_TEXT/{ key = sprintf("%d", $3); consts[$2] = key; }/^#define GETDNS_[A-Z_]+[ ]+\(\(getdns_(return|append_name)_t) [0-9]+ \)/{ key = sprintf("%d", $4); consts[$2] = key; }END{ n = asorti(consts, const_vals); for ( i = 1; i <= n; i++) { val = const_vals[i]; name = consts[val]; print "\t{ \""val"\", "name" },"}}' getdns/getdns.h.in getdns/getdns_extra.h.in | sed 's/,,/,/g' >> const-info.c +cat >> const-info.c << END_OF_TAIL }; + static int const_name_info_cmp(const void *a, const void *b) { return strcmp( ((struct const_name_info *) a)->name , ((struct const_name_info *) b)->name ); } -static int + +int _getdns_get_const_name_info(const char *name, uint32_t *code) { struct const_name_info key = { name, 0 }; @@ -71,5 +73,4 @@ _getdns_get_const_name_info(const char *name, uint32_t *code) return 1; } END_OF_TAIL -mv test/new-getdns_str2dict.c test/getdns_str2dict.c diff --git a/src/test/Makefile.in b/src/test/Makefile.in index 797f2e6e..f66494e7 100644 --- a/src/test/Makefile.in +++ b/src/test/Makefile.in @@ -66,16 +66,13 @@ CHECK_CFLAGS=@CHECK_CFLAGS@ CHECK_OBJS=check_getdns_common.lo check_getdns_context_set_timeout.lo \ check_getdns.lo check_getdns_transport.lo -DECOMPOSED_OBJS_WITHOUT_JSMN=getdns_str2dict.lo getdns_context_config.lo \ - getdns_context_set_listen_addresses.lo - -DECOMPOSED_OBJS=$(DECOMPOSED_OBJS_WITHOUT_JSMN) jsmn.lo +DECOMPOSED_OBJS=getdns_context_config.lo getdns_context_set_listen_addresses.lo ALL_OBJS=$(CHECK_OBJS) check_getdns_libevent.lo check_getdns_libev.lo \ check_getdns_selectloop.lo getdns_query.lo scratchpad.lo \ testmessages.lo tests_dict.lo tests_list.lo tests_namespaces.lo \ tests_stub_async.lo tests_stub_sync.lo \ - $(DECOMPOSED_OBJS_WITHOUT_JSMN) + $(DECOMPOSED_OBJS) NON_C99_OBJS=check_getdns_libuv.lo @@ -94,9 +91,6 @@ default: all all: $(PROGRAMS) -jsmn.lo: - $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -DJSMN_GETDNS -c $(srcdir)/jsmn/jsmn.c -o $@ - $(ALL_OBJS): $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $(srcdir)/$(@:.lo=.c) -o $@ @@ -221,7 +215,6 @@ depend: -e 's? \$$(srcdir)/\.\./config\.h? ../config.h?g' \ -e 's? \$$(srcdir)/\.\./getdns/getdns\.h? ../getdns/getdns.h?g' \ -e 's? \$$(srcdir)/\.\./getdns/getdns_extra\.h? ../getdns/getdns_extra.h?g' \ - -e 's? jsmn/jsmn\.h? $$(srcdir)/jsmn/jsmn.h?g' \ -e 's!\(.*\)\.o[ :]*!\1.lo \1.o: !g' >> Makefile.in.new ) (cd $(srcdir) ; diff Makefile.in.new Makefile.in && rm Makefile.in.new \ || mv Makefile.in.new Makefile.in ) @@ -273,20 +266,18 @@ check_getdns_selectloop.lo check_getdns_selectloop.o: $(srcdir)/check_getdns_sel check_getdns_transport.lo check_getdns_transport.o: $(srcdir)/check_getdns_transport.c \ $(srcdir)/check_getdns_transport.h $(srcdir)/check_getdns_common.h ../getdns/getdns.h \ ../getdns/getdns_extra.h +const-info.lo const-info.o: $(srcdir)/const-info.c getdns_context_config.lo getdns_context_config.o: $(srcdir)/getdns_context_config.c $(srcdir)/getdns_context_config.h \ ../getdns/getdns.h ../getdns/getdns_extra.h getdns_context_set_listen_addresses.lo getdns_context_set_listen_addresses.o: \ $(srcdir)/getdns_context_set_listen_addresses.c ../config.h \ $(srcdir)/getdns_context_set_listen_addresses.h ../getdns/getdns.h \ ../getdns/getdns_extra.h $(srcdir)/../types-internal.h ../getdns/getdns.h \ - ../getdns/getdns_extra.h $(srcdir)/../util/rbtree.h + ../getdns/getdns_extra.h $(srcdir)/../util/rbtree.h $(srcdir)/../debug.h ../config.h getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c ../config.h $(srcdir)/../debug.h ../config.h \ - $(srcdir)/getdns_str2dict.h ../getdns/getdns.h $(srcdir)/getdns_context_config.h \ + $(srcdir)/getdns_context_config.h ../getdns/getdns.h \ $(srcdir)/getdns_context_set_listen_addresses.h ../getdns/getdns_extra.h -getdns_str2dict.lo getdns_str2dict.o: $(srcdir)/getdns_str2dict.c ../config.h $(srcdir)/../const-info.h \ - $(srcdir)/jsmn/jsmn.h $(srcdir)/getdns_str2dict.h ../getdns/getdns.h $(srcdir)/../types-internal.h \ - ../getdns/getdns.h ../getdns/getdns_extra.h $(srcdir)/../util/rbtree.h $(srcdir)/../list.h \ - $(srcdir)/../types-internal.h $(srcdir)/../dict.h +new-getdns_str2dict.lo new-getdns_str2dict.o: $(srcdir)/new-getdns_str2dict.c scratchpad.template.lo scratchpad.template.o: scratchpad.template.c ../getdns/getdns.h \ ../getdns/getdns_extra.h testmessages.lo testmessages.o: $(srcdir)/testmessages.c $(srcdir)/testmessages.h diff --git a/src/test/getdns_query.c b/src/test/getdns_query.c index 09184e6d..ced608bb 100644 --- a/src/test/getdns_query.c +++ b/src/test/getdns_query.c @@ -27,7 +27,6 @@ #include "config.h" #include "debug.h" -#include "getdns_str2dict.h" #include "getdns_context_config.h" #include "getdns_context_set_listen_addresses.h" #include diff --git a/src/test/getdns_str2dict.c b/src/test/getdns_str2dict.c deleted file mode 100644 index ae5fb1d9..00000000 --- a/src/test/getdns_str2dict.c +++ /dev/null @@ -1,951 +0,0 @@ -/* - * Copyright (c) 2013, NLNet Labs, Verisign, 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 names of the copyright holders 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 "config.h" -#include "const-info.h" -#include "jsmn/jsmn.h" -#include "getdns_str2dict.h" -#include "types-internal.h" /* For getdns_item */ -#include "list.h" /* For _getdns_list_create_from_mf() */ -#include "dict.h" /* For _getdns_dict_create_from_mf() */ -#include /* For bsearch */ - -static struct mem_funcs _getdns_plain_mem_funcs = { - MF_PLAIN, .mf.pln = { malloc, realloc, free } -}; - -/* TODO: Replace with gldns_b64_pton - * once getdns_ipaddr_dict becomes part of the library - */ -static int _gldns_b64_pton(char const *src, uint8_t *target, size_t targsize) -{ - const uint8_t pad64 = 64; /* is 64th in the b64 array */ - const char* s = src; - uint8_t in[4]; - size_t o = 0, incount = 0; - - while(*s) { - /* skip any character that is not base64 */ - /* conceptually we do: - const char* b64 = pad'=' is appended to array - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - const char* d = strchr(b64, *s++); - and use d-b64; - */ - char d = *s++; - if(d <= 'Z' && d >= 'A') - d -= 'A'; - else if(d <= 'z' && d >= 'a') - d = d - 'a' + 26; - else if(d <= '9' && d >= '0') - d = d - '0' + 52; - else if(d == '+') - d = 62; - else if(d == '/') - d = 63; - else if(d == '=') - d = 64; - else continue; - in[incount++] = (uint8_t)d; - if(incount != 4) - continue; - /* process whole block of 4 characters into 3 output bytes */ - if(in[3] == pad64 && in[2] == pad64) { /* A B = = */ - if(o+1 > targsize) - return -1; - target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); - o += 1; - break; /* we are done */ - } else if(in[3] == pad64) { /* A B C = */ - if(o+2 > targsize) - return -1; - target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); - target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2); - o += 2; - break; /* we are done */ - } else { - if(o+3 > targsize) - return -1; - /* write xxxxxxyy yyyyzzzz zzwwwwww */ - target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); - target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2); - target[o+2]= ((in[2]&0x03)<<6) | in[3]; - o += 3; - } - incount = 0; - } - return (int)o; -} - -static getdns_dict * -_getdns_ipaddr_dict_mf(struct mem_funcs *mf, char *ipstr) -{ - getdns_dict *r = _getdns_dict_create_with_mf(mf); - char *s = strchr(ipstr, '%'), *scope_id_str = ""; - char *p = strchr(ipstr, '@'), *portstr = ""; - char *t = strchr(ipstr, '#'), *tls_portstr = ""; - char *n = strchr(ipstr, '~'), *tls_namestr = ""; - /* ^[alg:]name:key */ - char *T = strchr(ipstr, '^'), *tsig_name_str = "" - , *tsig_secret_str = "" - , *tsig_algorithm_str = ""; - char *br, *c; - int tsig_secret_size; - uint8_t tsig_secret_buf[256]; /* 4 times SHA512 */ - getdns_bindata tsig_secret; - uint8_t buf[sizeof(struct in6_addr)]; - getdns_bindata addr; - - addr.data = buf; - - if (!r) return NULL; - - if (*ipstr == '[') { - char *br = strchr(ipstr, ']'); - if (br) { - ipstr += 1; - *br = 0; - if ((c = strchr(br + 1, ':'))) { - p = c; - } - } - } else if ((br = strchr(ipstr, '.')) && (c = strchr(br + 1, ':')) - && (T == NULL || c < T)) - p = c; - - else if ((*ipstr == '*') && (c = strchr(ipstr+1, ':'))) - p = c; - - if (s) { - *s = 0; - scope_id_str = s + 1; - } - if (p) { - *p = 0; - portstr = p + 1; - } - if (t) { - *t = 0; - tls_portstr = t + 1; - } - if (n) { - *n = 0; - tls_namestr = n + 1; - } - if (T) { - *T = 0; - tsig_name_str = T + 1; - if ((T = strchr(tsig_name_str, ':'))) { - *T = 0; - tsig_secret_str = T + 1; - if ((T = strchr(tsig_secret_str, ':'))) { - *T = 0; - tsig_algorithm_str = tsig_name_str; - tsig_name_str = tsig_secret_str; - tsig_secret_str = T + 1; - } - } else { - tsig_name_str = ""; - } - } - if (*ipstr == '*') { - getdns_dict_util_set_string(r, "address_type", "IPv6"); - addr.size = 16; - (void) memset(buf, 0, 16); - } else if (strchr(ipstr, ':')) { - getdns_dict_util_set_string(r, "address_type", "IPv6"); - addr.size = 16; - if (inet_pton(AF_INET6, ipstr, buf) <= 0) { - getdns_dict_destroy(r); - return NULL; - } - } else { - getdns_dict_util_set_string(r, "address_type", "IPv4"); - addr.size = 4; - if (inet_pton(AF_INET, ipstr, buf) <= 0) { - getdns_dict_destroy(r); - return NULL; - } - } - getdns_dict_set_bindata(r, "address_data", &addr); - if (*portstr) - getdns_dict_set_int(r, "port", (int32_t)atoi(portstr)); - if (*tls_portstr) - getdns_dict_set_int(r, "tls_port", (int32_t)atoi(tls_portstr)); - if (*tls_namestr) { - getdns_dict_util_set_string(r, "tls_auth_name", tls_namestr); - } - if (*scope_id_str) - getdns_dict_util_set_string(r, "scope_id", scope_id_str); - if (*tsig_name_str) - getdns_dict_util_set_string(r, "tsig_name", tsig_name_str); - if (*tsig_algorithm_str) - getdns_dict_util_set_string(r, "tsig_algorithm", tsig_algorithm_str); - if (*tsig_secret_str) { - tsig_secret_size = _gldns_b64_pton( - tsig_secret_str, tsig_secret_buf, sizeof(tsig_secret_buf)); - if (tsig_secret_size > 0) { - tsig_secret.size = tsig_secret_size; - tsig_secret.data = tsig_secret_buf; - getdns_dict_set_bindata(r, "tsig_secret", &tsig_secret); - } - } - return r; -} - -static int _jsmn_get_ipdict(struct mem_funcs *mf, const char *js, jsmntok_t *t, - getdns_dict **value) -{ - char value_str[3072]; - int size = t->end - t->start; - - if (size <= 0 || size >= sizeof(value_str)) - return 0; - - (void) memcpy(value_str, js + t->start, size); - value_str[size] = '\0'; - - *value = _getdns_ipaddr_dict_mf(mf, value_str); - return *value != NULL; -} - -static int _jsmn_get_data(struct mem_funcs *mf, const char *js, jsmntok_t *t, - getdns_bindata **value) -{ - size_t i, j; - uint8_t h, l; - - if ((t->end - t->start) < 4 || (t->end - t->start) % 2 == 1 || - js[t->start] != '0' || js[t->start + 1] != 'x') - return 0; - - for (i = t->start + 2; i < t->end; i++) - if (!((js[i] >= '0' && js[i] <= '9') - ||(js[i] >= 'a' && js[i] <= 'f') - ||(js[i] >= 'A' && js[i] <= 'F'))) - return 0; - - if (!(*value = GETDNS_MALLOC(*mf, getdns_bindata))) - return 0; - - else if (!((*value)->data = GETDNS_XMALLOC( - *mf, uint8_t, (t->end - t->start) / 2 - 1))) { - GETDNS_FREE(*mf, *value); - return 0; - } - for (i = t->start + 2, j = 0; i < t->end; i++, j++) { - h = js[i] >= '0' && js[i] <= '9' ? js[i] - '0' - : js[i] >= 'A' && js[i] <= 'F' ? js[i] + 10 - 'A' - : js[i] + 10 - 'a'; - h <<= 4; - i++; - l = js[i] >= '0' && js[i] <= '9' ? js[i] - '0' - : js[i] >= 'A' && js[i] <= 'F' ? js[i] + 10 - 'A' - : js[i] + 10 - 'a'; - (*value)->data[j] = h | l; - } - (*value)->size = j; - return 1; -} - -static int _jsmn_get_dname(struct mem_funcs *mf, const char *js, jsmntok_t *t, - getdns_bindata **value) -{ - char value_str[1025]; - int size = t->end - t->start; - - if (size <= 0 || size >= sizeof(value_str) || js[t->end - 1] != '.') - return 0; - - (void) memcpy(value_str, js + t->start, size); - value_str[size] = '\0'; - - return !getdns_convert_fqdn_to_dns_name(value_str, value); -} - -static int _jsmn_get_ipv4(struct mem_funcs *mf, const char *js, jsmntok_t *t, - getdns_bindata **value) -{ - char value_str[16]; - int size = t->end - t->start; - uint8_t buf[4]; - - if (size <= 0 || size >= sizeof(value_str)) - return 0; - - (void) memcpy(value_str, js + t->start, size); - value_str[size] = '\0'; - - if (inet_pton(AF_INET, value_str, buf) <= 0) - ; /* pass */ - - else if (!(*value = GETDNS_MALLOC(*mf, getdns_bindata))) - ; /* pass */ - - else if (!((*value)->data = GETDNS_XMALLOC(*mf, uint8_t, 4))) - GETDNS_FREE(*mf, *value); - - else { - (*value)->size = 4; - (void) memcpy((*value)->data, buf, 4); - return 1; - } - return 0; -} - -static int _jsmn_get_ipv6(struct mem_funcs *mf, const char *js, jsmntok_t *t, - getdns_bindata **value) -{ - char value_str[40]; - int size = t->end - t->start; - uint8_t buf[16]; - - if (size <= 0 || size >= sizeof(value_str)) - return 0; - - (void) memcpy(value_str, js + t->start, size); - value_str[size] = '\0'; - - if (inet_pton(AF_INET6, value_str, buf) <= 0) - ; /* pass */ - - else if (!(*value = GETDNS_MALLOC(*mf, getdns_bindata))) - ; /* pass */ - - else if (!((*value)->data = GETDNS_XMALLOC(*mf, uint8_t, 16))) - GETDNS_FREE(*mf, *value); - - else { - (*value)->size = 16; - (void) memcpy((*value)->data, buf, 16); - return 1; - } - return 0; -} - -static int _jsmn_get_int(struct mem_funcs *mf, const char *js, jsmntok_t *t, - uint32_t *value) -{ - char value_str[11]; - int size = t->end - t->start; - char *endptr; - - if (size <= 0 || size >= sizeof(value_str)) - return 0; - - (void) memcpy(value_str, js + t->start, size); - value_str[size] = '\0'; - - *value = (uint32_t)strtoul(value_str, &endptr, 10); - return *value_str != '\0' && *endptr == '\0'; -} - -static int _getdns_get_const_name_info(const char *name, uint32_t *code); - -static int _jsmn_get_const(struct mem_funcs *mf, const char *js, jsmntok_t *t, - uint32_t *value) -{ - char value_str[80]; - int size = t->end - t->start; - - if (size <= 0 || size >= sizeof(value_str)) - return 0; - - (void) memcpy(value_str, js + t->start, size); - value_str[size] = '\0'; - - return _getdns_get_const_name_info(value_str, value); -} - -static void -_getdns_destroy_item_data(struct mem_funcs *mf, getdns_item *item) -{ - switch (item->dtype) { - case t_dict: - getdns_dict_destroy(item->data.dict); - break; - - case t_list: - getdns_list_destroy(item->data.list); - break; - - case t_bindata: - GETDNS_FREE(*mf, item->data.bindata->data); - GETDNS_FREE(*mf, item->data.bindata); - default: - break; - } -} -static int _jsmn_get_item(struct mem_funcs *mf, const char *js, jsmntok_t *t, - size_t count, getdns_item *item, getdns_return_t *r); - -static int _jsmn_get_dict(struct mem_funcs *mf, const char *js, jsmntok_t *t, - size_t count, getdns_dict *dict, getdns_return_t *r) -{ - size_t i, j = 1; - char key_spc[1024], *key = NULL; - getdns_item child_item; - - for (i = 0; i < t->size; i++) { - if (t[j].type != JSMN_STRING && - t[j].type != JSMN_PRIMITIVE) { - - /* Key must be string or primitive */ - *r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; - break; - } - if (t[j].end <= t[j].start) { - /* Key must be at least 1 character */ - *r = GETDNS_RETURN_GENERIC_ERROR; /* range error */ - break; - } - if (t[j].end - t[j].start < sizeof(key_spc)) - key = key_spc; - - else if (!(key = GETDNS_XMALLOC( - *mf, char, t[j].end - t[j].start + 1))) { - - *r = GETDNS_RETURN_MEMORY_ERROR; - break; - } - (void) memcpy(key, js + t[j].start, t[j].end - t[j].start); - key[t[j].end - t[j].start] = '\0'; - j += 1; - - j += _jsmn_get_item(mf, js, t + j, count - j, &child_item, r); - if (*r) break; - - switch (child_item.dtype) { - case t_int: - *r = getdns_dict_set_int(dict, key, - child_item.data.n); - break; - case t_bindata: - *r = getdns_dict_set_bindata(dict, key, - child_item.data.bindata); - break; - case t_list: - *r = getdns_dict_set_list(dict, key, - child_item.data.list); - break; - case t_dict: - *r = getdns_dict_set_dict(dict, key, - child_item.data.dict); - break; - default: - *r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; - break; - - } - _getdns_destroy_item_data(mf, &child_item); - if (*r) break; - if (key && key != key_spc) { - GETDNS_FREE(*mf, key); - key = NULL; - } - } - if (key && key != key_spc) - GETDNS_FREE(*mf, key); - - if (*r) { - getdns_dict_destroy(dict); - return 0; - } - return j; -} - -static int _jsmn_get_list(struct mem_funcs *mf, const char *js, jsmntok_t *t, - size_t count, getdns_list *list, getdns_return_t *r) -{ - size_t i, j = 1, index = 0; - getdns_item child_item; - - for (i = 0; i < t->size; i++) { - j += _jsmn_get_item(mf, js, t + j, count - j, &child_item, r); - if (*r) break; - - switch (child_item.dtype) { - case t_int: - *r = getdns_list_set_int(list, index++, - child_item.data.n); - break; - case t_bindata: - *r = getdns_list_set_bindata(list, index++, - child_item.data.bindata); - break; - case t_list: - *r = getdns_list_set_list(list, index++, - child_item.data.list); - break; - case t_dict: - *r = getdns_list_set_dict(list, index++, - child_item.data.dict); - break; - default: - *r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; - break; - - } - _getdns_destroy_item_data(mf, &child_item); - if (*r) break; - } - if (*r) { - getdns_list_destroy(list); - return 0; - } - return j; -} - -static int _jsmn_get_item(struct mem_funcs *mf, const char *js, jsmntok_t *t, - size_t count, getdns_item *item, getdns_return_t *r) -{ - assert(item); - - switch (t->type) { - case JSMN_STRING: - if (t->end < t->start) - *r = GETDNS_RETURN_GENERIC_ERROR; - - else if (!(item->data.bindata = - GETDNS_MALLOC(*mf, getdns_bindata))) - *r = GETDNS_RETURN_MEMORY_ERROR; - - else if (!(item->data.bindata->data = GETDNS_XMALLOC( - *mf, uint8_t, t->end - t->start + 1))) { - GETDNS_FREE(*mf, item->data.bindata); - *r = GETDNS_RETURN_MEMORY_ERROR; - } else { - item->dtype = t_bindata; - if (t->end - t->start) { - (void) memcpy(item->data.bindata->data, - js + t->start, t->end - t->start); - } - item->data.bindata->data[t->end - t->start] = '\0'; - item->data.bindata->size = t->end - t->start; - *r = GETDNS_RETURN_GOOD; - return 1; - } - break; - - case JSMN_PRIMITIVE: - /* There is no such thing as an empty primitive */ - if (t->end <= t->start) { - *r = GETDNS_RETURN_GENERIC_ERROR; - break; - - } else if (_jsmn_get_int(mf, js, t, &item->data.n) - || _jsmn_get_const(mf, js, t, &item->data.n)) { - - item->dtype = t_int; - } - else if (_jsmn_get_data(mf, js, t, &item->data.bindata) - || _jsmn_get_dname(mf, js, t, &item->data.bindata) - || _jsmn_get_ipv4(mf, js, t, &item->data.bindata) - || _jsmn_get_ipv6(mf, js, t, &item->data.bindata)) - - item->dtype = t_bindata; - - else if (_jsmn_get_ipdict(mf, js, t, &item->data.dict)) - - item->dtype = t_dict; - else { - *r = GETDNS_RETURN_GENERIC_ERROR; - break; - } - *r = GETDNS_RETURN_GOOD; - return 1; - - case JSMN_OBJECT: - if (!(item->data.dict = _getdns_dict_create_with_mf(mf))) { - *r = GETDNS_RETURN_MEMORY_ERROR; - break; - } - item->dtype = t_dict; - return _jsmn_get_dict(mf, js, t, count, item->data.dict, r); - - case JSMN_ARRAY: - if (!(item->data.list = _getdns_list_create_with_mf(mf))) { - *r = GETDNS_RETURN_MEMORY_ERROR; - break; - } - item->dtype = t_list; - return _jsmn_get_list(mf, js, t, count, item->data.list, r); - - default: - *r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; - break; - } - return 0; -} - -static getdns_return_t -_getdns_str2item_mf(struct mem_funcs *mf, const char *str, getdns_item *item) -{ - jsmn_parser p; - jsmntok_t *tok = NULL, *new_tok; - size_t tokcount = 100; - int r; - getdns_return_t gr; - - jsmn_init(&p); - tok = GETDNS_XMALLOC(*mf, jsmntok_t, tokcount); - do { - r = jsmn_parse(&p, str, strlen(str), tok, tokcount); - if (r == JSMN_ERROR_NOMEM) { - tokcount *= 2; - if (!(new_tok = GETDNS_XREALLOC( - *mf, tok, jsmntok_t, tokcount))) { - GETDNS_FREE(*mf, tok); - return GETDNS_RETURN_MEMORY_ERROR; - } - tok = new_tok; - } - } while (r == JSMN_ERROR_NOMEM); - if (r < 0) - gr = GETDNS_RETURN_GENERIC_ERROR; - else - (void) _jsmn_get_item(mf, str, tok, p.toknext, item, &gr); - GETDNS_FREE(*mf, tok); - return gr; -} - -getdns_return_t -getdns_str2dict(const char *str, getdns_dict **dict) -{ - getdns_item item; - getdns_return_t r; - - if ((r = _getdns_str2item_mf(&_getdns_plain_mem_funcs, str, &item))) - return r; - - else if (item.dtype != t_dict) { - uint8_t buf[16]; - getdns_dict *dict_r; - - if (item.dtype != t_bindata) - r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; - - else if (item.data.bindata->size == 4 && - inet_pton(AF_INET, str, buf) == 1) { - - if (!(dict_r = getdns_dict_create())) - r = GETDNS_RETURN_MEMORY_ERROR; - - else if ((r = getdns_dict_util_set_string( - dict_r, "address_type", "IPv4"))) - getdns_dict_destroy(dict_r); - - else if ((r = getdns_dict_set_bindata( - dict_r, "address_data", item.data.bindata))) - getdns_dict_destroy(dict_r); - else - *dict = dict_r; - - } else if (item.data.bindata->size == 16 && - inet_pton(AF_INET6, str, buf) == 1) { - - if (!(dict_r = getdns_dict_create())) - r = GETDNS_RETURN_MEMORY_ERROR; - - else if ((r = getdns_dict_util_set_string( - dict_r, "address_type", "IPv6"))) - getdns_dict_destroy(dict_r); - - else if ((r = getdns_dict_set_bindata( - dict_r, "address_data", item.data.bindata))) - getdns_dict_destroy(dict_r); - else - *dict = dict_r; - } else - r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; - - _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); - return r; - } - *dict = item.data.dict; - return GETDNS_RETURN_GOOD; -} - -getdns_return_t -getdns_str2list(const char *str, getdns_list **list) -{ - getdns_item item; - getdns_return_t r; - - if ((r = _getdns_str2item_mf(&_getdns_plain_mem_funcs, str, &item))) - return r; - - else if (item.dtype != t_list) { - _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); - return GETDNS_RETURN_WRONG_TYPE_REQUESTED; - } - *list = item.data.list; - return GETDNS_RETURN_GOOD; -} - -getdns_return_t -getdns_str2bindata(const char *str, getdns_bindata **bindata) -{ - getdns_item item; - getdns_return_t r; - - if ((r = _getdns_str2item_mf(&_getdns_plain_mem_funcs, str, &item))) - return r; - - else if (item.dtype != t_bindata) { - _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); - return GETDNS_RETURN_WRONG_TYPE_REQUESTED; - } - *bindata = item.data.bindata; - return GETDNS_RETURN_GOOD; -} - -getdns_return_t -getdns_str2int(const char *str, uint32_t *value) -{ - getdns_item item; - getdns_return_t r; - - if ((r = _getdns_str2item_mf(&_getdns_plain_mem_funcs, str, &item))) - return r; - - else if (item.dtype != t_int) { - _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); - return GETDNS_RETURN_WRONG_TYPE_REQUESTED; - } - *value = item.data.n; - return GETDNS_RETURN_GOOD; -} - - -struct const_name_info { const char *name; uint32_t code; }; -static struct const_name_info consts_name_info[] = { - { "GETDNS_APPEND_NAME_ALWAYS", 550 }, - { "GETDNS_APPEND_NAME_NEVER", 553 }, - { "GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE", 552 }, - { "GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE", 551 }, - { "GETDNS_APPEND_NAME_TO_SINGLE_LABEL_FIRST", 554 }, - { "GETDNS_AUTHENTICATION_NONE", 1300 }, - { "GETDNS_AUTHENTICATION_REQUIRED", 1301 }, - { "GETDNS_BAD_DNS_ALL_NUMERIC_LABEL", 1101 }, - { "GETDNS_BAD_DNS_CNAME_IN_TARGET", 1100 }, - { "GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE", 1102 }, - { "GETDNS_CALLBACK_CANCEL", 701 }, - { "GETDNS_CALLBACK_COMPLETE", 700 }, - { "GETDNS_CALLBACK_ERROR", 703 }, - { "GETDNS_CALLBACK_TIMEOUT", 702 }, - { "GETDNS_CONTEXT_CODE_APPEND_NAME", 607 }, - { "GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW", 614 }, - { "GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS", 609 }, - { "GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS", 604 }, - { "GETDNS_CONTEXT_CODE_DNS_TRANSPORT", 605 }, - { "GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE", 619 }, - { "GETDNS_CONTEXT_CODE_EDNS_DO_BIT", 613 }, - { "GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE", 611 }, - { "GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE", 610 }, - { "GETDNS_CONTEXT_CODE_EDNS_VERSION", 612 }, - { "GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS", 602 }, - { "GETDNS_CONTEXT_CODE_IDLE_TIMEOUT", 617 }, - { "GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES", 606 }, - { "GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS", 615 }, - { "GETDNS_CONTEXT_CODE_NAMESPACES", 600 }, - { "GETDNS_CONTEXT_CODE_PUBKEY_PINSET", 621 }, - { "GETDNS_CONTEXT_CODE_RESOLUTION_TYPE", 601 }, - { "GETDNS_CONTEXT_CODE_SUFFIX", 608 }, - { "GETDNS_CONTEXT_CODE_TIMEOUT", 616 }, - { "GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION", 618 }, - { "GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE", 620 }, - { "GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS", 603 }, - { "GETDNS_DNSSEC_BOGUS", 401 }, - { "GETDNS_DNSSEC_INDETERMINATE", 402 }, - { "GETDNS_DNSSEC_INSECURE", 403 }, - { "GETDNS_DNSSEC_NOT_PERFORMED", 404 }, - { "GETDNS_DNSSEC_SECURE", 400 }, - { "GETDNS_EXTENSION_FALSE", 1001 }, - { "GETDNS_EXTENSION_TRUE", 1000 }, - { "GETDNS_NAMESPACE_DNS", 500 }, - { "GETDNS_NAMESPACE_LOCALNAMES", 501 }, - { "GETDNS_NAMESPACE_MDNS", 503 }, - { "GETDNS_NAMESPACE_NETBIOS", 502 }, - { "GETDNS_NAMESPACE_NIS", 504 }, - { "GETDNS_NAMETYPE_DNS", 800 }, - { "GETDNS_NAMETYPE_WINS", 801 }, - { "GETDNS_OPCODE_IQUERY", 1 }, - { "GETDNS_OPCODE_NOTIFY", 4 }, - { "GETDNS_OPCODE_QUERY", 0 }, - { "GETDNS_OPCODE_STATUS", 2 }, - { "GETDNS_OPCODE_UPDATE", 5 }, - { "GETDNS_RCODE_BADALG", 21 }, - { "GETDNS_RCODE_BADKEY", 17 }, - { "GETDNS_RCODE_BADMODE", 19 }, - { "GETDNS_RCODE_BADNAME", 20 }, - { "GETDNS_RCODE_BADSIG", 16 }, - { "GETDNS_RCODE_BADTIME", 18 }, - { "GETDNS_RCODE_BADTRUNC", 22 }, - { "GETDNS_RCODE_BADVERS", 16 }, - { "GETDNS_RCODE_FORMERR", 1 }, - { "GETDNS_RCODE_NOERROR", 0 }, - { "GETDNS_RCODE_NOTAUTH", 9 }, - { "GETDNS_RCODE_NOTIMP", 4 }, - { "GETDNS_RCODE_NOTZONE", 10 }, - { "GETDNS_RCODE_NXDOMAIN", 3 }, - { "GETDNS_RCODE_NXRRSET", 8 }, - { "GETDNS_RCODE_REFUSED", 5 }, - { "GETDNS_RCODE_SERVFAIL", 2 }, - { "GETDNS_RCODE_YXDOMAIN", 6 }, - { "GETDNS_RCODE_YXRRSET", 7 }, - { "GETDNS_REDIRECTS_DO_NOT_FOLLOW", 531 }, - { "GETDNS_REDIRECTS_FOLLOW", 530 }, - { "GETDNS_RESOLUTION_RECURSING", 521 }, - { "GETDNS_RESOLUTION_STUB", 520 }, - { "GETDNS_RESPSTATUS_ALL_BOGUS_ANSWERS", 904 }, - { "GETDNS_RESPSTATUS_ALL_TIMEOUT", 902 }, - { "GETDNS_RESPSTATUS_GOOD", 900 }, - { "GETDNS_RESPSTATUS_NO_NAME", 901 }, - { "GETDNS_RESPSTATUS_NO_SECURE_ANSWERS", 903 }, - { "GETDNS_RETURN_BAD_CONTEXT", 301 }, - { "GETDNS_RETURN_BAD_DOMAIN_NAME", 300 }, - { "GETDNS_RETURN_CONTEXT_UPDATE_FAIL", 302 }, - { "GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED", 309 }, - { "GETDNS_RETURN_EXTENSION_MISFORMAT", 308 }, - { "GETDNS_RETURN_GENERIC_ERROR", 1 }, - { "GETDNS_RETURN_GOOD", 0 }, - { "GETDNS_RETURN_INVALID_PARAMETER", 311 }, - { "GETDNS_RETURN_MEMORY_ERROR", 310 }, - { "GETDNS_RETURN_NEED_MORE_SPACE", 399 }, - { "GETDNS_RETURN_NOT_IMPLEMENTED", 312 }, - { "GETDNS_RETURN_NO_SUCH_DICT_NAME", 305 }, - { "GETDNS_RETURN_NO_SUCH_EXTENSION", 307 }, - { "GETDNS_RETURN_NO_SUCH_LIST_ITEM", 304 }, - { "GETDNS_RETURN_UNKNOWN_TRANSACTION", 303 }, - { "GETDNS_RETURN_WRONG_TYPE_REQUESTED", 306 }, - { "GETDNS_RRCLASS_ANY", 255 }, - { "GETDNS_RRCLASS_CH", 3 }, - { "GETDNS_RRCLASS_HS", 4 }, - { "GETDNS_RRCLASS_IN", 1 }, - { "GETDNS_RRCLASS_NONE", 254 }, - { "GETDNS_RRTYPE_A", 1 }, - { "GETDNS_RRTYPE_AAAA", 28 }, - { "GETDNS_RRTYPE_AFSDB", 18 }, - { "GETDNS_RRTYPE_ANY", 255 }, - { "GETDNS_RRTYPE_APL", 42 }, - { "GETDNS_RRTYPE_ATMA", 34 }, - { "GETDNS_RRTYPE_AXFR", 252 }, - { "GETDNS_RRTYPE_CAA", 257 }, - { "GETDNS_RRTYPE_CDNSKEY", 60 }, - { "GETDNS_RRTYPE_CDS", 59 }, - { "GETDNS_RRTYPE_CERT", 37 }, - { "GETDNS_RRTYPE_CNAME", 5 }, - { "GETDNS_RRTYPE_CSYNC", 62 }, - { "GETDNS_RRTYPE_DHCID", 49 }, - { "GETDNS_RRTYPE_DLV", 32769 }, - { "GETDNS_RRTYPE_DNAME", 39 }, - { "GETDNS_RRTYPE_DNSKEY", 48 }, - { "GETDNS_RRTYPE_DS", 43 }, - { "GETDNS_RRTYPE_EID", 31 }, - { "GETDNS_RRTYPE_GID", 102 }, - { "GETDNS_RRTYPE_GPOS", 27 }, - { "GETDNS_RRTYPE_HINFO", 13 }, - { "GETDNS_RRTYPE_HIP", 55 }, - { "GETDNS_RRTYPE_IPSECKEY", 45 }, - { "GETDNS_RRTYPE_ISDN", 20 }, - { "GETDNS_RRTYPE_IXFR", 251 }, - { "GETDNS_RRTYPE_KEY", 25 }, - { "GETDNS_RRTYPE_KX", 36 }, - { "GETDNS_RRTYPE_LOC", 29 }, - { "GETDNS_RRTYPE_LP", 107 }, - { "GETDNS_RRTYPE_MAILA", 254 }, - { "GETDNS_RRTYPE_MAILB", 253 }, - { "GETDNS_RRTYPE_MB", 7 }, - { "GETDNS_RRTYPE_MD", 3 }, - { "GETDNS_RRTYPE_MF", 4 }, - { "GETDNS_RRTYPE_MG", 8 }, - { "GETDNS_RRTYPE_MINFO", 14 }, - { "GETDNS_RRTYPE_MR", 9 }, - { "GETDNS_RRTYPE_MX", 15 }, - { "GETDNS_RRTYPE_NAPTR", 35 }, - { "GETDNS_RRTYPE_NID", 104 }, - { "GETDNS_RRTYPE_NIMLOC", 32 }, - { "GETDNS_RRTYPE_NINFO", 56 }, - { "GETDNS_RRTYPE_NS", 2 }, - { "GETDNS_RRTYPE_NSAP", 22 }, - { "GETDNS_RRTYPE_NSEC", 47 }, - { "GETDNS_RRTYPE_NULL", 10 }, - { "GETDNS_RRTYPE_NXT", 30 }, - { "GETDNS_RRTYPE_OPENPGPKEY", 61 }, - { "GETDNS_RRTYPE_OPT", 41 }, - { "GETDNS_RRTYPE_PTR", 12 }, - { "GETDNS_RRTYPE_PX", 26 }, - { "GETDNS_RRTYPE_RKEY", 57 }, - { "GETDNS_RRTYPE_RP", 17 }, - { "GETDNS_RRTYPE_RRSIG", 46 }, - { "GETDNS_RRTYPE_RT", 21 }, - { "GETDNS_RRTYPE_SIG", 24 }, - { "GETDNS_RRTYPE_SINK", 40 }, - { "GETDNS_RRTYPE_SOA", 6 }, - { "GETDNS_RRTYPE_SPF", 99 }, - { "GETDNS_RRTYPE_SRV", 33 }, - { "GETDNS_RRTYPE_SSHFP", 44 }, - { "GETDNS_RRTYPE_TA", 32768 }, - { "GETDNS_RRTYPE_TALINK", 58 }, - { "GETDNS_RRTYPE_TKEY", 249 }, - { "GETDNS_RRTYPE_TLSA", 52 }, - { "GETDNS_RRTYPE_TSIG", 250 }, - { "GETDNS_RRTYPE_TXT", 16 }, - { "GETDNS_RRTYPE_UID", 101 }, - { "GETDNS_RRTYPE_UINFO", 100 }, - { "GETDNS_RRTYPE_UNSPEC", 103 }, - { "GETDNS_RRTYPE_URI", 256 }, - { "GETDNS_RRTYPE_WKS", 11 }, - { "GETDNS_TRANSPORT_TCP", 1201 }, - { "GETDNS_TRANSPORT_TCP_ONLY", 542 }, - { "GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN", 543 }, - { "GETDNS_TRANSPORT_TLS", 1202 }, - { "GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN", 545 }, - { "GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN", 544 }, - { "GETDNS_TRANSPORT_UDP", 1200 }, - { "GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP", 540 }, - { "GETDNS_TRANSPORT_UDP_ONLY", 541 }, -}; -static int const_name_info_cmp(const void *a, const void *b) -{ - return strcmp( ((struct const_name_info *) a)->name - , ((struct const_name_info *) b)->name ); -} -static int -_getdns_get_const_name_info(const char *name, uint32_t *code) -{ - struct const_name_info key = { name, 0 }; - struct const_name_info *i = bsearch(&key, consts_name_info, - sizeof(consts_name_info) / sizeof(struct const_name_info), - sizeof(struct const_name_info), const_name_info_cmp); - if (!i) - return 0; - if (code) - *code = i->code; - return 1; -} diff --git a/src/test/getdns_str2dict.h b/src/test/getdns_str2dict.h deleted file mode 100644 index 71cb26c8..00000000 --- a/src/test/getdns_str2dict.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2013, NLNet Labs, Verisign, 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 names of the copyright holders 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. - */ - -#ifndef GETDNS_STR2DICT_H_ -#define GETDNS_STR2DICT_H_ -#include "getdns/getdns.h" - -getdns_return_t getdns_str2dict(const char *str, getdns_dict **dict); -getdns_return_t getdns_str2list(const char *str, getdns_list **list); -getdns_return_t getdns_str2bindata(const char *str, getdns_bindata **bindata); -getdns_return_t getdns_str2int(const char *str, uint32_t *value); - -#endif From 8fa84c836a19b8655caea6d3fb8ac842843a6f3e Mon Sep 17 00:00:00 2001 From: Sara Dickinson Date: Thu, 23 Jun 2016 15:53:51 +0100 Subject: [PATCH 03/61] Initial re-work of stateful transport selection and timeout/error handling. Also update transport test to avoid timeout. --- src/context.c | 68 ++- src/context.h | 55 +- src/request-internal.c | 3 +- src/stub.c | 574 +++++++++--------- .../check_getdns_context_set_dns_transport.h | 1 + src/types-internal.h | 11 +- src/util-internal.c | 5 +- 7 files changed, 389 insertions(+), 328 deletions(-) diff --git a/src/context.c b/src/context.c index b46dc3bd..529bb19c 100644 --- a/src/context.c +++ b/src/context.c @@ -264,7 +264,6 @@ create_default_dns_transports(struct getdns_context *context) context->dns_transports[0] = GETDNS_TRANSPORT_UDP; context->dns_transports[1] = GETDNS_TRANSPORT_TCP; context->dns_transport_count = 2; - context->dns_transport_current = 0; return GETDNS_RETURN_GOOD; } @@ -616,7 +615,7 @@ upstreams_create(getdns_context *context, size_t size) r->mf = context->mf; r->referenced = 1; r->count = 0; - r->current = 0; + r->current_udp = 0; return r; } @@ -675,30 +674,54 @@ _getdns_upstreams_dereference(getdns_upstreams *upstreams) void _getdns_upstream_shutdown(getdns_upstream *upstream) { - /*There is a race condition with a new request being scheduled - while this happens so take ownership of the fd asap*/ - int fd = upstream->fd; - upstream->fd = -1; - /* If the connection had a problem, but had worked this time, - * then allow re-use in the future*/ - if (upstream->tcp.write_error == 1 && - upstream->responses_received > 0) - upstream->tcp.write_error = 0; - upstream->writes_done = 0; + /*Set condition to tear down asap to stop any further scheduling*/ + upstream->conn_state = GETDNS_CONN_TEARDOWN; + /* Update total stats for the upstream.*/ + upstream->total_responses+=upstream->responses_received; + upstream->total_timeouts+=upstream->responses_timeouts; + /* Pick up the auth state if it is of interest*/ + if (upstream->tls_auth_state != GETDNS_AUTH_NONE) + upstream->past_tls_auth_state = upstream->tls_auth_state; + + DEBUG_STUB("%s %-35s: FD: %d Stats on shutdown: TR=%d,TT=%d,CC=%d,CSF=%d,CS=%d,AS=%d\n", + STUB_DEBUG_CLEANUP, __FUNCTION__, upstream->fd, + (int)upstream->total_responses, (int)upstream->total_timeouts, + (int)upstream->conn_completed, (int)upstream->conn_setup_failed, + (int)upstream->conn_shutdowns, upstream->past_tls_auth_state); + + /* Back off connections that never got up service at all (probably no + TCP service or incompatible TLS version/cipher). + Leave choice between working upstreams to the stub. + This back-off should be time based for TLS according to RFC7858. For now, + use the same basis if we simply can't get TCP service either.*/ + + /* [TLS1]TODO: This arbitrary logic at the moment - review and improve!*/ + if (upstream->conn_setup_failed >= GETDNS_MAX_CONN_FAILS || + (upstream->conn_shutdowns >= GETDNS_MAX_CONN_FAILS*GETDNS_CONN_FAIL_MULT + && upstream->total_responses == 0) || + (upstream->total_timeouts > 0 && + upstream->total_responses*GETDNS_MAX_CONN_FAILS == 0)) + upstream->conn_state = GETDNS_CONN_BACKOFF; + // Reset per connection counters + upstream->queries_sent = 0; upstream->responses_received = 0; + upstream->responses_timeouts = 0; upstream->keepalive_timeout = 0; - if (upstream->tls_hs_state != GETDNS_HS_FAILED) { - upstream->tls_hs_state = GETDNS_HS_NONE; - upstream->tls_auth_failed = 0; - } + /* Now TLS stuff*/ + upstream->tls_auth_state = GETDNS_AUTH_NONE; if (upstream->tls_obj != NULL) { SSL_shutdown(upstream->tls_obj); SSL_free(upstream->tls_obj); upstream->tls_obj = NULL; } - if (fd != -1) - close(fd); + if (upstream->fd != -1) { + close(upstream->fd); + upstream->fd = -1; + } + /* Set connection ready for use again*/ + if (upstream->conn_state != GETDNS_CONN_BACKOFF) + upstream->conn_state = GETDNS_CONN_CLOSED; } static int @@ -803,8 +826,12 @@ upstream_init(getdns_upstream *upstream, (void) memcpy(&upstream->addr, ai->ai_addr, ai->ai_addrlen); /* How is this upstream doing? */ - upstream->writes_done = 0; + upstream->conn_setup_failed = 0; + upstream->conn_shutdowns = 0; + upstream->conn_state = GETDNS_CONN_CLOSED; + upstream->queries_sent = 0; upstream->responses_received = 0; + upstream->responses_timeouts = 0; upstream->keepalive_timeout = 0; upstream->to_retry = 2; upstream->back_off = 1; @@ -815,10 +842,9 @@ upstream_init(getdns_upstream *upstream, upstream->tls_session = NULL; upstream->transport = GETDNS_TRANSPORT_TCP; upstream->tls_hs_state = GETDNS_HS_NONE; - upstream->tls_auth_failed = 0; upstream->tls_auth_name[0] = '\0'; + upstream->tls_auth_state = GETDNS_AUTH_NONE; upstream->tls_pubkey_pinset = NULL; - upstream->tcp.write_error = 0; upstream->loop = NULL; (void) getdns_eventloop_event_init( &upstream->event, upstream, NULL, NULL, NULL); diff --git a/src/context.h b/src/context.h index 46ed6c88..3da073f0 100644 --- a/src/context.h +++ b/src/context.h @@ -80,6 +80,14 @@ typedef enum getdns_tls_hs_state { GETDNS_HS_FAILED } getdns_tls_hs_state_t; +typedef enum getdns_conn_state { + GETDNS_CONN_CLOSED, + GETDNS_CONN_SETUP, + GETDNS_CONN_OPEN, + GETDNS_CONN_TEARDOWN, + GETDNS_CONN_BACKOFF +} getdns_conn_state_t; + typedef enum getdns_tsig_algo { GETDNS_NO_TSIG = 0, /* Do not use tsig */ GETDNS_HMAC_MD5 = 1, /* 128 bits */ @@ -116,30 +124,45 @@ typedef struct getdns_upstream { socklen_t addr_len; struct sockaddr_storage addr; - /* How is this upstream doing? */ - size_t writes_done; - size_t responses_received; - uint64_t keepalive_timeout; + /* How is this upstream doing over UDP? */ int to_retry; int back_off; - /* For sharing a TCP socket to this upstream */ + /* For stateful upstreams, need to share the connection and track the + activity on the connection */ int fd; getdns_transport_list_t transport; - SSL* tls_obj; - SSL_SESSION* tls_session; - getdns_tls_hs_state_t tls_hs_state; getdns_eventloop_event event; getdns_eventloop *loop; getdns_tcp_state tcp; - char tls_auth_name[256]; - size_t tls_auth_failed; - sha256_pin_t *tls_pubkey_pinset; + /* These are running totals or historical info */ + size_t conn_completed; + size_t conn_shutdowns; + size_t conn_setup_failed; + size_t total_responses; + size_t total_timeouts; + getdns_auth_state_t past_tls_auth_state; + /* These are per connection. */ + getdns_conn_state_t conn_state; + size_t queries_sent; + size_t responses_received; + size_t responses_timeouts; + uint64_t keepalive_timeout; - /* Pipelining of TCP network requests */ + /* Management of outstanding requests on stateful transports */ getdns_network_req *write_queue; getdns_network_req *write_queue_last; - _getdns_rbtree_t netreq_by_query_id; + _getdns_rbtree_t netreq_by_query_id; + + /* TLS specific connection handling*/ + SSL* tls_obj; + SSL_SESSION* tls_session; + getdns_tls_hs_state_t tls_hs_state; + getdns_auth_state_t tls_auth_state; + unsigned tls_fallback_ok : 1; + /* Auth credentials*/ + char tls_auth_name[256]; + sha256_pin_t *tls_pubkey_pinset; /* When requests have been scheduled asynchronously on an upstream * that is kept open, and a synchronous call is then done with the @@ -157,6 +180,7 @@ typedef struct getdns_upstream { */ getdns_dns_req *finished_dnsreqs; getdns_eventloop_event finished_event; + unsigned is_sync_loop : 1; /* EDNS cookies */ uint32_t secret; @@ -168,8 +192,6 @@ typedef struct getdns_upstream { unsigned has_prev_client_cookie : 1; unsigned has_server_cookie : 1; unsigned server_cookie_len : 5; - unsigned tls_fallback_ok : 1; - unsigned is_sync_loop : 1; /* TSIG */ uint8_t tsig_dname[256]; @@ -184,7 +206,7 @@ typedef struct getdns_upstreams { struct mem_funcs mf; size_t referenced; size_t count; - size_t current; + size_t current_udp; getdns_upstream upstreams[]; } getdns_upstreams; @@ -219,7 +241,6 @@ struct getdns_context { getdns_transport_list_t *dns_transports; size_t dns_transport_count; - size_t dns_transport_current; uint8_t edns_extended_rcode; uint8_t edns_version; diff --git a/src/request-internal.c b/src/request-internal.c index 797fde50..10df0897 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -177,11 +177,10 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, net_req->fd = -1; net_req->transport_current = 0; memset(&net_req->event, 0, sizeof(net_req->event)); - memset(&net_req->tcp, 0, sizeof(net_req->tcp)); net_req->keepalive_sent = 0; net_req->write_queue_tail = NULL; /* Some fields to record info for return_call_reporting */ - net_req->debug_tls_auth_status = 0; + net_req->debug_tls_auth_status = GETDNS_AUTH_NONE; net_req->debug_udp = 0; if (max_query_sz == 0) { diff --git a/src/stub.c b/src/stub.c index 4aa14dae..90a8c935 100644 --- a/src/stub.c +++ b/src/stub.c @@ -63,9 +63,11 @@ typedef u_short sa_family_t; * STUB_TCP_WOULDBLOCK added to deal with edge triggered event loops (versus * level triggered). See also lines containing WSA TODO below... */ +#define STUB_NO_AUTH -8 /* Existing TLS connection is not authenticated */ +#define STUB_CONN_GONE -7 /* Connection has failed, clear queue*/ #define STUB_TCP_WOULDBLOCK -6 #define STUB_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */ -#define STUB_TLS_SETUP_ERROR -4 +#define STUB_SETUP_ERROR -4 #define STUB_TCP_AGAIN -3 #define STUB_TCP_ERROR -2 @@ -85,6 +87,9 @@ static void upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq); static void upstream_reschedule_events(getdns_upstream *upstream, size_t idle_timeout); +static int upstream_working_ok(getdns_upstream *upstream); +static int upstream_auth_status_ok(getdns_upstream *upstream, + getdns_network_req *netreq); static int upstream_connect(getdns_upstream *upstream, getdns_transport_list_t transport, getdns_dns_req *dnsreq); @@ -368,12 +373,15 @@ static int tcp_connect(getdns_upstream *upstream, getdns_transport_list_t transport) { int fd = -1; - DEBUG_STUB("%s %-35s: Creating TCP connection: %p\n", STUB_DEBUG_SETUP, + DEBUG_STUB("%s %-35s: Creating TCP connection: %p\n", STUB_DEBUG_SETUP, __FUNCTION__, upstream); if ((fd = socket(upstream->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) return -1; getdns_sock_nonblock(fd); + /* Note that error detection is different with TFO. Since the handshake + doesn't start till the sendto() lack of connection is often delayed until + then or even the subsequent event depending on the error and platform.*/ #ifdef USE_TCP_FASTOPEN /* Leave the connect to the later call to sendto() if using TCP*/ if (transport == GETDNS_TRANSPORT_TCP) @@ -407,29 +415,30 @@ tcp_connect(getdns_upstream *upstream, getdns_transport_list_t transport) static int tcp_connected(getdns_upstream *upstream) { - /* Already tried and failed, so let the fallback code take care of things */ - /* TODO: We _should_ use a timeout on the TCP handshake*/ - if (upstream->fd == -1 || upstream->tcp.write_error != 0) - return STUB_TCP_ERROR; - int error = 0; socklen_t len = (socklen_t)sizeof(error); getsockopt(upstream->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &len); #ifdef USE_WINSOCK if (error == WSAEINPROGRESS) - return STUB_TCP_WOULDBLOCK; + return STUB_TCP_AGAIN; else if (error == WSAEWOULDBLOCK) return STUB_TCP_WOULDBLOCK; else if (error != 0) - return STUB_TCP_ERROR; + return STUB_SETUP_ERROR; #else if (error == EINPROGRESS) - return STUB_TCP_WOULDBLOCK; + return STUB_TCP_AGAIN; else if (error == EWOULDBLOCK || error == EAGAIN) return STUB_TCP_WOULDBLOCK; - else if (error != 0) - return STUB_TCP_ERROR; + else if (error != 0) { + return STUB_SETUP_ERROR; + } #endif + if (upstream->transport == GETDNS_TRANSPORT_TCP && + upstream->queries_sent == 0) { + upstream->conn_state = GETDNS_CONN_OPEN; + upstream->conn_completed++; + } return 0; } @@ -445,12 +454,9 @@ stub_next_upstream(getdns_network_req *netreq) if (! --netreq->upstream->to_retry) netreq->upstream->to_retry = -(netreq->upstream->back_off *= 2); - /*[TLS]:TODO - This works because the next message won't try the exact - * same upstream (and the next message may not use the same transport), - * but the next message will find the next matching one thanks to logic in - * upstream_select, but this could be better */ - if (++dnsreq->upstreams->current >= dnsreq->upstreams->count) - dnsreq->upstreams->current = 0; + dnsreq->upstreams->current_udp+=GETDNS_UPSTREAM_TRANSPORTS; + if (dnsreq->upstreams->current_udp >= dnsreq->upstreams->count) + dnsreq->upstreams->current_udp = 0; } static void @@ -465,8 +471,6 @@ stub_cleanup(getdns_network_req *netreq) GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event); - GETDNS_NULL_FREE(dnsreq->context->mf, netreq->tcp.read_buf); - /* Nothing globally scheduled? Then nothing queued */ if (!(upstream = netreq->upstream)->event.ev) return; @@ -495,85 +499,74 @@ stub_cleanup(getdns_network_req *netreq) upstream_reschedule_events(upstream, upstream->keepalive_timeout); } -static int -tls_cleanup(getdns_upstream *upstream, int handshake_fail) -{ - DEBUG_STUB("%s %-35s: FD: %d\n", - STUB_DEBUG_CLEANUP, __FUNCTION__, upstream->fd); - if (upstream->tls_obj != NULL) - SSL_free(upstream->tls_obj); - upstream->tls_obj = NULL; - /* This will prevent the connection from being tried again for the cases - where we know it didn't work. Otherwise leave it to try again.*/ - if (handshake_fail) - upstream->tls_hs_state = GETDNS_HS_FAILED; - /* Reset timeout on failure*/ - GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); - GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, TIMEOUT_FOREVER, - getdns_eventloop_event_init(&upstream->event, upstream, - NULL, upstream_write_cb, NULL)); - return STUB_TLS_SETUP_ERROR; -} - static void -upstream_erred(getdns_upstream *upstream) +upstream_failed(getdns_upstream *upstream, int during_setup) { - DEBUG_STUB("%s %-35s: FD: %d\n", - STUB_DEBUG_CLEANUP, __FUNCTION__, upstream->fd); - getdns_network_req *netreq; - - while ((netreq = upstream->write_queue)) { - stub_cleanup(netreq); - netreq->state = NET_REQ_FINISHED; - _getdns_check_dns_req_complete(netreq->owner); + DEBUG_STUB("%s %-35s: FD: %d During setup = %d\n", + STUB_DEBUG_CLEANUP, __FUNCTION__, upstream->fd, during_setup); + /* Fallback code should take care of queue queries and then close conn + when idle.*/ + /* [TLS1]TODO: Work out how to re-open the connection and re-try + the queries if there is only one upstream.*/ + if (during_setup) { + /* Reset timeout on setup failure to trigger fallback handling.*/ + GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); + GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, TIMEOUT_FOREVER, + getdns_eventloop_event_init(&upstream->event, upstream, + NULL, upstream_write_cb, NULL)); + /* Special case if failure was due to authentication issues since this + upstream could be used oppotunistically with no problem.*/ + if (!(upstream->transport == GETDNS_TRANSPORT_TLS && + upstream->tls_auth_state == GETDNS_AUTH_FAILED)) + upstream->conn_setup_failed++; + } else { + upstream->conn_shutdowns++; + /* [TLS1]TODO: Re-try these queries if possible.*/ + getdns_network_req *netreq; + while (upstream->netreq_by_query_id.count) { + netreq = (getdns_network_req *) + _getdns_rbtree_first(&upstream->netreq_by_query_id); + stub_cleanup(netreq); + netreq->state = NET_REQ_FINISHED; + _getdns_check_dns_req_complete(netreq->owner); + } } - while (upstream->netreq_by_query_id.count) { - netreq = (getdns_network_req *) - _getdns_rbtree_first(&upstream->netreq_by_query_id); - stub_cleanup(netreq); - netreq->state = NET_REQ_FINISHED; - _getdns_check_dns_req_complete(netreq->owner); - } - _getdns_upstream_shutdown(upstream); + + upstream->conn_state = GETDNS_CONN_TEARDOWN; } void _getdns_cancel_stub_request(getdns_network_req *netreq) { + DEBUG_STUB("%s %-35s: MSG: %p\n", + STUB_DEBUG_CLEANUP, __FUNCTION__, netreq); stub_cleanup(netreq); if (netreq->fd >= 0) close(netreq->fd); } -/* May be needed in future for better UDP error handling?*/ -/*static void -stub_erred(getdns_network_req *netreq) -{ - DEBUG_STUB("*** %s\n", __FUNCTION__); - stub_next_upstream(netreq); - stub_cleanup(netreq); - if (netreq->fd >= 0) close(netreq->fd); - netreq->state = NET_REQ_FINISHED; - _getdns_check_dns_req_complete(netreq->owner); -}*/ - static void stub_timeout_cb(void *userarg) { getdns_network_req *netreq = (getdns_network_req *)userarg; DEBUG_STUB("%s %-35s: MSG: %p\n", STUB_DEBUG_CLEANUP, __FUNCTION__, netreq); - stub_next_upstream(netreq); stub_cleanup(netreq); - if (netreq->fd >= 0) close(netreq->fd); netreq->state = NET_REQ_TIMED_OUT; - if (netreq->owner->user_callback) { + /* Handle upstream*/ + if (netreq->fd >= 0) { + close(netreq->fd); + stub_next_upstream(netreq); + } else { + netreq->upstream->responses_timeouts++; + } + if (netreq->owner->user_callback) { netreq->debug_end_time = _getdns_get_time_as_uintt64(); + /* Note this calls cancel_request which calls stub_cleanup again....!*/ (void) _getdns_context_request_timed_out(netreq->owner); } else _getdns_check_dns_req_complete(netreq->owner); } - static void upstream_idle_timeout_cb(void *userarg) { @@ -588,13 +581,13 @@ upstream_idle_timeout_cb(void *userarg) } static void -upstream_tls_timeout_cb(void *userarg) +upstream_setup_timeout_cb(void *userarg) { getdns_upstream *upstream = (getdns_upstream *)userarg; DEBUG_STUB("%s %-35s: FD: %d\n", STUB_DEBUG_CLEANUP, __FUNCTION__, upstream->fd); /* Clean up and trigger a write to let the fallback code to its job */ - tls_cleanup(upstream, 1); + upstream_failed(upstream, 1); /* Need to handle the case where the far end doesn't respond to a * TCP SYN and doesn't do a reset (as is the case with e.g. 8.8.8.8@853). @@ -609,38 +602,13 @@ upstream_tls_timeout_cb(void *userarg) tval.tv_usec = 0; ret = select(upstream->fd+1, NULL, &fds, NULL, &tval); if (ret == 0) { + DEBUG_STUB("%s %-35s: FD: %d Cleaning up dangling queue\n", + STUB_DEBUG_CLEANUP, __FUNCTION__, upstream->fd); while (upstream->write_queue) upstream_write_cb(upstream); } } -static void -stub_tls_timeout_cb(void *userarg) -{ - getdns_network_req *netreq = (getdns_network_req *)userarg; - getdns_upstream *upstream = netreq->upstream; - DEBUG_STUB("%s %-35s: MSG: %p\n", - STUB_DEBUG_CLEANUP, __FUNCTION__, netreq); - /* Clean up and trigger a write to let the fallback code to its job */ - tls_cleanup(upstream, 0); - - /* Need to handle the case where the far end doesn't respond to a - * TCP SYN and doesn't do a reset (as is the case with e.g. 8.8.8.8@853). - * For that case the socket never becomes writable so doesn't trigger any - * callbacks. If so then clear out the queue in one go.*/ - int ret; - fd_set fds; - FD_ZERO(&fds); - FD_SET(FD_SET_T upstream->fd, &fds); - struct timeval tval; - tval.tv_sec = 0; - tval.tv_usec = 0; - ret = select(upstream->fd+1, NULL, &fds, NULL, &tval); - if (ret == 0) { - while (upstream->write_queue) - upstream_write_cb(upstream); - } -} /****************************/ /* TCP read/write functions */ @@ -751,7 +719,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) if (netreq->owner->edns_client_subnet_private) if (attach_edns_client_subnet_private(netreq)) return STUB_OUT_OF_OPTIONS; - if (netreq->upstream->writes_done == 0 && + if (netreq->upstream->queries_sent == 0 && netreq->owner->context->idle_timeout != 0) { /* Add the keepalive option to the first query on this connection*/ DEBUG_STUB("%s %-35s: FD: %d Requesting keepalive \n", @@ -840,36 +808,6 @@ tls_requested(getdns_network_req *netreq) 1 : 0; } -static int -tls_should_write(getdns_upstream *upstream) -{ - /* Should messages be written on TLS upstream. */ - return ((upstream->transport == GETDNS_TRANSPORT_TLS) && - upstream->tls_hs_state != GETDNS_HS_NONE) ? 1 : 0; -} - -static int -tls_should_read(getdns_upstream *upstream) -{ - return ((upstream->transport == GETDNS_TRANSPORT_TLS) && - !(upstream->tls_hs_state == GETDNS_HS_FAILED || - upstream->tls_hs_state == GETDNS_HS_NONE)) ? 1 : 0; -} - -static int -tls_failed(getdns_upstream *upstream) -{ - /* No messages should be scheduled onto an upstream in this state */ - return ((upstream->transport == GETDNS_TRANSPORT_TLS) && - upstream->tls_hs_state == GETDNS_HS_FAILED) ? 1 : 0; -} - -static int -tls_auth_status_ok(getdns_upstream *upstream, getdns_network_req *netreq) { - return (netreq->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED && - upstream->tls_auth_failed) ? 0 : 1; -} - int tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { @@ -887,9 +825,17 @@ tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) #ifdef X509_V_ERR_HOSTNAME_MISMATCH /*Report if error is hostname mismatch*/ - if (upstream && upstream->tls_fallback_ok && err == X509_V_ERR_HOSTNAME_MISMATCH) + if (upstream && upstream->tls_fallback_ok && err == X509_V_ERR_HOSTNAME_MISMATCH) { DEBUG_STUB("%s %-35s: FD: %d WARNING: Proceeding even though hostname validation failed!\n", STUB_DEBUG_SETUP_TLS, __FUNCTION__, upstream->fd); + upstream->tls_auth_state = GETDNS_AUTH_FAILED; + } +#else + /* if we weren't built against OpenSSL with hostname matching we + * could not have matched the hostname, so this would be an automatic + * tls_auth_fail if there is a hostname provided*/ + if (upstream->tls_auth_name[0]) + upstream->tls_auth_state = GETDNS_AUTH_FAILED; #endif if (upstream && upstream->tls_pubkey_pinset) pinset_ret = _getdns_verify_pinset_match(upstream->tls_pubkey_pinset, ctx); @@ -898,11 +844,15 @@ tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) DEBUG_STUB("%s %-35s: FD: %d, WARNING: Pinset validation failure!\n", STUB_DEBUG_SETUP_TLS, __FUNCTION__, upstream->fd); preverify_ok = 0; - upstream->tls_auth_failed = 1; + upstream->tls_auth_state = GETDNS_AUTH_FAILED; if (upstream->tls_fallback_ok) DEBUG_STUB("%s %-35s: FD: %d, WARNING: Proceeding even though pinset validation failed!\n", STUB_DEBUG_SETUP_TLS, __FUNCTION__, upstream->fd); } + /* If nothing has failed yet and we had credentials, we have succesfully authenticated*/ + if (upstream->tls_auth_state == GETDNS_AUTH_NONE && + (upstream->tls_pubkey_pinset || upstream->tls_auth_name[0])) + upstream->tls_auth_state = GETDNS_AUTH_OK; /* If fallback is allowed, proceed regardless of what the auth error is (might not be hostname or pinset related) */ return (upstream && upstream->tls_fallback_ok) ? 1 : preverify_ok; @@ -948,11 +898,9 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) X509_VERIFY_PARAM_set1_host(param, upstream->tls_auth_name, 0); #else if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) { - /* TODO: Trigger post-handshake custom validation*/ DEBUG_STUB("%s %-35s: ERROR: TLS Authentication functionality not available\n", STUB_DEBUG_SETUP_TLS, __FUNCTION__); upstream->tls_hs_state = GETDNS_HS_FAILED; - upstream->tls_auth_failed = 1; return NULL; } #endif @@ -970,14 +918,12 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) DEBUG_STUB("%s %-35s: ERROR: No host name or pubkey pinset provided for TLS authentication\n", STUB_DEBUG_SETUP_TLS, __FUNCTION__); upstream->tls_hs_state = GETDNS_HS_FAILED; - upstream->tls_auth_failed = 1; return NULL; } } else { /* no hostname verification, so we will make opportunistic connections */ DEBUG_STUB("%s %-35s: Proceeding even though no hostname provided!\n", STUB_DEBUG_SETUP_TLS, __FUNCTION__); - upstream->tls_auth_failed = 1; upstream->tls_fallback_ok = 1; } } @@ -1027,24 +973,14 @@ tls_do_handshake(getdns_upstream *upstream) DEBUG_STUB("%s %-35s: FD: %d Handshake failed %d\n", STUB_DEBUG_SETUP_TLS, __FUNCTION__, upstream->fd, want); - return tls_cleanup(upstream, 1); + return STUB_SETUP_ERROR; } } upstream->tls_hs_state = GETDNS_HS_DONE; - DEBUG_STUB("%s %-35s: FD: %d Handshake succeeded\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__, upstream->fd); - r = SSL_get_verify_result(upstream->tls_obj); - if (upstream->tls_auth_name[0]) -#ifdef X509_V_ERR_HOSTNAME_MISMATCH - if (r == X509_V_ERR_HOSTNAME_MISMATCH) -#else - /* if we weren't built against OpenSSL with hostname matching we - * could not have matched the hostname, so this would be an automatic - * tls_auth_fail. */ -#endif - upstream->tls_auth_failed = 1; - DEBUG_STUB("%s %-35s: FD: %d Session is %s\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__, upstream->fd, + upstream->conn_state = GETDNS_CONN_OPEN; + upstream->conn_completed++; + DEBUG_STUB("%s %-35s: FD: %d Handshake succeeded with auth state %d. Session is %s.\n", + STUB_DEBUG_SETUP_TLS, __FUNCTION__, upstream->fd, upstream->tls_auth_state, SSL_session_reused(upstream->tls_obj) ?"re-used":"new"); if (upstream->tls_session != NULL) SSL_SESSION_free(upstream->tls_session); @@ -1063,21 +999,17 @@ static int tls_connected(getdns_upstream* upstream) { /* Already have a TLS connection*/ - if (upstream->tls_hs_state == GETDNS_HS_DONE && - (upstream->tls_obj != NULL)) + if (upstream->tls_hs_state == GETDNS_HS_DONE) return 0; /* Already tried and failed, so let the fallback code take care of things */ if (upstream->tls_hs_state == GETDNS_HS_FAILED) - return STUB_TLS_SETUP_ERROR; + return STUB_SETUP_ERROR; - /* Lets make sure the connection is up before we try a handshake*/ + /* Lets make sure the TCP connection is up before we try a handshake*/ int q = tcp_connected(upstream); - if (q != 0) { - if (q == STUB_TCP_ERROR) - tls_cleanup(upstream, 0); + if (q != 0) return q; - } return tls_do_handshake(upstream); } @@ -1182,8 +1114,12 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, int q = tls_connected(upstream); if (q != 0) return q; - if (!tls_auth_status_ok(upstream, netreq)) - return STUB_TLS_SETUP_ERROR; + /* This is the case where the upstream is connected but it isn't an authenticated + connection, but the request needs an authenticated connection. For now, we + fail the write as a special case, since other oppotunistic requests can still use + this upstream. but this needs more thought: Should we open a second connection? */ + if (!upstream_auth_status_ok(upstream, netreq)) + return STUB_NO_AUTH; /* Do we have remaining data that we could not write before? */ if (! tcp->write_buf) { @@ -1214,7 +1150,7 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, if (netreq->owner->edns_client_subnet_private) if (attach_edns_client_subnet_private(netreq)) return STUB_OUT_OF_OPTIONS; - if (netreq->upstream->writes_done % EDNS_KEEPALIVE_RESEND == 0 && + if (netreq->upstream->queries_sent % EDNS_KEEPALIVE_RESEND == 0 && netreq->owner->context->idle_timeout != 0) { /* Add the keepalive option to every nth query on this connection */ @@ -1306,6 +1242,7 @@ stub_udp_read_cb(void *userarg) return; /* Client cookie didn't match? */ close(netreq->fd); + netreq->fd = -1; while (GLDNS_TC_WIRE(netreq->response)) { DEBUG_STUB("%s %-35s: MSG: %p TC bit set in response \n", STUB_DEBUG_READ, __FUNCTION__, netreq); @@ -1329,7 +1266,7 @@ stub_udp_read_cb(void *userarg) return; } netreq->response_len = read; - dnsreq->upstreams->current = 0; + dnsreq->upstreams->current_udp = 0; netreq->debug_end_time = _getdns_get_time_as_uintt64(); netreq->state = NET_REQ_FINISHED; _getdns_check_dns_req_complete(dnsreq); @@ -1412,7 +1349,7 @@ upstream_read_cb(void *userarg) intptr_t query_id_intptr; getdns_dns_req *dnsreq; - if (tls_should_read(upstream)) + if (upstream->transport == GETDNS_TRANSPORT_TLS) q = stub_tls_read(upstream, &upstream->tcp, &upstream->upstreams->mf); else @@ -1425,9 +1362,9 @@ upstream_read_cb(void *userarg) */ case STUB_TCP_WOULDBLOCK: return; - + case STUB_SETUP_ERROR: /* Can happen for TLS HS*/ case STUB_TCP_ERROR: - upstream_erred(upstream); + upstream_failed(upstream, (q == STUB_TCP_ERROR ? 0:1) ); return; default: @@ -1452,15 +1389,12 @@ upstream_read_cb(void *userarg) upstream->tcp.read_pos - upstream->tcp.read_buf; upstream->tcp.read_buf = NULL; upstream->responses_received++; - /* TODO[TLS]: I don't think we should do this for TCP. We should stay - * on a working connection until we hit a problem.*/ - upstream->upstreams->current = 0; /* !THIS CODE NEEDS TESTING! */ if (netreq->owner->edns_cookies && match_and_process_server_cookie( - netreq->upstream, netreq->tcp.read_buf, - netreq->tcp.read_pos - netreq->tcp.read_buf)) + netreq->upstream, upstream->tcp.read_buf, + upstream->tcp.read_pos - upstream->tcp.read_buf)) return; /* Client cookie didn't match (or FORMERR) */ if (netreq->owner->context->idle_timeout != 0) @@ -1520,18 +1454,24 @@ upstream_write_cb(void *userarg) getdns_upstream *upstream = (getdns_upstream *)userarg; getdns_network_req *netreq = upstream->write_queue; int q; - + if (!netreq) { GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); upstream->event.write_cb = NULL; return; } - /* TODO: think about TCP AGAIN */ + netreq->debug_start_time = _getdns_get_time_as_uintt64(); DEBUG_STUB("%s %-35s: MSG: %p (writing)\n", STUB_DEBUG_WRITE, __FUNCTION__, netreq); - if (tls_requested(netreq) && tls_should_write(upstream)) + /* Health checks on current connection */ + if (upstream->conn_state == GETDNS_CONN_TEARDOWN) + q = STUB_CONN_GONE; + else if (!upstream_working_ok(upstream)) + q = STUB_TCP_ERROR; + /* Seems ok, now try to write */ + else if (tls_requested(netreq)) q = stub_tls_write(upstream, &upstream->tcp, netreq); else q = stub_tcp_write(upstream->fd, &upstream->tcp, netreq); @@ -1540,32 +1480,32 @@ upstream_write_cb(void *userarg) case STUB_TCP_AGAIN: /* WSA TODO: if callback is still upstream_write_cb, do it again */ - case STUB_TCP_WOULDBLOCK: return; - case STUB_TCP_ERROR: - /* Problem with the TCP connection itself. Need to fallback.*/ - DEBUG_STUB("%s %-35s: MSG: %p ERROR!\n", STUB_DEBUG_WRITE, - __FUNCTION__, ((getdns_network_req *)userarg)); - upstream->tcp.write_error = 1; - /* Use policy of trying next upstream in this case. Need more work on - * TCP connection re-use.*/ - stub_next_upstream(netreq); + /* New problem with the TCP connection itself. Need to fallback.*/ /* Fall through */ - case STUB_TLS_SETUP_ERROR: - /* Could not complete the TLS set up. Need to fallback.*/ + case STUB_SETUP_ERROR: + /* Could not complete the set up. Need to fallback.*/ + DEBUG_STUB("%s %-35s: MSG: %p ERROR = %d\n", STUB_DEBUG_WRITE, + __FUNCTION__, ((getdns_network_req *)userarg), q); + upstream_failed(upstream, (q == STUB_TCP_ERROR ? 0:1)); + /* Fall through */ + case STUB_CONN_GONE: + case STUB_NO_AUTH: + /* Cleaning up after connection or auth check failure. Need to fallback. */ stub_cleanup(netreq); if (fallback_on_write(netreq) == STUB_TCP_ERROR) { + /* TODO: Need new state to report transport unavailable*/ netreq->state = NET_REQ_FINISHED; _getdns_check_dns_req_complete(netreq->owner); } return; default: - /* Need this because auth status is reset on connection clode */ - netreq->debug_tls_auth_status = netreq->upstream->tls_auth_failed; - upstream->writes_done++; + /* Need this because auth status is reset on connection close */ + netreq->debug_tls_auth_status = netreq->upstream->tls_auth_state; + upstream->queries_sent++; netreq->query_id = (uint16_t) q; /* Unqueue the netreq from the write_queue */ if (!(upstream->write_queue = netreq->write_queue_tail)) { @@ -1598,86 +1538,153 @@ upstream_write_cb(void *userarg) /*****************************/ static int -upstream_transport_valid(getdns_upstream *upstream, +upstream_working_ok(getdns_upstream *upstream) +{ + /* [TLS1]TODO: This arbitrary logic at the moment - review and improve!*/ + return (upstream->responses_timeouts > + upstream->responses_received*GETDNS_MAX_CONN_FAILS ? 0 : 1); +} + +static int +upstream_active(getdns_upstream *upstream) +{ + return ((upstream->conn_state == GETDNS_CONN_SETUP || + upstream->conn_state == GETDNS_CONN_OPEN) ? 1 : 0); +} + +static int +upstream_auth_status_ok(getdns_upstream *upstream, getdns_network_req *netreq) { + if (netreq->tls_auth_min != GETDNS_AUTHENTICATION_REQUIRED) + return 1; + return (upstream->tls_auth_state == GETDNS_AUTH_OK ? 1 : 0); +} + +static int +upstream_stats(getdns_upstream *upstream) +{ + /* [TLS1]TODO: This arbitrary logic at the moment - review and improve!*/ + return (upstream->total_responses - upstream->total_timeouts + - upstream->conn_shutdowns*GETDNS_CONN_FAIL_MULT); +} + +static int +upstream_valid(getdns_upstream *upstream, + getdns_transport_list_t transport, + getdns_network_req *netreq) +{ + if (upstream->transport != transport || upstream->conn_state != GETDNS_CONN_CLOSED) + return 0; + if (transport == GETDNS_TRANSPORT_TCP) + return 1; + /* We need to check past authentication history to see if this is usable for TLS.*/ + if (netreq->tls_auth_min != GETDNS_AUTHENTICATION_REQUIRED) + return 1; + return ((upstream->past_tls_auth_state == GETDNS_AUTH_OK || + upstream->past_tls_auth_state == GETDNS_AUTH_NONE) ? 1 : 0); +} + +static int +upstream_valid_and_open(getdns_upstream *upstream, getdns_transport_list_t transport, getdns_network_req *netreq) { - /* Single shot UDP, uses same upstream as plain TCP. */ - if (transport == GETDNS_TRANSPORT_UDP) - return (upstream->transport == GETDNS_TRANSPORT_TCP ? 1:0); - /* If we got an error and have never managed to write to this TCP then - treat it as a hard failure */ - if (transport == GETDNS_TRANSPORT_TCP && - upstream->transport == GETDNS_TRANSPORT_TCP && - upstream->tcp.write_error != 0) { + if (!(upstream->transport == transport && upstream_active(upstream))) return 0; - } - /* Otherwise, transport must match, and not have failed */ - if (upstream->transport != transport) + if (transport == GETDNS_TRANSPORT_TCP) + return 1; + /* Connection is complete, we know the auth status so check*/ + if (upstream->conn_state == GETDNS_CONN_OPEN && + !upstream_auth_status_ok(upstream, netreq) == 1) return 0; - if (tls_failed(upstream) || !tls_auth_status_ok(upstream, netreq)) - return 0; - return 1; + /* We must have a TLS connection still setting up so schedule and the + write code will check again once the connection is complete*/ + return 1; } static getdns_upstream * -upstream_select(getdns_network_req *netreq, getdns_transport_list_t transport) +upstream_select_stateful(getdns_network_req *netreq, getdns_transport_list_t transport) { - getdns_upstream *upstream; + getdns_upstream *upstream = NULL; getdns_upstreams *upstreams = netreq->owner->upstreams; size_t i; if (!upstreams->count) return NULL; - - - /* Only do this when a new message is scheduled?*/ - for (i = 0; i < upstreams->count; i++) - if (upstreams->upstreams[i].to_retry <= 0) - upstreams->upstreams[i].to_retry++; - /* TODO[TLS]: Should we create a tmp array of upstreams with correct*/ - /* transport type and/or maintain separate current for transports?*/ - i = upstreams->current; - DEBUG_STUB("%s %-35s: Starting from upstream: %d of %d available \n", STUB_DEBUG_SETUP, - __FUNCTION__, (int)i, (int)upstreams->count); - do { - if (upstreams->upstreams[i].to_retry > 0 && - upstream_transport_valid(&upstreams->upstreams[i], transport, netreq)) { - upstreams->current = i; - DEBUG_STUB("%s %-35s: Selected upstream: %d %p transport: %d\n", - STUB_DEBUG_SETUP, __FUNCTION__, (int)i, - &upstreams->upstreams[i], transport); + /* [TLS1]TODO: Add check to re-instate backed-off upstreams after X amount + of time*/ + + /* First find if an open upstream has the correct properties and use that*/ + for (i = 0; i < upstreams->count; i++) { + if (upstream_valid_and_open(&upstreams->upstreams[i], transport, netreq)) return &upstreams->upstreams[i]; - } - if (++i >= upstreams->count) - i = 0; - } while (i != upstreams->current); - - upstream = upstreams->upstreams; - for (i = 0; i < upstreams->count; i++) - if (upstreams->upstreams[i].back_off < upstream->back_off && - upstream_transport_valid(&upstreams->upstreams[i], transport, netreq)) - upstream = &upstreams->upstreams[i]; - - /* Need to check again that the transport is valid */ - if (!upstream_transport_valid(upstream, transport, netreq)) { - DEBUG_STUB("%s %-35s: No valid upstream available for transport %d!\n", - STUB_DEBUG_SETUP, __FUNCTION__, transport); - return NULL; } - upstream->back_off++; - upstream->to_retry = 1; - upstreams->current = upstream - upstreams->upstreams; + + /* OK - we will have to open one. Choose the first one that has the best stats + and the right properties, but because we completely back off failed + upstreams we may have no valid upstream at all (in contrast to UDP). This + will be better communicated to the user when we have better error codes*/ + for (i = 0; i < upstreams->count; i++) { + DEBUG_STUB("%s %-35s: Testing %d %d\n", STUB_DEBUG_SETUP, + __FUNCTION__, (int)i, (int)upstreams->upstreams[i].conn_state); + if (upstream_valid(&upstreams->upstreams[i], transport, netreq)) { + upstream = &upstreams->upstreams[i]; + break; + } + } + if (!upstream) + return NULL; + for (i++; i < upstreams->count; i++) { + if (upstream_valid(&upstreams->upstreams[i], transport, netreq) && + upstream_stats(&upstreams->upstreams[i]) > upstream_stats(upstream)) + upstream = &upstreams->upstreams[i]; + } return upstream; } +static getdns_upstream * +upstream_select(getdns_network_req *netreq) +{ + getdns_upstream *upstream; + getdns_upstreams *upstreams = netreq->owner->upstreams; + size_t i; + + if (!upstreams->count) + return NULL; + /* First UPD/TCP upstream is always at i=0 and then start of each upstream block*/ + /* TODO: Have direct access to sets of upstreams for different transports*/ + for (i = 0; i < upstreams->count; i+=GETDNS_UPSTREAM_TRANSPORTS) + if (upstreams->upstreams[i].to_retry <= 0) + upstreams->upstreams[i].to_retry++; + + i = upstreams->current_udp; + do { + if (upstreams->upstreams[i].to_retry > 0) { + upstreams->current_udp = i; + return &upstreams->upstreams[i]; + } + i+=GETDNS_UPSTREAM_TRANSPORTS; + if (i > upstreams->count) + i = 0; + } while (i != upstreams->current_udp); + + upstream = upstreams->upstreams; + for (i = 0; i < upstreams->count; i+=GETDNS_UPSTREAM_TRANSPORTS) + if (upstreams->upstreams[i].back_off < + upstream->back_off) + upstream = &upstreams->upstreams[i]; + + upstream->back_off++; + upstream->to_retry = 1; + upstreams->current_udp = (upstream - upstreams->upstreams) / GETDNS_UPSTREAM_TRANSPORTS; + return upstream; +} int upstream_connect(getdns_upstream *upstream, getdns_transport_list_t transport, getdns_dns_req *dnsreq) { - DEBUG_STUB("%s %-35s: Checking upstream connection: %p\n", STUB_DEBUG_SETUP, + DEBUG_STUB("%s %-35s: Getting upstream connection: %p\n", STUB_DEBUG_SETUP, __FUNCTION__, upstream); int fd = -1; switch(transport) { @@ -1686,36 +1693,33 @@ upstream_connect(getdns_upstream *upstream, getdns_transport_list_t transport, upstream->addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) return -1; getdns_sock_nonblock(fd); - return fd; + break; case GETDNS_TRANSPORT_TCP: + case GETDNS_TRANSPORT_TLS: /* Use existing if available*/ if (upstream->fd != -1) return upstream->fd; fd = tcp_connect(upstream, transport); - upstream->loop = dnsreq->loop; - upstream->is_sync_loop = dnsreq->is_sync_request; - upstream->fd = fd; - break; - - case GETDNS_TRANSPORT_TLS: - /* Use existing if available*/ - if (upstream->fd != -1 && !tls_failed(upstream)) - return upstream->fd; - fd = tcp_connect(upstream, transport); - if (fd == -1) return -1; - upstream->tls_obj = tls_create_object(dnsreq, fd, upstream); - if (upstream->tls_obj == NULL) { - close(fd); + if (fd == -1) { + upstream_failed(upstream, 1); return -1; } - - if (upstream->tls_session != NULL) - SSL_set_session(upstream->tls_obj, upstream->tls_session); - upstream->tls_hs_state = GETDNS_HS_WRITE; upstream->loop = dnsreq->loop; upstream->is_sync_loop = dnsreq->is_sync_request; upstream->fd = fd; + if (transport == GETDNS_TRANSPORT_TLS) { + upstream->tls_obj = tls_create_object(dnsreq, fd, upstream); + if (upstream->tls_obj == NULL) { + upstream_failed(upstream, 1); + close(fd); + return -1; + } + if (upstream->tls_session != NULL) + SSL_set_session(upstream->tls_obj, upstream->tls_session); + upstream->tls_hs_state = GETDNS_HS_WRITE; + } + upstream->conn_state = GETDNS_CONN_SETUP; break; default: return -1; @@ -1726,16 +1730,24 @@ upstream_connect(getdns_upstream *upstream, getdns_transport_list_t transport, static getdns_upstream* upstream_find_for_transport(getdns_network_req *netreq, - getdns_transport_list_t transport, - int *fd) + getdns_transport_list_t transport, + int *fd) { - // TODO[TLS]: Need to loop over upstreams here!! - getdns_upstream *upstream = upstream_select(netreq, transport); + /* [TLS1]TODO: Don't currently loop over upstreams here as UDP will timeout + and stateful will fallback. But there is a case where connect returns -1 + that we need to deal with!!!! so add a while loop to test fd*/ + getdns_upstream *upstream = NULL; + if (transport == GETDNS_TRANSPORT_UDP) { + upstream = upstream_select(netreq); + } + else + upstream = upstream_select_stateful(netreq, transport); if (!upstream) return NULL; *fd = upstream_connect(upstream, transport, netreq->owner); - DEBUG_STUB("%s %-35s: FD: %d Connected for upstream: %p\n", - STUB_DEBUG_SETUP, __FUNCTION__, *fd, upstream); + DEBUG_STUB("%s %-35s: FD: %d Connecting to upstream: %p No: %d\n", + STUB_DEBUG_SETUP, __FUNCTION__, *fd, upstream, + (int)(upstream - netreq->owner->context->upstreams->upstreams)); return upstream; } @@ -1756,6 +1768,8 @@ upstream_find_for_netreq(getdns_network_req *netreq) netreq->keepalive_sent = 0; return fd; } + /* Handle better, will give generic error*/ + DEBUG_STUB("%s %-35s: MSG: %p No valid upstream! \n", STUB_DEBUG_SCHEDULE, __FUNCTION__, netreq); return -1; } @@ -1767,8 +1781,7 @@ static int fallback_on_write(getdns_network_req *netreq) { - /* Deal with UDP and change error code*/ - + /* Deal with UDP one day*/ DEBUG_STUB("%s %-35s: MSG: %p FALLING BACK \n", STUB_DEBUG_SCHEDULE, __FUNCTION__, netreq); /* Try to find a fallback transport*/ @@ -1807,7 +1820,7 @@ upstream_reschedule_events(getdns_upstream *upstream, size_t idle_timeout) { DEBUG_STUB("%s %-35s: FD: %d Connection idle - timeout is %d\n", STUB_DEBUG_SCHEDULE, __FUNCTION__, upstream->fd, (int)idle_timeout); upstream->event.timeout_cb = upstream_idle_timeout_cb; - if (upstream->tcp.write_error != 0) + if (upstream->conn_state != GETDNS_CONN_OPEN) idle_timeout = 0; GETDNS_SCHEDULE_EVENT(upstream->loop, -1, idle_timeout, &upstream->event); @@ -1833,11 +1846,9 @@ upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq) } upstream->event.timeout_cb = NULL; upstream->event.write_cb = upstream_write_cb; - if (upstream->tls_hs_state == GETDNS_HS_WRITE) { + if (upstream->queries_sent == 0) { /* Set a timeout on the upstream so we can catch failed setup*/ - /* TODO[TLS]: When generic fallback supported, we should decide how - * to split the timeout between transports. */ - upstream->event.timeout_cb = upstream_tls_timeout_cb; + upstream->event.timeout_cb = upstream_setup_timeout_cb; GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, netreq->owner->context->timeout / 2, &upstream->event); @@ -1879,6 +1890,7 @@ _getdns_submit_stub_request(getdns_network_req *netreq) * All other set up is done async*/ fd = upstream_find_for_netreq(netreq); if (fd == -1) + /* Handle better, will give unhelpful error is some cases */ return GETDNS_RETURN_GENERIC_ERROR; getdns_transport_list_t transport = @@ -1962,14 +1974,10 @@ _getdns_submit_stub_request(getdns_network_req *netreq) */ GETDNS_SCHEDULE_EVENT( dnsreq->loop, -1, - dnsreq->context->timeout, - getdns_eventloop_event_init( &netreq->event, netreq, NULL, NULL, - - ( transport == GETDNS_TRANSPORT_TLS - ? stub_tls_timeout_cb : stub_timeout_cb))); + stub_timeout_cb)); return GETDNS_RETURN_GOOD; default: diff --git a/src/test/check_getdns_context_set_dns_transport.h b/src/test/check_getdns_context_set_dns_transport.h index 9b4aac23..fba6c195 100644 --- a/src/test/check_getdns_context_set_dns_transport.h +++ b/src/test/check_getdns_context_set_dns_transport.h @@ -300,6 +300,7 @@ } CONTEXT_DESTROY; + getdns_dict_destroy(extensions); getdns_list_destroy(root_servers); diff --git a/src/types-internal.h b/src/types-internal.h index bf7bfd7e..f6e58619 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -57,6 +57,11 @@ typedef struct getdns_item { getdns_union data; } getdns_item; +typedef enum getdns_auth_state { + GETDNS_AUTH_NONE, /* Not tried (Oppotunistic)*/ + GETDNS_AUTH_FAILED, /* Tried but failed or not possible*/ + GETDNS_AUTH_OK, /* Tried and worked (Strict) */ +} getdns_auth_state_t; struct getdns_context; struct getdns_upstreams; @@ -115,6 +120,8 @@ struct getdns_upstream; #define GETDNS_TRANSPORTS_MAX 3 #define GETDNS_UPSTREAM_TRANSPORTS 2 +#define GETDNS_MAX_CONN_FAILS 2 +#define GETDNS_CONN_FAIL_MULT 5 /* declarations */ @@ -164,7 +171,6 @@ typedef struct getdns_tcp_state { uint8_t *write_buf; size_t write_buf_len; size_t written; - int write_error; uint8_t *read_buf; size_t read_buf_len; @@ -212,7 +218,6 @@ typedef struct getdns_network_req size_t transport_current; getdns_tls_authentication_t tls_auth_min; getdns_eventloop_event event; - getdns_tcp_state tcp; uint16_t query_id; int edns_maximum_udp_payload_size; @@ -226,7 +231,7 @@ typedef struct getdns_network_req /* Some fields to record info for return_call_reporting */ uint64_t debug_start_time; uint64_t debug_end_time; - size_t debug_tls_auth_status; + getdns_auth_state_t debug_tls_auth_status; size_t debug_udp; /* When more space is needed for the wire_data response than is diff --git a/src/util-internal.c b/src/util-internal.c index 47a3fd21..1b154b3a 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -864,9 +864,10 @@ _getdns_create_call_reporting_dict( return netreq_debug; /* Only include the auth status if TLS was used */ + /* TODO: output all 3 options */ if (getdns_dict_util_set_string(netreq_debug, "tls_auth_status", - netreq->debug_tls_auth_status == 0 ? - "OK: Hostname matched valid cert":"FAILED: Server not validated")){ + netreq->debug_tls_auth_status == GETDNS_AUTH_OK ? + "OK: Server authenticated":"FAILED or NOT TRIED: Server not authenticated")){ getdns_dict_destroy(netreq_debug); return NULL; From 5e1575dabc5de48e1007cd195ca50edb0cf2c7a7 Mon Sep 17 00:00:00 2001 From: Sara Dickinson Date: Sat, 2 Jul 2016 16:20:08 +0100 Subject: [PATCH 04/61] Correct the logic for upstream back off --- src/context.c | 9 +++++---- src/stub.c | 4 ++-- src/types-internal.h | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/context.c b/src/context.c index 529bb19c..495217f4 100644 --- a/src/context.c +++ b/src/context.c @@ -696,11 +696,12 @@ _getdns_upstream_shutdown(getdns_upstream *upstream) use the same basis if we simply can't get TCP service either.*/ /* [TLS1]TODO: This arbitrary logic at the moment - review and improve!*/ - if (upstream->conn_setup_failed >= GETDNS_MAX_CONN_FAILS || - (upstream->conn_shutdowns >= GETDNS_MAX_CONN_FAILS*GETDNS_CONN_FAIL_MULT + if (upstream->conn_setup_failed >= GETDNS_CONN_ATTEMPTS || + (upstream->conn_shutdowns >= GETDNS_CONN_ATTEMPTS*GETDNS_TRANSPORT_FAIL_MULT && upstream->total_responses == 0) || - (upstream->total_timeouts > 0 && - upstream->total_responses*GETDNS_MAX_CONN_FAILS == 0)) + (upstream->conn_completed >= GETDNS_CONN_ATTEMPTS && + upstream->total_responses == 0 && + upstream->total_timeouts > GETDNS_TRANSPORT_FAIL_MULT)) upstream->conn_state = GETDNS_CONN_BACKOFF; // Reset per connection counters upstream->queries_sent = 0; diff --git a/src/stub.c b/src/stub.c index 90a8c935..efd293f8 100644 --- a/src/stub.c +++ b/src/stub.c @@ -1542,7 +1542,7 @@ upstream_working_ok(getdns_upstream *upstream) { /* [TLS1]TODO: This arbitrary logic at the moment - review and improve!*/ return (upstream->responses_timeouts > - upstream->responses_received*GETDNS_MAX_CONN_FAILS ? 0 : 1); + upstream->responses_received*GETDNS_CONN_ATTEMPTS ? 0 : 1); } static int @@ -1564,7 +1564,7 @@ upstream_stats(getdns_upstream *upstream) { /* [TLS1]TODO: This arbitrary logic at the moment - review and improve!*/ return (upstream->total_responses - upstream->total_timeouts - - upstream->conn_shutdowns*GETDNS_CONN_FAIL_MULT); + - upstream->conn_shutdowns*GETDNS_TRANSPORT_FAIL_MULT); } static int diff --git a/src/types-internal.h b/src/types-internal.h index f6e58619..f6c3cf5b 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -120,8 +120,8 @@ struct getdns_upstream; #define GETDNS_TRANSPORTS_MAX 3 #define GETDNS_UPSTREAM_TRANSPORTS 2 -#define GETDNS_MAX_CONN_FAILS 2 -#define GETDNS_CONN_FAIL_MULT 5 +#define GETDNS_CONN_ATTEMPTS 2 +#define GETDNS_TRANSPORT_FAIL_MULT 5 /* declarations */ From 105d7acfa94a75a9d1abbabc0267c69aea5681ee Mon Sep 17 00:00:00 2001 From: Sara Dickinson Date: Sat, 2 Jul 2016 16:43:47 +0100 Subject: [PATCH 05/61] Just re-read RFC7858 and realised that TLS does support idle connections without keepalive. It is just TCP that doesn't. --- src/stub.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/stub.c b/src/stub.c index efd293f8..ef9362e9 100644 --- a/src/stub.c +++ b/src/stub.c @@ -326,14 +326,17 @@ process_keepalive( int found = match_edns_opt_rr(GLDNS_EDNS_KEEPALIVE, response, response_len, &position, &option_len); if (found != 2 || option_len != 2) { - if (netreq->keepalive_sent == 1) - /* If no keepalive sent back, then we must use 0 idle timeout - as server does not support it.*/ -#if defined(KEEP_CONNECTIONS_OPEN_DEBUG) && KEEP_CONNECTIONS_OPEN_DEBUG - upstream->keepalive_timeout = netreq->owner->context->idle_timeout; -#else - upstream->keepalive_timeout = 0; + if (netreq->keepalive_sent == 1) { + /* For TCP if no keepalive sent back, then we must use 0 idle timeout + as server does not support it. TLS allows idle connections without + keepalive, according to RFC7858. */ +#if !defined(KEEP_CONNECTIONS_OPEN_DEBUG) && !KEEP_CONNECTIONS_OPEN_DEBUG + if (upstream->transport != GETDNS_TRANSPORT_TLS) + upstream->keepalive_timeout = 0; + else #endif + upstream->keepalive_timeout = netreq->owner->context->idle_timeout; + } return; } /* Use server sent value unless the client specified a shorter one. From d0f01b6bc459e88fb1d8dd090f9e55006a621b49 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Thu, 7 Jul 2016 14:47:38 +0200 Subject: [PATCH 06/61] Default values for extensions in context --- src/context.c | 31 +++++++++++++++--- src/context.h | 20 ++++++++++-- src/request-internal.c | 71 ++++++++++++++++++++++++------------------ 3 files changed, 85 insertions(+), 37 deletions(-) diff --git a/src/context.c b/src/context.c index b46dc3bd..160b1c01 100644 --- a/src/context.c +++ b/src/context.c @@ -1272,6 +1272,27 @@ getdns_context_create_with_extended_memory_functions( _getdns_default_eventloop_init(&result->default_eventloop); _getdns_default_eventloop_init(&result->sync_eventloop); + /* request extension defaults + */ + result->header = NULL; + result->add_opt_parameters = NULL; + result->add_warning_for_bad_dns = 0; + result->dnssec_return_all_statuses = 0; + result->dnssec_return_full_validation_chain = 0; + result->dnssec_return_only_secure = 0; + result->dnssec_return_status = 0; + result->dnssec_return_validation_chain = 0; +#ifdef DNSSEC_ROADBLOCK_AVOIDANCE + result->dnssec_roadblock_avoidance = 0; +#endif + result->edns_cookies = 0; + result->return_api_information = 0; + result->return_both_v4_and_v6 = 0; + result->return_call_reporting = 0; + result->specify_class = GETDNS_RRCLASS_IN; + + /* state data used to detect changes to the system config files + */ result->fchg_resolvconf = NULL; result->fchg_hosts = NULL; @@ -1291,7 +1312,6 @@ getdns_context_create_with_extended_memory_functions( result->tls_auth = GETDNS_AUTHENTICATION_NONE; result->tls_auth_min = GETDNS_AUTHENTICATION_NONE; result->limit_outstanding_queries = 0; - result->return_dnssec_status = GETDNS_EXTENSION_FALSE; /* unbound context is initialized here */ /* Unbound needs SSL to be init'ed this early when TLS is used. However we @@ -1401,8 +1421,7 @@ getdns_context_destroy(struct getdns_context *context) if (context->tls_ctx) SSL_CTX_free(context->tls_ctx); - if (context->dns_root_servers) - getdns_list_destroy(context->dns_root_servers); + getdns_list_destroy(context->dns_root_servers); #if defined(HAVE_LIBUNBOUND) && !defined(HAVE_UB_CTX_SET_STUB) if (context->root_servers_fn[0]) @@ -1419,6 +1438,10 @@ getdns_context_destroy(struct getdns_context *context) _getdns_traverse_postorder(&context->local_hosts, destroy_local_host, context); + + getdns_dict_destroy(context->header); + getdns_dict_destroy(context->add_opt_parameters); + #ifdef USE_WINSOCK WSACleanup(); #endif @@ -3416,7 +3439,7 @@ getdns_context_set_return_dnssec_status(getdns_context* context, int enabled) { enabled != GETDNS_EXTENSION_FALSE) { return GETDNS_RETURN_INVALID_PARAMETER; } - context->return_dnssec_status = enabled; + context->dnssec_return_status = enabled == GETDNS_EXTENSION_TRUE; return GETDNS_RETURN_GOOD; } diff --git a/src/context.h b/src/context.h index 46ed6c88..2ccea5c4 100644 --- a/src/context.h +++ b/src/context.h @@ -250,8 +250,6 @@ struct getdns_context { /* A tree to hold local host information*/ _getdns_rbtree_t local_hosts; - int return_dnssec_status; - /* which resolution type the contexts are configured for * 0 means nothing set */ @@ -275,6 +273,24 @@ struct getdns_context { _getdns_default_eventloop default_eventloop; _getdns_default_eventloop sync_eventloop; + /* request extension defaults */ + getdns_dict *header; + getdns_dict *add_opt_parameters; + int add_warning_for_bad_dns : 1; + int dnssec_return_all_statuses : 1; + int dnssec_return_full_validation_chain : 1; + int dnssec_return_only_secure : 1; + int dnssec_return_status : 1; + int dnssec_return_validation_chain : 1; +#ifdef DNSSEC_ROADBLOCK_AVOIDANCE + int dnssec_roadblock_avoidance : 1; +#endif + int edns_cookies : 1; + int return_api_information : 1; /* Not used */ + int return_both_v4_and_v6 : 1; + int return_call_reporting : 1; + uint16_t specify_class; + /* * state data used to detect changes to the system config files */ diff --git a/src/request-internal.c b/src/request-internal.c index 797fde50..b35b3cae 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -85,20 +85,20 @@ getdns_dict *dnssec_ok_checking_disabled_avoid_roadblocks static int -is_extension_set(getdns_dict *extensions, const char *extension) +is_extension_set(getdns_dict *extensions, const char *name, int default_value) { getdns_return_t r; uint32_t value; - if (! extensions) - return 0; - else if (extensions == dnssec_ok_checking_disabled + if ( ! extensions + || extensions == dnssec_ok_checking_disabled || extensions == dnssec_ok_checking_disabled_roadblock_avoidance || extensions == dnssec_ok_checking_disabled_avoid_roadblocks) return 0; - r = getdns_dict_get_int(extensions, extension, &value); - return r == GETDNS_RETURN_GOOD && value == GETDNS_EXTENSION_TRUE; + r = getdns_dict_get_int(extensions, name, &value); + return r == GETDNS_RETURN_GOOD ? ( value == GETDNS_EXTENSION_TRUE ) + : default_value; } static void @@ -206,6 +206,8 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, buf = netreq_reset(net_req); gldns_buffer_init_frm_data( &gbuf, net_req->query, net_req->wire_data_sz - 2); + if (owner->context->header) + _getdns_reply_dict2wire(owner->context->header, &gbuf, 1); _getdns_reply_dict2wire(extensions, &gbuf, 1); if (dnssec_extension_set) /* We will do validation ourselves */ GLDNS_CD_SET(net_req->query); @@ -658,28 +660,32 @@ getdns_dns_req * _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, const char *name, uint16_t request_type, getdns_dict *extensions) { - int dnssec_return_status - = context->return_dnssec_status == GETDNS_EXTENSION_TRUE - || is_extension_set(extensions, "dnssec_return_status"); - int dnssec_return_only_secure - = is_extension_set(extensions, "dnssec_return_only_secure"); - int dnssec_return_all_statuses - = is_extension_set(extensions, "dnssec_return_all_statuses"); - int dnssec_return_full_validation_chain - = is_extension_set(extensions, "dnssec_return_full_validation_chain"); - int dnssec_return_validation_chain - = is_extension_set(extensions, "dnssec_return_validation_chain"); - int edns_cookies - = is_extension_set(extensions, "edns_cookies"); + int dnssec_return_status = is_extension_set( + extensions, "dnssec_return_status", + context->dnssec_return_status); + int dnssec_return_only_secure = is_extension_set( + extensions, "dnssec_return_only_secure", + context->dnssec_return_only_secure); + int dnssec_return_all_statuses = is_extension_set( + extensions, "dnssec_return_all_statuses", + context->dnssec_return_all_statuses); + int dnssec_return_full_validation_chain = is_extension_set( + extensions, "dnssec_return_full_validation_chain", + context->dnssec_return_full_validation_chain); + int dnssec_return_validation_chain = is_extension_set( + extensions, "dnssec_return_validation_chain", + context->dnssec_return_validation_chain); + int edns_cookies = is_extension_set( + extensions, "edns_cookies", + context->edns_cookies); #ifdef DNSSEC_ROADBLOCK_AVOIDANCE int avoid_dnssec_roadblocks = (extensions == dnssec_ok_checking_disabled_avoid_roadblocks); - int dnssec_roadblock_avoidance - = is_extension_set(extensions, "dnssec_roadblock_avoidance") + int dnssec_roadblock_avoidance = avoid_dnssec_roadblocks || (extensions == dnssec_ok_checking_disabled_roadblock_avoidance) - || avoid_dnssec_roadblocks; + || is_extension_set(extensions, "dnssec_roadblock_avoidance", + context->dnssec_roadblock_avoidance); #endif - int dnssec_extension_set = dnssec_return_status || dnssec_return_only_secure || dnssec_return_all_statuses || dnssec_return_validation_chain @@ -713,9 +719,9 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, int with_opt; getdns_dns_req *result = NULL; - uint32_t klass = GLDNS_RR_CLASS_IN; - int a_aaaa_query = - is_extension_set(extensions, "return_both_v4_and_v6") && + uint32_t klass = context->specify_class; + int a_aaaa_query = is_extension_set(extensions, + "return_both_v4_and_v6", context->return_both_v4_and_v6) && ( request_type == GETDNS_RRTYPE_A || request_type == GETDNS_RRTYPE_AAAA ); /* Reserve for the buffer at least one more byte @@ -732,7 +738,10 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, have_add_opt_parameters = getdns_dict_get_dict(extensions, "add_opt_parameters", &add_opt_parameters) == GETDNS_RETURN_GOOD; - + if (!have_add_opt_parameters && context->add_opt_parameters) { + add_opt_parameters = context->add_opt_parameters; + have_add_opt_parameters = 1; + } if (dnssec_extension_set) { edns_maximum_udp_payload_size = -1; edns_extended_rcode = 0; @@ -895,10 +904,10 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, #endif result->edns_client_subnet_private = context->edns_client_subnet_private; result->tls_query_padding_blocksize = context->tls_query_padding_blocksize; - result->return_call_reporting = - is_extension_set(extensions, "return_call_reporting"); - result->add_warning_for_bad_dns = - is_extension_set(extensions, "add_warning_for_bad_dns"); + result->return_call_reporting = is_extension_set(extensions, + "return_call_reporting" , context->return_call_reporting); + result->add_warning_for_bad_dns = is_extension_set(extensions, + "add_warning_for_bad_dns", context->add_warning_for_bad_dns); /* will be set by caller */ result->user_pointer = NULL; From 69b607176ce3bb95a451408d4d68be32a1136bbc Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Mon, 11 Jul 2016 20:42:50 +0200 Subject: [PATCH 07/61] Move getdns_context_config into the library --- src/Makefile.in | 4 +- src/context.c | 205 ++++++++++++++++++++++++++++ src/getdns/getdns_extra.h.in | 3 + src/libgetdns.symbols | 1 + src/request-internal.c | 1 + src/test/Makefile.in | 8 +- src/test/getdns_context_config.c | 220 ------------------------------- src/test/getdns_context_config.h | 41 ------ src/test/getdns_query.c | 4 +- 9 files changed, 216 insertions(+), 271 deletions(-) delete mode 100644 src/test/getdns_context_config.c delete mode 100644 src/test/getdns_context_config.h diff --git a/src/Makefile.in b/src/Makefile.in index 1c66530c..5960c7ff 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -243,8 +243,8 @@ convert.lo convert.o: $(srcdir)/convert.c config.h getdns/getdns.h getdns/getdns getdns/getdns.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ - $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/const-info.h $(srcdir)/dict.h \ - $(srcdir)/list.h $(srcdir)/jsmn/jsmn.h $(srcdir)/convert.h + $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/parseutil.h \ + $(srcdir)/const-info.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/jsmn/jsmn.h $(srcdir)/convert.h dict.lo dict.o: $(srcdir)/dict.c config.h $(srcdir)/types-internal.h getdns/getdns.h \ getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/util-internal.h \ $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h \ diff --git a/src/context.c b/src/context.c index 160b1c01..0618814a 100644 --- a/src/context.c +++ b/src/context.c @@ -3914,4 +3914,209 @@ getdns_context_get_tls_query_padding_blocksize(getdns_context *context, uint16_t return GETDNS_RETURN_GOOD; } +static int _streq(const getdns_bindata *name, const char *str) +{ + if (strlen(str) != name->size) + return 0; + else return strncmp((const char *)name->data, str, name->size) == 0; +} + +static getdns_return_t _get_list_or_read_file(const getdns_dict *config_dict, + const char *setting, getdns_list **r_list, int *destroy_list) +{ + getdns_bindata *fn_bd; + char fn[FILENAME_MAX]; + FILE *fh; + getdns_return_t r; + + assert(r_list); + assert(destroy_list); + + *destroy_list = 0; + if (!(r = getdns_dict_get_list(config_dict, setting, r_list))) + return GETDNS_RETURN_GOOD; + + else if ((r = getdns_dict_get_bindata(config_dict, setting, &fn_bd))) + return r; + + else if (fn_bd->size >= FILENAME_MAX) + return GETDNS_RETURN_INVALID_PARAMETER; + + (void)memcpy(fn, fn_bd->data, fn_bd->size); + fn[fn_bd->size] = 0; + + if (!(fh = fopen(fn, "r"))) + return GETDNS_RETURN_GENERIC_ERROR; + + if (!(r = getdns_fp2rr_list(fh, r_list, NULL, 3600))) + *destroy_list = 1; + + fclose(fh); + return r; +} + +#define CONTEXT_SETTING_INT(X) \ + } else if (_streq(setting, #X)) { \ + if (!(r = getdns_dict_get_int(config_dict, #X , &n))) \ + r = getdns_context_set_ ## X (context, n); + +#define CONTEXT_SETTING_LIST(X) \ + } else if (_streq(setting, #X)) { \ + if (!(r = getdns_dict_get_list(config_dict, #X , &list))) \ + r = getdns_context_set_ ## X (context, list); + +#define CONTEXT_SETTING_LIST_OR_ZONEFILE(X) \ + } else if (_streq(setting, #X)) { \ + if (!(r = _get_list_or_read_file( \ + config_dict, #X , &list, &destroy_list))) \ + r = getdns_context_set_ ## X(context, list); \ + if (destroy_list) getdns_list_destroy(list); + +#define CONTEXT_SETTING_ARRAY(X, T) \ + } else if (_streq(setting, #X )) { \ + if (!(r = getdns_dict_get_list(config_dict, #X , &list)) && \ + !(r = getdns_list_get_length(list, &count))) { \ + for (i=0; iX = 1; \ + else if (n == GETDNS_EXTENSION_FALSE) context->X = 0; \ + else r = GETDNS_RETURN_INVALID_PARAMETER; \ + } + +static getdns_return_t +_getdns_context_config_setting(getdns_context *context, + const getdns_dict *config_dict, const getdns_bindata *setting) +{ + getdns_return_t r = GETDNS_RETURN_GOOD; + getdns_dict *dict; + getdns_list *list; + getdns_namespace_t namespaces[100]; + getdns_transport_list_t dns_transport_list[100]; + size_t count, i; + uint32_t n; + int destroy_list = 0; + + if (_streq(setting, "all_context")) { + if (!(r = getdns_dict_get_dict(config_dict, "all_context", &dict))) + r = getdns_context_config(context, dict); + + CONTEXT_SETTING_INT(resolution_type) + CONTEXT_SETTING_ARRAY(namespaces, namespace) + CONTEXT_SETTING_INT(dns_transport) + CONTEXT_SETTING_ARRAY(dns_transport_list, transport_list) + CONTEXT_SETTING_INT(idle_timeout) + CONTEXT_SETTING_INT(limit_outstanding_queries) + CONTEXT_SETTING_INT(timeout) + CONTEXT_SETTING_INT(follow_redirects) + CONTEXT_SETTING_LIST_OR_ZONEFILE(dns_root_servers) + CONTEXT_SETTING_INT(append_name) + CONTEXT_SETTING_LIST(suffix) + CONTEXT_SETTING_LIST_OR_ZONEFILE(dnssec_trust_anchors) + CONTEXT_SETTING_INT(dnssec_allowed_skew) + CONTEXT_SETTING_LIST(upstream_recursive_servers) + CONTEXT_SETTING_INT(edns_maximum_udp_payload_size) + CONTEXT_SETTING_INT(edns_extended_rcode) + CONTEXT_SETTING_INT(edns_version) + CONTEXT_SETTING_INT(edns_do_bit) + + /***************************************/ + /**** ****/ + /**** Unofficial context settings ****/ + /**** ****/ + /***************************************/ + + CONTEXT_SETTING_INT(edns_client_subnet_private) + CONTEXT_SETTING_INT(tls_authentication) + CONTEXT_SETTING_INT(tls_query_padding_blocksize) + + /**************************************/ + /**** ****/ + /**** Default extensions setting ****/ + /**** ****/ + /**************************************/ + EXTENSION_SETTING_BOOL(add_warning_for_bad_dns) + EXTENSION_SETTING_BOOL(dnssec_return_all_statuses) + EXTENSION_SETTING_BOOL(dnssec_return_full_validation_chain) + EXTENSION_SETTING_BOOL(dnssec_return_only_secure) + EXTENSION_SETTING_BOOL(dnssec_return_status) + EXTENSION_SETTING_BOOL(dnssec_return_validation_chain) +#if defined(DNSSEC_ROADBLOCK_AVOIDANCE) && defined(HAVE_LIBUNBOUND) + EXTENSION_SETTING_BOOL(dnssec_roadblock_avoidance) +#endif +#ifdef EDNS_COOKIES + EXTENSION_SETTING_BOOL(edns_cookies) +#endif + EXTENSION_SETTING_BOOL(return_api_information) + EXTENSION_SETTING_BOOL(return_both_v4_and_v6) + EXTENSION_SETTING_BOOL(return_call_reporting) + + } else if (_streq(setting, "add_opt_parameters")) { + if (!(r = getdns_dict_get_dict(config_dict, "add_opt_parameters" , &dict))) { + if (context->add_opt_parameters) + getdns_dict_destroy(context->add_opt_parameters); + context->add_opt_parameters = NULL; + r = _getdns_dict_copy(dict, &context->add_opt_parameters); + } + + } else if (_streq(setting, "header")) { + if (!(r = getdns_dict_get_dict(config_dict, "header" , &dict))) { + if (context->header) + getdns_dict_destroy(context->header); + if (!(context->header = + getdns_dict_create_with_context(context))) + r = GETDNS_RETURN_MEMORY_ERROR; + else r = getdns_dict_set_dict( + context->header, "header", dict); + } + + } else if (_streq(setting, "specify_class")) { + if (!(r = getdns_dict_get_int( + config_dict, "specify_class" , &n))) + context->specify_class = (uint16_t)n; + + + /************************************/ + /**** ****/ + /**** Ignored context settings ****/ + /**** ****/ + /************************************/ + } else if (!_streq(setting, "implementation_string") && + !_streq(setting, "version_string")) { + r = GETDNS_RETURN_NOT_IMPLEMENTED; + } + return r; +} + +getdns_return_t +getdns_context_config(getdns_context *context, const getdns_dict *config_dict) +{ + getdns_list *settings; + getdns_return_t r; + getdns_bindata *setting; + size_t i; + + if ((r = getdns_dict_get_names(config_dict, &settings))) + return r; + + for (i = 0; !(r = getdns_list_get_bindata(settings,i,&setting)); i++) { + if ((r = _getdns_context_config_setting( + context, config_dict, setting))) + break; + } + if (r == GETDNS_RETURN_NO_SUCH_LIST_ITEM) + r = GETDNS_RETURN_GOOD; + + getdns_list_destroy(settings); + return r; +} + /* context.c */ diff --git a/src/getdns/getdns_extra.h.in b/src/getdns/getdns_extra.h.in index a8d9740b..011275cd 100644 --- a/src/getdns/getdns_extra.h.in +++ b/src/getdns/getdns_extra.h.in @@ -827,6 +827,9 @@ getdns_return_t getdns_str2list(const char *str, getdns_list **list); getdns_return_t getdns_str2bindata(const char *str, getdns_bindata **bindata); getdns_return_t getdns_str2int(const char *str, uint32_t *value); +getdns_return_t +getdns_context_config(getdns_context *context, const getdns_dict *config_dict); + #ifdef __cplusplus } #endif diff --git a/src/libgetdns.symbols b/src/libgetdns.symbols index 88d1cebe..6b5a28fe 100644 --- a/src/libgetdns.symbols +++ b/src/libgetdns.symbols @@ -1,6 +1,7 @@ getdns_address getdns_address_sync getdns_cancel_callback +getdns_context_config getdns_context_create getdns_context_create_with_extended_memory_functions getdns_context_create_with_memory_functions diff --git a/src/request-internal.c b/src/request-internal.c index b35b3cae..8e4ec303 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -208,6 +208,7 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, &gbuf, net_req->query, net_req->wire_data_sz - 2); if (owner->context->header) _getdns_reply_dict2wire(owner->context->header, &gbuf, 1); + gldns_buffer_rewind(&gbuf); _getdns_reply_dict2wire(extensions, &gbuf, 1); if (dnssec_extension_set) /* We will do validation ourselves */ GLDNS_CD_SET(net_req->query); diff --git a/src/test/Makefile.in b/src/test/Makefile.in index f66494e7..e3906eb8 100644 --- a/src/test/Makefile.in +++ b/src/test/Makefile.in @@ -66,7 +66,7 @@ CHECK_CFLAGS=@CHECK_CFLAGS@ CHECK_OBJS=check_getdns_common.lo check_getdns_context_set_timeout.lo \ check_getdns.lo check_getdns_transport.lo -DECOMPOSED_OBJS=getdns_context_config.lo getdns_context_set_listen_addresses.lo +DECOMPOSED_OBJS=getdns_context_set_listen_addresses.lo ALL_OBJS=$(CHECK_OBJS) check_getdns_libevent.lo check_getdns_libev.lo \ check_getdns_selectloop.lo getdns_query.lo scratchpad.lo \ @@ -266,7 +266,6 @@ check_getdns_selectloop.lo check_getdns_selectloop.o: $(srcdir)/check_getdns_sel check_getdns_transport.lo check_getdns_transport.o: $(srcdir)/check_getdns_transport.c \ $(srcdir)/check_getdns_transport.h $(srcdir)/check_getdns_common.h ../getdns/getdns.h \ ../getdns/getdns_extra.h -const-info.lo const-info.o: $(srcdir)/const-info.c getdns_context_config.lo getdns_context_config.o: $(srcdir)/getdns_context_config.c $(srcdir)/getdns_context_config.h \ ../getdns/getdns.h ../getdns/getdns_extra.h getdns_context_set_listen_addresses.lo getdns_context_set_listen_addresses.o: \ @@ -275,9 +274,8 @@ getdns_context_set_listen_addresses.lo getdns_context_set_listen_addresses.o: \ ../getdns/getdns_extra.h $(srcdir)/../types-internal.h ../getdns/getdns.h \ ../getdns/getdns_extra.h $(srcdir)/../util/rbtree.h $(srcdir)/../debug.h ../config.h getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c ../config.h $(srcdir)/../debug.h ../config.h \ - $(srcdir)/getdns_context_config.h ../getdns/getdns.h \ - $(srcdir)/getdns_context_set_listen_addresses.h ../getdns/getdns_extra.h -new-getdns_str2dict.lo new-getdns_str2dict.o: $(srcdir)/new-getdns_str2dict.c + $(srcdir)/getdns_context_set_listen_addresses.h ../getdns/getdns.h \ + ../getdns/getdns_extra.h scratchpad.template.lo scratchpad.template.o: scratchpad.template.c ../getdns/getdns.h \ ../getdns/getdns_extra.h testmessages.lo testmessages.o: $(srcdir)/testmessages.c $(srcdir)/testmessages.h diff --git a/src/test/getdns_context_config.c b/src/test/getdns_context_config.c deleted file mode 100644 index 3cb7e272..00000000 --- a/src/test/getdns_context_config.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (c) 2013, NLNet Labs, Verisign, 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 names of the copyright holders 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_context_config.h" -#include "getdns/getdns_extra.h" -#include -#include -#include - -static int _streq(const getdns_bindata *name, const char *str) -{ - if (strlen(str) != name->size) - return 0; - else return strncmp((const char *)name->data, str, name->size) == 0; -} - -static getdns_return_t _get_list_or_read_file(const getdns_dict *config_dict, - const char *setting, getdns_list **r_list, int *destroy_list) -{ - getdns_bindata *fn_bd; - char fn[FILENAME_MAX]; - FILE *fh; - getdns_return_t r; - - assert(r_list); - assert(destroy_list); - - *destroy_list = 0; - if (!(r = getdns_dict_get_list(config_dict, setting, r_list))) - return GETDNS_RETURN_GOOD; - - else if ((r = getdns_dict_get_bindata(config_dict, setting, &fn_bd))) - return r; - - else if (fn_bd->size >= FILENAME_MAX) - return GETDNS_RETURN_INVALID_PARAMETER; - - (void)memcpy(fn, fn_bd->data, fn_bd->size); - fn[fn_bd->size] = 0; - - if (!(fh = fopen(fn, "r"))) - return GETDNS_RETURN_GENERIC_ERROR; - - if (!(r = getdns_fp2rr_list(fh, r_list, NULL, 3600))) - *destroy_list = 1; - - fclose(fh); - return r; -} - -#define CONTEXT_SETTING_INT(X) \ - } else if (_streq(setting, #X)) { \ - if (!(r = getdns_dict_get_int(config_dict, #X , &n))) \ - r = getdns_context_set_ ## X (context, n); - -#define CONTEXT_SETTING_LIST(X) \ - } else if (_streq(setting, #X)) { \ - if (!(r = getdns_dict_get_list(config_dict, #X , &list))) \ - r = getdns_context_set_ ## X (context, list); - -#define CONTEXT_SETTING_LIST_OR_ZONEFILE(X) \ - } else if (_streq(setting, #X)) { \ - if (!(r = _get_list_or_read_file( \ - config_dict, #X , &list, &destroy_list))) \ - r = getdns_context_set_ ## X(context, list); \ - if (destroy_list) getdns_list_destroy(list); - -#define CONTEXT_SETTING_ARRAY(X, T) \ - } else if (_streq(setting, #X )) { \ - if (!(r = getdns_dict_get_list(config_dict, #X , &list)) && \ - !(r = getdns_list_get_length(list, &count))) { \ - for (i=0; i #include @@ -463,8 +462,7 @@ static void parse_config(const char *config_str) touched_listen_list = 1; } - if ((r = _getdns_context_config_( - context, extensions, config_dict))) { + if ((r = getdns_context_config(context, config_dict))) { fprintf(stderr, "Could not configure context with " "config dict: %s\n", getdns_get_errorstr_by_id(r)); } From be97bd1d71a16ab5757eb8c29fa5f5b6aac410a1 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Wed, 13 Jul 2016 14:50:44 +0200 Subject: [PATCH 08/61] Mv getdns_context_set_listen_addresses in the lib Also, check for request_id + cancel a reply by specifying NULL as response to getdns_reply --- src/Makefile.in | 48 +++-- src/context.c | 5 + src/context.h | 3 + src/getdns/getdns_extra.h.in | 13 ++ src/libgetdns.symbols | 2 + ...ontext_set_listen_addresses.c => server.c} | 177 ++++++++++-------- ...ontext_set_listen_addresses.h => server.h} | 32 ++-- src/test/Makefile.in | 19 +- src/test/getdns_query.c | 19 +- 9 files changed, 176 insertions(+), 142 deletions(-) rename src/{test/getdns_context_set_listen_addresses.c => server.c} (86%) rename src/{test/getdns_context_set_listen_addresses.h => server.h} (70%) diff --git a/src/Makefile.in b/src/Makefile.in index 5960c7ff..c9ff78db 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -65,7 +65,7 @@ C99COMPATFLAGS=@C99COMPATFLAGS@ GETDNS_OBJ=const-info.lo convert.lo dict.lo dnssec.lo general.lo \ list.lo request-internal.lo pubkey-pinning.lo rr-dict.lo \ - rr-iter.lo stub.lo sync.lo ub_loop.lo util-internal.lo + rr-iter.lo server.lo stub.lo sync.lo ub_loop.lo util-internal.lo GLDNS_OBJ=keyraw.lo gbuffer.lo wire2str.lo parse.lo parseutil.lo rrdef.lo \ str2wire.lo @@ -237,70 +237,78 @@ context.lo context.o: $(srcdir)/context.c config.h $(srcdir)/debug.h $(srcdir)/g $(srcdir)/gldns/wire2str.h $(srcdir)/context.h getdns/getdns.h getdns/getdns_extra.h \ getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ - $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ - $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h $(srcdir)/pubkey-pinning.h + $(srcdir)/server.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h \ + $(srcdir)/pubkey-pinning.h convert.lo convert.o: $(srcdir)/convert.c config.h getdns/getdns.h getdns/getdns_extra.h \ getdns/getdns.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ - $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ + $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/parseutil.h \ $(srcdir)/const-info.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/jsmn/jsmn.h $(srcdir)/convert.h dict.lo dict.o: $(srcdir)/dict.c config.h $(srcdir)/types-internal.h getdns/getdns.h \ getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/util-internal.h \ $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h \ - $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ - $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/const-info.h $(srcdir)/gldns/wire2str.h + $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/const-info.h $(srcdir)/gldns/wire2str.h dnssec.lo dnssec.o: $(srcdir)/dnssec.c config.h $(srcdir)/debug.h getdns/getdns.h $(srcdir)/context.h \ getdns/getdns_extra.h getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ - $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ - $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h \ - $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/parseutil.h $(srcdir)/general.h $(srcdir)/dict.h $(srcdir)/list.h \ - $(srcdir)/util/val_secalgo.h + $(srcdir)/server.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \ + $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/parseutil.h $(srcdir)/general.h $(srcdir)/dict.h \ + $(srcdir)/list.h $(srcdir)/util/val_secalgo.h general.lo general.o: $(srcdir)/general.c config.h $(srcdir)/general.h getdns/getdns.h $(srcdir)/types-internal.h \ getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/ub_loop.h $(srcdir)/debug.h \ $(srcdir)/gldns/wire2str.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h config.h \ - getdns/getdns_extra.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ + getdns/getdns_extra.h $(srcdir)/server.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h $(srcdir)/dict.h list.lo list.o: $(srcdir)/list.c $(srcdir)/types-internal.h getdns/getdns.h getdns/getdns_extra.h \ getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/util-internal.h config.h $(srcdir)/context.h \ $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ - $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/list.h $(srcdir)/dict.h + $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ + $(srcdir)/list.h $(srcdir)/dict.h pubkey-pinning.lo pubkey-pinning.o: $(srcdir)/pubkey-pinning.c config.h $(srcdir)/debug.h getdns/getdns.h \ $(srcdir)/context.h getdns/getdns.h getdns/getdns_extra.h $(srcdir)/types-internal.h \ $(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h config.h \ - getdns/getdns_extra.h $(srcdir)/ub_loop.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ - $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h + getdns/getdns_extra.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h \ + $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h request-internal.lo request-internal.o: $(srcdir)/request-internal.c config.h $(srcdir)/types-internal.h \ getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h config.h \ - getdns/getdns_extra.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ + getdns/getdns_extra.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h \ $(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/convert.h rr-dict.lo rr-dict.o: $(srcdir)/rr-dict.c $(srcdir)/rr-dict.h config.h getdns/getdns.h $(srcdir)/gldns/gbuffer.h \ $(srcdir)/util-internal.h $(srcdir)/context.h getdns/getdns_extra.h getdns/getdns.h \ $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h config.h \ - getdns/getdns_extra.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h + getdns/getdns_extra.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/rr-iter.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h rr-iter.lo rr-iter.o: $(srcdir)/rr-iter.c $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h config.h getdns/getdns.h \ $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h +server.lo server.o: $(srcdir)/server.c config.h getdns/getdns_extra.h getdns/getdns.h \ + $(srcdir)/context.h getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ + $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ + $(srcdir)/debug.h $(srcdir)/server.h stub.lo stub.o: $(srcdir)/stub.c config.h $(srcdir)/debug.h $(srcdir)/stub.h getdns/getdns.h $(srcdir)/types-internal.h \ getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/gldns/gbuffer.h \ $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \ $(srcdir)/gldns/wire2str.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/context.h \ $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ - $(srcdir)/util-internal.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h + $(srcdir)/server.h $(srcdir)/util-internal.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h sync.lo sync.o: $(srcdir)/sync.c getdns/getdns.h config.h $(srcdir)/context.h getdns/getdns_extra.h \ getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ - $(srcdir)/debug.h $(srcdir)/general.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h $(srcdir)/gldns/wire2str.h + $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/general.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ + $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h \ + $(srcdir)/gldns/wire2str.h ub_loop.lo ub_loop.o: $(srcdir)/ub_loop.c $(srcdir)/ub_loop.h config.h getdns/getdns.h \ getdns/getdns_extra.h getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ $(srcdir)/debug.h util-internal.lo util-internal.o: $(srcdir)/util-internal.c config.h getdns/getdns.h $(srcdir)/dict.h \ $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h getdns/getdns_extra.h getdns/getdns.h \ $(srcdir)/list.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h config.h \ - getdns/getdns_extra.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ + getdns/getdns_extra.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/dnssec.h \ $(srcdir)/gldns/rrdef.h version.lo version.o: version.c diff --git a/src/context.c b/src/context.c index 0618814a..a47124de 100644 --- a/src/context.c +++ b/src/context.c @@ -1216,6 +1216,8 @@ getdns_context_create_with_extended_memory_functions( _getdns_rbtree_init(&result->outbound_requests, transaction_id_cmp); _getdns_rbtree_init(&result->local_hosts, local_host_cmp); + result->server = NULL; + #ifdef HAVE_LIBUNBOUND result->resolution_type = GETDNS_RESOLUTION_RECURSING; #else @@ -1389,6 +1391,9 @@ getdns_context_destroy(struct getdns_context *context) /* cancel all outstanding requests */ cancel_outstanding_requests(context, 1); + /* Destroy listening addresses */ + (void) getdns_context_set_listen_addresses(context, NULL, NULL); + /* This needs to be done before cleaning the extension, because there * might be an idle_timeout schedules, which will not get unscheduled * with cancel_outstanding_requests. diff --git a/src/context.h b/src/context.h index 2ccea5c4..fd603b6d 100644 --- a/src/context.h +++ b/src/context.h @@ -44,6 +44,7 @@ #include "extension/default_eventloop.h" #include "util/rbtree.h" #include "ub_loop.h" +#include "server.h" struct getdns_dns_req; struct ub_ctx; @@ -260,6 +261,8 @@ struct getdns_context { */ _getdns_rbtree_t outbound_requests; + struct listen_set *server; + /* Event loop extension. */ getdns_eventloop *extension; diff --git a/src/getdns/getdns_extra.h.in b/src/getdns/getdns_extra.h.in index 011275cd..d2bcd290 100644 --- a/src/getdns/getdns_extra.h.in +++ b/src/getdns/getdns_extra.h.in @@ -830,6 +830,19 @@ getdns_return_t getdns_str2int(const char *str, uint32_t *value); getdns_return_t getdns_context_config(getdns_context *context, const getdns_dict *config_dict); +typedef void (*getdns_request_handler_t)( + getdns_context *context, + getdns_dict *request, + getdns_transaction_t request_id +); + +getdns_return_t +getdns_context_set_listen_addresses(getdns_context *context, + getdns_request_handler_t handler, const getdns_list *listen_addresses); + +getdns_return_t getdns_reply(getdns_context *context, + getdns_transaction_t request_id, getdns_dict *reply); + #ifdef __cplusplus } #endif diff --git a/src/libgetdns.symbols b/src/libgetdns.symbols index 6b5a28fe..6e3cb128 100644 --- a/src/libgetdns.symbols +++ b/src/libgetdns.symbols @@ -51,6 +51,7 @@ getdns_context_set_extended_memory_functions getdns_context_set_follow_redirects getdns_context_set_idle_timeout getdns_context_set_limit_outstanding_queries +getdns_context_set_listen_addresses getdns_context_set_memory_functions getdns_context_set_namespaces getdns_context_set_resolution_type @@ -124,6 +125,7 @@ getdns_print_json_dict getdns_print_json_list getdns_pubkey_pin_create_from_string getdns_pubkey_pinset_sanity_check +getdns_reply getdns_root_trust_anchor getdns_rr_dict2str getdns_rr_dict2str_buf diff --git a/src/test/getdns_context_set_listen_addresses.c b/src/server.c similarity index 86% rename from src/test/getdns_context_set_listen_addresses.c rename to src/server.c index 3b05e803..c42008dd 100644 --- a/src/test/getdns_context_set_listen_addresses.c +++ b/src/server.c @@ -26,11 +26,13 @@ */ #include "config.h" -#include "getdns_context_set_listen_addresses.h" +#include #include "getdns/getdns_extra.h" +#include "context.h" #include "types-internal.h" #include "debug.h" -#include +#include "util/rbtree.h" +#include "server.h" #define DNS_REQUEST_SZ 4096 #define DOWNSTREAM_IDLE_TIMEOUT 5000 @@ -63,9 +65,9 @@ struct listener { */ struct listen_set { getdns_context *context; - listen_set *next; getdns_request_handler_t handler; + _getdns_rbtree_t connections_set; size_t count; listener items[]; }; @@ -79,6 +81,9 @@ struct tcp_to_write { }; struct connection { + /* struct connection is a sub struct of _getdns_rbnode_t */ + _getdns_rbnode_t super; + listener *l; struct sockaddr_storage remote_in; socklen_t addrlen; @@ -88,14 +93,8 @@ struct connection { }; typedef struct tcp_connection { - /* A TCP connection is a connection */ - listener *l; - struct sockaddr_storage remote_in; - socklen_t addrlen; - - connection *next; - connection **prev_next; - /************************************/ + /* struct tcp_connection is a sub struct of connection */ + connection super; int fd; getdns_eventloop_event event; @@ -118,10 +117,10 @@ static void tcp_connection_destroy(tcp_connection *conn) tcp_to_write *cur, *next; - if (!(mf = priv_getdns_context_mf(conn->l->set->context))) + if (!(mf = &conn->super.l->set->context->mf)) return; - if (getdns_context_get_eventloop(conn->l->set->context, &loop)) + if (getdns_context_get_eventloop(conn->super.l->set->context, &loop)) return; if (conn->event.read_cb||conn->event.write_cb||conn->event.timeout_cb) @@ -139,10 +138,14 @@ static void tcp_connection_destroy(tcp_connection *conn) return; /* Unlink this connection */ - if ((*conn->prev_next = conn->next)) - conn->next->prev_next = conn->prev_next; + (void) _getdns_rbtree_delete( + &conn->super.l->set->connections_set, conn); + DEBUG_SERVER("[connection del] count: %d\n", + (int)conn->super.l->set->connections_set.count); + if ((*conn->super.prev_next = conn->super.next)) + conn->super.next->prev_next = conn->super.prev_next; - free_listen_set_when_done(conn->l->set); + free_listen_set_when_done(conn->super.l->set); GETDNS_FREE(*mf, conn); } @@ -157,10 +160,10 @@ static void tcp_write_cb(void *userarg) assert(userarg); - if (!(mf = priv_getdns_context_mf(conn->l->set->context))) + if (!(mf = &conn->super.l->set->context->mf)) return; - if (getdns_context_get_eventloop(conn->l->set->context, &loop)) + if (getdns_context_get_eventloop(conn->super.l->set->context, &loop)) return; /* Reset tcp_connection idle timeout */ @@ -195,28 +198,30 @@ static void tcp_write_cb(void *userarg) DOWNSTREAM_IDLE_TIMEOUT, &conn->event); } -void -_getdns_cancel_reply(getdns_context *context, getdns_transaction_t request_id) +static void +_getdns_cancel_reply(getdns_context *context, connection *conn) { - /* TODO: Check request_id at context->outbound_requests */ - connection *conn = (connection *)(intptr_t)request_id; struct mem_funcs *mf; if (!context || !conn) return; if (conn->l->transport == GETDNS_TRANSPORT_TCP) { - tcp_connection *conn = (tcp_connection *)(intptr_t)request_id; + tcp_connection *conn = (tcp_connection *)conn; if (conn->to_answer > 0 && --conn->to_answer == 0 && conn->fd == -1) tcp_connection_destroy(conn); } else if (conn->l->transport == GETDNS_TRANSPORT_UDP && - (mf = priv_getdns_context_mf(conn->l->set->context))) { + (mf = &conn->l->set->context->mf)) { listen_set *set = conn->l->set; /* Unlink this connection */ + (void) _getdns_rbtree_delete( + &set->connections_set, conn); + DEBUG_SERVER("[connection del] count: %d\n", + (int)set->connections_set.count); if ((*conn->prev_next = conn->next)) conn->next->prev_next = conn->prev_next; GETDNS_FREE(*mf, conn); @@ -236,10 +241,21 @@ getdns_reply( size_t len; getdns_return_t r; - if (!context || !reply || !conn) + if (!context || !conn) return GETDNS_RETURN_INVALID_PARAMETER; - if (!(mf = priv_getdns_context_mf(conn->l->set->context))) + if (!context->server) + return GETDNS_RETURN_GENERIC_ERROR;; + + if (_getdns_rbtree_search(&context->server->connections_set, conn) + != &conn->super) + return GETDNS_RETURN_NO_SUCH_LIST_ITEM; + + if (!reply) { + _getdns_cancel_reply(context, conn); + return GETDNS_RETURN_GOOD; + } + if (!(mf = &conn->l->set->context->mf)) return GETDNS_RETURN_GENERIC_ERROR;; if ((r = getdns_context_get_eventloop(conn->l->set->context, &loop))) @@ -260,6 +276,10 @@ getdns_reply( conn->l->fd = -1; } /* Unlink this connection */ + (void) _getdns_rbtree_delete( + &l->set->connections_set, conn); + DEBUG_SERVER("[connection del] count: %d\n", + (int)l->set->connections_set.count); if ((*conn->prev_next = conn->next)) conn->next->prev_next = conn->prev_next; @@ -320,10 +340,10 @@ static void tcp_read_cb(void *userarg) assert(userarg); - if (!(mf = priv_getdns_context_mf(conn->l->set->context))) + if (!(mf = &conn->super.l->set->context->mf)) return; - if ((r = getdns_context_get_eventloop(conn->l->set->context, &loop))) + if ((r = getdns_context_get_eventloop(conn->super.l->set->context, &loop))) return; /* Reset tcp_connection idle timeout */ @@ -381,8 +401,8 @@ static void tcp_read_cb(void *userarg) conn->to_answer++; /* Call request handler */ - conn->l->set->handler( - conn->l->set->context, request_dict, (intptr_t)conn); + conn->super.l->set->handler( + conn->super.l->set->context, request_dict, (intptr_t)conn); conn->read_pos = conn->read_buf; conn->to_read = 2; @@ -402,7 +422,8 @@ static void tcp_timeout_cb(void *userarg) if (conn->to_answer) { getdns_eventloop *loop; - if (getdns_context_get_eventloop(conn->l->set->context, &loop)) + if (getdns_context_get_eventloop( + conn->super.l->set->context, &loop)) return; loop->vmt->clear(loop, &conn->event); @@ -423,7 +444,7 @@ static void tcp_accept_cb(void *userarg) assert(userarg); - if (!(mf = priv_getdns_context_mf(l->set->context))) + if (!(mf = &l->set->context->mf)) return; if ((r = getdns_context_get_eventloop(l->set->context, &loop))) @@ -433,11 +454,10 @@ static void tcp_accept_cb(void *userarg) return; (void) memset(conn, 0, sizeof(tcp_connection)); - - conn->l = l; - conn->addrlen = sizeof(conn->remote_in); - if ((conn->fd = accept(l->fd, - (struct sockaddr *)&conn->remote_in, &conn->addrlen)) == -1) { + conn->super.l = l; + conn->super.addrlen = sizeof(conn->super.remote_in); + if ((conn->fd = accept(l->fd, (struct sockaddr *) + &conn->super.remote_in, &conn->super.addrlen)) == -1) { /* IO error, cleanup this listener */ loop->vmt->clear(loop, &l->event); close(l->fd); @@ -458,10 +478,20 @@ static void tcp_accept_cb(void *userarg) conn->event.timeout_cb = tcp_timeout_cb; /* Insert connection */ - if ((conn->next = l->connections)) - conn->next->prev_next = &conn->next; - conn->prev_next = &l->connections; + conn->super.super.key = conn; + if (!_getdns_rbtree_insert( + &l->set->connections_set, &conn->super.super)) { + /* Memory error */ + GETDNS_FREE(*mf, conn); + return; + } + DEBUG_SERVER("[connection add] count: %d\n", + (int)l->set->connections_set.count); + if ((conn->super.next = l->connections)) + conn->super.next->prev_next = &conn->super.next; + conn->super.prev_next = &l->connections; l->connections = (connection *)conn; + (void) loop->vmt->schedule(loop, conn->fd, DOWNSTREAM_IDLE_TIMEOUT, &conn->event); @@ -485,7 +515,7 @@ static void udp_read_cb(void *userarg) if (l->fd == -1) return; - if (!(mf = priv_getdns_context_mf(l->set->context))) + if (!(mf = &l->set->context->mf)) return; if ((r = getdns_context_get_eventloop(l->set->context, &loop))) @@ -574,6 +604,15 @@ static void udp_read_cb(void *userarg) else { /* Insert connection */ + conn->super.key = conn; + if (!_getdns_rbtree_insert( + &l->set->connections_set, &conn->super)) { + /* Memory error */ + GETDNS_FREE(*mf, conn); + return; + } + DEBUG_SERVER("[connection add] count: %d\n", + (int)l->set->connections_set.count); if ((conn->next = l->connections)) conn->next->prev_next = &conn->next; conn->prev_next = &l->connections; @@ -586,25 +625,6 @@ static void udp_read_cb(void *userarg) GETDNS_FREE(*mf, conn); } -static void rm_listen_set(listen_set **root, listen_set *set) -{ - assert(root); - - while (*root && *root != set) - root = &(*root)->next; - - *root = set->next; - set->next = NULL; -} - -static listen_set *lookup_listen_set(listen_set *root, getdns_context *key) -{ - while (root && root->context != key) - root = root->next; - - return root; -} - static void free_listen_set_when_done(listen_set *set) { struct mem_funcs *mf; @@ -613,7 +633,7 @@ static void free_listen_set_when_done(listen_set *set) assert(set); assert(set->context); - if (!(mf = priv_getdns_context_mf(set->context))) + if (!(mf = &set->context->mf)) return; DEBUG_SERVER("To free listen set: %p\n", set); @@ -639,7 +659,7 @@ static void remove_listeners(listen_set *set) assert(set); assert(set->context); - if (!(mf = priv_getdns_context_mf(set->context))) + if (!(mf = &set->context->mf)) return; if (getdns_context_get_eventloop(set->context, &loop)) @@ -663,7 +683,8 @@ static void remove_listeners(listen_set *set) while (*conn_p) { tcp_connection_destroy(*conn_p); if (*conn_p && (*conn_p)->to_answer > 0) - conn_p = (tcp_connection **)&(*conn_p)->next; + conn_p = (tcp_connection **) + &(*conn_p)->super.next; } } free_listen_set_when_done(set); @@ -681,7 +702,7 @@ static getdns_return_t add_listeners(listen_set *set) assert(set); assert(set->context); - if (!(mf = priv_getdns_context_mf(set->context))) + if (!(mf = &set->context->mf)) return GETDNS_RETURN_GENERIC_ERROR; if ((r = getdns_context_get_eventloop(set->context, &loop))) @@ -738,6 +759,12 @@ static getdns_return_t add_listeners(listen_set *set) return GETDNS_RETURN_GOOD; } +static int +ptr_cmp(const void *a, const void *b) +{ + return a == b ? 0 : (a < b ? -1 : 1); +} + getdns_return_t getdns_context_set_listen_addresses(getdns_context *context, getdns_request_handler_t request_handler, const getdns_list *listen_addresses) @@ -747,8 +774,6 @@ getdns_return_t getdns_context_set_listen_addresses(getdns_context *context, static const uint32_t transport_ports[] = { 53, 53 }; static const size_t n_transports = sizeof( listen_transports) / sizeof(*listen_transports); - static listen_set *root = NULL; - listen_set *current_set; listen_set *new_set; size_t new_set_count; @@ -761,9 +786,11 @@ getdns_return_t getdns_context_set_listen_addresses(getdns_context *context, size_t i; struct addrinfo hints; - DEBUG_SERVER("getdns_context_set_listen_addresses(%p, %p, %p)\n", context, request_handler, + DEBUG_SERVER("getdns_context_set_listen_addresses(%p, %p, %p)\n", + context, request_handler, + listen_addresses); - if (!(mf = priv_getdns_context_mf(context))) + if (!(mf = &context->mf)) return GETDNS_RETURN_GENERIC_ERROR; if ((r = getdns_context_get_eventloop(context, &loop))) @@ -775,7 +802,7 @@ getdns_return_t getdns_context_set_listen_addresses(getdns_context *context, else if ((r = getdns_list_get_length(listen_addresses, &new_set_count))) return r; - if ((current_set = lookup_listen_set(root, context))) { + if ((current_set = context->server)) { for (i = 0; i < current_set->count; i++) current_set->items[i].action = to_remove; } @@ -783,7 +810,7 @@ getdns_return_t getdns_context_set_listen_addresses(getdns_context *context, if (!current_set) return GETDNS_RETURN_GOOD; - rm_listen_set(&root, current_set); + context->server = NULL; /* action is already to_remove */ remove_listeners(current_set); return GETDNS_RETURN_GOOD; @@ -796,10 +823,12 @@ getdns_return_t getdns_context_set_listen_addresses(getdns_context *context, sizeof(listener) * new_set_count * n_transports))) return GETDNS_RETURN_MEMORY_ERROR; - DEBUG_SERVER("New listen set: %p, current_set: %p\n", new_set, current_set); + _getdns_rbtree_init(&new_set->connections_set, ptr_cmp); + + DEBUG_SERVER("New listen set: %p, current_set: %p\n", + new_set, current_set); new_set->context = context; - new_set->next = root; new_set->handler = request_handler; new_set->count = new_set_count * n_transports; (void) memset(new_set->items, 0, @@ -938,10 +967,10 @@ getdns_return_t getdns_context_set_listen_addresses(getdns_context *context, } } if (current_set) { - rm_listen_set(&root, current_set); + context->server = NULL; remove_listeners(current_set); /* Is already remove */ } - root = new_set; + context->server = new_set; return GETDNS_RETURN_GOOD; } diff --git a/src/test/getdns_context_set_listen_addresses.h b/src/server.h similarity index 70% rename from src/test/getdns_context_set_listen_addresses.h rename to src/server.h index fac16f48..f60f267e 100644 --- a/src/test/getdns_context_set_listen_addresses.h +++ b/src/server.h @@ -1,3 +1,11 @@ +/** + * \file server.h + * @brief Functions for serving requests + * + * getdns_context_set_listen_addresses() and getdns_reply() are implemented + * here. + */ + /* * Copyright (c) 2013, NLNet Labs, Verisign, Inc. * All rights reserved. @@ -24,25 +32,9 @@ * (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_SERVER_H_ +#define _GETDNS_SERVER_H_ -#ifndef GETDNS_CONTEXT_SET_LISTEN_ADDRESSES_H_ -#define GETDNS_CONTEXT_SET_LISTEN_ADDRESSES_H_ -#include "getdns/getdns.h" +struct listen_set; -typedef void (*getdns_request_handler_t)( - getdns_context *context, - getdns_dict *request, - getdns_transaction_t request_id -); - -getdns_return_t getdns_context_set_listen_addresses( - getdns_context *context, getdns_request_handler_t request_handler, - const getdns_list *listen_addresses); - -getdns_return_t getdns_reply(getdns_context *context, - getdns_transaction_t request_id, getdns_dict *reply); - -void _getdns_cancel_reply(getdns_context *context, - getdns_transaction_t request_id); - -#endif +#endif /* _GETDNS_SERVER_H_ */ diff --git a/src/test/Makefile.in b/src/test/Makefile.in index e3906eb8..a33ec15f 100644 --- a/src/test/Makefile.in +++ b/src/test/Makefile.in @@ -66,13 +66,10 @@ CHECK_CFLAGS=@CHECK_CFLAGS@ CHECK_OBJS=check_getdns_common.lo check_getdns_context_set_timeout.lo \ check_getdns.lo check_getdns_transport.lo -DECOMPOSED_OBJS=getdns_context_set_listen_addresses.lo - ALL_OBJS=$(CHECK_OBJS) check_getdns_libevent.lo check_getdns_libev.lo \ check_getdns_selectloop.lo getdns_query.lo scratchpad.lo \ testmessages.lo tests_dict.lo tests_list.lo tests_namespaces.lo \ - tests_stub_async.lo tests_stub_sync.lo \ - $(DECOMPOSED_OBJS) + tests_stub_async.lo tests_stub_sync.lo NON_C99_OBJS=check_getdns_libuv.lo @@ -127,8 +124,8 @@ check_getdns_uv: check_getdns.lo check_getdns_common.lo check_getdns_context_set check_getdns_ev: check_getdns.lo check_getdns_common.lo check_getdns_context_set_timeout.lo check_getdns_transport.lo check_getdns_libev.lo ../libgetdns_ext_ev.la $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ check_getdns.lo check_getdns_common.lo check_getdns_context_set_timeout.lo check_getdns_transport.lo check_getdns_libev.lo $(LDFLAGS) $(LDLIBS) $(CHECK_CFLAGS) $(CHECK_LIBS) ../libgetdns_ext_ev.la $(EXTENSION_LIBEV_LDFLAGS) $(EXTENSION_LIBEV_EXT_LIBS) -getdns_query: getdns_query.lo $(DECOMPOSED_OBJS) - $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ getdns_query.lo $(DECOMPOSED_OBJS) $(LDFLAGS) $(LDLIBS) +getdns_query: getdns_query.lo + $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ getdns_query.lo $(LDFLAGS) $(LDLIBS) scratchpad: scratchpad.lo $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ scratchpad.lo $(LDFLAGS) $(LDLIBS) @@ -266,16 +263,8 @@ check_getdns_selectloop.lo check_getdns_selectloop.o: $(srcdir)/check_getdns_sel check_getdns_transport.lo check_getdns_transport.o: $(srcdir)/check_getdns_transport.c \ $(srcdir)/check_getdns_transport.h $(srcdir)/check_getdns_common.h ../getdns/getdns.h \ ../getdns/getdns_extra.h -getdns_context_config.lo getdns_context_config.o: $(srcdir)/getdns_context_config.c $(srcdir)/getdns_context_config.h \ - ../getdns/getdns.h ../getdns/getdns_extra.h -getdns_context_set_listen_addresses.lo getdns_context_set_listen_addresses.o: \ - $(srcdir)/getdns_context_set_listen_addresses.c ../config.h \ - $(srcdir)/getdns_context_set_listen_addresses.h ../getdns/getdns.h \ - ../getdns/getdns_extra.h $(srcdir)/../types-internal.h ../getdns/getdns.h \ - ../getdns/getdns_extra.h $(srcdir)/../util/rbtree.h $(srcdir)/../debug.h ../config.h getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c ../config.h $(srcdir)/../debug.h ../config.h \ - $(srcdir)/getdns_context_set_listen_addresses.h ../getdns/getdns.h \ - ../getdns/getdns_extra.h + ../getdns/getdns.h ../getdns/getdns_extra.h scratchpad.template.lo scratchpad.template.o: scratchpad.template.c ../getdns/getdns.h \ ../getdns/getdns_extra.h testmessages.lo testmessages.o: $(srcdir)/testmessages.c $(srcdir)/testmessages.h diff --git a/src/test/getdns_query.c b/src/test/getdns_query.c index 6df3fdc9..2bc21332 100644 --- a/src/test/getdns_query.c +++ b/src/test/getdns_query.c @@ -27,7 +27,6 @@ #include "config.h" #include "debug.h" -#include "getdns_context_set_listen_addresses.h" #include #include #include @@ -1346,14 +1345,11 @@ static void request_cb( else if (n == 0) SERVFAIL("Recursion not available", 0, msg, &response); - if (!response) - /* No response, no reply */ - _getdns_cancel_reply(context, msg->request_id); - - else if ((r = getdns_reply(context, msg->request_id, response))) { + if ((r = getdns_reply(context, msg->request_id, response))) { fprintf(stderr, "Could not reply: %s\n", getdns_get_errorstr_by_id(r)); - _getdns_cancel_reply(context, msg->request_id); + /* Cancel reply */ + (void) getdns_reply(context, msg->request_id, NULL); } if (msg) { getdns_dict_destroy(msg->request); @@ -1510,14 +1506,11 @@ error: free(request_str); } while(0); #endif - if (!response) - /* No response, no reply */ - _getdns_cancel_reply(context, request_id); - - else if ((r = getdns_reply(context, request_id, response))) { + if ((r = getdns_reply(context, request_id, response))) { fprintf(stderr, "Could not reply: %s\n", getdns_get_errorstr_by_id(r)); - _getdns_cancel_reply(context, request_id); + /* Cancel reply */ + getdns_reply(context, request_id, NULL); } if (msg) { if (msg->request) From 6c73144b5005e19078e17495f3a4a80f2031722d Mon Sep 17 00:00:00 2001 From: Sara Dickinson Date: Wed, 13 Jul 2016 17:39:26 +0100 Subject: [PATCH 09/61] Minor logging updates --- src/context.c | 7 +++++-- src/debug.h | 2 +- src/stub.c | 6 +++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/context.c b/src/context.c index 495217f4..a7a84ca4 100644 --- a/src/context.c +++ b/src/context.c @@ -683,7 +683,7 @@ _getdns_upstream_shutdown(getdns_upstream *upstream) if (upstream->tls_auth_state != GETDNS_AUTH_NONE) upstream->past_tls_auth_state = upstream->tls_auth_state; - DEBUG_STUB("%s %-35s: FD: %d Stats on shutdown: TR=%d,TT=%d,CC=%d,CSF=%d,CS=%d,AS=%d\n", + DEBUG_STUB("%s %-35s: FD: %d Upstream Stats: Resp=%d,Timeouts=%d,Conns=%d,Conn_fails=%d,Conn_shutdowns=%d,Auth=%d\n", STUB_DEBUG_CLEANUP, __FUNCTION__, upstream->fd, (int)upstream->total_responses, (int)upstream->total_timeouts, (int)upstream->conn_completed, (int)upstream->conn_setup_failed, @@ -701,8 +701,11 @@ _getdns_upstream_shutdown(getdns_upstream *upstream) && upstream->total_responses == 0) || (upstream->conn_completed >= GETDNS_CONN_ATTEMPTS && upstream->total_responses == 0 && - upstream->total_timeouts > GETDNS_TRANSPORT_FAIL_MULT)) + upstream->total_timeouts > GETDNS_TRANSPORT_FAIL_MULT)) { + DEBUG_STUB("%s %-35s: FD: %d BACKING OFF THIS UPSTREAM! \n", + STUB_DEBUG_CLEANUP, __FUNCTION__, upstream->fd); upstream->conn_state = GETDNS_CONN_BACKOFF; + } // Reset per connection counters upstream->queries_sent = 0; upstream->responses_received = 0; diff --git a/src/debug.h b/src/debug.h index e106cf67..91051435 100644 --- a/src/debug.h +++ b/src/debug.h @@ -37,7 +37,7 @@ #include "config.h" -#define STUB_DEBUG_ENTRY "-> ENTRY: " +#define STUB_DEBUG_ENTRY "=> ENTRY: " #define STUB_DEBUG_SETUP "--- SETUP: " #define STUB_DEBUG_SETUP_TLS "--- SETUP(TLS): " #define STUB_DEBUG_TSIG "--- TSIG: " diff --git a/src/stub.c b/src/stub.c index ef9362e9..94627d24 100644 --- a/src/stub.c +++ b/src/stub.c @@ -251,8 +251,8 @@ match_edns_opt_rr(uint16_t code, uint8_t *response, size_t response_len, size_t data_len = rr_iter->nxt - rr_iter->pos; (void) gldns_wire2str_rr_scan( &data, &data_len, &str, &str_len, (uint8_t *)rr_iter->pkt, rr_iter->pkt_end - rr_iter->pkt); - DEBUG_STUB("%s %-35s: OPT RR: %s\n", - STUB_DEBUG_CLEANUP, __FUNCTION__, str_spc); + DEBUG_STUB("%s %-35s: OPT RR: %s", + STUB_DEBUG_READ, __FUNCTION__, str_spc); #endif /* OPT found, now search for the specified option */ @@ -347,7 +347,7 @@ process_keepalive( else { upstream->keepalive_timeout = server_keepalive; DEBUG_STUB("%s %-35s: FD: %d Server Keepalive used: %d ms\n", - STUB_DEBUG_CLEANUP, __FUNCTION__, upstream->fd, + STUB_DEBUG_READ, __FUNCTION__, upstream->fd, (int)server_keepalive); } } From fed4818c2739dea98f9110b3998679cd12331704 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Thu, 14 Jul 2016 11:03:33 +0200 Subject: [PATCH 10/61] Fix idle_timeout without keepalive for TLS --- src/stub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stub.c b/src/stub.c index 94627d24..30e80125 100644 --- a/src/stub.c +++ b/src/stub.c @@ -330,7 +330,7 @@ process_keepalive( /* For TCP if no keepalive sent back, then we must use 0 idle timeout as server does not support it. TLS allows idle connections without keepalive, according to RFC7858. */ -#if !defined(KEEP_CONNECTIONS_OPEN_DEBUG) && !KEEP_CONNECTIONS_OPEN_DEBUG +#if !defined(KEEP_CONNECTIONS_OPEN_DEBUG) || !KEEP_CONNECTIONS_OPEN_DEBUG if (upstream->transport != GETDNS_TRANSPORT_TLS) upstream->keepalive_timeout = 0; else From 470fb7a5fbeb2f8a1eba68c11fddeb1494fceaaa Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Thu, 14 Jul 2016 11:42:21 +0200 Subject: [PATCH 11/61] !0 is not necessarily 1 --- src/stub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stub.c b/src/stub.c index 30e80125..2b6f9c36 100644 --- a/src/stub.c +++ b/src/stub.c @@ -1597,7 +1597,7 @@ upstream_valid_and_open(getdns_upstream *upstream, return 1; /* Connection is complete, we know the auth status so check*/ if (upstream->conn_state == GETDNS_CONN_OPEN && - !upstream_auth_status_ok(upstream, netreq) == 1) + !upstream_auth_status_ok(upstream, netreq)) return 0; /* We must have a TLS connection still setting up so schedule and the write code will check again once the connection is complete*/ From ea69d31dba214399ea386b3b5af31731bce72e3a Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Thu, 14 Jul 2016 13:54:58 +0200 Subject: [PATCH 12/61] move getdns_query to src/tools --- .gitignore | 2 +- Makefile.in | 11 +- configure.ac | 8 +- src/Makefile.in | 31 +- src/test/Makefile.in | 16 +- src/test/getdns_query.c | 1614 ----------------- src/test/tpkg/110-link.tpkg/110-link.test | 2 +- .../210-stub-only-link.test | 2 +- 8 files changed, 25 insertions(+), 1661 deletions(-) delete mode 100644 src/test/getdns_query.c diff --git a/.gitignore b/.gitignore index fce9d682..0f4482ef 100644 --- a/.gitignore +++ b/.gitignore @@ -36,9 +36,9 @@ src/test/check_getdns src/test/check_getdns_event src/test/check_getdns_uv src/test/check_getdns_ev -src/test/getdns_query src/test/scratchpad src/test/scratchpad.c +src/tools/getdns_query doc/*.3 src/getdns/getdns.h *.log diff --git a/Makefile.in b/Makefile.in index 331c889e..8364c14e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -111,10 +111,10 @@ pad: scratchpad src/test/scratchpad || ./libtool exec gdb src/test/scratchpad install-getdns_query: - cd src/test && $(MAKE) install + cd src/tools && $(MAKE) install uninstall-getdns_query: - cd src/test && $(MAKE) uninstall + cd src/tools && $(MAKE) uninstall clean: cd src && $(MAKE) $@ @@ -182,6 +182,8 @@ $(distdir): mkdir -p $(distdir)/src/compat mkdir -p $(distdir)/src/util mkdir -p $(distdir)/src/gldns + mkdir -p $(distdir)/src/tools + mkdir -p $(distdir)/src/jsmn mkdir -p $(distdir)/doc mkdir -p $(distdir)/spec mkdir -p $(distdir)/spec/example @@ -224,6 +226,11 @@ $(distdir): cp $(srcdir)/spec/*.tgz $(distdir)/spec || true cp $(srcdir)/spec/example/Makefile.in $(distdir)/spec/example cp $(srcdir)/spec/example/*.[ch] $(distdir)/spec/example + cp $(srcdir)/src/tools/Makefile.in $(distdir)/src/tools + cp $(srcdir)/src/tools/*.[ch] $(distdir)/src/tools + cp $(srcdir)/src/jsmn/*.[ch] $(distdir)/src/jsmn + cp $(srcdir)/src/jsmn/LICENSE $(distdir)/src/jsmn + cp $(srcdir)/src/jsmn/README.md $(distdir)/src/jsmn rm -f $(distdir)/Makefile $(distdir)/src/Makefile $(distdir)/src/getdns/getdns.h $(distdir)/spec/example/Makefile $(distdir)/src/test/Makefile $(distdir)/doc/Makefile $(distdir)/src/config.h distcheck: $(distdir).tar.gz diff --git a/configure.ac b/configure.ac index 468178ce..2651ec1a 100644 --- a/configure.ac +++ b/configure.ac @@ -889,9 +889,9 @@ AC_DEFINE_UNQUOTED([TRUST_ANCHOR_FILE], ["$TRUST_ANCHOR_FILE"], [Default trust a AC_SUBST(TRUST_ANCHOR_FILE) AC_MSG_NOTICE([Default trust anchor: $TRUST_ANCHOR_FILE]) -AC_ARG_WITH(getdns_query, AS_HELP_STRING([--with-getdns_query], - [Also compile and install the getdns_query tool]), - [], [withval="no"]) +AC_ARG_WITH(getdns_query, AS_HELP_STRING([--without-getdns_query], + [Do not compile and install the getdns_query tool]), + [], [withval="yes"]) if test x_$withval = x_no; then GETDNS_QUERY="" INSTALL_GETDNS_QUERY="" @@ -917,7 +917,7 @@ AC_SUBST(GETDNS_QUERY) AC_SUBST(INSTALL_GETDNS_QUERY) AC_SUBST(UNINSTALL_GETDNS_QUERY) -AC_CONFIG_FILES([Makefile src/Makefile src/version.c src/getdns/getdns.h src/getdns/getdns_extra.h spec/example/Makefile src/test/Makefile doc/Makefile getdns.pc getdns_ext_event.pc]) +AC_CONFIG_FILES([Makefile src/Makefile src/version.c src/getdns/getdns.h src/getdns/getdns_extra.h spec/example/Makefile src/test/Makefile src/tools/Makefile doc/Makefile getdns.pc getdns_ext_event.pc]) if [ test -n "$DOXYGEN" ] then AC_CONFIG_FILES([src/Doxyfile]) fi diff --git a/src/Makefile.in b/src/Makefile.in index c9ff78db..212b7180 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -157,7 +157,7 @@ test: all cd test && $(MAKE) $@ getdns_query: all - cd test && $(MAKE) $@ + cd tools && $(MAKE) $@ scratchpad: all cd test && $(MAKE) $@ @@ -165,11 +165,13 @@ scratchpad: all pad: scratchpad clean: + cd tools && $(MAKE) $@ cd test && $(MAKE) $@ rm -f *.o *.lo extension/*.lo extension/*.o $(PROGRAMS) libgetdns.la libgetdns_ext_*.la rm -rf .libs extension/.libs distclean : clean + cd tools && $(MAKE) $@ cd test && $(MAKE) $@ rmdir test 2>/dev/null || true rm -f Makefile config.status config.log Doxyfile config.h version.c getdns/Makefile getdns/getdns.h getdns/getdns_extra.h @@ -177,35 +179,9 @@ distclean : clean rmdir extension 2>/dev/null || true rm -Rf autom4te.cache -$(distdir): FORCE - mkdir -p $(distdir)/src - cp configure.ac $(distdir) - cp configure $(distdir) - cp Makefile.in $(distdir) - cp src/Makefile.in $(distdir)/src - -distcheck: $(distdir).tar.gz - gzip -cd $(distdir).tar.gz | tar xvf - - cd $(distdir) && ./configure - cd $(distdir) && $(MAKE) all - cd $(distdir) && $(MAKE) check - cd $(distdir) && $(MAKE) DESTDIR=$${PWD}/_inst install - cd $(distdir) && $(MAKE) DESTDIR=$${PWD}/_inst uninstall - @remaining="`find $${PWD}/$(distdir)/_inst -type f | wc -l`"; \ - if test "$${remaining}" -ne 0; then - echo "@@@ $${remaining} file(s) remaining in stage directory!"; \ - exit 1; \ - fi - cd $(distdir) && $(MAKE) clean - rm -rf $(distdir) - @echo "*** Package $(distdir).tar.gz is ready for distribution" - Makefile: $(srcdir)/Makefile.in ../config.status cd .. && ./config.status src/Makefile -configure.status: configure - cd .. && ./config.status --recheck - depend: (cd $(srcdir) ; awk 'BEGIN{P=1}{if(P)print}/^# Dependencies/{P=0}' Makefile.in > Makefile.in.new ) (blddir=`pwd`; cd $(srcdir) ; gcc -MM -I. -I"$$blddir" *.c gldns/*.c compat/*.c util/*.c jsmn/*.c extension/*.c| \ @@ -225,6 +201,7 @@ depend: -e 's!\(.*\)\.o[ :]*!\1.lo \1.o: !g' >> Makefile.in.new ) (cd $(srcdir) ; diff Makefile.in.new Makefile.in && rm Makefile.in.new \ || mv Makefile.in.new Makefile.in ) + cd tools && $(MAKE) $@ cd test && $(MAKE) $@ .PHONY: clean test diff --git a/src/test/Makefile.in b/src/test/Makefile.in index a33ec15f..83e9e9c6 100644 --- a/src/test/Makefile.in +++ b/src/test/Makefile.in @@ -67,13 +67,13 @@ CHECK_OBJS=check_getdns_common.lo check_getdns_context_set_timeout.lo \ check_getdns.lo check_getdns_transport.lo ALL_OBJS=$(CHECK_OBJS) check_getdns_libevent.lo check_getdns_libev.lo \ - check_getdns_selectloop.lo getdns_query.lo scratchpad.lo \ + check_getdns_selectloop.lo scratchpad.lo \ testmessages.lo tests_dict.lo tests_list.lo tests_namespaces.lo \ tests_stub_async.lo tests_stub_sync.lo NON_C99_OBJS=check_getdns_libuv.lo -PROGRAMS=tests_dict tests_list tests_namespaces tests_stub_async tests_stub_sync getdns_query $(CHECK_GETDNS) $(CHECK_EV_PROG) $(CHECK_EVENT_PROG) $(CHECK_UV_PROG) +PROGRAMS=tests_dict tests_list tests_namespaces tests_stub_async tests_stub_sync $(CHECK_GETDNS) $(CHECK_EV_PROG) $(CHECK_EVENT_PROG) $(CHECK_UV_PROG) .SUFFIXES: .c .o .a .lo .h @@ -124,9 +124,6 @@ check_getdns_uv: check_getdns.lo check_getdns_common.lo check_getdns_context_set check_getdns_ev: check_getdns.lo check_getdns_common.lo check_getdns_context_set_timeout.lo check_getdns_transport.lo check_getdns_libev.lo ../libgetdns_ext_ev.la $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ check_getdns.lo check_getdns_common.lo check_getdns_context_set_timeout.lo check_getdns_transport.lo check_getdns_libev.lo $(LDFLAGS) $(LDLIBS) $(CHECK_CFLAGS) $(CHECK_LIBS) ../libgetdns_ext_ev.la $(EXTENSION_LIBEV_LDFLAGS) $(EXTENSION_LIBEV_EXT_LIBS) -getdns_query: getdns_query.lo - $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ getdns_query.lo $(LDFLAGS) $(LDLIBS) - scratchpad: scratchpad.lo $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ scratchpad.lo $(LDFLAGS) $(LDLIBS) @@ -135,12 +132,11 @@ scratchpad.lo: scratchpad.c $(srcdir)/scratchpad.c: scratchpad.template.c [ ! -f $(srcdir)/scratchpad.c ] && cp -p $(srcdir)/scratchpad.template.c $(srcdir)/scratchpad.c || true -install: getdns_query - $(INSTALL) -m 755 -d $(DESTDIR)$(bindir) - $(LIBTOOL) --mode=install cp getdns_query $(DESTDIR)$(bindir) +install: + echo nothing to install uninstall: - $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(bindir)/getdns_query + echo nothing to uninstall nolibcheck: @echo "***" @@ -263,8 +259,6 @@ check_getdns_selectloop.lo check_getdns_selectloop.o: $(srcdir)/check_getdns_sel check_getdns_transport.lo check_getdns_transport.o: $(srcdir)/check_getdns_transport.c \ $(srcdir)/check_getdns_transport.h $(srcdir)/check_getdns_common.h ../getdns/getdns.h \ ../getdns/getdns_extra.h -getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c ../config.h $(srcdir)/../debug.h ../config.h \ - ../getdns/getdns.h ../getdns/getdns_extra.h scratchpad.template.lo scratchpad.template.o: scratchpad.template.c ../getdns/getdns.h \ ../getdns/getdns_extra.h testmessages.lo testmessages.o: $(srcdir)/testmessages.c $(srcdir)/testmessages.h diff --git a/src/test/getdns_query.c b/src/test/getdns_query.c deleted file mode 100644 index 81ebd79d..00000000 --- a/src/test/getdns_query.c +++ /dev/null @@ -1,1614 +0,0 @@ -/* - * Copyright (c) 2013, NLNet Labs, Verisign, 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 names of the copyright holders 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 "config.h" -#include "debug.h" -#include -#include -#include -#include -#include -#include -#include -#ifndef USE_WINSOCK -#include -#include -#include -#else -#include -#include -typedef unsigned short in_port_t; -#include -#include -#endif - -#define EXAMPLE_PIN "pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"" - -static int quiet = 0; -static int batch_mode = 0; -static char *query_file = NULL; -static int json = 0; -static char *the_root = "."; -static char *name; -static getdns_context *context; -static getdns_dict *extensions; -static getdns_dict *query_extensions_spc = NULL; -static getdns_list *pubkey_pinset = NULL; -static getdns_list *listen_list = NULL; -int touched_listen_list; -static getdns_dict *listen_dict = NULL; -static size_t pincount = 0; -static size_t listen_count = 0; -static uint16_t request_type = GETDNS_RRTYPE_NS; -static int timeout, edns0_size, padding_blocksize; -static int async = 0, interactive = 0; -static enum { GENERAL, ADDRESS, HOSTNAME, SERVICE } calltype = GENERAL; - -static int get_rrtype(const char *t) -{ - char buf[1024] = "GETDNS_RRTYPE_"; - uint32_t rrtype; - long int l; - size_t i; - char *endptr; - - if (strlen(t) > sizeof(buf) - 15) - return -1; - for (i = 14; *t && i < sizeof(buf) - 1; i++, t++) - buf[i] = toupper(*t); - buf[i] = '\0'; - - if (!getdns_str2int(buf, &rrtype)) - return (int)rrtype; - - if (strncasecmp(buf + 14, "TYPE", 4) == 0) { - l = strtol(buf + 18, &endptr, 10); - if (!*endptr && l >= 0 && l < 65536) - return l; - } - return -1; -} - -static int get_rrclass(const char *t) -{ - char buf[1024] = "GETDNS_RRCLASS_"; - uint32_t rrclass; - long int l; - size_t i; - char *endptr; - - if (strlen(t) > sizeof(buf) - 16) - return -1; - for (i = 15; *t && i < sizeof(buf) - 1; i++, t++) - buf[i] = toupper(*t); - buf[i] = '\0'; - - if (!getdns_str2int(buf, &rrclass)) - return (int)rrclass; - - if (strncasecmp(buf + 15, "CLASS", 5) == 0) { - l = strtol(buf + 20, &endptr, 10); - if (!*endptr && l >= 0 && l < 65536) - return l; - } - return -1; -} - -static getdns_return_t -fill_transport_list(getdns_context *context, char *transport_list_str, - getdns_transport_list_t *transports, size_t *transport_count) -{ - size_t max_transports = *transport_count; - *transport_count = 0; - for ( size_t i = 0 - ; i < max_transports && i < strlen(transport_list_str) - ; i++, (*transport_count)++) { - switch(*(transport_list_str + i)) { - case 'U': - transports[i] = GETDNS_TRANSPORT_UDP; - break; - case 'T': - transports[i] = GETDNS_TRANSPORT_TCP; - break; - case 'L': - transports[i] = GETDNS_TRANSPORT_TLS; - break; - default: - fprintf(stderr, "Unrecognised transport '%c' in string %s\n", - *(transport_list_str + i), transport_list_str); - return GETDNS_RETURN_GENERIC_ERROR; - } - } - return GETDNS_RETURN_GOOD; -} - -void -print_usage(FILE *out, const char *progname) -{ - fprintf(out, "usage: %s [