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/ChangeLog b/ChangeLog index b3a1dbc1..4dae9ffb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,49 @@ -* 2016-??-??: Version 1.0.0 +* 2016-??-??: Version 1.0.0b2 + * Collect coverage information from the unit tests + Thanks Shane Kerr + * pkg-config for the getdns_ext_event library + Thanks Tom Pusateri + * Bugfix: Multiple requests on the same upstream with a transport + that keeps connections open in synchronous stub mode. + * Canonicalized DNSSEC chain with dnssec_return_validation_chain + (when validated) + * A dnssec_return_full_validation_chain extension which includes + then validated resource records. + * Bugfix: Callbacks fired while scheduling (answer from cache) + with the unbound plugable event API + * header extension to set opcode and flags in stub mode + * Unit tests that cover more code + * Static checking with the clang analyzer + * getdns_pretty_print_dict prints dname's as primitives + * Accept just bindata's instead of address dicts. + Allow misshing "address_type" in address dicts. + * TLS session resumption + * -C option to getdns_query to configure context + from a json like formated file. The output of -i (print API + information) can be used as config file directly. + Settings may also be given in this format as arguments of + the getdns_query command directly. + * DNS server mode for getdns_query. Enable by providing addresses + to listen on, either by giving "-z " options or by + providing "listen_addresses" in the config file or settings. + * Bugfixes from deckard testing: CNAME loop protection. + * "srv_addresses" in response dict with getdns_service() + * use libbsd when available + Thanks Guillem Jover + * Bugfix: DNSSEC wildcard validation issue + * Bugfix: TLS timeouts not re-using a connection + * A getdns_context_get_eventloop(), to get the current + (pluggable) eventloop from context + * getdns_query now uses the default event loop (instead of custom) + * Return call_reporting info in case of timeout + Thanks Robert Groenenberg + * Bugfix: Build fails with autoconf 2.63, works with 2.68. + Thanks Robert Groenenberg + * Doxygen output for getdns.h and getdns_extra.h only + * Do not call SSL_library_init() from getdns_context_create() when + the second bit from the set_from_os parameter is set. + +* 2016-03-31: Version 1.0.0b1 * openssl 1.1.0 support * GETDNS_APPEND_NAME_TO_SINGLE_LABEL_FIRST default suffix handling * getdns_context_set_follow_redirects() diff --git a/configure.ac b/configure.ac index cddf86ac..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, [b1]) +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, [0x00100100]) +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" diff --git a/project-doc/getdns_query-deamon-behaviour.ods b/project-doc/getdns_query-deamon-behaviour.ods new file mode 100644 index 00000000..041cebc7 Binary files /dev/null and b/project-doc/getdns_query-deamon-behaviour.ods differ diff --git a/project-doc/getdns_query-deamon-behaviour.pdf b/project-doc/getdns_query-deamon-behaviour.pdf new file mode 100644 index 00000000..f97f81b8 Binary files /dev/null and b/project-doc/getdns_query-deamon-behaviour.pdf differ diff --git a/src/Makefile.in b/src/Makefile.in index 3766b318..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 @@ -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' \ @@ -231,69 +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)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/convert.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 @@ -324,6 +339,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/context.c b/src/context.c index b46dc3bd..851ef2be 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 @@ -1272,6 +1274,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,13 +1314,14 @@ 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 * don't know that till later so we will have to do this every time. */ - SSL_library_init(); + if (set_from_os & 2 == 0) + SSL_library_init(); + #ifdef HAVE_LIBUNBOUND result->unbound_ctx = NULL; if ((r = rebuild_ub_ctx(result))) @@ -1369,6 +1393,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. @@ -1401,8 +1428,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 +1445,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 +3446,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; } @@ -3891,4 +3921,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/context.h b/src/context.h index 46ed6c88..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; @@ -250,8 +251,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 */ @@ -262,6 +261,8 @@ struct getdns_context { */ _getdns_rbtree_t outbound_requests; + struct listen_set *server; + /* Event loop extension. */ getdns_eventloop *extension; @@ -275,6 +276,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/convert.c b/src/convert.c index 2539d7bd..9c220ebb 100644 --- a/src/convert.c +++ b/src/convert.c @@ -48,9 +48,14 @@ #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 "debug.h" /* stuff to make it compile pedantically */ #define UNUSED_PARAM(x) ((void)(x)) @@ -611,6 +616,15 @@ _getdns_wire2msg_dict_scan(struct mem_funcs *mf, if (!wire || !*wire || !wire_len || !msg_dict) return GETDNS_RETURN_INVALID_PARAMETER; +#if 0 && defined(SERVER_DEBUG) && SERVER_DEBUG + do { + char *str = gldns_wire2str_pkt((uint8_t *)*wire, *wire_len); + DEBUG_SERVER("_getdns_wire2msg_dict_scan for a packet size: %d: %s\n", + (int)*wire_len, str); + free(str); + } while(0); +#endif + if (!(result = _getdns_dict_create_with_mf(mf)) || !(header = _getdns_dict_create_with_mf(mf)) || !(sections[SECTION_ANSWER] @@ -768,11 +782,12 @@ _getdns_reply_dict2wire( const getdns_dict *reply, gldns_buffer *buf, int reuse_header) { uint8_t header_spc[GLDNS_HEADER_SIZE], *header; - uint32_t n, qtype, qclass = GETDNS_RRCLASS_IN; + uint32_t n, qtype, qclass = GETDNS_RRCLASS_IN, rr_type; size_t pkt_start, i; getdns_list *section; getdns_dict *rr_dict; getdns_bindata *qname; + int remove_dnssec; pkt_start = gldns_buffer_position(buf); if (reuse_header) { @@ -814,11 +829,18 @@ _getdns_reply_dict2wire( buf, pkt_start+GLDNS_ARCOUNT_OFF, 0); } } + remove_dnssec = !getdns_dict_get_int(reply, "/header/do", &n) && n == 0; + DEBUG_SERVER("remove_dnssec: %d\n", remove_dnssec); + if (!getdns_dict_get_list(reply, "answer", §ion)) { for ( n = 0, i = 0 ; !getdns_list_get_dict(section, i, &rr_dict); i++) { - if (!_getdns_rr_dict2wire(rr_dict, buf)) + if (remove_dnssec && + !getdns_dict_get_int(rr_dict, "type", &rr_type) && + rr_type == GETDNS_RRTYPE_RRSIG) + continue; + if (!_getdns_rr_dict2wire(rr_dict, buf)) n++; } gldns_buffer_write_u16_at(buf, pkt_start+GLDNS_ANCOUNT_OFF, n); @@ -827,7 +849,15 @@ _getdns_reply_dict2wire( for ( n = 0, i = 0 ; !getdns_list_get_dict(section, i, &rr_dict); i++) { - if (!_getdns_rr_dict2wire(rr_dict, buf)) + if (remove_dnssec && + !getdns_dict_get_int(rr_dict, "type", &rr_type) && + ( rr_type == GETDNS_RRTYPE_RRSIG + || rr_type == GETDNS_RRTYPE_NSEC + || rr_type == GETDNS_RRTYPE_NSEC3 + || rr_type == GETDNS_RRTYPE_DS + )) + continue; + if (!_getdns_rr_dict2wire(rr_dict, buf)) n++; } gldns_buffer_write_u16_at(buf, pkt_start+GLDNS_NSCOUNT_OFF, n); @@ -836,6 +866,10 @@ _getdns_reply_dict2wire( for ( n = 0, i = 0 ; !getdns_list_get_dict(section, i, &rr_dict); i++) { + if (remove_dnssec && + !getdns_dict_get_int(rr_dict, "type", &rr_type) && + rr_type == GETDNS_RRTYPE_RRSIG) + continue; if (!_getdns_rr_dict2wire(rr_dict, buf)) n++; } @@ -1031,5 +1065,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 3f7647d4..d7b4bc24 100644 --- a/src/getdns/getdns_extra.h.in +++ b/src/getdns/getdns_extra.h.in @@ -918,10 +918,30 @@ getdns_return_t getdns_strerror(getdns_return_t err, char *buf, size_t buflen); */ /** @} */ - /** @} */ +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); + +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/jsmn b/src/jsmn new file mode 160000 index 00000000..49024a6e --- /dev/null +++ b/src/jsmn @@ -0,0 +1 @@ +Subproject commit 49024a6e11739c866bce0e9f3617278b98906ad0 diff --git a/src/libgetdns.symbols b/src/libgetdns.symbols index 2eb8e381..6e3cb128 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 @@ -50,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 @@ -123,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 @@ -134,6 +137,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/request-internal.c b/src/request-internal.c index 797fde50..8e4ec303 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,9 @@ 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); + 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); @@ -658,28 +661,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 +720,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 +739,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 +905,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; diff --git a/src/test/getdns_context_set_listen_addresses.c b/src/server.c similarity index 79% rename from src/test/getdns_context_set_listen_addresses.c rename to src/server.c index eeeac3ad..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))) @@ -503,11 +533,86 @@ static void udp_read_cb(void *userarg) close(l->fd); l->fd = -1; +#if 0 && defined(SERVER_DEBUG) && SERVER_DEBUG + } else { + char addrbuf[100]; + char hexbuf[4096], *hexptr; + size_t l, i, j; + + if (conn->remote_in.ss_family == AF_INET) { + if (inet_ntop(AF_INET, + &((struct sockaddr_in*)&conn->remote_in)->sin_addr, + addrbuf, sizeof(addrbuf))) { + + l = strlen(addrbuf); + (void) snprintf(addrbuf + l, + sizeof(addrbuf) - l, ":%d", + (int)((struct sockaddr_in*) + &conn->remote_in)->sin_port); + } else + (void) strncpy( + addrbuf, "error ipv4", sizeof(addrbuf)); + + } else if (conn->remote_in.ss_family == AF_INET6) { + addrbuf[0] = '['; + if (inet_ntop(AF_INET6, + &((struct sockaddr_in6*) + &conn->remote_in)->sin6_addr, + addrbuf, sizeof(addrbuf))) { + + l = strlen(addrbuf); + (void) snprintf(addrbuf + l, + sizeof(addrbuf) - l, ":%d", + (int)((struct sockaddr_in6*) + &conn->remote_in)->sin6_port); + } else + (void) strncpy( + addrbuf, "error ipv6", sizeof(addrbuf)); + + } else { + (void) strncpy( + addrbuf, "unknown address", sizeof(addrbuf)); + } + *(hexptr = hexbuf) = 0; + for (i = 0; i < len; i++) { + if (i % 12 == 0) { + hexptr += snprintf(hexptr, + sizeof(hexbuf) - (hexptr - hexbuf) - 1, + "\n%.4x", (int)i); + } else if (i % 4 == 0) { + hexptr += snprintf(hexptr, + sizeof(hexbuf) - (hexptr - hexbuf) - 1, + " "); + } + if (hexptr - hexbuf > sizeof(hexbuf)) + break; + hexptr += snprintf(hexptr, + sizeof(hexbuf) - (hexptr - hexbuf) - 1, + " %.2x", (int)buf[i]); + if (hexptr - hexbuf > sizeof(hexbuf)) + break; + } + DEBUG_SERVER("Received %d bytes from %s: %s\n", + (int)len, addrbuf, hexbuf); + } + if (len == -1) { + ; /* pass */ +#endif + } else if ((r = getdns_wire2msg_dict(buf, len, &request_dict))) ; /* FROMERR on input, ignore */ 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; @@ -520,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; @@ -547,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); @@ -573,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)) @@ -597,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); @@ -615,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))) @@ -672,16 +759,21 @@ 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, getdns_list *listen_addresses) + getdns_request_handler_t request_handler, + const getdns_list *listen_addresses) { static const getdns_transport_list_t listen_transports[] = { GETDNS_TRANSPORT_UDP, GETDNS_TRANSPORT_TCP }; 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; @@ -694,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))) @@ -708,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; } @@ -716,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; @@ -729,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, @@ -871,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_config.h b/src/server.h similarity index 82% rename from src/test/getdns_context_config.h rename to src/server.h index 7252f367..f60f267e 100644 --- a/src/test/getdns_context_config.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,18 +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_ -#include "getdns/getdns.h" - -#ifndef GETDNS_CONTEXT_CONFIG_H_ -#define GETDNS_CONTEXT_CONFIG_H_ - -/* -getdns_return_t getdns_context_config( - getdns_context *context, const getdns_dict *config_dict); - */ -getdns_return_t _getdns_context_config_(getdns_context *context, - getdns_dict *extensions, const getdns_dict *config_dict); - -#endif +struct listen_set; +#endif /* _GETDNS_SERVER_H_ */ diff --git a/src/test/Makefile.in b/src/test/Makefile.in index 797f2e6e..a33ec15f 100644 --- a/src/test/Makefile.in +++ b/src/test/Makefile.in @@ -66,16 +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_WITHOUT_JSMN=getdns_str2dict.lo getdns_context_config.lo \ - getdns_context_set_listen_addresses.lo - -DECOMPOSED_OBJS=$(DECOMPOSED_OBJS_WITHOUT_JSMN) jsmn.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) + tests_stub_async.lo tests_stub_sync.lo NON_C99_OBJS=check_getdns_libuv.lo @@ -94,9 +88,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 $@ @@ -133,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) @@ -221,7 +212,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 +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 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_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 + ../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 #include #include +#include #include #include #ifndef USE_WINSOCK @@ -70,7 +68,55 @@ static int timeout, edns0_size, padding_blocksize; static int async = 0, interactive = 0; static enum { GENERAL, ADDRESS, HOSTNAME, SERVICE } calltype = GENERAL; -int get_rrtype(const char *t); +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, @@ -415,8 +461,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)); } @@ -457,34 +502,13 @@ getdns_return_t parse_args(int argc, char **argv) break; } } else if (strncmp(arg+1, "specify_class=", 14) == 0) { - if (strncasecmp(arg+15, "IN", 3) == 0) + if ((klass = get_rrclass(arg+15)) >= 0) r = getdns_dict_set_int(extensions, - "specify_class", GETDNS_RRCLASS_IN); - else if (strncasecmp(arg+15, "CH", 3) == 0) - r = getdns_dict_set_int(extensions, - "specify_class", GETDNS_RRCLASS_CH); - else if (strncasecmp(arg+15, "HS", 3) == 0) - r = getdns_dict_set_int(extensions, - "specify_class", GETDNS_RRCLASS_HS); - else if (strncasecmp(arg+15, "NONE", 5) == 0) - r = getdns_dict_set_int(extensions, - "specify_class", GETDNS_RRCLASS_NONE); - else if (strncasecmp(arg+15, "ANY", 4) == 0) - r = getdns_dict_set_int(extensions, - "specify_class", GETDNS_RRCLASS_ANY); - else if (strncasecmp(arg+15, "CLASS", 5) == 0) { - klass = strtol(arg + 20, &endptr, 10); - if (*endptr || klass > 255) - fprintf(stderr, - "Unknown class: %s\n", - arg+15); - else - r = getdns_dict_set_int(extensions, "specify_class", klass); - - } else + else fprintf(stderr, "Unknown class: %s\n", arg+15); + } else if (arg[1] == '0') { /* Unset all existing extensions*/ getdns_dict_destroy(extensions); @@ -499,8 +523,23 @@ getdns_return_t parse_args(int argc, char **argv) continue; } else if (arg[0] == '@') { - getdns_dict *upstream = _getdns_ipaddr_dict(arg + 1); - if (upstream) { + getdns_dict *upstream; + getdns_bindata *address; + + if ((r = getdns_str2dict(arg + 1, &upstream))) + fprintf(stderr, "Could not convert \"%s\" to " + "an IP dict: %s\n", arg + 1, + getdns_get_errorstr_by_id(r)); + + else if ((r = getdns_dict_get_bindata( + upstream, "address_data", &address))) { + + fprintf(stderr, "\"%s\" did not translate to " + "an IP dict: %s\n", arg + 1, + getdns_get_errorstr_by_id(r)); + + getdns_dict_destroy(upstream); + } else { if (!upstream_list && !(upstream_list = getdns_list_create_with_context(context))){ @@ -521,6 +560,9 @@ getdns_return_t parse_args(int argc, char **argv) continue; } for (c = arg+1; *c; c++) { + getdns_dict *downstream; + getdns_bindata *address; + switch (*c) { case 'a': async = 1; @@ -896,23 +938,33 @@ getdns_return_t parse_args(int argc, char **argv) DEBUG_SERVER("Clear listen list\n"); break; } - getdns_dict *downstream = - _getdns_ipaddr_dict(argv[i]); - if (!downstream) { - fprintf(stderr, "could not parse " - "listen address: %s", argv[i]); + + if ((r = getdns_str2dict(argv[i], &downstream))) + fprintf(stderr, "Could not convert \"%s\" to " + "an IP dict: %s\n", argv[i], + getdns_get_errorstr_by_id(r)); + + else if ((r = getdns_dict_get_bindata( + downstream, "address_data", &address))) { + + fprintf(stderr, "\"%s\" did not translate to " + "an IP dict: %s\n", argv[i], + getdns_get_errorstr_by_id(r)); + + getdns_dict_destroy(downstream); + } else { + if (!listen_list && + !(listen_list = + getdns_list_create_with_context(context))){ + fprintf(stderr, "Could not create " + "downstream list\n"); + return GETDNS_RETURN_MEMORY_ERROR; + } + getdns_list_set_dict(listen_list, + listen_count++, downstream); + getdns_dict_destroy(downstream); + touched_listen_list = 1; } - if (!listen_list && - !(listen_list = - getdns_list_create_with_context(context))){ - fprintf(stderr, "Could not create " - "downstram list\n"); - return GETDNS_RETURN_MEMORY_ERROR; - } - getdns_list_set_dict(listen_list, - listen_count++, downstream); - getdns_dict_destroy(downstream); - touched_listen_list = 1; break; default: fprintf(stderr, "Unknown option " @@ -976,14 +1028,26 @@ getdns_return_t do_the_call(void) { getdns_return_t r; getdns_dict *address = NULL; + getdns_bindata *address_bindata; getdns_dict *response = NULL; char *response_str; uint32_t status; - if (calltype == HOSTNAME && - !(address = _getdns_ipaddr_dict(name))) { - fprintf(stderr, "Could not convert \"%s\" " - "to an IP address", name); + if (calltype != HOSTNAME) + ; /* pass */ + + else if ((r = getdns_str2dict(name, &address))) { + + fprintf(stderr, "Could not convert \"%s\" to an IP dict: %s\n" + , name, getdns_get_errorstr_by_id(r)); + return GETDNS_RETURN_GOOD; + + } else if ((r = getdns_dict_get_bindata( + address, "address_data", &address_bindata))) { + + fprintf(stderr, "Could not convert \"%s\" to an IP dict: %s\n" + , name, getdns_get_errorstr_by_id(r)); + getdns_dict_destroy(address); return GETDNS_RETURN_GOOD; } if (async) { @@ -1132,8 +1196,10 @@ typedef struct dns_msg { getdns_transaction_t request_id; getdns_dict *request; uint32_t rt; + uint32_t ad_bit; uint32_t do_bit; uint32_t cd_bit; + int has_edns0; } dns_msg; #if defined(SERVER_DEBUG) && SERVER_DEBUG @@ -1168,15 +1234,55 @@ void servfail(dns_msg *msg, getdns_dict **resp_p) (void) getdns_dict_set_int(*resp_p, "/header/ad", 0); } -void request_cb(getdns_context *context, getdns_callback_type_t callback_type, +static getdns_return_t _handle_edns0( + getdns_dict *response, int has_edns0) +{ + getdns_return_t r; + getdns_list *additional; + size_t len, i; + getdns_dict *rr; + uint32_t rr_type; + char remove_str[100] = "/replies_tree/0/additional/"; + + if ((r = getdns_dict_set_int( + response, "/replies_tree/0/header/do", 0))) + return r; + if ((r = getdns_dict_get_list(response, "/replies_tree/0/additional", + &additional))) + return r; + if ((r = getdns_list_get_length(additional, &len))) + return r; + for (i = 0; i < len; i++) { + if ((r = getdns_list_get_dict(additional, i, &rr))) + return r; + if ((r = getdns_dict_get_int(rr, "type", &rr_type))) + return r; + if (rr_type != GETDNS_RRTYPE_OPT) + continue; + if (has_edns0) { + (void) getdns_dict_set_int(rr, "do", 0); + break; + } + (void) snprintf(remove_str + 27, 60, "%d", (int)i); + if ((r = getdns_dict_remove_name(response, remove_str))) + return r; + break; + } + return GETDNS_RETURN_GOOD; +} + +static void request_cb( + getdns_context *context, getdns_callback_type_t callback_type, getdns_dict *response, void *userarg, getdns_transaction_t transaction_id) { dns_msg *msg = (dns_msg *)userarg; uint32_t qid; getdns_return_t r = GETDNS_RETURN_GOOD; - uint32_t n; + uint32_t n, rcode, dnssec_status; - DEBUG_SERVER("reply for: %p %"PRIu64" %d\n", msg, transaction_id, (int)callback_type); + DEBUG_SERVER("reply for: %p %"PRIu64" %d (edns0: %d, do: %d, ad: %d," + " cd: %d)\n", msg, transaction_id, (int)callback_type, + msg->has_edns0, msg->do_bit, msg->ad_bit, msg->cd_bit); assert(msg); #if 0 @@ -1195,21 +1301,36 @@ void request_cb(getdns_context *context, getdns_callback_type_t callback_type, SERVFAIL("Could not copy QID", r, msg, &response); else if (getdns_dict_get_int( - response, "/replies_tree/0/header/rcode", &n)) + response, "/replies_tree/0/header/rcode", &rcode)) SERVFAIL("No reply in replies tree", 0, msg, &response); - else if (msg->cd_bit != 1 && !getdns_dict_get_int( - response, "/replies_tree/0/dnssec_status", &n) - && n == GETDNS_DNSSEC_BOGUS) + /* ansers when CD or not BOGUS */ + else if (!msg->cd_bit && !getdns_dict_get_int( + response, "/replies_tree/0/dnssec_status", &dnssec_status) + && dnssec_status == GETDNS_DNSSEC_BOGUS) SERVFAIL("DNSSEC status was bogus", 0, msg, &response); - else if ((r = getdns_dict_get_int( - response, "/replies_tree/0/header/rcode", &n))) - SERVFAIL("Could not get rcode from reply", r, msg, &response); - - else if (n == GETDNS_RCODE_SERVFAIL) + else if (rcode == GETDNS_RCODE_SERVFAIL) servfail(msg, &response); + /* RRsigs when DO and (CD or not BOGUS) + * Implemented in conversion to wireformat function by checking for DO + * bit. In recursing resolution mode we have to copy the do bit from + * the request, because libunbound has it in the answer always. + */ + else if (msg->rt == GETDNS_RESOLUTION_RECURSING && !msg->do_bit && + (r = _handle_edns0(response, msg->has_edns0))) + SERVFAIL("Could not handle EDNS0", r, msg, &response); + + /* AD when (DO or AD) and SECURE */ + else if ((r = getdns_dict_set_int(response,"/replies_tree/0/header/ad", + ((msg->do_bit || msg->ad_bit) + && ( (!msg->cd_bit && dnssec_status == GETDNS_DNSSEC_SECURE) + || ( msg->cd_bit && !getdns_dict_get_int(response, + "/replies_tree/0/dnssec_status", &dnssec_status) + && dnssec_status == GETDNS_DNSSEC_SECURE ))) ? 1 : 0))) + SERVFAIL("Could not set AD bit", r, msg, &response); + else if (msg->rt == GETDNS_RESOLUTION_STUB) ; /* following checks are for RESOLUTION_RECURSING only */ @@ -1224,14 +1345,11 @@ void request_cb(getdns_context *context, getdns_callback_type_t callback_type, 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); @@ -1256,6 +1374,10 @@ static void incoming_request_handler(getdns_context *context, getdns_dict *qext = NULL; dns_msg *msg = NULL; getdns_dict *response = NULL; + size_t i, len; + getdns_list *additional; + getdns_dict *rr; + uint32_t rr_type; if (!query_extensions_spc && !(query_extensions_spc = getdns_dict_create())) @@ -1277,10 +1399,26 @@ static void incoming_request_handler(getdns_context *context, n = 0; msg->request_id = request_id; msg->request = request; - msg->do_bit = msg->cd_bit = 0; - msg->rt = GETDNS_RESOLUTION_STUB; - (void) getdns_dict_get_int(request, "/additional/0/do", &msg->do_bit); + msg->ad_bit = msg->do_bit = msg->cd_bit = 0; + msg->has_edns0 = 0; + msg->rt = GETDNS_RESOLUTION_RECURSING; + (void) getdns_dict_get_int(request, "/header/ad", &msg->ad_bit); (void) getdns_dict_get_int(request, "/header/cd", &msg->cd_bit); + if (!getdns_dict_get_list(request, "additional", &additional)) { + if (getdns_list_get_length(additional, &len)) + len = 0; + for (i = 0; i < len; i++) { + if (getdns_list_get_dict(additional, i, &rr)) + break; + if (getdns_dict_get_int(rr, "type", &rr_type)) + break; + if (rr_type != GETDNS_RRTYPE_OPT) + continue; + msg->has_edns0 = 1; + (void) getdns_dict_get_int(rr, "do", &msg->do_bit); + break; + } + } if ((r = getdns_context_get_resolution_type(context, &msg->rt))) fprintf(stderr, "Could get resolution type from context: %s\n", getdns_get_errorstr_by_id(r)); @@ -1291,15 +1429,10 @@ static void incoming_request_handler(getdns_context *context, if (!getdns_dict_get_dict(request, "header", &header)) (void)getdns_dict_set_dict(qext, "header", header); - } else if (getdns_dict_get_int(extensions,"dnssec_return_status",&n) || - n == GETDNS_EXTENSION_FALSE) - (void)getdns_dict_set_int(qext, "dnssec_return_status", - msg->do_bit ? GETDNS_EXTENSION_TRUE : GETDNS_EXTENSION_FALSE); - - if (!getdns_dict_get_int(qext, "dnssec_return_status", &n) && - n == GETDNS_EXTENSION_TRUE) - (void) getdns_dict_set_int(qext, "dnssec_return_all_statuses", - msg->cd_bit ? GETDNS_EXTENSION_TRUE : GETDNS_EXTENSION_FALSE); + } + if (msg->cd_bit) + getdns_dict_set_int(qext, "dnssec_return_all_statuses", + GETDNS_EXTENSION_TRUE); if (!getdns_dict_get_int(request, "/additional/0/extended_rcode",&n)) (void)getdns_dict_set_int( @@ -1363,14 +1496,21 @@ error: if (qname_str) free(qname_str); servfail(msg, &response); - if (!response) - /* No response, no reply */ - _getdns_cancel_reply(context, request_id); - - else if ((r = getdns_reply(context, request_id, response))) { +#if defined(SERVER_DEBUG) && SERVER_DEBUG + do { + char *request_str = getdns_pretty_print_dict(request); + char *response_str = getdns_pretty_print_dict(response); + DEBUG_SERVER("request error, request: %s\n, response: %s\n" + , request_str, response_str); + free(response_str); + free(request_str); + } while(0); +#endif + 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) @@ -1471,462 +1611,4 @@ done_destroy_context: return r; } -int get_rrtype(const char *t) { - char *endptr; - int r; - - switch (t[0]) { - case 'A': - case 'a': switch (t[1]) { - case '\0': return GETDNS_RRTYPE_A; - case '6': if (t[2] == '\0') return GETDNS_RRTYPE_A6; - return -1; - case 'A': - case 'a': /* before "AA", final "AA" (GETDNS_RRTYPE_AAAA) */ - if ((t[2]|0x20) == 'a' && (t[3]|0x20) == 'a' && t[4] == '\0') - return GETDNS_RRTYPE_AAAA; - return -1; - case 'F': - case 'f': /* before "AF", final "SDB" (GETDNS_RRTYPE_AFSDB) */ - if ((t[2]|0x20) == 's' && (t[3]|0x20) == 'd' && (t[4]|0x20) == 'b' && t[5] == '\0') - return GETDNS_RRTYPE_AFSDB; - return -1; - case 'P': - case 'p': /* before "AP", final "L" (GETDNS_RRTYPE_APL) */ - if ((t[2]|0x20) == 'l' && t[3] == '\0') - return GETDNS_RRTYPE_APL; - return -1; - case 'T': - case 't': /* before "AT", final "MA" (GETDNS_RRTYPE_ATMA) */ - if ((t[2]|0x20) == 'm' && (t[3]|0x20) == 'a' && t[4] == '\0') - return GETDNS_RRTYPE_ATMA; - return -1; - case 'X': - case 'x': /* before "AX", final "FR" (GETDNS_RRTYPE_AXFR) */ - if ((t[2]|0x20) == 'f' && (t[3]|0x20) == 'r' && t[4] == '\0') - return GETDNS_RRTYPE_AXFR; - return -1; - default : return -1; - }; - case 'C': - case 'c': switch (t[1]) { - case 'A': - case 'a': /* before "CA", final "A" (GETDNS_RRTYPE_CAA) */ - if ((t[2]|0x20) == 'a' && t[3] == '\0') - return GETDNS_RRTYPE_CAA; - return -1; - case 'D': - case 'd': switch (t[2]) { - case 'N': - case 'n': /* before "CDN", final "SKEY" (GETDNS_RRTYPE_CDNSKEY) */ - if ((t[3]|0x20) == 's' && (t[4]|0x20) == 'k' && (t[5]|0x20) == 'e' && (t[6]|0x20) == 'y' && t[7] == '\0') - return GETDNS_RRTYPE_CDNSKEY; - return -1; - case 'S': - case 's': if (t[3] == '\0') return GETDNS_RRTYPE_CDS; - return -1; - default : return -1; - }; - case 'E': - case 'e': /* before "CE", final "RT" (GETDNS_RRTYPE_CERT) */ - if ((t[2]|0x20) == 'r' && (t[3]|0x20) == 't' && t[4] == '\0') - return GETDNS_RRTYPE_CERT; - return -1; - case 'N': - case 'n': /* before "CN", final "AME" (GETDNS_RRTYPE_CNAME) */ - if ((t[2]|0x20) == 'a' && (t[3]|0x20) == 'm' && (t[4]|0x20) == 'e' && t[5] == '\0') - return GETDNS_RRTYPE_CNAME; - return -1; - case 'S': - case 's': /* before "CS", final "YNC" (GETDNS_RRTYPE_CSYNC) */ - if ((t[2]|0x20) == 'y' && (t[3]|0x20) == 'n' && (t[4]|0x20) == 'c' && t[5] == '\0') - return GETDNS_RRTYPE_CSYNC; - return -1; - - default : return -1; - }; - case 'D': - case 'd': switch (t[1]) { - case 'H': - case 'h': /* before "DH", final "CID" (GETDNS_RRTYPE_DHCID) */ - if ((t[2]|0x20) == 'c' && (t[3]|0x20) == 'i' && (t[4]|0x20) == 'd' && t[5] == '\0') - return GETDNS_RRTYPE_DHCID; - return -1; - case 'L': - case 'l': /* before "DL", final "V" (GETDNS_RRTYPE_DLV) */ - if ((t[2]|0x20) == 'v' && t[3] == '\0') - return GETDNS_RRTYPE_DLV; - return -1; - case 'N': - case 'n': switch (t[2]) { - case 'A': - case 'a': /* before "DNA", final "ME" (GETDNS_RRTYPE_DNAME) */ - if ((t[3]|0x20) == 'm' && (t[4]|0x20) == 'e' && t[5] == '\0') - return GETDNS_RRTYPE_DNAME; - return -1; - case 'S': - case 's': /* before "DNS", final "KEY" (GETDNS_RRTYPE_DNSKEY) */ - if ((t[3]|0x20) == 'k' && (t[4]|0x20) == 'e' && (t[5]|0x20) == 'y' && t[6] == '\0') - return GETDNS_RRTYPE_DNSKEY; - return -1; - default : return -1; - }; - case 'S': - case 's': if (t[2] == '\0') return GETDNS_RRTYPE_DS; - return -1; - default : return -1; - }; - case 'E': - case 'e': switch (t[1]) { - case 'I': - case 'i': /* before "EI", final "D" (GETDNS_RRTYPE_EID) */ - if ((t[2]|0x20) == 'd' && t[3] == '\0') - return GETDNS_RRTYPE_EID; - return -1; - case 'U': - case 'u': /* before "EU", next "I" */ - if ((t[2]|0x20) != 'i') - return -1; - switch (t[3]) { - case '4': /* before "EUI4", final "8" (GETDNS_RRTYPE_EUI48) */ - if (t[4] == '8' && t[5] == '\0') - return GETDNS_RRTYPE_EUI48; - return -1; - case '6': /* before "EUI6", final "4" (GETDNS_RRTYPE_EUI64) */ - if (t[4] == '4' && t[5] == '\0') - return GETDNS_RRTYPE_EUI64; - return -1; - default : return -1; - }; - default : return -1; - }; - case 'G': - case 'g': switch (t[1]) { - case 'I': - case 'i': /* before "GI", final "D" (GETDNS_RRTYPE_GID) */ - if ((t[2]|0x20) == 'd' && t[3] == '\0') - return GETDNS_RRTYPE_GID; - return -1; - case 'P': - case 'p': /* before "GP", final "OS" (GETDNS_RRTYPE_GPOS) */ - if ((t[2]|0x20) == 'o' && (t[3]|0x20) == 's' && t[4] == '\0') - return GETDNS_RRTYPE_GPOS; - return -1; - default : return -1; - }; - case 'H': - case 'h': /* before "H", next "I" */ - if ((t[1]|0x20) != 'i') - return -1; - switch (t[2]) { - case 'N': - case 'n': /* before "HIN", final "FO" (GETDNS_RRTYPE_HINFO) */ - if ((t[3]|0x20) == 'f' && (t[4]|0x20) == 'o' && t[5] == '\0') - return GETDNS_RRTYPE_HINFO; - return -1; - case 'P': - case 'p': if (t[3] == '\0') return GETDNS_RRTYPE_HIP; - return -1; - default : return -1; - }; - case 'I': - case 'i': switch (t[1]) { - case 'P': - case 'p': /* before "IP", final "SECKEY" (GETDNS_RRTYPE_IPSECKEY) */ - if ((t[2]|0x20) == 's' && (t[3]|0x20) == 'e' && (t[4]|0x20) == 'c' && (t[5]|0x20) == 'k' && (t[6]|0x20) == 'e' && (t[7]|0x20) == 'y' && t[8] == '\0') - return GETDNS_RRTYPE_IPSECKEY; - return -1; - case 'S': - case 's': /* before "IS", final "DN" (GETDNS_RRTYPE_ISDN) */ - if ((t[2]|0x20) == 'd' && (t[3]|0x20) == 'n' && t[4] == '\0') - return GETDNS_RRTYPE_ISDN; - return -1; - case 'X': - case 'x': /* before "IX", final "FR" (GETDNS_RRTYPE_IXFR) */ - if ((t[2]|0x20) == 'f' && (t[3]|0x20) == 'r' && t[4] == '\0') - return GETDNS_RRTYPE_IXFR; - return -1; - default : return -1; - }; - case 'K': - case 'k': switch (t[1]) { - case 'E': - case 'e': /* before "KE", final "Y" (GETDNS_RRTYPE_KEY) */ - if ((t[2]|0x20) == 'y' && t[3] == '\0') - return GETDNS_RRTYPE_KEY; - return -1; - case 'X': - case 'x': if (t[2] == '\0') return GETDNS_RRTYPE_KX; - return -1; - default : return -1; - }; - case 'L': - case 'l': switch (t[1]) { - case '3': /* before "L3", final "2" (GETDNS_RRTYPE_L32) */ - if (t[2] == '2' && t[3] == '\0') - return GETDNS_RRTYPE_L32; - return -1; - case '6': /* before "L6", final "4" (GETDNS_RRTYPE_L64) */ - if (t[2] == '4' && t[3] == '\0') - return GETDNS_RRTYPE_L64; - return -1; - case 'O': - case 'o': /* before "LO", final "C" (GETDNS_RRTYPE_LOC) */ - if ((t[2]|0x20) == 'c' && t[3] == '\0') - return GETDNS_RRTYPE_LOC; - return -1; - case 'P': - case 'p': if (t[2] == '\0') return GETDNS_RRTYPE_LP; - return -1; - default : return -1; - }; - case 'M': - case 'm': switch (t[1]) { - case 'A': - case 'a': /* before "MA", next "IL" */ - if ((t[2]|0x20) != 'i' && (t[3]|0x20) != 'l') - return -1; - switch (t[4]) { - case 'A': - case 'a': if (t[5] == '\0') return GETDNS_RRTYPE_MAILA; - return -1; - case 'B': - case 'b': if (t[5] == '\0') return GETDNS_RRTYPE_MAILB; - return -1; - default : return -1; - }; - case 'B': - case 'b': if (t[2] == '\0') return GETDNS_RRTYPE_MB; - return -1; - case 'D': - case 'd': if (t[2] == '\0') return GETDNS_RRTYPE_MD; - return -1; - case 'F': - case 'f': if (t[2] == '\0') return GETDNS_RRTYPE_MF; - return -1; - case 'G': - case 'g': if (t[2] == '\0') return GETDNS_RRTYPE_MG; - return -1; - case 'I': - case 'i': /* before "MI", final "NFO" (GETDNS_RRTYPE_MINFO) */ - if ((t[2]|0x20) == 'n' && (t[3]|0x20) == 'f' && (t[4]|0x20) == 'o' && t[5] == '\0') - return GETDNS_RRTYPE_MINFO; - return -1; - case 'R': - case 'r': if (t[2] == '\0') return GETDNS_RRTYPE_MR; - return -1; - case 'X': - case 'x': if (t[2] == '\0') return GETDNS_RRTYPE_MX; - return -1; - default : return -1; - }; - case 'N': - case 'n': switch (t[1]) { - case 'A': - case 'a': /* before "NA", final "PTR" (GETDNS_RRTYPE_NAPTR) */ - if ((t[2]|0x20) == 'p' && (t[3]|0x20) == 't' && (t[4]|0x20) == 'r' && t[5] == '\0') - return GETDNS_RRTYPE_NAPTR; - return -1; - case 'I': - case 'i': switch (t[2]) { - case 'D': - case 'd': if (t[3] == '\0') return GETDNS_RRTYPE_NID; - return -1; - case 'M': - case 'm': /* before "NIM", final "LOC" (GETDNS_RRTYPE_NIMLOC) */ - if ((t[3]|0x20) == 'l' && (t[4]|0x20) == 'o' && (t[5]|0x20) == 'c' && t[6] == '\0') - return GETDNS_RRTYPE_NIMLOC; - return -1; - case 'N': - case 'n': /* before "NIN", final "FO" (GETDNS_RRTYPE_NINFO) */ - if ((t[3]|0x20) == 'f' && (t[4]|0x20) == 'o' && t[5] == '\0') - return GETDNS_RRTYPE_NINFO; - return -1; - default : return -1; - }; - case 'S': - case 's': switch (t[2]) { - case '\0': return GETDNS_RRTYPE_NS; - case 'A': - case 'a': /* before "NSA", final "P" (GETDNS_RRTYPE_NSAP) */ - if ((t[3]|0x20) == 'p' && t[4] == '\0') - return GETDNS_RRTYPE_NSAP; - return -1; - case 'E': - case 'e': /* before "NSE", final "C3PARAM" (GETDNS_RRTYPE_NSEC3PARAM) */ - if ((t[3]|0x20) == 'c' && t[4] == '3' && (t[5]|0x20) == 'p' && (t[6]|0x20) == 'a' && (t[7]|0x20) == 'r' && (t[8]|0x20) == 'a' && (t[9]|0x20) == 'm' && t[10] == '\0') - return GETDNS_RRTYPE_NSEC3PARAM; - return -1; - default : return -1; - }; - case 'U': - case 'u': /* before "NU", final "LL" (GETDNS_RRTYPE_NULL) */ - if ((t[2]|0x20) == 'l' && (t[3]|0x20) == 'l' && t[4] == '\0') - return GETDNS_RRTYPE_NULL; - return -1; - case 'X': - case 'x': /* before "NX", final "T" (GETDNS_RRTYPE_NXT) */ - if ((t[2]|0x20) == 't' && t[3] == '\0') - return GETDNS_RRTYPE_NXT; - return -1; - default : return -1; - }; - case 'O': - case 'o': /* before "O", next "P" */ - if ((t[1]|0x20) != 'p') - return -1; - switch (t[2]) { - case 'E': - case 'e': /* before "OPE", final "NPGPKEY" (GETDNS_RRTYPE_OPENPGPKEY) */ - if ((t[3]|0x20) == 'n' && (t[4]|0x20) == 'p' && (t[5]|0x20) == 'g' && (t[6]|0x20) == 'p' && (t[7]|0x20) == 'k' && (t[8]|0x20) == 'e' && (t[9]|0x20) == 'y' && t[10] == '\0') - return GETDNS_RRTYPE_OPENPGPKEY; - return -1; - case 'T': - case 't': if (t[3] == '\0') return GETDNS_RRTYPE_OPT; - return -1; - default : return -1; - }; - case 'P': - case 'p': switch (t[1]) { - case 'T': - case 't': /* before "PT", final "R" (GETDNS_RRTYPE_PTR) */ - if ((t[2]|0x20) == 'r' && t[3] == '\0') - return GETDNS_RRTYPE_PTR; - return -1; - case 'X': - case 'x': if (t[2] == '\0') return GETDNS_RRTYPE_PX; - return -1; - default : return -1; - }; - case 'R': - case 'r': switch (t[1]) { - case 'K': - case 'k': /* before "RK", final "EY" (GETDNS_RRTYPE_RKEY) */ - if ((t[2]|0x20) == 'e' && (t[3]|0x20) == 'y' && t[4] == '\0') - return GETDNS_RRTYPE_RKEY; - return -1; - case 'P': - case 'p': if (t[2] == '\0') return GETDNS_RRTYPE_RP; - return -1; - case 'R': - case 'r': /* before "RR", final "SIG" (GETDNS_RRTYPE_RRSIG) */ - if ((t[2]|0x20) == 's' && (t[3]|0x20) == 'i' && (t[4]|0x20) == 'g' && t[5] == '\0') - return GETDNS_RRTYPE_RRSIG; - return -1; - case 'T': - case 't': if (t[2] == '\0') return GETDNS_RRTYPE_RT; - return -1; - default : return -1; - }; - case 'S': - case 's': switch (t[1]) { - case 'I': - case 'i': switch (t[2]) { - case 'G': - case 'g': if (t[3] == '\0') return GETDNS_RRTYPE_SIG; - return -1; - case 'N': - case 'n': /* before "SIN", final "K" (GETDNS_RRTYPE_SINK) */ - if ((t[3]|0x20) == 'k' && t[4] == '\0') - return GETDNS_RRTYPE_SINK; - return -1; - default : return -1; - }; - case 'O': - case 'o': /* before "SO", final "A" (GETDNS_RRTYPE_SOA) */ - if ((t[2]|0x20) == 'a' && t[3] == '\0') - return GETDNS_RRTYPE_SOA; - return -1; - case 'P': - case 'p': /* before "SP", final "F" (GETDNS_RRTYPE_SPF) */ - if ((t[2]|0x20) == 'f' && t[3] == '\0') - return GETDNS_RRTYPE_SPF; - return -1; - case 'R': - case 'r': /* before "SR", final "V" (GETDNS_RRTYPE_SRV) */ - if ((t[2]|0x20) == 'v' && t[3] == '\0') - return GETDNS_RRTYPE_SRV; - return -1; - case 'S': - case 's': /* before "SS", final "HFP" (GETDNS_RRTYPE_SSHFP) */ - if ((t[2]|0x20) == 'h' && (t[3]|0x20) == 'f' && (t[4]|0x20) == 'p' && t[5] == '\0') - return GETDNS_RRTYPE_SSHFP; - return -1; - default : return -1; - }; - case 'T': - case 't': switch (t[1]) { - case 'A': - case 'a': /* before "TA", final "LINK" (GETDNS_RRTYPE_TALINK) */ - if ((t[2]|0x20) == 'l' && (t[3]|0x20) == 'i' && (t[4]|0x20) == 'n' && (t[5]|0x20) == 'k' && t[6] == '\0') - return GETDNS_RRTYPE_TALINK; - return -1; - case 'K': - case 'k': /* before "TK", final "EY" (GETDNS_RRTYPE_TKEY) */ - if ((t[2]|0x20) == 'e' && (t[3]|0x20) == 'y' && t[4] == '\0') - return GETDNS_RRTYPE_TKEY; - return -1; - case 'L': - case 'l': /* before "TL", final "SA" (GETDNS_RRTYPE_TLSA) */ - if ((t[2]|0x20) == 's' && (t[3]|0x20) == 'a' && t[4] == '\0') - return GETDNS_RRTYPE_TLSA; - return -1; - case 'S': - case 's': /* before "TS", final "IG" (GETDNS_RRTYPE_TSIG) */ - if ((t[2]|0x20) == 'i' && (t[3]|0x20) == 'g' && t[4] == '\0') - return GETDNS_RRTYPE_TSIG; - return -1; - case 'X': - case 'x': /* before "TX", final "T" (GETDNS_RRTYPE_TXT) */ - if ((t[2]|0x20) == 't' && t[3] == '\0') - return GETDNS_RRTYPE_TXT; - return -1; - case 'Y': - case 'y': /* before "TY", then "PE" followed by a number */ - if ((t[2]|0x20) == 'p' && (t[3]|0x20) == 'e' && t[4] != '\0') { - r = (int) strtol(t + 4, &endptr, 10); - if (*endptr == '\0') return r; - } - return -1; - default : return -1; - }; - case 'U': - case 'u': switch (t[1]) { - case 'I': - case 'i': switch (t[2]) { - case 'D': - case 'd': if (t[3] == '\0') return GETDNS_RRTYPE_UID; - return -1; - case 'N': - case 'n': /* before "UIN", final "FO" (GETDNS_RRTYPE_UINFO) */ - if ((t[3]|0x20) == 'f' && (t[4]|0x20) == 'o' && t[5] == '\0') - return GETDNS_RRTYPE_UINFO; - return -1; - default : return -1; - }; - case 'N': - case 'n': /* before "UN", final "SPEC" (GETDNS_RRTYPE_UNSPEC) */ - if ((t[2]|0x20) == 's' && (t[3]|0x20) == 'p' && (t[4]|0x20) == 'e' && (t[5]|0x20) == 'c' && t[6] == '\0') - return GETDNS_RRTYPE_UNSPEC; - return -1; - case 'R': - case 'r': /* before "UR", final "I" (GETDNS_RRTYPE_URI) */ - if ((t[2]|0x20) == 'i' && t[3] == '\0') - return GETDNS_RRTYPE_URI; - return -1; - default : return -1; - }; - case 'W': - case 'w': /* before "W", final "KS" (GETDNS_RRTYPE_WKS) */ - if ((t[1]|0x20) == 'k' && (t[2]|0x20) == 's' && t[3] == '\0') - return GETDNS_RRTYPE_WKS; - return -1; - case 'X': - case 'x': /* before "X", final "25" (GETDNS_RRTYPE_X25) */ - if (t[1] == '2' && t[2] == '5' && t[3] == '\0') - return GETDNS_RRTYPE_X25; - return -1; - default : return -1; - }; -} diff --git a/src/test/getdns_str2dict.c b/src/test/getdns_str2dict.c deleted file mode 100644 index 7cfc875c..00000000 --- a/src/test/getdns_str2dict.c +++ /dev/null @@ -1,926 +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; -} - -getdns_dict * -_getdns_ipaddr_dict(const char *ipstr) -{ - char value_str[3072]; - size_t size = strlen(ipstr); - - if (size >= sizeof(value_str)) - return NULL; - - (void) memcpy(value_str, ipstr, size); - value_str[size] = '\0'; - - return _getdns_ipaddr_dict_mf(&_getdns_plain_mem_funcs, value_str); -} - -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) { - _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); - return GETDNS_RETURN_WRONG_TYPE_REQUESTED; - } - *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 f8d7e926..00000000 --- a/src/test/getdns_str2dict.h +++ /dev/null @@ -1,39 +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_dict *_getdns_ipaddr_dict(const char *ipstr); - -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 diff --git a/src/test/jsmn b/src/test/jsmn deleted file mode 160000 index daa17063..00000000 --- a/src/test/jsmn +++ /dev/null @@ -1 +0,0 @@ -Subproject commit daa17063c67f0dfe873af25ab6b664641c8cf90c