From ecee874eb8bcb3d39f2f7e5b84756e493e7897bb Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Tue, 4 Feb 2014 03:49:02 +0000 Subject: update to ldns 1.6.17, ok sthen@ --- usr.sbin/unbound/ldns/Changelog | 58 + usr.sbin/unbound/ldns/README | 40 +- usr.sbin/unbound/ldns/README.git | 22 + usr.sbin/unbound/ldns/acx_nlnetlabs.m4 | 44 +- usr.sbin/unbound/ldns/ax_python_devel.m4 | 61 +- usr.sbin/unbound/ldns/compat/b64_ntop.c | 31 +- usr.sbin/unbound/ldns/compat/b64_pton.c | 17 - usr.sbin/unbound/ldns/compat/snprintf.c | 1750 ++++++++++++++---------- usr.sbin/unbound/ldns/dane.c | 14 +- usr.sbin/unbound/ldns/dnssec.c | 308 +++-- usr.sbin/unbound/ldns/dnssec_sign.c | 81 +- usr.sbin/unbound/ldns/dnssec_verify.c | 20 +- usr.sbin/unbound/ldns/dnssec_zone.c | 205 +-- usr.sbin/unbound/ldns/doc/API.xml | 2 +- usr.sbin/unbound/ldns/drill/chasetrace.c | 2 + usr.sbin/unbound/ldns/drill/configure | 37 +- usr.sbin/unbound/ldns/drill/configure.ac | 2 +- usr.sbin/unbound/ldns/drill/drill.1.in | 11 + usr.sbin/unbound/ldns/drill/drill.c | 55 +- usr.sbin/unbound/ldns/drill/drill_util.c | 6 +- usr.sbin/unbound/ldns/drill/securetrace.c | 28 +- usr.sbin/unbound/ldns/drill/work.c | 1 + usr.sbin/unbound/ldns/error.c | 19 + usr.sbin/unbound/ldns/higher.c | 48 +- usr.sbin/unbound/ldns/host2str.c | 685 +++++++--- usr.sbin/unbound/ldns/host2wire.c | 20 +- usr.sbin/unbound/ldns/install-sh | 14 +- usr.sbin/unbound/ldns/keys.c | 22 +- usr.sbin/unbound/ldns/ldns/common.h.in | 3 + usr.sbin/unbound/ldns/ldns/config.h.in | 37 +- usr.sbin/unbound/ldns/ldns/dane.h | 2 + usr.sbin/unbound/ldns/ldns/dnssec.h | 28 +- usr.sbin/unbound/ldns/ldns/dnssec_sign.h | 4 +- usr.sbin/unbound/ldns/ldns/dnssec_verify.h | 4 +- usr.sbin/unbound/ldns/ldns/dnssec_zone.h | 18 +- usr.sbin/unbound/ldns/ldns/error.h | 11 +- usr.sbin/unbound/ldns/ldns/host2str.h | 168 ++- usr.sbin/unbound/ldns/ldns/keys.h | 4 +- usr.sbin/unbound/ldns/ldns/ldns.h | 7 +- usr.sbin/unbound/ldns/ldns/net.h.in | 1 - usr.sbin/unbound/ldns/ldns/packet.h | 36 +- usr.sbin/unbound/ldns/ldns/radix.h | 240 ++++ usr.sbin/unbound/ldns/ldns/rdata.h | 62 +- usr.sbin/unbound/ldns/ldns/resolver.h | 55 +- usr.sbin/unbound/ldns/ldns/rr.h | 52 +- usr.sbin/unbound/ldns/ldns/str2host.h | 60 +- usr.sbin/unbound/ldns/ldns/util.h.in | 70 +- usr.sbin/unbound/ldns/net.c | 830 ++++++----- usr.sbin/unbound/ldns/packaging/ldns-config.1 | 6 +- usr.sbin/unbound/ldns/packaging/ldns-config.in | 5 + usr.sbin/unbound/ldns/packet.c | 110 +- usr.sbin/unbound/ldns/parse.c | 22 +- usr.sbin/unbound/ldns/radix.c | 1590 +++++++++++++++++++++ usr.sbin/unbound/ldns/rdata.c | 91 +- usr.sbin/unbound/ldns/resolver.c | 184 ++- usr.sbin/unbound/ldns/rr.c | 933 ++++++++----- usr.sbin/unbound/ldns/sha1.c | 2 +- usr.sbin/unbound/ldns/sha2.c | 17 +- usr.sbin/unbound/ldns/str2host.c | 382 +++++- usr.sbin/unbound/ldns/tsig.c | 12 +- usr.sbin/unbound/ldns/util.c | 348 ++++- usr.sbin/unbound/ldns/wire2host.c | 55 +- usr.sbin/unbound/ldns/zone.c | 113 -- 63 files changed, 6583 insertions(+), 2582 deletions(-) create mode 100644 usr.sbin/unbound/ldns/README.git create mode 100644 usr.sbin/unbound/ldns/ldns/radix.h create mode 100644 usr.sbin/unbound/ldns/radix.c diff --git a/usr.sbin/unbound/ldns/Changelog b/usr.sbin/unbound/ldns/Changelog index 845d5b8a738..48ea9bbda3a 100644 --- a/usr.sbin/unbound/ldns/Changelog +++ b/usr.sbin/unbound/ldns/Changelog @@ -1,3 +1,61 @@ +1.6.17 2014-01-10 + * Fix ldns_dnssec_zone_new_frm_fp_l to allow the last parsed line of a + zone to be an NSEC3 (or its RRSIG) covering an empty non terminal. + * Add --disable-dane option to configure and check availability of the + for dane needed X509_check_ca function in openssl. + * bugfix #490: Get rid of type-punned pointer warnings. + Thanks Adam Tkac. + * Make sure executables are linked against libcrypto with the + LIBSSL_LDFLAGS. Thanks Leo Baltus. + * Miscellaneous prototype fixes. Thanks Dag-Erling Smørgrav. + * README now shows preferred way to configure for examples and drill. + * Bind to source address for resolvers. drill binds to source with -I. + Thanks Bryan Duff. + * -T option for ldns-dane that has specific exit status for PKIX + validated connections without (secure) TLSA records. + * Fix b{32,64}_{ntop,pton} detection and handling. + * New RR type TKEY, but without operational practice. + * New RR types HIP, NINFO, RKEY, CDS, EUI48, EUI64, URI, CAA and TA. + * New output format flag (and accompanying functions) to print certain + RR's as unknown type + * -u and -U parameter for ldns-read-zone to mark/unmark a RR type + for printing as unknown type + * bugfix #504: GPOS RR has three rdata fields. Thanks Jelte Jansen. + * bugfix #497: Properly test for EOF when reading key files with drill. + * New functions: ldns_pkt_ixfr_request_new and + ldns_pkt_ixfr_request_new_frm_str. + * Use SNI with ldns-dane + * bugfix #507: ldnsx Fix use of non-existent variables and not + properly referring to instance variable. Patch from shussain. + * bugfix #508: ldnsx Adding NSEC3PARAM to known/allowable RR type + dictionary. Patch from shussain. + * bugfix #517: ldns_resolver_new_frm_fp error when invoked using a NULL + file pointer. + * Fix memory leak in contrib/python: ldns_pkt.new_query. + * Fix buffer overflow in fget_token and bget_token. + * ldns-verify-zone NSEC3 checking from quadratic to linear performance. + Thanks NIC MX (nicmexico.mx) + * ldns-dane setup new ssl session for each new connect to prevent hangs + * bugfix #521: drill trace continue on empty non-terminals with NSEC3 + * bugfix #525: Fix documentation of ldns_resolver_set_retry + * Remove unused LDNS_RDF_TYPE_TSIG and associated functions. + * Fix ldns_nsec_covers_name for zones with an apex only. Thanks Miek. + * Configure option to build perl bindings: --with-p5-dns-ldns + (DNS::LDNS is a contribution from Erik Ostlyngen) + * bugfix #527: Move -lssl before -lcrypto when linking + * Optimize TSIG digest function name comparison (Thanks Marc Buijsman) + * Compare names case insensitive with ldns_pkt_rr_list_by_name and + ldns_pkt_rr_list_by_name_and_type (thanks Johannes Naab) + * A separate --enable for each draft RR type: --enable-rrtype-ninfo, + --enable-rrtype-rkey, --enable-rrtype-cds, --enable-rrtype-uri and + --enable-rrtype-ta + * bugfix #530: Don't sign and verify duplicate RRs (Thanks Jelte Jansen) + * bugfix #505: Manpage and usage output fixes (Thanks Tomas Hozza) + * Adjust ldns_sha1() so that the input data is not modified (Thanks + Marc Buijsman) + * Messages to stderr are now off by default and can be reenabled with + the --enable-stderr-msgs configure option. + 1.6.16 2012-11-13 * Fix Makefile to build pyldns with BSD make * Fix typo in exporting b32_* symbols to make pyldns load again diff --git a/usr.sbin/unbound/ldns/README b/usr.sbin/unbound/ldns/README index 70eb3dc0f89..6319c6f5255 100644 --- a/usr.sbin/unbound/ldns/README +++ b/usr.sbin/unbound/ldns/README @@ -22,6 +22,8 @@ compile on other systems like Solaris and Mac OS X. REQUIREMENTS - OpenSSL (Optional, but needed for features like DNSSEC) + - OpenSSL >= 0.9.7f for DANE support + - OpenSSL >= 1.0.0 for ECDSA and GOST support - libpcap (Optional, but needed for examples/ldns-dpa) - (GNU) libtool (in OSX, that's glibtool, not libtool) - GNU make @@ -29,39 +31,17 @@ REQUIREMENTS INSTALLATION 1. Unpack the tarball 2. cd ldns- -3. ./configure -4. gmake (it needs gnu make to compile, on systems where GNU make is the - default you can just use 'make') -5. sudo gmake install -6. Optional. (cd examples; ./configure; gmake), make example programs included. -7. Optional. (cd drill; ./configure; gmake; gmake install), to build drill. +3. ./configure --with-examples --with-drill + (optionally compile python bindings too with: --with-pyldns) +4. make +5. make install -You can configure and compile it in a separate build directory. -* Examples -There are some examples and dns related tools in the examples/ directory. -These can be built with: -1. cd examples/ -2. ./configure [--with-ldns=] -3. gmake - -* Drill -Drill can be built with: -1. cd drill/ -2. ./configure [--with-ldns=] -3. gmake - -Note that you need to set LD_LIBRARY_PATH if you want to run the binaries -and you have not installed the library to a system directory. You can use -the make target all-static for the examples to run them if you don't want to -install the library. - - -* Building from subversion repository +* Building from repository If you are building from the repository you will need to have (gnu) autotools like libtool and autoreconf installed. A list of all the commands -needed to build everything can be found in README.svn. Note that the actual +needed to build everything can be found in README.git. Note that the actual commands may be a little bit different on your machine. Most notable, you'll need to run libtoolize (or glibtoolize), if you skip this step, you'll get an error about missing config.sub. * Developers @@ -84,6 +64,10 @@ We have received patches from the following people, thanks! o Paul Wouters o Simon Vallet o Ondřej Surý + o Karel Slany + o Havard Eidnes + o Leo Baltus + o Dag-Erling Smørgrav INFORMATION FOR SPECIFIC OPERATING SYSTEMS diff --git a/usr.sbin/unbound/ldns/README.git b/usr.sbin/unbound/ldns/README.git new file mode 100644 index 00000000000..34c9ae54f5e --- /dev/null +++ b/usr.sbin/unbound/ldns/README.git @@ -0,0 +1,22 @@ +# The ldns git repository can found at: +# git.nlnetlabs.nl/ldns/ + +# small list of commands to build all on a linux system +# libtoolize is needed for most other targets + +# on Solaris, and other systems that may not have +# the default 'automake' and 'aclocal' script aliases, +# the correct versions may need to be set. On those +# systems, the 'autoreconf' line should be changed to: +# AUTOMAKE=automake-1.10 ACLOCAL=aclocal-1.10 autoreconf + +# older versions of libtoolize do not support --install +# so you might need to remove that (with newer versions +# it is needed) +libtoolize -c --install +autoreconf --install +./configure --with-examples --with-drill # --with-pyldns --with-p5-dns-ldns +make +make doc # needs doxygen for the html pages +(cd pcat && autoreconf && ./configure && make) +(cd examples/nsd-test && autoreconf && ./configure && make) diff --git a/usr.sbin/unbound/ldns/acx_nlnetlabs.m4 b/usr.sbin/unbound/ldns/acx_nlnetlabs.m4 index e90c81ea02a..a4047332ff2 100644 --- a/usr.sbin/unbound/ldns/acx_nlnetlabs.m4 +++ b/usr.sbin/unbound/ldns/acx_nlnetlabs.m4 @@ -2,7 +2,12 @@ # Copyright 2009, Wouter Wijngaards, NLnet Labs. # BSD licensed. # -# Version 21 +# Version 26 +# 2013-09-19 FLTO help text improved. +# 2013-07-18 Enable ACX_CHECK_COMPILER_FLAG to test for -Wstrict-prototypes +# 2013-06-25 FLTO has --disable-flto option. +# 2013-05-03 Update W32_SLEEP for newer mingw that links but not defines it. +# 2013-03-22 Fix ACX_RSRC_VERSION for long version numbers. # 2012-02-09 Fix AHX_MEMCMP_BROKEN with undef in compat/memcmp.h. # 2012-01-20 Fix COMPILER_FLAGS_UNBOUND for gcc 4.6.2 assigned-not-used-warns. # 2011-12-05 Fix getaddrinfowithincludes on windows with fedora16 mingw32-gcc. @@ -17,7 +22,7 @@ # 2010-07-02 Add check for ss_family (for minix). # 2010-04-26 Fix to use CPPFLAGS for CHECK_COMPILER_FLAGS. # 2010-03-01 Fix RPATH using CONFIG_COMMANDS to run at the very end. -# 2010-02-18 WITH_SSL outputs the LIBSSL_LDFLAGS, LIBS, CPPFLAGS seperate, -ldl +# 2010-02-18 WITH_SSL outputs the LIBSSL_LDFLAGS, LIBS, CPPFLAGS separate, -ldl # 2010-02-01 added ACX_CHECK_MEMCMP_SIGNED, AHX_MEMCMP_BROKEN # 2010-01-20 added AHX_COONFIG_STRLCAT # 2009-07-14 U_CHAR detection improved for windows crosscompile. @@ -101,7 +106,7 @@ dnl Calculate comma separated windows-resource numbers from package version. dnl Picks the first three(,0) or four numbers out of the name. dnl $1: variable for the result AC_DEFUN([ACX_RSRC_VERSION], -[$1=[`echo $PACKAGE_VERSION | sed -e 's/^[^0-9]*\([0-9]\)[^0-9]*\([0-9]\)[^0-9]*\([0-9]\)[^0-9]*\([0-9]\).*$/\1,\2,\3,\4/' -e 's/^[^0-9]*\([0-9]\)[^0-9]*\([0-9]\)[^0-9]*\([0-9]\)[^0-9]*$/\1,\2,\3,0/' `] +[$1=[`echo $PACKAGE_VERSION | sed -e 's/^[^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\).*$/\1,\2,\3,\4/' -e 's/^[^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9]*$/\1,\2,\3,0/' `] ]) dnl Routine to help check for compiler flags. @@ -116,7 +121,7 @@ AC_MSG_CHECKING(whether $CC supports -$1) cache=`echo $1 | sed 'y%.=/+-%___p_%'` AC_CACHE_VAL(cv_prog_cc_flag_$cache, [ -echo 'void f(){}' >conftest.c +echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -$1 -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else @@ -405,19 +410,22 @@ int test() { dnl Check if CC supports -flto. dnl in a way that supports clang and suncc (that flag does something else, dnl but fails to link). It sets it in CFLAGS if it works. -AC_DEFUN([ACX_CHECK_FLTO], -[AC_MSG_CHECKING([if $CC supports -flto]) -BAKCFLAGS="$CFLAGS" -CFLAGS="$CFLAGS -flto" -AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [ - if $CC $CFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then - CFLAGS="$BAKCFLAGS" - AC_MSG_RESULT(no) - else - AC_MSG_RESULT(yes) - fi - rm -f conftest conftest.c conftest.o -], [CFLAGS="$BAKCFLAGS" ; AC_MSG_RESULT(no)]) +AC_DEFUN([ACX_CHECK_FLTO], [ + AC_ARG_ENABLE([flto], AS_HELP_STRING([--disable-flto], [Disable link-time optimization (gcc specific option)])) + AS_IF([test "x$enable_flto" != "xno"], [ + AC_MSG_CHECKING([if $CC supports -flto]) + BAKCFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -flto" + AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [ + if $CC $CFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then + CFLAGS="$BAKCFLAGS" + AC_MSG_RESULT(no) + else + AC_MSG_RESULT(yes) + fi + rm -f conftest conftest.c conftest.o + ], [CFLAGS="$BAKCFLAGS" ; AC_MSG_RESULT(no)]) + ]) ]) dnl Check the printf-format attribute (if any) @@ -1208,7 +1216,7 @@ struct tm *gmtime_r(const time_t *timep, struct tm *result); dnl provide w32 compat definition for sleep AC_DEFUN([AHX_CONFIG_W32_SLEEP], [ -#ifndef HAVE_SLEEP +#if !defined(HAVE_SLEEP) || defined(HAVE_WINDOWS_H) #define sleep(x) Sleep((x)*1000) /* on win32 */ #endif /* HAVE_SLEEP */ ]) diff --git a/usr.sbin/unbound/ldns/ax_python_devel.m4 b/usr.sbin/unbound/ldns/ax_python_devel.m4 index 2ce6afe8350..87e7c8c253b 100644 --- a/usr.sbin/unbound/ldns/ax_python_devel.m4 +++ b/usr.sbin/unbound/ldns/ax_python_devel.m4 @@ -34,11 +34,12 @@ # LICENSE # # Copyright (c) 2009 Sebastian Huber -# Copyright (c) 2009 Alan W. Irwin +# Copyright (c) 2009 Alan W. Irwin # Copyright (c) 2009 Rafael Laboissiere -# Copyright (c) 2009 Andrew Collier +# Copyright (c) 2009 Andrew Collier # Copyright (c) 2009 Matteo Settenvini # Copyright (c) 2009 Horst Knorr +# Copyright (c) 2013 Daniel Mullner # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the @@ -66,7 +67,7 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 8 +#serial 16 AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL]) AC_DEFUN([AX_PYTHON_DEVEL],[ @@ -153,8 +154,14 @@ $ac_distutils_result]) if test -z "$PYTHON_CPPFLAGS"; then python_path=`$PYTHON -c "import distutils.sysconfig; \ print (distutils.sysconfig.get_python_inc ());"` + plat_python_path=`$PYTHON -c "import distutils.sysconfig; \ + print (distutils.sysconfig.get_python_inc (plat_specific=1));"` if test -n "${python_path}"; then - python_path="-I$python_path" + if test "${plat_python_path}" != "${python_path}"; then + python_path="-I$python_path -I$plat_python_path" + else + python_path="-I$python_path" + fi fi PYTHON_CPPFLAGS=$python_path fi @@ -173,13 +180,10 @@ $ac_distutils_result]) # join all versioning strings, on some systems # major/minor numbers could be in different list elements from distutils.sysconfig import * -ret = '' -for e in get_config_vars ('VERSION'): - if (e != None): - ret += e -print (ret) -EOD -` +e = get_config_var('VERSION') +if e is not None: + print(e) +EOD` if test -z "$ac_python_version"; then if test -n "$PYTHON_VERSION"; then @@ -199,34 +203,27 @@ EOD # There should be only one import distutils.sysconfig -for e in distutils.sysconfig.get_config_vars ('LIBDIR'): - if e != None: - print (e) - break -EOD -` - - # Before checking for libpythonX.Y, we need to know - # the extension the OS we're on uses for libraries - # (we take the first one, if there's more than one fix me!): - ac_python_soext=`$PYTHON -c \ - "import distutils.sysconfig; \ - print (distutils.sysconfig.get_config_vars('SO')[[0]])"` +e = distutils.sysconfig.get_config_var('LIBDIR') +if e is not None: + print (e) +EOD` # Now, for the library: - ac_python_soname=`$PYTHON -c \ - "import distutils.sysconfig; \ - print (distutils.sysconfig.get_config_vars('LDLIBRARY')[[0]])"` + ac_python_library=`cat< - -#include -#include -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif - #include -#include #include #include -#define Assert(Cond) if (!(Cond)) abort() - static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; @@ -154,10 +137,10 @@ ldns_b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsiz output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); output[3] = input[2] & 0x3f; - Assert(output[0] < 64); - Assert(output[1] < 64); - Assert(output[2] < 64); - Assert(output[3] < 64); + assert(output[0] < 64); + assert(output[1] < 64); + assert(output[2] < 64); + assert(output[3] < 64); if (datalength + 4 > targsize) { return (-1); @@ -178,9 +161,9 @@ ldns_b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsiz output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); - Assert(output[0] < 64); - Assert(output[1] < 64); - Assert(output[2] < 64); + assert(output[0] < 64); + assert(output[1] < 64); + assert(output[2] < 64); if (datalength + 4 > targsize) { return (-2); diff --git a/usr.sbin/unbound/ldns/compat/b64_pton.c b/usr.sbin/unbound/ldns/compat/b64_pton.c index aa637d22754..abe32819e92 100644 --- a/usr.sbin/unbound/ldns/compat/b64_pton.c +++ b/usr.sbin/unbound/ldns/compat/b64_pton.c @@ -40,27 +40,10 @@ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include - -#include -#include -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif - #include -#include #include #include -#define Assert(Cond) if (!(Cond)) abort() - static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; diff --git a/usr.sbin/unbound/ldns/compat/snprintf.c b/usr.sbin/unbound/ldns/compat/snprintf.c index b7445111cb3..d869ba5e7d0 100644 --- a/usr.sbin/unbound/ldns/compat/snprintf.c +++ b/usr.sbin/unbound/ldns/compat/snprintf.c @@ -1,770 +1,1036 @@ -#include - -#ifndef HAVE_SNPRINTF +/* snprintf - compatibility implementation of snprintf, vsnprintf + * + * Copyright (c) 2013, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS 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 THE REGENTS OR CONTRIBUTORS 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 +#include #include -#include +#include +#include +#include +#include +#ifdef HAVE_STDINT_H +#include +#endif -/* Define this as a fall through, HAVE_STDARG_H is probably already set */ +/* for test */ +/* #define SNPRINTF_TEST 1 */ +#ifdef SNPRINTF_TEST +#define snprintf my_snprintf +#define vsnprintf my_vsnprintf +#endif /* SNPRINTF_TEST */ -#define HAVE_VARARGS_H +int snprintf(char* str, size_t size, const char* format, ...); +int vsnprintf(char* str, size_t size, const char* format, va_list arg); -/************************************************************** - * Original: - * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 - * A bombproof version of doprnt (dopr) included. - * Sigh. This sort of thing is always nasty do deal with. Note that - * the version here does not include floating point... - * - * snprintf() is used instead of sprintf() as it does limit checks - * for string length. This covers a nasty loophole. - * - * The other functions are there to prevent NULL pointers from - * causing nast effects. +/** + * Very portable snprintf implementation, limited in functionality, + * esp. for %[capital] %[nonportable] and so on. Reduced float functionality, + * mostly in formatting and range (e+-16), for %f and %g. * - * More Recently: - * Brandon Long (blong@fiction.net) 9/15/96 for mutt 0.43 - * This was ugly. It is still ugly. I opted out of floating point - * numbers, but the formatter understands just about everything - * from the normal C string format, at least as far as I can tell from - * the Solaris 2.5 printf(3S) man page. - * - * Brandon Long (blong@fiction.net) 10/22/97 for mutt 0.87.1 - * Ok, added some minimal floating point support, which means this - * probably requires libm on most operating systems. Don't yet - * support the exponent (e,E) and sigfig (g,G). Also, fmtint() - * was pretty badly broken, it just wasn't being exercised in ways - * which showed it, so that's been fixed. Also, formated the code - * to mutt conventions, and removed dead code left over from the - * original. Also, there is now a builtin-test, just compile with: - * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm - * and run snprintf for results. - * - **************************************************************/ + * %s, %d, %u, %i, %x, %c, %n and %% are fully supported. + * This includes width, precision, flags 0- +, and *(arg for wid,prec). + * %f, %g, %m, %p have reduced support, support for wid,prec,flags,*, but + * less floating point range, no %e formatting for %g. + */ +int snprintf(char* str, size_t size, const char* format, ...) +{ + int r; + va_list args; + va_start(args, format); + r = vsnprintf(str, size, format, args); + va_end(args); + return r; +} +/** add padding to string */ +static void +print_pad(char** at, size_t* left, int* ret, char p, int num) +{ + while(num--) { + if(*left > 1) { + *(*at)++ = p; + (*left)--; + } + (*ret)++; + } +} -/* varargs declarations: */ +/** get negative symbol, 0 if none */ +static char +get_negsign(int negative, int plus, int space) +{ + if(negative) + return '-'; + if(plus) + return '+'; + if(space) + return ' '; + return 0; +} -#if defined(HAVE_STDARG_H) -# include -# define HAVE_STDARGS /* let's hope that works everywhere (mj) */ -# define VA_LOCAL_DECL va_list ap -# define VA_START(f) va_start(ap, f) -# define VA_SHIFT(v,t) ; /* no-op for ANSI */ -# define VA_END va_end(ap) -#else -# if defined(HAVE_VARARGS_H) -# include -# undef HAVE_STDARGS -# define VA_LOCAL_DECL va_list ap -# define VA_START(f) va_start(ap) /* f is ignored! */ -# define VA_SHIFT(v,t) v = va_arg(ap,t) -# define VA_END va_end(ap) -# else -/*XX ** NO VARARGS ** XX*/ -# endif -#endif +#define PRINT_DEC_BUFSZ 32 /* 20 is enough for 64 bit decimals */ +/** print decimal into buffer, returns length */ +static int +print_dec(char* buf, int max, unsigned int value) +{ + int i = 0; + if(value == 0) { + if(max > 0) { + buf[0] = '0'; + i = 1; + } + } else while(value && i < max) { + buf[i++] = '0' + value % 10; + value /= 10; + } + return i; +} + +/** print long decimal into buffer, returns length */ +static int +print_dec_l(char* buf, int max, unsigned long value) +{ + int i = 0; + if(value == 0) { + if(max > 0) { + buf[0] = '0'; + i = 1; + } + } else while(value && i < max) { + buf[i++] = '0' + value % 10; + value /= 10; + } + return i; +} + +/** print long decimal into buffer, returns length */ +static int +print_dec_ll(char* buf, int max, unsigned long long value) +{ + int i = 0; + if(value == 0) { + if(max > 0) { + buf[0] = '0'; + i = 1; + } + } else while(value && i < max) { + buf[i++] = '0' + value % 10; + value /= 10; + } + return i; +} + +/** print hex into buffer, returns length */ +static int +print_hex(char* buf, int max, unsigned int value) +{ + const char* h = "0123456789abcdef"; + int i = 0; + if(value == 0) { + if(max > 0) { + buf[0] = '0'; + i = 1; + } + } else while(value && i < max) { + buf[i++] = h[value & 0x0f]; + value >>= 4; + } + return i; +} + +/** print long hex into buffer, returns length */ +static int +print_hex_l(char* buf, int max, unsigned long value) +{ + const char* h = "0123456789abcdef"; + int i = 0; + if(value == 0) { + if(max > 0) { + buf[0] = '0'; + i = 1; + } + } else while(value && i < max) { + buf[i++] = h[value & 0x0f]; + value >>= 4; + } + return i; +} + +/** print long long hex into buffer, returns length */ +static int +print_hex_ll(char* buf, int max, unsigned long long value) +{ + const char* h = "0123456789abcdef"; + int i = 0; + if(value == 0) { + if(max > 0) { + buf[0] = '0'; + i = 1; + } + } else while(value && i < max) { + buf[i++] = h[value & 0x0f]; + value >>= 4; + } + return i; +} + +/** copy string into result, reversed */ +static void +spool_str_rev(char** at, size_t* left, int* ret, const char* buf, int len) +{ + int i = len; + while(i) { + if(*left > 1) { + *(*at)++ = buf[--i]; + (*left)--; + } else --i; + (*ret)++; + } +} + +/** copy string into result */ +static void +spool_str(char** at, size_t* left, int* ret, const char* buf, int len) +{ + int i; + for(i=0; i 1) { + *(*at)++ = buf[i]; + (*left)--; + } + (*ret)++; + } +} + +/** print number formatted */ +static void +print_num(char** at, size_t* left, int* ret, int minw, int precision, + int prgiven, int zeropad, int minus, int plus, int space, + int zero, int negative, char* buf, int len) +{ + int w = len; /* excludes minus sign */ + char s = get_negsign(negative, plus, space); + if(minus) { + /* left adjust the number into the field, space padding */ + /* calc numw = [sign][zeroes][number] */ + int numw = w; + if(precision == 0 && zero) numw = 0; + if(numw < precision) numw = precision; + if(s) numw++; + + /* sign */ + if(s) print_pad(at, left, ret, s, 1); + + /* number */ + if(precision == 0 && zero) { + /* "" for the number */ + } else { + if(w < precision) + print_pad(at, left, ret, '0', precision - w); + spool_str_rev(at, left, ret, buf, len); + } + /* spaces */ + if(numw < minw) + print_pad(at, left, ret, ' ', minw - numw); + } else { + /* pad on the left of the number */ + /* calculate numw has width of [sign][zeroes][number] */ + int numw = w; + if(precision == 0 && zero) numw = 0; + if(numw < precision) numw = precision; + if(!prgiven && zeropad && numw < minw) numw = minw; + else if(s) numw++; + + /* pad with spaces */ + if(numw < minw) + print_pad(at, left, ret, ' ', minw - numw); + /* print sign (and one less zeropad if so) */ + if(s) { + print_pad(at, left, ret, s, 1); + numw--; + } + /* pad with zeroes */ + if(w < numw) + print_pad(at, left, ret, '0', numw - w); + if(precision == 0 && zero) + return; + /* print the characters for the value */ + spool_str_rev(at, left, ret, buf, len); + } +} + +/** print %d and %i */ +static void +print_num_d(char** at, size_t* left, int* ret, int value, + int minw, int precision, int prgiven, int zeropad, int minus, + int plus, int space) +{ + char buf[PRINT_DEC_BUFSZ]; + int negative = (value < 0); + int zero = (value == 0); + int len = print_dec(buf, (int)sizeof(buf), + (unsigned int)(negative?-value:value)); + print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, + plus, space, zero, negative, buf, len); +} + +/** print %ld and %li */ +static void +print_num_ld(char** at, size_t* left, int* ret, long value, + int minw, int precision, int prgiven, int zeropad, int minus, + int plus, int space) +{ + char buf[PRINT_DEC_BUFSZ]; + int negative = (value < 0); + int zero = (value == 0); + int len = print_dec_l(buf, (int)sizeof(buf), + (unsigned long)(negative?-value:value)); + print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, + plus, space, zero, negative, buf, len); +} + +/** print %lld and %lli */ +static void +print_num_lld(char** at, size_t* left, int* ret, long long value, + int minw, int precision, int prgiven, int zeropad, int minus, + int plus, int space) +{ + char buf[PRINT_DEC_BUFSZ]; + int negative = (value < 0); + int zero = (value == 0); + int len = print_dec_ll(buf, (int)sizeof(buf), + (unsigned long long)(negative?-value:value)); + print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, + plus, space, zero, negative, buf, len); +} + +/** print %u */ +static void +print_num_u(char** at, size_t* left, int* ret, unsigned int value, + int minw, int precision, int prgiven, int zeropad, int minus, + int plus, int space) +{ + char buf[PRINT_DEC_BUFSZ]; + int negative = 0; + int zero = (value == 0); + int len = print_dec(buf, (int)sizeof(buf), value); + print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, + plus, space, zero, negative, buf, len); +} + +/** print %lu */ +static void +print_num_lu(char** at, size_t* left, int* ret, unsigned long value, + int minw, int precision, int prgiven, int zeropad, int minus, + int plus, int space) +{ + char buf[PRINT_DEC_BUFSZ]; + int negative = 0; + int zero = (value == 0); + int len = print_dec_l(buf, (int)sizeof(buf), value); + print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, + plus, space, zero, negative, buf, len); +} + +/** print %llu */ +static void +print_num_llu(char** at, size_t* left, int* ret, unsigned long long value, + int minw, int precision, int prgiven, int zeropad, int minus, + int plus, int space) +{ + char buf[PRINT_DEC_BUFSZ]; + int negative = 0; + int zero = (value == 0); + int len = print_dec_ll(buf, (int)sizeof(buf), value); + print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, + plus, space, zero, negative, buf, len); +} -int snprintf (char *str, size_t count, const char *fmt, ...); -int vsnprintf (char *str, size_t count, const char *fmt, va_list arg); +/** print %x */ +static void +print_num_x(char** at, size_t* left, int* ret, unsigned int value, + int minw, int precision, int prgiven, int zeropad, int minus, + int plus, int space) +{ + char buf[PRINT_DEC_BUFSZ]; + int negative = 0; + int zero = (value == 0); + int len = print_hex(buf, (int)sizeof(buf), value); + print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, + plus, space, zero, negative, buf, len); +} -static void dopr (char *buffer, size_t maxlen, const char *format, - va_list args); -static void fmtstr (char *buffer, size_t *currlen, size_t maxlen, - char *value, int flags, int min, int max); -static void fmtint (char *buffer, size_t *currlen, size_t maxlen, - long value, int base, int min, int max, int flags); -static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, - long double fvalue, int min, int max, int flags); -static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c ); +/** print %lx */ +static void +print_num_lx(char** at, size_t* left, int* ret, unsigned long value, + int minw, int precision, int prgiven, int zeropad, int minus, + int plus, int space) +{ + char buf[PRINT_DEC_BUFSZ]; + int negative = 0; + int zero = (value == 0); + int len = print_hex_l(buf, (int)sizeof(buf), value); + print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, + plus, space, zero, negative, buf, len); +} -int vsnprintf (char *str, size_t count, const char *fmt, va_list args) +/** print %llx */ +static void +print_num_llx(char** at, size_t* left, int* ret, unsigned long long value, + int minw, int precision, int prgiven, int zeropad, int minus, + int plus, int space) { - str[0] = 0; - dopr(str, count, fmt, args); - return(strlen(str)); + char buf[PRINT_DEC_BUFSZ]; + int negative = 0; + int zero = (value == 0); + int len = print_hex_ll(buf, (int)sizeof(buf), value); + print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, + plus, space, zero, negative, buf, len); } -/* VARARGS3 */ -#ifdef HAVE_STDARGS -int snprintf (char *str,size_t count,const char *fmt,...) +/** print %llp */ +static void +print_num_llp(char** at, size_t* left, int* ret, void* value, + int minw, int precision, int prgiven, int zeropad, int minus, + int plus, int space) +{ + char buf[PRINT_DEC_BUFSZ]; + int negative = 0; + int zero = (value == 0); +#if defined(UINTPTR_MAX) && defined(UINT32_MAX) && (UINTPTR_MAX == UINT32_MAX) + /* avoid warning about upcast on 32bit systems */ + unsigned long long llvalue = (unsigned long)value; #else -int snprintf (va_alist) va_dcl + unsigned long long llvalue = (unsigned long long)value; #endif + int len = print_hex_ll(buf, (int)sizeof(buf), llvalue); + if(zero) { + buf[0]=')'; + buf[1]='l'; + buf[2]='i'; + buf[3]='n'; + buf[4]='('; + len = 5; + } else { + /* put '0x' in front of the (reversed) buffer result */ + if(len < PRINT_DEC_BUFSZ) + buf[len++] = 'x'; + if(len < PRINT_DEC_BUFSZ) + buf[len++] = '0'; + } + print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, + plus, space, zero, negative, buf, len); +} + +#define PRINT_FLOAT_BUFSZ 64 /* xx.yy with 20.20 about the max */ +/** spool remainder after the decimal point to buffer, in reverse */ +static int +print_remainder(char* buf, int max, double r, int prec) { -#ifndef HAVE_STDARGS - char *str; - size_t count; - char *fmt; -#endif - VA_LOCAL_DECL; - - VA_START (fmt); - VA_SHIFT (str, char *); - VA_SHIFT (count, size_t ); - VA_SHIFT (fmt, char *); - (void) vsnprintf(str, count, fmt, ap); - VA_END; - return(strlen(str)); -} - -/* - * dopr(): poor man's version of doprintf - */ + unsigned long long cap = 1; + unsigned long long value; + int len, i; + if(prec > 19) prec = 19; /* max we can do */ + if(max < prec) return 0; + for(i=0; i= 5) { + value++; + /* that might carry to numbers before the comma, if so, + * just ignore that rounding. failure because 64bitprintout */ + if(value >= cap) + value = cap-1; + } + len = print_dec_ll(buf, max, value); + while(len < prec) { /* pad with zeroes, e.g. if 0.0012 */ + buf[len++] = '0'; + } + if(len < max) + buf[len++] = '.'; + return len; +} -/* format read states */ -#define DP_S_DEFAULT 0 -#define DP_S_FLAGS 1 -#define DP_S_MIN 2 -#define DP_S_DOT 3 -#define DP_S_MAX 4 -#define DP_S_MOD 5 -#define DP_S_CONV 6 -#define DP_S_DONE 7 - -/* format flags - Bits */ -#define DP_F_MINUS 1 -#define DP_F_PLUS 2 -#define DP_F_SPACE 4 -#define DP_F_NUM 8 -#define DP_F_ZERO 16 -#define DP_F_UP 32 - -/* Conversion Flags */ -#define DP_C_SHORT 1 -#define DP_C_LONG 2 -#define DP_C_LDOUBLE 3 - -#define char_to_int(p) (p - '0') -#define MAX(p,q) ((p >= q) ? p : q) - -static void dopr (char *buffer, size_t maxlen, const char *format, va_list args) -{ - char ch; - long value; - long double fvalue; - char *strvalue; - int min; - int max; - int state; - int flags; - int cflags; - size_t currlen; - - state = DP_S_DEFAULT; - currlen = flags = cflags = min = 0; - max = -1; - ch = *format++; - - while (state != DP_S_DONE) - { - if ((ch == '\0') || (currlen >= maxlen)) - state = DP_S_DONE; - - switch(state) - { - case DP_S_DEFAULT: - if (ch == '%') - state = DP_S_FLAGS; - else - dopr_outch (buffer, &currlen, maxlen, ch); - ch = *format++; - break; - case DP_S_FLAGS: - switch (ch) - { - case '-': - flags |= DP_F_MINUS; - ch = *format++; - break; - case '+': - flags |= DP_F_PLUS; - ch = *format++; - break; - case ' ': - flags |= DP_F_SPACE; - ch = *format++; - break; - case '#': - flags |= DP_F_NUM; - ch = *format++; - break; - case '0': - flags |= DP_F_ZERO; - ch = *format++; - break; - default: - state = DP_S_MIN; - break; - } - break; - case DP_S_MIN: - if (isdigit((int) ch)) - { - min = 10*min + char_to_int (ch); - ch = *format++; - } - else if (ch == '*') - { - min = va_arg (args, int); - ch = *format++; - state = DP_S_DOT; - } - else - state = DP_S_DOT; - break; - case DP_S_DOT: - if (ch == '.') - { - state = DP_S_MAX; - ch = *format++; - } - else - state = DP_S_MOD; - break; - case DP_S_MAX: - if (isdigit((int) ch)) - { - if (max < 0) - max = 0; - max = 10*max + char_to_int (ch); - ch = *format++; - } - else if (ch == '*') - { - max = va_arg (args, int); - ch = *format++; - state = DP_S_MOD; - } - else - state = DP_S_MOD; - break; - case DP_S_MOD: - /* Currently, we don't support Long Long, bummer */ - switch (ch) - { - case 'h': - cflags = DP_C_SHORT; - ch = *format++; - break; - case 'l': - cflags = DP_C_LONG; - ch = *format++; - break; - case 'L': - cflags = DP_C_LDOUBLE; - ch = *format++; - break; - default: - break; - } - state = DP_S_CONV; - break; - case DP_S_CONV: - switch (ch) - { - case 'd': - case 'i': - if (cflags == DP_C_SHORT) - value = va_arg (args, int); - else if (cflags == DP_C_LONG) - value = va_arg (args, long int); - else - value = va_arg (args, int); - fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); - break; - case 'o': - flags &= ~DP_F_PLUS; - if (cflags == DP_C_SHORT) - value = va_arg (args, unsigned int); - else if (cflags == DP_C_LONG) - value = va_arg (args, unsigned long int); - else - value = va_arg (args, unsigned int); - fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); - break; - case 'u': - flags &= ~DP_F_PLUS; - if (cflags == DP_C_SHORT) - value = va_arg (args, unsigned int); - else if (cflags == DP_C_LONG) - value = va_arg (args, unsigned long int); - else - value = va_arg (args, unsigned int); - fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); - break; - case 'X': - flags |= DP_F_UP; - case 'x': - flags &= ~DP_F_PLUS; - if (cflags == DP_C_SHORT) - value = va_arg (args, unsigned int); - else if (cflags == DP_C_LONG) - value = va_arg (args, unsigned long int); - else - value = va_arg (args, unsigned int); - fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); - break; - case 'f': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg (args, long double); - else - fvalue = va_arg (args, double); - /* um, floating point? */ - fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); - break; - case 'E': - flags |= DP_F_UP; - case 'e': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg (args, long double); - else - fvalue = va_arg (args, double); - break; - case 'G': - flags |= DP_F_UP; - case 'g': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg (args, long double); - else - fvalue = va_arg (args, double); - break; - case 'c': - dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); - break; - case 's': - strvalue = va_arg (args, char *); - if (max < 0) - max = maxlen; /* ie, no max */ - fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max); - break; - case 'p': - strvalue = va_arg (args, void *); - fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); - break; - case 'n': - if (cflags == DP_C_SHORT) - { - short int *num; - num = va_arg (args, short int *); - *num = currlen; - } - else if (cflags == DP_C_LONG) - { - long int *num; - num = va_arg (args, long int *); - *num = currlen; - } - else - { - int *num; - num = va_arg (args, int *); - *num = currlen; - } - break; - case '%': - dopr_outch (buffer, &currlen, maxlen, ch); - break; - case 'w': - /* not supported yet, treat as next char */ - ch = *format++; - break; - default: - /* Unknown, skip */ - break; - } - ch = *format++; - state = DP_S_DEFAULT; - flags = cflags = min = 0; - max = -1; - break; - case DP_S_DONE: - break; - default: - /* hmm? */ - break; /* some picky compilers need this */ - } - } - if (currlen < maxlen - 1) - buffer[currlen] = '\0'; - else - buffer[maxlen - 1] = '\0'; -} - -static void fmtstr (char *buffer, size_t *currlen, size_t maxlen, - char *value, int flags, int min, int max) -{ - int padlen, strln; /* amount to pad */ - int cnt = 0; - - if (value == 0) - { - value = (char *) ""; - } - - for (strln = 0; value[strln]; ++strln); /* strlen */ - padlen = min - strln; - if (padlen < 0) - padlen = 0; - if (flags & DP_F_MINUS) - padlen = -padlen; /* Left Justify */ - - while ((padlen > 0) && (cnt < max)) - { - dopr_outch (buffer, currlen, maxlen, ' '); - --padlen; - ++cnt; - } - while (*value && (cnt < max)) - { - dopr_outch (buffer, currlen, maxlen, *value++); - ++cnt; - } - while ((padlen < 0) && (cnt < max)) - { - dopr_outch (buffer, currlen, maxlen, ' '); - ++padlen; - ++cnt; - } -} - -/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ - -static void fmtint (char *buffer, size_t *currlen, size_t maxlen, - long value, int base, int min, int max, int flags) -{ - int signvalue = 0; - unsigned long uvalue; - char convert[20]; - int place = 0; - int spadlen = 0; /* amount to space pad */ - int zpadlen = 0; /* amount to zero pad */ - int caps = 0; - - if (max < 0) - max = 0; - - uvalue = value; - if( value < 0 ) { - signvalue = '-'; - uvalue = -value; - } - else - if (flags & DP_F_PLUS) /* Do a sign (+/i) */ - signvalue = '+'; - else - if (flags & DP_F_SPACE) - signvalue = ' '; - - if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ - - do { - convert[place++] = - (caps? "0123456789ABCDEF":"0123456789abcdef") - [uvalue % (unsigned)base ]; - uvalue = (uvalue / (unsigned)base ); - } while(uvalue && (place < 20)); - if (place == 20) place--; - convert[place] = 0; - - zpadlen = max - place; - spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); - if (zpadlen < 0) zpadlen = 0; - if (spadlen < 0) spadlen = 0; - if (flags & DP_F_ZERO) - { - zpadlen = MAX(zpadlen, spadlen); - spadlen = 0; - } - if (flags & DP_F_MINUS) - spadlen = -spadlen; /* Left Justifty */ - -#ifdef DEBUG_SNPRINTF - dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", - zpadlen, spadlen, min, max, place)); -#endif +/** spool floating point to buffer */ +static int +print_float(char* buf, int max, double value, int prec) +{ + /* as xxx.xxx if prec==0, no '.', with prec decimals after . */ + /* no conversion for NAN and INF, because we do not want to require + linking with -lm. */ + /* Thus, the conversions use 64bit integers to convert the numbers, + * which makes 19 digits before and after the decimal point the max */ + unsigned long long whole = (unsigned long long)value; + double remain = value - (double)whole; + int len = 0; + if(prec != 0) + len = print_remainder(buf, max, remain, prec); + len += print_dec_ll(buf+len, max-len, whole); + return len; +} - /* Spaces */ - while (spadlen > 0) - { - dopr_outch (buffer, currlen, maxlen, ' '); - --spadlen; - } - - /* Sign */ - if (signvalue) - dopr_outch (buffer, currlen, maxlen, signvalue); - - /* Zeros */ - if (zpadlen > 0) - { - while (zpadlen > 0) - { - dopr_outch (buffer, currlen, maxlen, '0'); - --zpadlen; - } - } - - /* Digits */ - while (place > 0) - dopr_outch (buffer, currlen, maxlen, convert[--place]); - - /* Left Justified spaces */ - while (spadlen < 0) { - dopr_outch (buffer, currlen, maxlen, ' '); - ++spadlen; - } -} - -static long double abs_val (long double value) -{ - long double result = value; - - if (value < 0) - result = -value; - - return result; -} - -static double pow10 (double exp) -{ - long double result = 1; - - while (exp) - { - result *= 10; - exp--; - } - - return result; -} - -static double round (double value) -{ - long intpart; - - intpart = value; - value = value - intpart; - if (value >= 0.5) - intpart++; - - return intpart; -} - -static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, - long double fvalue, int min, int max, int flags) -{ - int signvalue = 0; - long double ufvalue; - char iconvert[20]; - char fconvert[20]; - int iplace = 0; - int fplace = 0; - int padlen = 0; /* amount to pad */ - int zpadlen = 0; - int caps = 0; - long intpart; - long fracpart; - - /* - * AIX manpage says the default is 0, but Solaris says the default - * is 6, and sprintf on AIX defaults to 6 - */ - if (max < 0) - max = 6; - - ufvalue = abs_val (fvalue); - - if (fvalue < 0) - signvalue = '-'; - else - if (flags & DP_F_PLUS) /* Do a sign (+/i) */ - signvalue = '+'; - else - if (flags & DP_F_SPACE) - signvalue = ' '; - -#if 0 - if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ -#endif +/** print %f */ +static void +print_num_f(char** at, size_t* left, int* ret, double value, + int minw, int precision, int prgiven, int zeropad, int minus, + int plus, int space) +{ + char buf[PRINT_FLOAT_BUFSZ]; + int negative = (value < 0); + int zero = 0; + int len; + if(!prgiven) precision = 6; + len = print_float(buf, (int)sizeof(buf), negative?-value:value, + precision); + print_num(at, left, ret, minw, 1, 0, zeropad, minus, + plus, space, zero, negative, buf, len); +} - intpart = ufvalue; +/* rudimentary %g support */ +static int +print_float_g(char* buf, int max, double value, int prec) +{ + unsigned long long whole = (unsigned long long)value; + double remain = value - (double)whole; + int before = 0; + int len = 0; + + /* number of digits before the decimal point */ + while(whole > 0) { + before++; + whole /= 10; + } + whole = (unsigned long long)value; + + if(prec > before && remain != 0.0) { + /* see if the last decimals are zero, if so, skip them */ + len = print_remainder(buf, max, remain, prec-before); + while(len > 0 && buf[0]=='0') { + memmove(buf, buf+1, --len); + } + } + len += print_dec_ll(buf+len, max-len, whole); + return len; +} - /* - * Sorry, we only support 9 digits past the decimal because of our - * conversion method - */ - if (max > 9) - max = 9; - /* We "cheat" by converting the fractional part to integer by - * multiplying by a factor of 10 - */ - fracpart = round ((pow10 (max)) * (ufvalue - intpart)); +/** print %g */ +static void +print_num_g(char** at, size_t* left, int* ret, double value, + int minw, int precision, int prgiven, int zeropad, int minus, + int plus, int space) +{ + char buf[PRINT_FLOAT_BUFSZ]; + int negative = (value < 0); + int zero = 0; + int len; + if(!prgiven) precision = 6; + if(precision == 0) precision = 1; + len = print_float_g(buf, (int)sizeof(buf), negative?-value:value, + precision); + print_num(at, left, ret, minw, 1, 0, zeropad, minus, + plus, space, zero, negative, buf, len); +} - if (fracpart >= pow10 (max)) - { - intpart++; - fracpart -= pow10 (max); - } -#ifdef DEBUG_SNPRINTF - dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart)); -#endif +/** strnlen (compat implementation) */ +static int +my_strnlen(const char* s, int max) +{ + int i; + for(i=0; i 0)) - { - if (signvalue) - { - dopr_outch (buffer, currlen, maxlen, signvalue); - --padlen; - signvalue = 0; - } - while (padlen > 0) - { - dopr_outch (buffer, currlen, maxlen, '0'); - --padlen; - } - } - while (padlen > 0) - { - dopr_outch (buffer, currlen, maxlen, ' '); - --padlen; - } - if (signvalue) - dopr_outch (buffer, currlen, maxlen, signvalue); - - while (iplace > 0) - dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); - - /* - * Decimal point. This should probably use locale to find the correct - * char to print out. - */ - dopr_outch (buffer, currlen, maxlen, '.'); - - while (zpadlen > 0) - { - dopr_outch (buffer, currlen, maxlen, '0'); - --zpadlen; - } - - while (fplace > 0) - dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); - - while (padlen < 0) - { - dopr_outch (buffer, currlen, maxlen, ' '); - ++padlen; - } -} - -static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c) -{ - if (*currlen < maxlen) - buffer[(*currlen)++] = c; -} - -#ifdef TEST_SNPRINTF -#ifndef LONG_STRING -#define LONG_STRING 1024 -#endif -int main (void) -{ - char buf1[LONG_STRING]; - char buf2[LONG_STRING]; - char *fp_fmt[] = { - "%-1.5f", - "%1.5f", - "%123.9f", - "%10.5f", - "% 10.5f", - "%+22.9f", - "%+4.9f", - "%01.3f", - "%4f", - "%3.1f", - "%3.2f", - NULL - }; - double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996, - 0.9996, 1.996, 4.136, 0}; - char *int_fmt[] = { - "%-1.5d", - "%1.5d", - "%123.9d", - "%5.5d", - "%10.5d", - "% 10.5d", - "%+22.33d", - "%01.3d", - "%4d", - NULL - }; - long int_nums[] = { -1, 134, 91340, 341, 0203, 0}; - int x, y; - int fail = 0; - int num = 0; - - printf ("Testing snprintf format codes against system sprintf...\n"); - - for (x = 0; fp_fmt[x] != NULL ; x++) - for (y = 0; fp_nums[y] != 0 ; y++) - { - snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]); - sprintf (buf2, fp_fmt[x], fp_nums[y]); - if (strcmp (buf1, buf2)) - { - printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n", - fp_fmt[x], buf1, buf2); - fail++; - } - num++; - } - - for (x = 0; int_fmt[x] != NULL ; x++) - for (y = 0; int_nums[y] != 0 ; y++) - { - snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]); - sprintf (buf2, int_fmt[x], int_nums[y]); - if (strcmp (buf1, buf2)) - { - printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n", - int_fmt[x], buf1, buf2); - fail++; - } - num++; - } - printf ("%d tests failed out of %d.\n", fail, num); +/** print %s */ +static void +print_str(char** at, size_t* left, int* ret, char* s, + int minw, int precision, int prgiven, int minus) +{ + int w; + /* with prec: no more than x characters from this string, stop at 0 */ + if(prgiven) + w = my_strnlen(s, precision); + else w = (int)strlen(s); /* up to the nul */ + if(w < minw && !minus) + print_pad(at, left, ret, ' ', minw - w); + spool_str(at, left, ret, s, w); + if(w < minw && minus) + print_pad(at, left, ret, ' ', minw - w); +} + +/** print %c */ +static void +print_char(char** at, size_t* left, int* ret, int c, + int minw, int minus) +{ + if(1 < minw && !minus) + print_pad(at, left, ret, ' ', minw - 1); + print_pad(at, left, ret, c, 1); + if(1 < minw && minus) + print_pad(at, left, ret, ' ', minw - 1); +} + + +/** + * Print to string. + * str: string buffer for result. result will be null terminated. + * size: size of the buffer. null is put inside buffer. + * format: printf format string. + * arg: '...' arguments to print. + * returns number of characters. a null is printed after this. + * return number of bytes that would have been written + * if the buffer had been large enough. + * + * supported format specifiers: + * %s, %u, %d, %x, %i, %f, %g, %c, %p, %n. + * length: l, ll (for d, u, x). + * precision: 6.6d (for d, u, x) + * %f, %g precisions, 0.3f + * %20s, '.*s' + * and %%. + */ +int vsnprintf(char* str, size_t size, const char* format, va_list arg) +{ + char* at = str; + size_t left = size; + int ret = 0; + const char* fmt = format; + int conv, minw, precision, prgiven, zeropad, minus, plus, space, length; + while(*fmt) { + /* copy string before % */ + while(*fmt && *fmt!='%') { + if(left > 1) { + *at++ = *fmt++; + left--; + } else fmt++; + ret++; + } + + /* see if we are at end */ + if(!*fmt) break; + + /* fetch next argument % designation from format string */ + fmt++; /* skip the '%' */ + + /********************************/ + /* get the argument designation */ + /********************************/ + /* we must do this vararg stuff inside this function for + * portability. Hence, get_designation, and print_designation + * are not their own functions. */ + + /* printout designation: + * conversion specifier: x, d, u, s, c, n, m, p + * flags: # not supported + * 0 zeropad (on the left) + * - left adjust (right by default) + * ' ' printspace for positive number (in - position). + * + alwayssign + * fieldwidth: [1-9][0-9]* minimum field width. + * if this is * then type int next argument specifies the minwidth. + * if this is negative, the - flag is set (with positive width). + * precision: period[digits]*, %.2x. + * if this is * then type int next argument specifies the precision. + * just '.' or negative value means precision=0. + * this is mindigits to print for d, i, u, x + * this is aftercomma digits for f + * this is max number significant digits for g + * maxnumber characters to be printed for s + * length: 0-none (int), 1-l (long), 2-ll (long long) + * notsupported: hh (char), h (short), L (long double), q, j, z, t + * Does not support %m$ and *m$ argument designation as array indices. + * Does not support %#x + * + */ + minw = 0; + precision = 1; + prgiven = 0; + zeropad = 0; + minus = 0; + plus = 0; + space = 0; + length = 0; + + /* get flags in any order */ + for(;;) { + if(*fmt == '0') + zeropad = 1; + else if(*fmt == '-') + minus = 1; + else if(*fmt == '+') + plus = 1; + else if(*fmt == ' ') + space = 1; + else break; + fmt++; + } + + /* field width */ + if(*fmt == '*') { + fmt++; /* skip char */ + minw = va_arg(arg, int); + if(minw < 0) { + minus = 1; + minw = -minw; + } + } else while(*fmt >= '0' && *fmt <= '9') { + minw = minw*10 + (*fmt++)-'0'; + } + + /* precision */ + if(*fmt == '.') { + fmt++; /* skip period */ + prgiven = 1; + precision = 0; + if(*fmt == '*') { + fmt++; /* skip char */ + precision = va_arg(arg, int); + if(precision < 0) + precision = 0; + } else while(*fmt >= '0' && *fmt <= '9') { + precision = precision*10 + (*fmt++)-'0'; + } + } + + /* length */ + if(*fmt == 'l') { + fmt++; /* skip char */ + length = 1; + if(*fmt == 'l') { + fmt++; /* skip char */ + length = 2; + } + } + + /* get the conversion */ + if(!*fmt) conv = 0; + else conv = *fmt++; + + /***********************************/ + /* print that argument designation */ + /***********************************/ + switch(conv) { + case 'i': + case 'd': + if(length == 0) + print_num_d(&at, &left, &ret, va_arg(arg, int), + minw, precision, prgiven, zeropad, minus, plus, space); + else if(length == 1) + print_num_ld(&at, &left, &ret, va_arg(arg, long), + minw, precision, prgiven, zeropad, minus, plus, space); + else if(length == 2) + print_num_lld(&at, &left, &ret, + va_arg(arg, long long), + minw, precision, prgiven, zeropad, minus, plus, space); + break; + case 'u': + if(length == 0) + print_num_u(&at, &left, &ret, + va_arg(arg, unsigned int), + minw, precision, prgiven, zeropad, minus, plus, space); + else if(length == 1) + print_num_lu(&at, &left, &ret, + va_arg(arg, unsigned long), + minw, precision, prgiven, zeropad, minus, plus, space); + else if(length == 2) + print_num_llu(&at, &left, &ret, + va_arg(arg, unsigned long long), + minw, precision, prgiven, zeropad, minus, plus, space); + break; + case 'x': + if(length == 0) + print_num_x(&at, &left, &ret, + va_arg(arg, unsigned int), + minw, precision, prgiven, zeropad, minus, plus, space); + else if(length == 1) + print_num_lx(&at, &left, &ret, + va_arg(arg, unsigned long), + minw, precision, prgiven, zeropad, minus, plus, space); + else if(length == 2) + print_num_llx(&at, &left, &ret, + va_arg(arg, unsigned long long), + minw, precision, prgiven, zeropad, minus, plus, space); + break; + case 's': + print_str(&at, &left, &ret, va_arg(arg, char*), + minw, precision, prgiven, minus); + break; + case 'c': + print_char(&at, &left, &ret, va_arg(arg, int), + minw, minus); + break; + case 'n': + *va_arg(arg, int*) = ret; + break; + case 'm': + print_str(&at, &left, &ret, strerror(errno), + minw, precision, prgiven, minus); + break; + case 'p': + print_num_llp(&at, &left, &ret, va_arg(arg, void*), + minw, precision, prgiven, zeropad, minus, plus, space); + break; + case '%': + print_pad(&at, &left, &ret, '%', 1); + break; + case 'f': + print_num_f(&at, &left, &ret, va_arg(arg, double), + minw, precision, prgiven, zeropad, minus, plus, space); + break; + case 'g': + print_num_g(&at, &left, &ret, va_arg(arg, double), + minw, precision, prgiven, zeropad, minus, plus, space); + break; + /* unknown */ + default: + case 0: break; + } + } + + /* zero terminate */ + if(left > 0) + *at = 0; + return ret; } -#endif /* SNPRINTF_TEST */ -#endif /* !HAVE_SNPRINTF */ +#ifdef SNPRINTF_TEST + +/** do tests */ +#undef snprintf +#define DOTEST(bufsz, result, retval, ...) do { \ + char buf[bufsz]; \ + printf("now test %s\n", #__VA_ARGS__); \ + int r=my_snprintf(buf, sizeof(buf), __VA_ARGS__); \ + if(r != retval || strcmp(buf, result) != 0) { \ + printf("error test(%s) was \"%s\":%d\n", \ + ""#bufsz", "#result", "#retval", "#__VA_ARGS__, \ + buf, r); \ + exit(1); \ + } \ + r=snprintf(buf, sizeof(buf), __VA_ARGS__); \ + if(r != retval || strcmp(buf, result) != 0) { \ + printf("error test(%s) differs with system, \"%s\":%d\n", \ + ""#bufsz", "#result", "#retval", "#__VA_ARGS__, \ + buf, r); \ + exit(1); \ + } \ + printf("test(\"%s\":%d) passed\n", buf, r); \ + } while(0); + +/** test program */ +int main(void) +{ + int x = 0; + + /* bufsize, expectedstring, expectedretval, snprintf arguments */ + DOTEST(1024, "hello", 5, "hello"); + DOTEST(1024, "h", 1, "h"); + /* warning from gcc for format string, but it does work + * DOTEST(1024, "", 0, ""); */ + + DOTEST(3, "he", 5, "hello"); + DOTEST(1, "", 7, "%d", 7823089); + + /* test positive numbers */ + DOTEST(1024, "0", 1, "%d", 0); + DOTEST(1024, "1", 1, "%d", 1); + DOTEST(1024, "9", 1, "%d", 9); + DOTEST(1024, "15", 2, "%d", 15); + DOTEST(1024, "ab15cd", 6, "ab%dcd", 15); + DOTEST(1024, "167", 3, "%d", 167); + DOTEST(1024, "7823089", 7, "%d", 7823089); + DOTEST(1024, " 12", 3, "%3d", 12); + DOTEST(1024, "012", 3, "%.3d", 12); + DOTEST(1024, "012", 3, "%3.3d", 12); + DOTEST(1024, "012", 3, "%03d", 12); + DOTEST(1024, " 012", 4, "%4.3d", 12); + DOTEST(1024, "", 0, "%.0d", 0); + + /* test negative numbers */ + DOTEST(1024, "-1", 2, "%d", -1); + DOTEST(1024, "-12", 3, "%3d", -12); + DOTEST(1024, " -2", 3, "%3d", -2); + DOTEST(1024, "-012", 4, "%.3d", -12); + DOTEST(1024, "-012", 4, "%3.3d", -12); + DOTEST(1024, "-012", 4, "%4.3d", -12); + DOTEST(1024, " -012", 5, "%5.3d", -12); + DOTEST(1024, "-12", 3, "%03d", -12); + DOTEST(1024, "-02", 3, "%03d", -2); + DOTEST(1024, "-15", 3, "%d", -15); + DOTEST(1024, "-7307", 5, "%d", -7307); + DOTEST(1024, "-12 ", 5, "%-5d", -12); + DOTEST(1024, "-00012", 6, "%-.5d", -12); + + /* test + and space flags */ + DOTEST(1024, "+12", 3, "%+d", 12); + DOTEST(1024, " 12", 3, "% d", 12); + + /* test %u */ + DOTEST(1024, "12", 2, "%u", 12); + DOTEST(1024, "0", 1, "%u", 0); + DOTEST(1024, "4294967295", 10, "%u", 0xffffffff); + + /* test %x */ + DOTEST(1024, "0", 1, "%x", 0); + DOTEST(1024, "c", 1, "%x", 12); + DOTEST(1024, "12ab34cd", 8, "%x", 0x12ab34cd); + + /* test %llu, %lld */ + DOTEST(1024, "18446744073709551615", 20, "%llu", + (long long)0xffffffffffffffff); + DOTEST(1024, "-9223372036854775808", 20, "%lld", + (long long)0x8000000000000000); + DOTEST(1024, "9223372036854775808", 19, "%llu", + (long long)0x8000000000000000); + + /* test %s */ + DOTEST(1024, "hello", 5, "%s", "hello"); + DOTEST(1024, " hello", 10, "%10s", "hello"); + DOTEST(1024, "hello ", 10, "%-10s", "hello"); + DOTEST(1024, "he", 2, "%.2s", "hello"); + DOTEST(1024, " he", 4, "%4.2s", "hello"); + DOTEST(1024, " h", 4, "%4.2s", "h"); + + /* test %c */ + DOTEST(1024, "a", 1, "%c", 'a'); + /* warning from gcc for format string, but it does work + DOTEST(1024, " a", 5, "%5c", 'a'); + DOTEST(1024, "a", 1, "%.0c", 'a'); */ + + /* test %n */ + DOTEST(1024, "hello", 5, "hello%n", &x); + if(x != 5) { printf("the %%n failed\n"); exit(1); } + + /* test %m */ + errno = 0; + DOTEST(1024, "Success", 7, "%m"); + + /* test %p */ + DOTEST(1024, "0x10", 4, "%p", (void*)0x10); + DOTEST(1024, "(nil)", 5, "%p", (void*)0x0); + + /* test %% */ + DOTEST(1024, "%", 1, "%%"); + + /* test %f */ + DOTEST(1024, "0.000000", 8, "%f", 0.0); + DOTEST(1024, "0.00", 4, "%.2f", 0.0); + /* differs, "-0.00" DOTEST(1024, "0.00", 4, "%.2f", -0.0); */ + DOTEST(1024, "234.00", 6, "%.2f", 234.005); + DOTEST(1024, "8973497.1246", 12, "%.4f", 8973497.12456); + DOTEST(1024, "-12.000000", 10, "%f", -12.0); + DOTEST(1024, "6", 1, "%.0f", 6.0); + + DOTEST(1024, "6", 1, "%g", 6.0); + DOTEST(1024, "6.1", 3, "%g", 6.1); + DOTEST(1024, "6.15", 4, "%g", 6.15); + + /* These format strings are from the code of NSD, Unbound, ldns */ + + DOTEST(1024, "abcdef", 6, "%s", "abcdef"); + DOTEST(1024, "005", 3, "%03u", 5); + DOTEST(1024, "12345", 5, "%03u", 12345); + DOTEST(1024, "5", 1, "%d", 5); + DOTEST(1024, "(nil)", 5, "%p", NULL); + DOTEST(1024, "12345", 5, "%ld", (long)12345); + DOTEST(1024, "12345", 5, "%lu", (long)12345); + DOTEST(1024, " 12345", 12, "%12u", (unsigned)12345); + DOTEST(1024, "12345", 5, "%u", (unsigned)12345); + DOTEST(1024, "12345", 5, "%llu", (unsigned long long)12345); + DOTEST(1024, "12345", 5, "%x", 0x12345); + DOTEST(1024, "12345", 5, "%llx", (long long)0x12345); + DOTEST(1024, "012345", 6, "%6.6d", 12345); + DOTEST(1024, "012345", 6, "%6.6u", 12345); + DOTEST(1024, "1234.54", 7, "%g", 1234.54); + DOTEST(1024, "123456789.54", 12, "%.12g", 123456789.54); + DOTEST(1024, "3456789123456.54", 16, "%.16g", 3456789123456.54); + /* %24g does not work with 24 digits, not enough accuracy, + * the first 16 digits are correct */ + DOTEST(1024, "12345", 5, "%3.3d", 12345); + DOTEST(1024, "000", 3, "%3.3d", 0); + DOTEST(1024, "001", 3, "%3.3d", 1); + DOTEST(1024, "012", 3, "%3.3d", 12); + DOTEST(1024, "-012", 4, "%3.3d", -12); + DOTEST(1024, "he", 2, "%.2s", "hello"); + DOTEST(1024, "helloworld", 10, "%s%s", "hello", "world"); + DOTEST(1024, "he", 2, "%.*s", 2, "hello"); + DOTEST(1024, " hello", 7, "%*s", 7, "hello"); + DOTEST(1024, "hello ", 7, "%*s", -7, "hello"); + DOTEST(1024, "0", 1, "%c", '0'); + DOTEST(1024, "A", 1, "%c", 'A'); + DOTEST(1024, "", 1, "%c", 0); + DOTEST(1024, "\010", 1, "%c", 8); + DOTEST(1024, "%", 1, "%%"); + DOTEST(1024, "0a", 2, "%02x", 0x0a); + DOTEST(1024, "bd", 2, "%02x", 0xbd); + DOTEST(1024, "12", 2, "%02ld", (long)12); + DOTEST(1024, "02", 2, "%02ld", (long)2); + DOTEST(1024, "02", 2, "%02u", (unsigned)2); + DOTEST(1024, "765432", 6, "%05u", (unsigned)765432); + DOTEST(1024, "10.234", 6, "%0.3f", 10.23421); + DOTEST(1024, "123456.234", 10, "%0.3f", 123456.23421); + DOTEST(1024, "123456789.234", 13, "%0.3f", 123456789.23421); + DOTEST(1024, "123456.23", 9, "%.2f", 123456.23421); + DOTEST(1024, "123456", 6, "%.0f", 123456.23421); + DOTEST(1024, "0123", 4, "%.4x", 0x0123); + DOTEST(1024, "00000123", 8, "%.8x", 0x0123); + DOTEST(1024, "ffeb0cde", 8, "%.8x", 0xffeb0cde); + DOTEST(1024, " 987654321", 10, "%10lu", (unsigned long)987654321); + DOTEST(1024, " 987654321", 12, "%12lu", (unsigned long)987654321); + DOTEST(1024, "987654321", 9, "%i", 987654321); + DOTEST(1024, "-87654321", 9, "%i", -87654321); + DOTEST(1024, "hello ", 16, "%-16s", "hello"); + DOTEST(1024, " ", 16, "%-16s", ""); + DOTEST(1024, "a ", 16, "%-16s", "a"); + DOTEST(1024, "foobarfoobar ", 16, "%-16s", "foobarfoobar"); + DOTEST(1024, "foobarfoobarfoobar", 18, "%-16s", "foobarfoobarfoobar"); + + /* combined expressions */ + DOTEST(1024, "foo 1.0 size 512 edns", 21, + "foo %s size %d %s%s", "1.0", 512, "", "edns"); + DOTEST(15, "foo 1.0 size 5", 21, + "foo %s size %d %s%s", "1.0", 512, "", "edns"); + DOTEST(1024, "packet 1203ceff id", 18, + "packet %2.2x%2.2x%2.2x%2.2x id", 0x12, 0x03, 0xce, 0xff); + DOTEST(1024, "/tmp/testbound_123abcd.tmp", 26, "/tmp/testbound_%u%s%s.tmp", 123, "ab", "cd"); + + return 0; +} +#endif /* SNPRINTF_TEST */ diff --git a/usr.sbin/unbound/ldns/dane.c b/usr.sbin/unbound/ldns/dane.c index 793005ddcb3..675dfa8bf33 100644 --- a/usr.sbin/unbound/ldns/dane.c +++ b/usr.sbin/unbound/ldns/dane.c @@ -8,6 +8,7 @@ */ #include +#ifdef USE_DANE #include #include @@ -15,8 +16,12 @@ #include #include #include +#ifdef HAVE_SYS_SOCKET_H #include +#endif +#ifdef HAVE_NETDB_H #include +#endif #ifdef HAVE_SSL #include @@ -119,13 +124,13 @@ ldns_dane_cert2rdf(ldns_rdf** rdf, X509* cert, case LDNS_TLSA_MATCHING_TYPE_SHA256: - digest = LDNS_XMALLOC(unsigned char, SHA256_DIGEST_LENGTH); + digest = LDNS_XMALLOC(unsigned char, LDNS_SHA256_DIGEST_LENGTH); if (digest == NULL) { LDNS_FREE(buf); return LDNS_STATUS_MEM_ERR; } (void) ldns_sha256(buf, (unsigned int)len, digest); - *rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, SHA256_DIGEST_LENGTH, + *rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, LDNS_SHA256_DIGEST_LENGTH, digest); LDNS_FREE(buf); @@ -134,13 +139,13 @@ ldns_dane_cert2rdf(ldns_rdf** rdf, X509* cert, case LDNS_TLSA_MATCHING_TYPE_SHA512: - digest = LDNS_XMALLOC(unsigned char, SHA512_DIGEST_LENGTH); + digest = LDNS_XMALLOC(unsigned char, LDNS_SHA512_DIGEST_LENGTH); if (digest == NULL) { LDNS_FREE(buf); return LDNS_STATUS_MEM_ERR; } (void) ldns_sha512(buf, (unsigned int)len, digest); - *rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, SHA512_DIGEST_LENGTH, + *rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, LDNS_SHA512_DIGEST_LENGTH, digest); LDNS_FREE(buf); @@ -740,3 +745,4 @@ ldns_dane_verify(ldns_rr_list* tlsas, return s; } #endif /* HAVE_SSL */ +#endif /* USE_DANE */ diff --git a/usr.sbin/unbound/ldns/dnssec.c b/usr.sbin/unbound/ldns/dnssec.c index 684d17169e2..a41a9f633c4 100644 --- a/usr.sbin/unbound/ldns/dnssec.c +++ b/usr.sbin/unbound/ldns/dnssec.c @@ -654,103 +654,113 @@ ldns_key_rr2ds(const ldns_rr *key, ldns_hash h) return ds; } +/* From RFC3845: + * + * 2.1.2. The List of Type Bit Map(s) Field + * + * The RR type space is split into 256 window blocks, each representing + * the low-order 8 bits of the 16-bit RR type space. Each block that + * has at least one active RR type is encoded using a single octet + * window number (from 0 to 255), a single octet bitmap length (from 1 + * to 32) indicating the number of octets used for the window block's + * bitmap, and up to 32 octets (256 bits) of bitmap. + * + * Window blocks are present in the NSEC RR RDATA in increasing + * numerical order. + * + * "|" denotes concatenation + * + * Type Bit Map(s) Field = ( Window Block # | Bitmap Length | Bitmap ) + + * + * + * + * Blocks with no types present MUST NOT be included. Trailing zero + * octets in the bitmap MUST be omitted. The length of each block's + * bitmap is determined by the type code with the largest numerical + * value within that block, among the set of RR types present at the + * NSEC RR's owner name. Trailing zero octets not specified MUST be + * interpreted as zero octets. + */ ldns_rdf * ldns_dnssec_create_nsec_bitmap(ldns_rr_type rr_type_list[], size_t size, ldns_rr_type nsec_type) { - size_t i; - uint8_t *bitmap; - uint16_t bm_len = 0; - uint16_t i_type; - ldns_rdf *bitmap_rdf; + uint8_t window; /* most significant octet of type */ + uint8_t subtype; /* least significant octet of type */ + uint16_t windows[256] /* Max subtype per window */ +#ifndef S_SPLINT_S + = { 0 } /* Initialize ALL elements with 0 */ +#endif + ; + ldns_rr_type* d; /* used to traverse rr_type_list*/ + size_t i; /* used to traverse windows array */ - uint8_t *data = NULL; - uint8_t cur_data[32]; - uint8_t cur_window = 0; - uint8_t cur_window_max = 0; - uint16_t cur_data_size = 0; + size_t sz; /* size needed for type bitmap rdf */ + uint8_t* data = NULL; /* rdf data */ + uint8_t* dptr; /* used to itraverse rdf data */ + ldns_rdf* rdf; /* bitmap rdf to return */ if (nsec_type != LDNS_RR_TYPE_NSEC && nsec_type != LDNS_RR_TYPE_NSEC3) { return NULL; } - i_type = 0; - for (i = 0; i < size; i++) { - if (i_type < rr_type_list[i]) - i_type = rr_type_list[i]; - } - if (i_type < nsec_type) { - i_type = nsec_type; - } - - bm_len = i_type / 8 + 2; - bitmap = LDNS_XMALLOC(uint8_t, bm_len); - if(!bitmap) return NULL; - for (i = 0; i < bm_len; i++) { - bitmap[i] = 0; - } - - for (i = 0; i < size; i++) { - i_type = rr_type_list[i]; - ldns_set_bit(bitmap + (int) i_type / 8, - (int) (7 - (i_type % 8)), - true); - } - - /* fold it into windows TODO: can this be done directly? */ - memset(cur_data, 0, 32); - for (i = 0; i < bm_len; i++) { - if (i / 32 > cur_window) { - /* check, copy, new */ - if (cur_window_max > 0) { - /* this window has stuff, add it */ - data = LDNS_XREALLOC(data, - uint8_t, - cur_data_size + cur_window_max + 3); - if(!data) { - LDNS_FREE(bitmap); - return NULL; - } - data[cur_data_size] = cur_window; - data[cur_data_size + 1] = cur_window_max + 1; - memcpy(data + cur_data_size + 2, - cur_data, - cur_window_max+1); - cur_data_size += cur_window_max + 3; - } - cur_window++; - cur_window_max = 0; - memset(cur_data, 0, 32); + /* Which other windows need to be in the bitmap rdf? + */ + for (d = rr_type_list; d < rr_type_list + size; d++) { + window = *d >> 8; + subtype = *d & 0xff; + if (windows[window] < subtype) { + windows[window] = subtype; } - cur_data[i%32] = bitmap[i]; - if (bitmap[i] > 0) { - cur_window_max = i%32; + } + + /* How much space do we need in the rdf for those windows? + */ + sz = 0; + for (i = 0; i < 256; i++) { + if (windows[i]) { + sz += windows[i] / 8 + 3; } } - if (cur_window_max > 0 || cur_data[0] != 0) { - /* this window has stuff, add it */ - data = LDNS_XREALLOC(data, - uint8_t, - cur_data_size + cur_window_max + 3); - if(!data) { - LDNS_FREE(bitmap); - return NULL; - } - data[cur_data_size] = cur_window; - data[cur_data_size + 1] = cur_window_max + 1; - memcpy(data + cur_data_size + 2, cur_data, cur_window_max+1); - cur_data_size += cur_window_max + 3; + if (sz > 0) { + /* Format rdf data according RFC3845 Section 2.1.2 (see above) + */ + dptr = data = LDNS_CALLOC(uint8_t, sz); + if (!data) { + return NULL; + } + for (i = 0; i < 256; i++) { + if (windows[i]) { + *dptr++ = (uint8_t)i; + *dptr++ = (uint8_t)(windows[i] / 8 + 1); + + /* Now let windows[i] index the bitmap + * within data + */ + windows[i] = (uint16_t)(dptr - data); + + dptr += dptr[-1]; + } + } } - bitmap_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_NSEC, - cur_data_size, - data); - LDNS_FREE(bitmap); - LDNS_FREE(data); + /* Set the bits? + */ + for (d = rr_type_list; d < rr_type_list + size; d++) { + subtype = *d & 0xff; + data[windows[*d >> 8] + subtype/8] |= (0x80 >> (subtype % 8)); + } - return bitmap_rdf; + /* Allocate and return rdf structure for the data + */ + rdf = ldns_rdf_new(LDNS_RDF_TYPE_BITMAP, sz, data); + if (!rdf) { + LDNS_FREE(data); + return NULL; + } + return rdf; } int @@ -987,7 +997,9 @@ ldns_nsec3_hash_name(ldns_rdf *name, /* prepare the owner name according to the draft section bla */ cann = ldns_rdf_clone(name); if(!cann) { +#ifdef STDERR_MSGS fprintf(stderr, "Memory error\n"); +#endif return NULL; } ldns_dname2canonical(cann); @@ -1032,11 +1044,13 @@ ldns_nsec3_hash_name(ldns_rdf *name, hashed_owner_b32, ldns_b32_ntop_calculate_size(hashed_owner_str_len)+1); if (hashed_owner_b32_len < 1) { +#ifdef STDERR_MSGS fprintf(stderr, "Error in base32 extended hex encoding "); fprintf(stderr, "of hashed owner name (name: "); ldns_rdf_print(stderr, name); fprintf(stderr, ", return code: %u)\n", (unsigned int) hashed_owner_b32_len); +#endif LDNS_FREE(hashed_owner_b32); return NULL; } @@ -1044,7 +1058,9 @@ ldns_nsec3_hash_name(ldns_rdf *name, status = ldns_str2rdf_dname(&hashed_owner, hashed_owner_b32); if (status != LDNS_STATUS_OK) { +#ifdef STDERR_MSGS fprintf(stderr, "Error creating rdf from %s\n", hashed_owner_b32); +#endif LDNS_FREE(hashed_owner_b32); return NULL; } @@ -1338,38 +1354,120 @@ ldns_nsec3_hash_name_frm_nsec3(const ldns_rr *nsec, ldns_rdf *name) } bool -ldns_nsec_bitmap_covers_type(const ldns_rdf *nsec_bitmap, ldns_rr_type type) +ldns_nsec_bitmap_covers_type(const ldns_rdf* bitmap, ldns_rr_type type) { - uint8_t window_block_nr; - uint8_t bitmap_length; - uint16_t cur_type; - uint16_t pos = 0; - uint16_t bit_pos; - uint8_t *data; - - if (nsec_bitmap == NULL) { + uint8_t* dptr; + uint8_t* dend; + + /* From RFC3845 Section 2.1.2: + * + * "The RR type space is split into 256 window blocks, each re- + * presenting the low-order 8 bits of the 16-bit RR type space." + */ + uint8_t window = type >> 8; + uint8_t subtype = type & 0xff; + + if (! bitmap) { return false; } - data = ldns_rdf_data(nsec_bitmap); - while(pos < ldns_rdf_size(nsec_bitmap)) { - window_block_nr = data[pos]; - bitmap_length = data[pos + 1]; - pos += 2; - - for (bit_pos = 0; bit_pos < (bitmap_length) * 8; bit_pos++) { - if (ldns_get_bit(&data[pos], bit_pos)) { - cur_type = 256 * (uint16_t) window_block_nr + bit_pos; - if (cur_type == type) { - return true; - } - } - } + assert(ldns_rdf_get_type(bitmap) == LDNS_RDF_TYPE_BITMAP); + + dptr = ldns_rdf_data(bitmap); + dend = ldns_rdf_data(bitmap) + ldns_rdf_size(bitmap); + + /* Type Bitmap = ( Window Block # | Bitmap Length | Bitmap ) + + * dptr[0] dptr[1] dptr[2:] + */ + while (dptr < dend && dptr[0] <= window) { + + if (dptr[0] == window && subtype / 8 < dptr[1] && + dptr + dptr[1] + 2 <= dend) { - pos += (uint16_t) bitmap_length; + return dptr[2 + subtype / 8] & (0x80 >> (subtype % 8)); + } + dptr += dptr[1] + 2; /* next window */ } return false; } +ldns_status +ldns_nsec_bitmap_set_type(ldns_rdf* bitmap, ldns_rr_type type) +{ + uint8_t* dptr; + uint8_t* dend; + + /* From RFC3845 Section 2.1.2: + * + * "The RR type space is split into 256 window blocks, each re- + * presenting the low-order 8 bits of the 16-bit RR type space." + */ + uint8_t window = type >> 8; + uint8_t subtype = type & 0xff; + + if (! bitmap) { + return false; + } + assert(ldns_rdf_get_type(bitmap) == LDNS_RDF_TYPE_BITMAP); + + dptr = ldns_rdf_data(bitmap); + dend = ldns_rdf_data(bitmap) + ldns_rdf_size(bitmap); + + /* Type Bitmap = ( Window Block # | Bitmap Length | Bitmap ) + + * dptr[0] dptr[1] dptr[2:] + */ + while (dptr < dend && dptr[0] <= window) { + + if (dptr[0] == window && subtype / 8 < dptr[1] && + dptr + dptr[1] + 2 <= dend) { + + dptr[2 + subtype / 8] |= (0x80 >> (subtype % 8)); + return LDNS_STATUS_OK; + } + dptr += dptr[1] + 2; /* next window */ + } + return LDNS_STATUS_TYPE_NOT_IN_BITMAP; +} + +ldns_status +ldns_nsec_bitmap_clear_type(ldns_rdf* bitmap, ldns_rr_type type) +{ + uint8_t* dptr; + uint8_t* dend; + + /* From RFC3845 Section 2.1.2: + * + * "The RR type space is split into 256 window blocks, each re- + * presenting the low-order 8 bits of the 16-bit RR type space." + */ + uint8_t window = type >> 8; + uint8_t subtype = type & 0xff; + + if (! bitmap) { + return false; + } + + assert(ldns_rdf_get_type(bitmap) == LDNS_RDF_TYPE_BITMAP); + + dptr = ldns_rdf_data(bitmap); + dend = ldns_rdf_data(bitmap) + ldns_rdf_size(bitmap); + + /* Type Bitmap = ( Window Block # | Bitmap Length | Bitmap ) + + * dptr[0] dptr[1] dptr[2:] + */ + while (dptr < dend && dptr[0] <= window) { + + if (dptr[0] == window && subtype / 8 < dptr[1] && + dptr + dptr[1] + 2 <= dend) { + + dptr[2 + subtype / 8] &= ~(0x80 >> (subtype % 8)); + return LDNS_STATUS_OK; + } + dptr += dptr[1] + 2; /* next window */ + } + return LDNS_STATUS_TYPE_NOT_IN_BITMAP; +} + + bool ldns_nsec_covers_name(const ldns_rr *nsec, const ldns_rdf *name) { @@ -1407,9 +1505,11 @@ ldns_nsec_covers_name(const ldns_rr *nsec, const ldns_rdf *name) if(ldns_dname_compare(nsec_owner, nsec_next) > 0) { result = (ldns_dname_compare(nsec_owner, name) <= 0 || ldns_dname_compare(name, nsec_next) < 0); - } else { + } else if(ldns_dname_compare(nsec_owner, nsec_next) < 0) { result = (ldns_dname_compare(nsec_owner, name) <= 0 && ldns_dname_compare(name, nsec_next) < 0); + } else { + result = true; } ldns_rdf_deep_free(nsec_next); diff --git a/usr.sbin/unbound/ldns/dnssec_sign.c b/usr.sbin/unbound/ldns/dnssec_sign.c index f2f9d9dda87..4af882a2845 100644 --- a/usr.sbin/unbound/ldns/dnssec_sign.c +++ b/usr.sbin/unbound/ldns/dnssec_sign.c @@ -566,7 +566,7 @@ ldns_dnssec_addresses_on_glue_list( * when walking the tree with the ldns_dnssec_name_node_next_nonglue() * function. But watch out! Names that are partially occluded (like glue with * the same name as the delegation) will not be marked and should specifically - * be taken into account seperately. + * be taken into account separately. * * When glue_list is given (not NULL), in the process of marking the names, all * glue resource records will be pushed to that list, even glue at delegation names. @@ -659,7 +659,7 @@ ldns_dnssec_zone_mark_and_get_glue(ldns_dnssec_zone *zone, * when walking the tree with the ldns_dnssec_name_node_next_nonglue() * function. But watch out! Names that are partially occluded (like glue with * the same name as the delegation) will not be marked and should specifically - * be taken into account seperately. + * be taken into account separately. * * \param[in] zone the zone in which to mark the names * \return LDNS_STATUS_OK on success, an error code otherwise @@ -771,10 +771,13 @@ ldns_dnssec_zone_create_nsecs(ldns_dnssec_zone *zone, } #ifdef HAVE_SSL -/* in dnssec_zone.c */ -extern int ldns_dname_compare_v(const void *a, const void *b); +static void +ldns_hashed_names_node_free(ldns_rbnode_t *node, void *arg) { + (void) arg; + LDNS_FREE(node); +} -ldns_status +static ldns_status ldns_dnssec_zone_create_nsec3s_mkmap(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, uint8_t algorithm, @@ -813,21 +816,24 @@ ldns_dnssec_zone_create_nsec3s_mkmap(ldns_dnssec_zone *zone, nsec_ttl = LDNS_DEFAULT_TTL; } - if (map) { - if ((*map = ldns_rbtree_create(ldns_dname_compare_v)) - == NULL) { - map = NULL; - }; + if (zone->hashed_names) { + ldns_traverse_postorder(zone->hashed_names, + ldns_hashed_names_node_free, NULL); + LDNS_FREE(zone->hashed_names); + } + zone->hashed_names = ldns_rbtree_create(ldns_dname_compare_v); + if (zone->hashed_names && map) { + *map = zone->hashed_names; } - nsec3_list = ldns_rr_list_new(); first_name_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_first(zone->names)); current_name_node = first_name_node; - while (current_name_node && - current_name_node != LDNS_RBTREE_NULL) { + while (current_name_node && current_name_node != LDNS_RBTREE_NULL && + result == LDNS_STATUS_OK) { + current_name = (ldns_dnssec_name *) current_name_node->data; nsec_rr = ldns_dnssec_create_nsec3(current_name, NULL, @@ -845,28 +851,49 @@ ldns_dnssec_zone_create_nsec3s_mkmap(ldns_dnssec_zone *zone, ldns_rr_set_ttl(nsec_rr, nsec_ttl); result = ldns_dnssec_name_add_rr(current_name, nsec_rr); ldns_rr_list_push_rr(new_rrs, nsec_rr); - ldns_rr_list_push_rr(nsec3_list, nsec_rr); - if (map) { + if (ldns_rr_owner(nsec_rr)) { hashmap_node = LDNS_MALLOC(ldns_rbnode_t); - if (hashmap_node && ldns_rr_owner(nsec_rr)) { - hashmap_node->key = ldns_dname_label( - ldns_rr_owner(nsec_rr), 0); - if (hashmap_node->key) { - hashmap_node->data = current_name->name; - (void) ldns_rbtree_insert( - *map, hashmap_node); - } + if (hashmap_node == NULL) { + return LDNS_STATUS_MEM_ERR; + } + current_name->hashed_name = + ldns_dname_label(ldns_rr_owner(nsec_rr), 0); + + if (current_name->hashed_name == NULL) { + LDNS_FREE(hashmap_node); + return LDNS_STATUS_MEM_ERR; + } + hashmap_node->key = current_name->hashed_name; + hashmap_node->data = current_name; + + if (! ldns_rbtree_insert(zone->hashed_names + , hashmap_node)) { + LDNS_FREE(hashmap_node); } } current_name_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_next(current_name_node)); } if (result != LDNS_STATUS_OK) { - ldns_rr_list_free(nsec3_list); return result; } - ldns_rr_list_sort_nsec3(nsec3_list); + /* Make sorted list of nsec3s (via zone->hashed_names) + */ + nsec3_list = ldns_rr_list_new(); + if (nsec3_list == NULL) { + return LDNS_STATUS_MEM_ERR; + } + for ( hashmap_node = ldns_rbtree_first(zone->hashed_names) + ; hashmap_node != LDNS_RBTREE_NULL + ; hashmap_node = ldns_rbtree_next(hashmap_node) + ) { + current_name = (ldns_dnssec_name *) hashmap_node->data; + nsec_rr = ((ldns_dnssec_name *) hashmap_node->data)->nsec; + if (nsec_rr) { + ldns_rr_list_push_rr(nsec3_list, nsec_rr); + } + } result = ldns_dnssec_chain_nsec3_list(nsec3_list); ldns_rr_list_free(nsec3_list); @@ -913,7 +940,9 @@ ldns_dnssec_remove_signatures( ldns_dnssec_rrs *signatures ldns_key_list_set_use(key_list, false); break; default: +#ifdef STDERR_MSGS fprintf(stderr, "[XX] unknown return value from callback\n"); +#endif break; } return NULL; @@ -965,7 +994,9 @@ ldns_dnssec_remove_signatures( ldns_dnssec_rrs *signatures LDNS_FREE(cur_rr); break; default: +#ifdef STDERR_MSGS fprintf(stderr, "[XX] unknown return value from callback\n"); +#endif break; } cur_rr = next_rr; diff --git a/usr.sbin/unbound/ldns/dnssec_verify.c b/usr.sbin/unbound/ldns/dnssec_verify.c index d435eedf6af..1af6635b9d2 100644 --- a/usr.sbin/unbound/ldns/dnssec_verify.c +++ b/usr.sbin/unbound/ldns/dnssec_verify.c @@ -16,7 +16,7 @@ #include ldns_dnssec_data_chain * -ldns_dnssec_data_chain_new() +ldns_dnssec_data_chain_new(void) { ldns_dnssec_data_chain *nc = LDNS_CALLOC(ldns_dnssec_data_chain, 1); if(!nc) return NULL; @@ -216,7 +216,7 @@ ldns_dnssec_build_data_chain_other(ldns_resolver *res, } } -ldns_dnssec_data_chain * +static ldns_dnssec_data_chain * ldns_dnssec_build_data_chain_nokeyname(ldns_resolver *res, uint16_t qflags, ldns_rr *orig_rr, @@ -439,7 +439,7 @@ ldns_dnssec_build_data_chain(ldns_resolver *res, } ldns_dnssec_trust_tree * -ldns_dnssec_trust_tree_new() +ldns_dnssec_trust_tree_new(void) { ldns_dnssec_trust_tree *new_tree = LDNS_XMALLOC(ldns_dnssec_trust_tree, 1); @@ -495,7 +495,7 @@ print_tabs(FILE *out, size_t nr, uint8_t *map, size_t treedepth) } } -void +static void ldns_dnssec_trust_tree_print_sm_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_trust_tree *tree, @@ -628,18 +628,6 @@ ldns_dnssec_trust_tree_print_sm_fmt(FILE *out, } } -void -ldns_dnssec_trust_tree_print_sm(FILE *out, - ldns_dnssec_trust_tree *tree, - size_t tabs, - bool extended, - uint8_t *sibmap, - size_t treedepth) -{ - ldns_dnssec_trust_tree_print_sm_fmt(out, ldns_output_format_default, - tree, tabs, extended, sibmap, treedepth); -} - void ldns_dnssec_trust_tree_print_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_trust_tree *tree, diff --git a/usr.sbin/unbound/ldns/dnssec_zone.c b/usr.sbin/unbound/ldns/dnssec_zone.c index df71a23c7ed..60d62eae09f 100644 --- a/usr.sbin/unbound/ldns/dnssec_zone.c +++ b/usr.sbin/unbound/ldns/dnssec_zone.c @@ -7,7 +7,7 @@ #include ldns_dnssec_rrs * -ldns_dnssec_rrs_new() +ldns_dnssec_rrs_new(void) { ldns_dnssec_rrs *new_rrs; new_rrs = LDNS_MALLOC(ldns_dnssec_rrs); @@ -54,10 +54,8 @@ ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr) /* this could be done more efficiently; name and type should already be equal */ - cmp = ldns_rr_compare(rrs->rr, - rr); - /* should we error on equal? */ - if (cmp <= 0) { + cmp = ldns_rr_compare(rrs->rr, rr); + if (cmp < 0) { if (rrs->next) { return ldns_dnssec_rrs_add_rr(rrs->next, rr); } else { @@ -74,6 +72,7 @@ ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr) rrs->rr = rr; rrs->next = new_rrs; } + /* Silently ignore equal rr's */ return LDNS_STATUS_OK; } @@ -102,7 +101,7 @@ ldns_dnssec_rrs_print(FILE *out, ldns_dnssec_rrs *rrs) ldns_dnssec_rrsets * -ldns_dnssec_rrsets_new() +ldns_dnssec_rrsets_new(void) { ldns_dnssec_rrsets *new_rrsets; new_rrsets = LDNS_MALLOC(ldns_dnssec_rrsets); @@ -164,7 +163,7 @@ ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets, return LDNS_STATUS_ERR; } -ldns_dnssec_rrsets * +static ldns_dnssec_rrsets * ldns_dnssec_rrsets_new_frm_rr(ldns_rr *rr) { ldns_dnssec_rrsets *new_rrsets; @@ -270,7 +269,7 @@ ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr) return result; } -void +static void ldns_dnssec_rrsets_print_soa_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_rrsets *rrsets, bool follow, @@ -298,16 +297,6 @@ ldns_dnssec_rrsets_print_soa_fmt(FILE *out, const ldns_output_format *fmt, } } -void -ldns_dnssec_rrsets_print_soa(FILE *out, - ldns_dnssec_rrsets *rrsets, - bool follow, - bool show_soa) -{ - ldns_dnssec_rrsets_print_soa_fmt(out, ldns_output_format_default, - rrsets, follow, show_soa); -} - void ldns_dnssec_rrsets_print_fmt(FILE *out, const ldns_output_format *fmt, @@ -325,7 +314,7 @@ ldns_dnssec_rrsets_print(FILE *out, ldns_dnssec_rrsets *rrsets, bool follow) } ldns_dnssec_name * -ldns_dnssec_name_new() +ldns_dnssec_name_new(void) { ldns_dnssec_name *new_name; @@ -428,14 +417,6 @@ ldns_dnssec_name_set_name(ldns_dnssec_name *rrset, } } -ldns_rr * -ldns_dnssec_name_nsec(ldns_dnssec_name *rrset) -{ - if (rrset) { - return rrset->nsec; - } - return NULL; -} void ldns_dnssec_name_set_nsec(ldns_dnssec_name *rrset, ldns_rr *nsec) @@ -468,8 +449,6 @@ ldns_dnssec_name_add_rr(ldns_dnssec_name *name, ldns_rr *rr) { ldns_status result = LDNS_STATUS_OK; - ldns_rdf *name_name; - bool hashed_name = false; ldns_rr_type rr_type; ldns_rr_type typecovered = 0; @@ -485,19 +464,6 @@ ldns_dnssec_name_add_rr(ldns_dnssec_name *name, typecovered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)); } -#ifdef HAVE_SSL - if (rr_type == LDNS_RR_TYPE_NSEC3 || - typecovered == LDNS_RR_TYPE_NSEC3) { - name_name = ldns_nsec3_hash_name_frm_nsec3(rr, - ldns_dnssec_name_name(name)); - hashed_name = true; - } else { - name_name = ldns_dnssec_name_name(name); - } -#else - name_name = ldns_dnssec_name_name(name); -#endif /* HAVE_SSL */ - if (rr_type == LDNS_RR_TYPE_NSEC || rr_type == LDNS_RR_TYPE_NSEC3) { /* XX check if is already set (and error?) */ @@ -519,11 +485,6 @@ ldns_dnssec_name_add_rr(ldns_dnssec_name *name, result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr); } } - - if (hashed_name) { - ldns_rdf_deep_free(name_name); - } - return result; } @@ -563,7 +524,7 @@ ldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone, } } -void +static void ldns_dnssec_name_print_soa_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_name *name, bool show_soa) @@ -589,12 +550,6 @@ ldns_dnssec_name_print_soa_fmt(FILE *out, const ldns_output_format *fmt, } } -void -ldns_dnssec_name_print_soa(FILE *out, ldns_dnssec_name *name, bool show_soa) -{ - ldns_dnssec_name_print_soa_fmt(out, ldns_output_format_default, - name, show_soa); -} void ldns_dnssec_name_print_fmt(FILE *out, const ldns_output_format *fmt, @@ -611,12 +566,14 @@ ldns_dnssec_name_print(FILE *out, ldns_dnssec_name *name) ldns_dnssec_zone * -ldns_dnssec_zone_new() +ldns_dnssec_zone_new(void) { ldns_dnssec_zone *zone = LDNS_MALLOC(ldns_dnssec_zone); if(!zone) return NULL; zone->soa = NULL; zone->names = NULL; + zone->hashed_names = NULL; + zone->_nsec3params = NULL; return zone; } @@ -699,6 +656,8 @@ ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin, ldns_rr_list_push_rr(todo_nsec3s, cur_rr); } + status = LDNS_STATUS_OK; + } else if (status != LDNS_STATUS_OK) goto error; @@ -722,18 +681,13 @@ ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin, if (ldns_rr_list_rr_count(todo_nsec3s) > 0) { (void) ldns_dnssec_zone_add_empty_nonterminals(newzone); - for (i = 0; status == LDNS_STATUS_OK && + for (i = 0; status == LDNS_STATUS_OK && i < ldns_rr_list_rr_count(todo_nsec3s); i++) { cur_rr = ldns_rr_list_rr(todo_nsec3s, i); status = ldns_dnssec_zone_add_rr(newzone, cur_rr); } - for (i = 0; status == LDNS_STATUS_OK && - i < ldns_rr_list_rr_count(todo_nsec3_rrsigs); - i++){ - cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i); - status = ldns_dnssec_zone_add_rr(newzone, cur_rr); - } - } else if (ldns_rr_list_rr_count(todo_nsec3_rrsigs) > 0) { + } + if (ldns_rr_list_rr_count(todo_nsec3_rrsigs) > 0) { for (i = 0; status == LDNS_STATUS_OK && i < ldns_rr_list_rr_count(todo_nsec3_rrsigs); i++){ @@ -777,14 +731,14 @@ ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin, return ldns_dnssec_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL); } -void +static void ldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) { (void) arg; ldns_dnssec_name_free((ldns_dnssec_name *)node->data); LDNS_FREE(node); } -void +static void ldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) { (void) arg; ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data); @@ -827,31 +781,99 @@ ldns_dname_compare_v(const void *a, const void *b) { return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b); } -ldns_rbnode_t * -ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone, - ldns_rr *rr) { - ldns_rbnode_t *current_node = ldns_rbtree_first(zone->names); - ldns_dnssec_name *current_name; - ldns_rdf *hashed_name; +static void +ldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone, + ldns_dnssec_name* name, ldns_rr* nsec3rr); - hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0); +static void +ldns_hashed_names_node_free(ldns_rbnode_t *node, void *arg) { + (void) arg; + LDNS_FREE(node); +} + +static void +ldns_dnssec_zone_hashed_names_from_nsec3( + ldns_dnssec_zone* zone, ldns_rr* nsec3rr) +{ + ldns_rbnode_t* current_node; + ldns_dnssec_name* current_name; - while (current_node != LDNS_RBTREE_NULL) { + assert(zone != NULL); + assert(nsec3rr != NULL); + + if (zone->hashed_names) { + ldns_traverse_postorder(zone->hashed_names, + ldns_hashed_names_node_free, NULL); + LDNS_FREE(zone->hashed_names); + } + zone->_nsec3params = nsec3rr; + + /* So this is a NSEC3 zone. + * Calculate hashes for all names already in the zone + */ + zone->hashed_names = ldns_rbtree_create(ldns_dname_compare_v); + if (zone->hashed_names == NULL) { + return; + } + for ( current_node = ldns_rbtree_first(zone->names) + ; current_node != LDNS_RBTREE_NULL + ; current_node = ldns_rbtree_next(current_node) + ) { current_name = (ldns_dnssec_name *) current_node->data; - if (!current_name->hashed_name) { - current_name->hashed_name = - ldns_nsec3_hash_name_frm_nsec3(rr, current_name->name); + ldns_dnssec_name_make_hashed_name(zone, current_name, nsec3rr); + + } +} + +static void +ldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone, + ldns_dnssec_name* name, ldns_rr* nsec3rr) +{ + ldns_rbnode_t* new_node; + + assert(name != NULL); + if (! zone->_nsec3params) { + if (! nsec3rr) { + return; } - if (ldns_dname_compare(hashed_name, - current_name->hashed_name) - == 0) { - ldns_rdf_deep_free(hashed_name); - return current_node; + ldns_dnssec_zone_hashed_names_from_nsec3(zone, nsec3rr); + + } else if (! nsec3rr) { + nsec3rr = zone->_nsec3params; + } + name->hashed_name = ldns_nsec3_hash_name_frm_nsec3(nsec3rr, name->name); + + /* Also store in zone->hashed_names */ + if ((new_node = LDNS_MALLOC(ldns_rbnode_t))) { + + new_node->key = name->hashed_name; + new_node->data = name; + + if (ldns_rbtree_insert(zone->hashed_names, new_node) == NULL) { + + LDNS_FREE(new_node); } - current_node = ldns_rbtree_next(current_node); } - ldns_rdf_deep_free(hashed_name); - return NULL; +} + + +static ldns_rbnode_t * +ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone, ldns_rr *rr) { + ldns_rdf *hashed_name; + + hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0); + if (hashed_name == NULL) { + return NULL; + } + if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 && ! zone->_nsec3params){ + + ldns_dnssec_zone_hashed_names_from_nsec3(zone, rr); + } + if (zone->hashed_names == NULL) { + ldns_rdf_deep_free(hashed_name); + return NULL; + } + return ldns_rbtree_search(zone->hashed_names, hashed_name); } ldns_status @@ -878,15 +900,13 @@ ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr) } if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 || type_covered == LDNS_RR_TYPE_NSEC3) { - cur_node = ldns_dnssec_zone_find_nsec3_original(zone, - rr); + cur_node = ldns_dnssec_zone_find_nsec3_original(zone, rr); if (!cur_node) { return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND; } } else { cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr)); } - if (!cur_node) { /* add */ cur_name = ldns_dnssec_name_new_frm_rr(rr); @@ -899,21 +919,14 @@ ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr) cur_node->key = ldns_rr_owner(rr); cur_node->data = cur_name; (void)ldns_rbtree_insert(zone->names, cur_node); + ldns_dnssec_name_make_hashed_name(zone, cur_name, NULL); } else { cur_name = (ldns_dnssec_name *) cur_node->data; result = ldns_dnssec_name_add_rr(cur_name, rr); } - - if (result != LDNS_STATUS_OK) { - fprintf(stderr, "error adding rr: "); - ldns_rr_print(stderr, rr); - } - - /*TODO ldns_dnssec_name_print_names(stdout, zone->names, 0);*/ if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) { zone->soa = cur_name; } - return result; } @@ -1059,6 +1072,8 @@ ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone) new_node->key = new_name->name; new_node->data = new_name; (void)ldns_rbtree_insert(zone->names, new_node); + ldns_dnssec_name_make_hashed_name( + zone, new_name, NULL); } ldns_rdf_deep_free(l1); ldns_rdf_deep_free(l2); diff --git a/usr.sbin/unbound/ldns/doc/API.xml b/usr.sbin/unbound/ldns/doc/API.xml index 07007b9a295..554420d11c2 100644 --- a/usr.sbin/unbound/ldns/doc/API.xml +++ b/usr.sbin/unbound/ldns/doc/API.xml @@ -196,7 +196,7 @@ TODO the 'set' functions of the 'get' In the DNS the atomic data type is an RRset. This is a list of RRs with the same ownername, type and class. Net::DNS doesn't -have rrsets as a seperate object. +have rrsets as a separate object. In lDNS we have the ldns_rr_list, which just holds a bunch of RR's. diff --git a/usr.sbin/unbound/ldns/drill/chasetrace.c b/usr.sbin/unbound/ldns/drill/chasetrace.c index 0a37ff3017e..370f627673e 100644 --- a/usr.sbin/unbound/ldns/drill/chasetrace.c +++ b/usr.sbin/unbound/ldns/drill/chasetrace.c @@ -74,6 +74,8 @@ do_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t, ldns_resolver_usevc(local_res)); ldns_resolver_set_random(res, ldns_resolver_random(local_res)); + ldns_resolver_set_source(res, + ldns_resolver_source(local_res)); ldns_resolver_set_recursive(res, false); /* setup the root nameserver in the new resolver */ diff --git a/usr.sbin/unbound/ldns/drill/configure b/usr.sbin/unbound/ldns/drill/configure index 6a4487d9a97..0937a1b288a 100755 --- a/usr.sbin/unbound/ldns/drill/configure +++ b/usr.sbin/unbound/ldns/drill/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68 for ldns 1.6.16. +# Generated by GNU Autoconf 2.68 for ldns 1.6.17. # # Report bugs to . # @@ -560,8 +560,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='ldns' PACKAGE_TARNAME='libdns' -PACKAGE_VERSION='1.6.16' -PACKAGE_STRING='ldns 1.6.16' +PACKAGE_VERSION='1.6.17' +PACKAGE_STRING='ldns 1.6.17' PACKAGE_BUGREPORT='libdns@nlnetlabs.nl' PACKAGE_URL='' @@ -1218,7 +1218,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures ldns 1.6.16 to adapt to many kinds of systems. +\`configure' configures ldns 1.6.17 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1279,7 +1279,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of ldns 1.6.16:";; + short | recursive ) echo "Configuration of ldns 1.6.17:";; esac cat <<\_ACEOF @@ -1378,7 +1378,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -ldns configure 1.6.16 +ldns configure 1.6.17 generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. @@ -1801,7 +1801,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by ldns $as_me 1.6.16, which was +It was created by ldns $as_me 1.6.17, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -2154,7 +2154,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu # Copyright 2009, Wouter Wijngaards, NLnet Labs. # BSD licensed. # -# Version 21 +# Version 26 +# 2013-09-19 FLTO help text improved. +# 2013-07-18 Enable ACX_CHECK_COMPILER_FLAG to test for -Wstrict-prototypes +# 2013-06-25 FLTO has --disable-flto option. +# 2013-05-03 Update W32_SLEEP for newer mingw that links but not defines it. +# 2013-03-22 Fix ACX_RSRC_VERSION for long version numbers. # 2012-02-09 Fix AHX_MEMCMP_BROKEN with undef in compat/memcmp.h. # 2012-01-20 Fix COMPILER_FLAGS_UNBOUND for gcc 4.6.2 assigned-not-used-warns. # 2011-12-05 Fix getaddrinfowithincludes on windows with fedora16 mingw32-gcc. @@ -2169,7 +2174,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu # 2010-07-02 Add check for ss_family (for minix). # 2010-04-26 Fix to use CPPFLAGS for CHECK_COMPILER_FLAGS. # 2010-03-01 Fix RPATH using CONFIG_COMMANDS to run at the very end. -# 2010-02-18 WITH_SSL outputs the LIBSSL_LDFLAGS, LIBS, CPPFLAGS seperate, -ldl +# 2010-02-18 WITH_SSL outputs the LIBSSL_LDFLAGS, LIBS, CPPFLAGS separate, -ldl # 2010-02-01 added ACX_CHECK_MEMCMP_SIGNED, AHX_MEMCMP_BROKEN # 2010-01-20 added AHX_COONFIG_STRLCAT # 2009-07-14 U_CHAR detection improved for windows crosscompile. @@ -4240,7 +4245,7 @@ if eval \${cv_prog_cc_flag_$cache+:} false; then : $as_echo_n "(cached) " >&6 else -echo 'void f(){}' >conftest.c +echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -std=c99 -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else @@ -4271,7 +4276,7 @@ if eval \${cv_prog_cc_flag_$cache+:} false; then : $as_echo_n "(cached) " >&6 else -echo 'void f(){}' >conftest.c +echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -xc99 -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else @@ -4314,7 +4319,7 @@ if eval \${cv_prog_cc_flag_$cache+:} false; then : $as_echo_n "(cached) " >&6 else -echo 'void f(){}' >conftest.c +echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -O2 -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else @@ -4347,7 +4352,7 @@ if eval \${cv_prog_cc_flag_$cache+:} false; then : $as_echo_n "(cached) " >&6 else -echo 'void f(){}' >conftest.c +echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -Werror -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else @@ -4378,7 +4383,7 @@ if eval \${cv_prog_cc_flag_$cache+:} false; then : $as_echo_n "(cached) " >&6 else -echo 'void f(){}' >conftest.c +echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -Wall -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else @@ -5945,7 +5950,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by ldns $as_me 1.6.16, which was +This file was extended by ldns $as_me 1.6.17, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -6007,7 +6012,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -ldns config.status 1.6.16 +ldns config.status 1.6.17 configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" diff --git a/usr.sbin/unbound/ldns/drill/configure.ac b/usr.sbin/unbound/ldns/drill/configure.ac index 17d7541c027..b7fe2aee07a 100644 --- a/usr.sbin/unbound/ldns/drill/configure.ac +++ b/usr.sbin/unbound/ldns/drill/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.56) -AC_INIT(ldns, 1.6.16, libdns@nlnetlabs.nl,libdns) +AC_INIT(ldns, 1.6.17, libdns@nlnetlabs.nl,libdns) AC_CONFIG_SRCDIR([drill.c]) sinclude(../acx_nlnetlabs.m4) diff --git a/usr.sbin/unbound/ldns/drill/drill.1.in b/usr.sbin/unbound/ldns/drill/drill.1.in index 15b15a42533..b6d74f6554d 100644 --- a/usr.sbin/unbound/ldns/drill/drill.1.in +++ b/usr.sbin/unbound/ldns/drill/drill.1.in @@ -82,6 +82,11 @@ the type arguments are not used. Chase the signature(s) of 'name' to a known key or as high up in the tree as possible. +.TP +\fB\-I \fIIPv4 or IPv6 address\fR +Source address to query from. The source address has to be present +on an interface of the host running drill. + .TP \fB\-V \fIlevel\fR Be more verbose. Set level to 5 to see the actual query that is sent. @@ -217,6 +222,12 @@ specify named base64 tsig key, and optional an algorithm (defaults to hmac-md5.s \fB\-z \fR don't randomize the nameserver list before sending queries. +.SH "EXIT STATUS" +The exit status is 0 if the looked up answer is secure and trusted, +or insecure. +The exit status is not 0 if the looked up answer is untrusted or bogus, +or an error occurred while performing the lookup. + .SH "FILES" .TP @LDNS_TRUST_ANCHOR_FILE@ diff --git a/usr.sbin/unbound/ldns/drill/drill.c b/usr.sbin/unbound/ldns/drill/drill.c index 574c8b98c85..b967ad949c8 100644 --- a/usr.sbin/unbound/ldns/drill/drill.c +++ b/usr.sbin/unbound/ldns/drill/drill.c @@ -33,6 +33,7 @@ usage(FILE *stream, const char *progname) fprintf(stream, "\t-T\t\ttrace from the root down to \n"); fprintf(stream, "\t-S\t\tchase signature(s) from to a know key [*]\n"); #endif /*HAVE_SSL*/ + fprintf(stream, "\t-I
\tsource address to query from\n"); fprintf(stream, "\t-V \tverbosity (0-5)\n"); fprintf(stream, "\t-Q\t\tquiet mode (overrules -V)\n"); fprintf(stream, "\n"); @@ -103,6 +104,7 @@ main(int argc, char *argv[]) ldns_pkt *pkt; ldns_pkt *qpkt; char *serv; + char *src = NULL; const char *name; char *name2; char *progname; @@ -110,6 +112,7 @@ main(int argc, char *argv[]) char *answer_file = NULL; ldns_buffer *query_buffer = NULL; ldns_rdf *serv_rdf; + ldns_rdf *src_rdf = NULL; ldns_rr_type type; ldns_rr_class clas; #if 0 @@ -157,7 +160,7 @@ main(int argc, char *argv[]) int_type = -1; serv = NULL; type = 0; int_clas = -1; name = NULL; clas = 0; - qname = NULL; + qname = NULL; src = NULL; progname = strdup(argv[0]); #ifdef USE_WINSOCK @@ -195,7 +198,7 @@ main(int argc, char *argv[]) /* global first, query opt next, option with parm's last * and sorted */ /* "46DITSVQf:i:w:q:achuvxzy:so:p:b:k:" */ - while ((c = getopt(argc, argv, "46ab:c:d:Df:hi:Ik:o:p:q:Qr:sStTuvV:w:xy:z")) != -1) { + while ((c = getopt(argc, argv, "46ab:c:d:Df:hi:I:k:o:p:q:Qr:sStTuvV:w:xy:z")) != -1) { switch(c) { /* global options */ case '4': @@ -208,7 +211,7 @@ main(int argc, char *argv[]) qdnssec = true; break; case 'I': - /* reserved for backward compatibility */ + src = optarg; break; case 'T': if (PURPOSE == DRILL_CHASE) { @@ -482,6 +485,14 @@ main(int argc, char *argv[]) } } + if (src) { + src_rdf = ldns_rdf_new_addr_frm_str(src); + if(!src_rdf) { + fprintf(stderr, "-I must be (or resolve) to a valid IP[v6] address.\n"); + exit(EXIT_FAILURE); + } + } + /* set the nameserver to use */ if (!serv) { /* no server given make a resolver from /etc/resolv.conf */ @@ -513,6 +524,7 @@ main(int argc, char *argv[]) ldns_resolver_set_ip6(cmdline_res, qfamily); ldns_resolver_set_fallback(cmdline_res, qfallback); ldns_resolver_set_usevc(cmdline_res, qusevc); + ldns_resolver_set_source(cmdline_res, src_rdf); cmdline_dname = ldns_dname_new_frm_str(serv); @@ -543,6 +555,7 @@ main(int argc, char *argv[]) } /* set the resolver options */ ldns_resolver_set_port(res, qport); + ldns_resolver_set_source(res, src_rdf); if (verbosity >= 5) { ldns_resolver_set_debug(res, true); } else { @@ -613,10 +626,17 @@ main(int argc, char *argv[]) ldns_resolver_set_dnssec_cd(res, true); /* set dnssec implies udp_size of 4096 */ ldns_resolver_set_edns_udp_size(res, 4096); - pkt = ldns_resolver_query(res, qname, type, clas, qflags); - + pkt = NULL; + status = ldns_resolver_query_status( + &pkt, res, qname, type, clas, qflags); + if (status != LDNS_STATUS_OK) { + error("error sending query: %s", + ldns_get_errorstr_by_id(status)); + } if (!pkt) { - error("%s", "error pkt sending"); + if (status == LDNS_STATUS_OK) { + error("%s", "error pkt sending"); + } result = EXIT_FAILURE; } else { if (verbosity >= 3) { @@ -742,9 +762,17 @@ main(int argc, char *argv[]) } /* create a packet and set the RD flag on it */ - pkt = ldns_resolver_query(res, qname, type, clas, qflags); + pkt = NULL; + status = ldns_resolver_query_status( + &pkt, res, qname, type, clas, qflags); + if (status != LDNS_STATUS_OK) { + error("error sending query: %s", + ldns_get_errorstr_by_id(status)); + } if (!pkt) { - error("%s", "pkt sending"); + if (status == LDNS_STATUS_OK) { + error("%s", "pkt sending"); + } result = EXIT_FAILURE; } else { if (verbosity != -1) { @@ -815,7 +843,15 @@ main(int argc, char *argv[]) goto exit; } else { /* create a packet and set the RD flag on it */ - pkt = ldns_resolver_query(res, qname, type, clas, qflags); + pkt = NULL; + status = ldns_resolver_query_status( + &pkt, res, qname, + type, clas, qflags); + if (status != LDNS_STATUS_OK) { + error("error sending query: %s" + , ldns_get_errorstr_by_id( + status)); + } } } @@ -926,6 +962,7 @@ main(int argc, char *argv[]) exit: ldns_rdf_deep_free(qname); + ldns_rdf_deep_free(src_rdf); ldns_resolver_deep_free(res); ldns_resolver_deep_free(cmdline_res); ldns_rr_list_deep_free(key_list); diff --git a/usr.sbin/unbound/ldns/drill/drill_util.c b/usr.sbin/unbound/ldns/drill/drill_util.c index db0433e77e1..9cf90a50ff0 100644 --- a/usr.sbin/unbound/ldns/drill/drill_util.c +++ b/usr.sbin/unbound/ldns/drill/drill_util.c @@ -17,10 +17,10 @@ static int read_line(FILE *input, char *line, size_t len) { int i; - - char c; + int c; + for (i = 0; i < (int)len-1; i++) { - c = (char)getc(input); + c = getc(input); if (c == EOF) { return -1; } else if (c != '\n') { diff --git a/usr.sbin/unbound/ldns/drill/securetrace.c b/usr.sbin/unbound/ldns/drill/securetrace.c index c6e7e588409..5fc493a7275 100644 --- a/usr.sbin/unbound/ldns/drill/securetrace.c +++ b/usr.sbin/unbound/ldns/drill/securetrace.c @@ -138,7 +138,7 @@ do_secure_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t, size_t j; size_t k; size_t l; - uint8_t labels_count; + uint8_t labels_count = 0; /* dnssec */ ldns_rr_list *key_list; @@ -156,6 +156,9 @@ do_secure_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t, /* empty non-terminal check */ bool ent; + ldns_rr *nsecrr; /* The nsec that proofs the non-terminal */ + ldns_rdf *hashed_name; /* The query hashed with nsec3 params */ + ldns_rdf *label0; /* The first label of an nsec3 owner name */ /* glue handling */ ldns_rr_list *new_ns_addr; @@ -220,6 +223,8 @@ do_secure_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t, ldns_resolver_usevc(local_res)); ldns_resolver_set_random(res, ldns_resolver_random(local_res)); + ldns_resolver_set_source(res, + ldns_resolver_source(local_res)); ldns_resolver_set_recursive(local_res, true); ldns_resolver_set_recursive(res, false); @@ -380,8 +385,27 @@ do_secure_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t, /* there might be an empty non-terminal, in which case we need to continue */ ent = false; for (j = 0; j < ldns_rr_list_rr_count(nsec_rrs); j++) { - if (ldns_dname_is_subdomain(ldns_rr_rdf(ldns_rr_list_rr(nsec_rrs, j), 0), labels[i])) { + nsecrr = ldns_rr_list_rr(nsec_rrs, j); + /* For NSEC when the next name is a subdomain of the question */ + if (ldns_rr_get_type(nsecrr) == LDNS_RR_TYPE_NSEC && + ldns_dname_is_subdomain(ldns_rr_rdf(nsecrr, 0), labels[i])) { ent = true; + + /* For NSEC3, the hash matches the name and the type bitmap is empty*/ + } else if (ldns_rr_get_type(nsecrr) == LDNS_RR_TYPE_NSEC3) { + hashed_name = ldns_nsec3_hash_name_frm_nsec3(nsecrr, labels[i]); + label0 = ldns_dname_label(ldns_rr_owner(nsecrr), 0); + if (hashed_name && label0 && + ldns_dname_compare(hashed_name, label0) == 0 && + ldns_nsec3_bitmap(nsecrr) == NULL) { + ent = true; + } + if (label0) { + LDNS_FREE(label0); + } + if (hashed_name) { + LDNS_FREE(hashed_name); + } } } if (!ent) { diff --git a/usr.sbin/unbound/ldns/drill/work.c b/usr.sbin/unbound/ldns/drill/work.c index 653145fe522..370d48b01b3 100644 --- a/usr.sbin/unbound/ldns/drill/work.c +++ b/usr.sbin/unbound/ldns/drill/work.c @@ -235,6 +235,7 @@ dump_hex(const ldns_pkt *pkt, const char *filename) if (status != LDNS_STATUS_OK) { error("Unable to convert packet: error code %u", status); LDNS_FREE(wire); + fclose(fp); return; } diff --git a/usr.sbin/unbound/ldns/error.c b/usr.sbin/unbound/ldns/error.c index 2fc63e9b099..82ea61a1dcc 100644 --- a/usr.sbin/unbound/ldns/error.c +++ b/usr.sbin/unbound/ldns/error.c @@ -65,6 +65,7 @@ ldns_lookup_table ldns_error_str[] = { { LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY, "authority section incomplete" }, { LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL, "additional section incomplete" }, { LDNS_STATUS_NO_DATA, "No data" }, + { LDNS_STATUS_EXISTS_ERR, "Element already exists" }, { LDNS_STATUS_CERT_BAD_ALGORITHM, "Bad algorithm type for CERT record" }, { LDNS_STATUS_SYNTAX_TYPE_ERR, "Syntax error, could not parse the RR's type" }, { LDNS_STATUS_SYNTAX_CLASS_ERR, "Syntax error, could not parse the RR's class" }, @@ -124,6 +125,24 @@ ldns_lookup_table ldns_error_str[] = { { LDNS_STATUS_DANE_PKIX_NO_SELF_SIGNED_TRUST_ANCHOR, "The validation path " "did not end in a self-signed certificate" }, + { LDNS_STATUS_INVALID_ILNP64, + "Conversion error, 4 colon separated hex numbers expected" }, + { LDNS_STATUS_INVALID_EUI48, + "Conversion error, 6 two character hex numbers " + "separated by dashes expected (i.e. xx-xx-xx-xx-xx-xx" }, + { LDNS_STATUS_INVALID_EUI64, + "Conversion error, 8 two character hex numbers " + "separated by dashes expected (i.e. xx-xx-xx-xx-xx-xx-xx-xx" }, + { LDNS_STATUS_WIRE_RDATA_ERR, "invalid rdata in wire format" }, + { LDNS_STATUS_INVALID_TAG, + "Conversion error, a non-zero sequence of US-ASCII letters " + "and numbers in lower case expected" }, + { LDNS_STATUS_TYPE_NOT_IN_BITMAP, + "The RR type bitmap rdata field did not have " + "a bit reserved for the specific RR type" }, + { LDNS_STATUS_INVALID_RDF_TYPE, + "The rdata field was not of the expected type" }, + { LDNS_STATUS_RDATA_OVERFLOW, "Rdata size overflow" }, { 0, NULL } }; diff --git a/usr.sbin/unbound/ldns/higher.c b/usr.sbin/unbound/ldns/higher.c index 990fb6afb25..8ce86a41d56 100644 --- a/usr.sbin/unbound/ldns/higher.c +++ b/usr.sbin/unbound/ldns/higher.c @@ -131,6 +131,7 @@ ldns_get_rr_list_name_by_addr(ldns_resolver *res, ldns_rdf *addr, ldns_rr_class /* extract the data we need */ names = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_PTR, LDNS_SECTION_ANSWER); + ldns_pkt_free(pkt); } return names; } @@ -303,39 +304,21 @@ ldns_getaddrinfo(ldns_resolver *res, ldns_rdf *node, ldns_rr_class c, bool ldns_nsec_type_check(ldns_rr *nsec, ldns_rr_type t) { - /* does the nsec cover the t given? */ - /* copied from host2str.c line 465: ldns_rdf2buffer_str_nsec */ - uint8_t window_block_nr; - uint8_t bitmap_length; - uint16_t type; - uint16_t pos = 0; - uint16_t bit_pos; - ldns_rdf *nsec_type_list = ldns_rr_rdf(nsec, 1); - uint8_t *data; - - if (nsec_type_list == NULL) { - return false; - } - data = ldns_rdf_data(nsec_type_list); - - while(pos < ldns_rdf_size(nsec_type_list)) { - window_block_nr = data[pos]; - bitmap_length = data[pos + 1]; - pos += 2; - - for (bit_pos = 0; bit_pos < (bitmap_length) * 8; bit_pos++) { - if (ldns_get_bit(&data[pos], bit_pos)) { - type = 256 * (uint16_t) window_block_nr + bit_pos; - - if ((ldns_rr_type)type == t) { - /* we have a winner */ - return true; - } - } - } - pos += (uint16_t) bitmap_length; + switch (ldns_rr_get_type(nsec)) { + case LDNS_RR_TYPE_NSEC : if (ldns_rr_rd_count(nsec) < 2) { + return false; + } + return ldns_nsec_bitmap_covers_type( + ldns_rr_rdf(nsec, 1), t); + + case LDNS_RR_TYPE_NSEC3 : if (ldns_rr_rd_count(nsec) < 6) { + return false; + } + return ldns_nsec_bitmap_covers_type( + ldns_rr_rdf(nsec, 5), t); + + default : return false; } - return false; } void @@ -358,3 +341,4 @@ ldns_print_rr_rdf(FILE *fp, ldns_rr *r, int rdfnum, ...) } va_end(va_rdf); } + diff --git a/usr.sbin/unbound/ldns/host2str.c b/usr.sbin/unbound/ldns/host2str.c index 521e2468ecd..e2c936baf1a 100644 --- a/usr.sbin/unbound/ldns/host2str.c +++ b/usr.sbin/unbound/ldns/host2str.c @@ -130,6 +130,55 @@ const ldns_output_format ldns_output_format_bubblebabble_record = { const ldns_output_format *ldns_output_format_bubblebabble = &ldns_output_format_bubblebabble_record; +static bool +ldns_output_format_covers_type(const ldns_output_format* fmt, ldns_rr_type t) +{ + return fmt && (fmt->flags & LDNS_FMT_RFC3597) && + ((ldns_output_format_storage*)fmt)->bitmap && + ldns_nsec_bitmap_covers_type( + ((ldns_output_format_storage*)fmt)->bitmap, t); +} + +ldns_status +ldns_output_format_set_type(ldns_output_format* fmt, ldns_rr_type t) +{ + ldns_output_format_storage* fmt_st = (ldns_output_format_storage*)fmt; + ldns_status s; + + assert(fmt != NULL); + + if (!(fmt_st->flags & LDNS_FMT_RFC3597)) { + ldns_output_format_set(fmt, LDNS_FMT_RFC3597); + } + if (! fmt_st->bitmap) { + s = ldns_rdf_bitmap_known_rr_types_space(&fmt_st->bitmap); + if (s != LDNS_STATUS_OK) { + return s; + } + } + return ldns_nsec_bitmap_set_type(fmt_st->bitmap, t); +} + +ldns_status +ldns_output_format_clear_type(ldns_output_format* fmt, ldns_rr_type t) +{ + ldns_output_format_storage* fmt_st = (ldns_output_format_storage*)fmt; + ldns_status s; + + assert(fmt != NULL); + + if (!(fmt_st->flags & LDNS_FMT_RFC3597)) { + ldns_output_format_set(fmt, LDNS_FMT_RFC3597); + } + if (! fmt_st->bitmap) { + s = ldns_rdf_bitmap_known_rr_types(&fmt_st->bitmap); + if (s != LDNS_STATUS_OK) { + return s; + } + } + return ldns_nsec_bitmap_clear_type(fmt_st->bitmap, t); +} + ldns_status ldns_pkt_opcode2buffer_str(ldns_buffer *output, ldns_pkt_opcode opcode) { @@ -381,18 +430,15 @@ ldns_rdf2buffer_str_aaaa(ldns_buffer *output, const ldns_rdf *rdf) return ldns_buffer_status(output); } -ldns_status -ldns_rdf2buffer_str_str(ldns_buffer *output, const ldns_rdf *rdf) +static void +ldns_characters2buffer_str(ldns_buffer* output, + size_t amount, const uint8_t* characters) { - const uint8_t *data = ldns_rdf_data(rdf); - uint8_t length = data[0]; - size_t i; - - ldns_buffer_printf(output, "\""); - for (i = 1; i <= length; ++i) { - char ch = (char) data[i]; - if (isprint((int)ch) || ch=='\t') { - if (ch=='\"'||ch=='\\') + uint8_t ch; + while (amount > 0) { + ch = *characters++; + if (isprint((int)ch) || ch == '\t') { + if (ch == '\"' || ch == '\\') ldns_buffer_printf(output, "\\%c", ch); else ldns_buffer_printf(output, "%c", ch); @@ -400,7 +446,22 @@ ldns_rdf2buffer_str_str(ldns_buffer *output, const ldns_rdf *rdf) ldns_buffer_printf(output, "\\%03u", (unsigned)(uint8_t) ch); } + amount--; } +} + +ldns_status +ldns_rdf2buffer_str_str(ldns_buffer *output, const ldns_rdf *rdf) +{ + if(ldns_rdf_size(rdf) < 1) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } + if((int)ldns_rdf_size(rdf) < (int)ldns_rdf_data(rdf)[0] + 1) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } + ldns_buffer_printf(output, "\""); + ldns_characters2buffer_str(output, + ldns_rdf_data(rdf)[0], ldns_rdf_data(rdf) + 1); ldns_buffer_printf(output, "\""); return ldns_buffer_status(output); } @@ -451,18 +512,27 @@ ldns_rdf2buffer_str_hex(ldns_buffer *output, const ldns_rdf *rdf) } ldns_status -ldns_rdf2buffer_str_type(ldns_buffer *output, const ldns_rdf *rdf) +ldns_rdf2buffer_str_type_fmt(ldns_buffer *output, + const ldns_output_format* fmt, const ldns_rdf *rdf) { uint16_t data = ldns_read_uint16(ldns_rdf_data(rdf)); - const ldns_rr_descriptor *descriptor; - descriptor = ldns_rr_descript(data); - if (descriptor && descriptor->_name) { - ldns_buffer_printf(output, "%s", descriptor->_name); + if (! ldns_output_format_covers_type(fmt, data) && + ldns_rr_descript(data) && + ldns_rr_descript(data)->_name) { + + ldns_buffer_printf(output, "%s",ldns_rr_descript(data)->_name); } else { ldns_buffer_printf(output, "TYPE%u", data); } - return ldns_buffer_status(output); + return ldns_buffer_status(output); +} + +ldns_status +ldns_rdf2buffer_str_type(ldns_buffer *output, const ldns_rdf *rdf) +{ + return ldns_rdf2buffer_str_type_fmt(output, + ldns_output_format_default, rdf); } ldns_status @@ -614,7 +684,7 @@ ldns_status ldns_rdf2buffer_str_loc(ldns_buffer *output, const ldns_rdf *rdf) { /* we could do checking (ie degrees < 90 etc)? */ - uint8_t version = ldns_rdf_data(rdf)[0]; + uint8_t version; uint8_t size; uint8_t horizontal_precision; uint8_t vertical_precision; @@ -629,7 +699,14 @@ ldns_rdf2buffer_str_loc(ldns_buffer *output, const ldns_rdf *rdf) uint32_t equator = (uint32_t) ldns_power(2, 31); + if(ldns_rdf_size(rdf) < 1) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } + version = ldns_rdf_data(rdf)[0]; if (version == 0) { + if(ldns_rdf_size(rdf) < 16) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } size = ldns_rdf_data(rdf)[1]; horizontal_precision = ldns_rdf_data(rdf)[2]; vertical_precision = ldns_rdf_data(rdf)[3]; @@ -669,12 +746,12 @@ ldns_rdf2buffer_str_loc(ldns_buffer *output, const ldns_rdf *rdf) h, m, s, easterness); - s = ((double) altitude) / 100; - s -= 100000; + s = ((double) altitude) / 100; + s -= 100000; if(altitude%100 != 0) ldns_buffer_printf(output, "%.2f", s); - else + else ldns_buffer_printf(output, "%.0f", s); ldns_buffer_printf(output, "m "); @@ -726,6 +803,9 @@ ldns_rdf2buffer_str_wks(ldns_buffer *output, const ldns_rdf *rdf) struct servent *service; uint16_t current_service; + if(ldns_rdf_size(rdf) < 1) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } protocol_nr = ldns_rdf_data(rdf)[0]; protocol = getprotobynumber((int) protocol_nr); if (protocol && (protocol->p_name != NULL)) { @@ -758,7 +838,8 @@ ldns_rdf2buffer_str_wks(ldns_buffer *output, const ldns_rdf *rdf) } ldns_status -ldns_rdf2buffer_str_nsec(ldns_buffer *output, const ldns_rdf *rdf) +ldns_rdf2buffer_str_nsec_fmt(ldns_buffer *output, + const ldns_output_format* fmt, const ldns_rdf *rdf) { /* Note: this code is duplicated in higher.c in * ldns_nsec_type_check() function @@ -769,33 +850,42 @@ ldns_rdf2buffer_str_nsec(ldns_buffer *output, const ldns_rdf *rdf) uint16_t pos = 0; uint16_t bit_pos; uint8_t *data = ldns_rdf_data(rdf); - const ldns_rr_descriptor *descriptor; - while(pos < ldns_rdf_size(rdf)) { + while((size_t)(pos + 2) < ldns_rdf_size(rdf)) { window_block_nr = data[pos]; bitmap_length = data[pos + 1]; pos += 2; - + if (ldns_rdf_size(rdf) < pos + bitmap_length) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } for (bit_pos = 0; bit_pos < (bitmap_length) * 8; bit_pos++) { - if (ldns_get_bit(&data[pos], bit_pos)) { - type = 256 * (uint16_t) window_block_nr + bit_pos; - descriptor = ldns_rr_descript(type); + if (! ldns_get_bit(&data[pos], bit_pos)) { + continue; + } + type = 256 * (uint16_t) window_block_nr + bit_pos; - if (descriptor && descriptor->_name) { - ldns_buffer_printf(output, "%s ", - descriptor->_name); - } else { - ldns_buffer_printf(output, "TYPE%u ", type); - } + if (! ldns_output_format_covers_type(fmt, type) && + ldns_rr_descript(type) && + ldns_rr_descript(type)->_name){ + + ldns_buffer_printf(output, "%s ", + ldns_rr_descript(type)->_name); + } else { + ldns_buffer_printf(output, "TYPE%u ", type); } } - pos += (uint16_t) bitmap_length; } - return ldns_buffer_status(output); } +ldns_status +ldns_rdf2buffer_str_nsec(ldns_buffer *output, const ldns_rdf *rdf) +{ + return ldns_rdf2buffer_str_nsec_fmt(output, + ldns_output_format_default, rdf); +} + ldns_status ldns_rdf2buffer_str_nsec3_salt(ldns_buffer *output, const ldns_rdf *rdf) { @@ -804,9 +894,8 @@ ldns_rdf2buffer_str_nsec3_salt(ldns_buffer *output, const ldns_rdf *rdf) uint8_t *data = ldns_rdf_data(rdf); - if(ldns_rdf_size(rdf) == 0) { - output->_status = LDNS_STATUS_ERR; - return ldns_buffer_status(output); + if(ldns_rdf_size(rdf) < 1) { + return LDNS_STATUS_WIRE_RDATA_ERR; } salt_length = data[0]; /* from now there are variable length entries so remember pos */ @@ -826,8 +915,10 @@ ldns_status ldns_rdf2buffer_str_period(ldns_buffer *output, const ldns_rdf *rdf) { /* period is the number of seconds */ - uint32_t p = ldns_read_uint32(ldns_rdf_data(rdf)); - ldns_buffer_printf(output, "%u", p); + if (ldns_rdf_size(rdf) != 4) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } + ldns_buffer_printf(output, "%u", ldns_read_uint32(ldns_rdf_data(rdf))); return ldns_buffer_status(output); } @@ -837,17 +928,20 @@ ldns_rdf2buffer_str_tsigtime(ldns_buffer *output,const ldns_rdf *rdf) /* tsigtime is 48 bits network order unsigned integer */ uint64_t tsigtime = 0; uint8_t *data = ldns_rdf_data(rdf); + uint64_t d0, d1, d2, d3, d4, d5; - if (ldns_rdf_size(rdf) != 6) { - return LDNS_STATUS_ERR; + if (ldns_rdf_size(rdf) < 6) { + return LDNS_STATUS_WIRE_RDATA_ERR; } + d0 = data[0]; /* cast to uint64 for shift operations */ + d1 = data[1]; + d2 = data[2]; + d3 = data[3]; + d4 = data[4]; + d5 = data[5]; + tsigtime = (d0<<40) | (d1<<32) | (d2<<24) | (d3<<16) | (d4<<8) | d5; - tsigtime = ldns_read_uint16(data); - tsigtime *= 65536; - tsigtime += ldns_read_uint16(data+2); - tsigtime *= 65536; - - ldns_buffer_printf(output, "%llu ", tsigtime); + ldns_buffer_printf(output, "%llu ", (long long)tsigtime); return ldns_buffer_status(output); } @@ -865,7 +959,7 @@ ldns_rdf2buffer_str_apl(ldns_buffer *output, const ldns_rdf *rdf) while (pos < (unsigned int) ldns_rdf_size(rdf)) { if(pos + 3 >= (unsigned)ldns_rdf_size(rdf)) - return LDNS_STATUS_SYNTAX_RDATA_ERR; + return LDNS_STATUS_WIRE_RDATA_ERR; address_family = ldns_read_uint16(&data[pos]); prefix = data[pos + 2]; negation = data[pos + 3] & LDNS_APL_NEGATION; @@ -883,7 +977,7 @@ ldns_rdf2buffer_str_apl(ldns_buffer *output, const ldns_rdf *rdf) } if (i < (unsigned short) adf_length) { if(pos+i+4 >= ldns_rdf_size(rdf)) - return LDNS_STATUS_SYNTAX_RDATA_ERR; + return LDNS_STATUS_WIRE_RDATA_ERR; ldns_buffer_printf(output, "%d", data[pos + i + 4]); } else { @@ -904,7 +998,7 @@ ldns_rdf2buffer_str_apl(ldns_buffer *output, const ldns_rdf *rdf) } if (i < (unsigned short) adf_length) { if(pos+i+4 >= ldns_rdf_size(rdf)) - return LDNS_STATUS_SYNTAX_RDATA_ERR; + return LDNS_STATUS_WIRE_RDATA_ERR; ldns_buffer_printf(output, "%02x", data[pos + i + 4]); } else { @@ -915,11 +1009,12 @@ ldns_rdf2buffer_str_apl(ldns_buffer *output, const ldns_rdf *rdf) } else { /* unknown address family */ - ldns_buffer_printf(output, "Unknown address family: %u data: ", + ldns_buffer_printf(output, + "Unknown address family: %u data: ", address_family); for (i = 1; i < (unsigned short) (4 + adf_length); i++) { if(pos+i >= ldns_rdf_size(rdf)) - return LDNS_STATUS_SYNTAX_RDATA_ERR; + return LDNS_STATUS_WIRE_RDATA_ERR; ldns_buffer_printf(output, "%02x", data[i]); } } @@ -931,21 +1026,27 @@ ldns_rdf2buffer_str_apl(ldns_buffer *output, const ldns_rdf *rdf) ldns_status ldns_rdf2buffer_str_int16_data(ldns_buffer *output, const ldns_rdf *rdf) { + size_t size; + char *b64; + if (ldns_rdf_size(rdf) < 2) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } /* Subtract the size (2) of the number that specifies the length */ - size_t size = ldns_b64_ntop_calculate_size(ldns_rdf_size(rdf) - 2); - char *b64 = LDNS_XMALLOC(char, size); - if(!b64) - return LDNS_STATUS_MEM_ERR; - + size = ldns_b64_ntop_calculate_size(ldns_rdf_size(rdf) - 2); ldns_buffer_printf(output, "%u ", ldns_rdf_size(rdf) - 2); - - if (ldns_rdf_size(rdf) > 2 && - ldns_b64_ntop(ldns_rdf_data(rdf) + 2, - ldns_rdf_size(rdf) - 2, - b64, size)) { - ldns_buffer_printf(output, "%s", b64); + if (ldns_rdf_size(rdf) > 2) { + b64 = LDNS_XMALLOC(char, size); + if(!b64) + return LDNS_STATUS_MEM_ERR; + + if (ldns_rdf_size(rdf) > 2 && + ldns_b64_ntop(ldns_rdf_data(rdf) + 2, + ldns_rdf_size(rdf) - 2, + b64, size)) { + ldns_buffer_printf(output, "%s", b64); + } + LDNS_FREE(b64); } - LDNS_FREE(b64); return ldns_buffer_status(output); } @@ -970,6 +1071,9 @@ ldns_rdf2buffer_str_ipseckey(ldns_buffer *output, const ldns_rdf *rdf) size_t offset = 0; ldns_status status; + if (ldns_rdf_size(rdf) < 3) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } precedence = data[0]; gateway_type = data[1]; algorithm = data[2]; @@ -983,8 +1087,12 @@ ldns_rdf2buffer_str_ipseckey(ldns_buffer *output, const ldns_rdf *rdf) gateway_data = LDNS_XMALLOC(uint8_t, LDNS_IP4ADDRLEN); if(!gateway_data) return LDNS_STATUS_MEM_ERR; + if (ldns_rdf_size(rdf) < offset + LDNS_IP4ADDRLEN) { + return LDNS_STATUS_ERR; + } memcpy(gateway_data, &data[offset], LDNS_IP4ADDRLEN); - gateway = ldns_rdf_new(LDNS_RDF_TYPE_A, LDNS_IP4ADDRLEN , gateway_data); + gateway = ldns_rdf_new(LDNS_RDF_TYPE_A, + LDNS_IP4ADDRLEN , gateway_data); offset += LDNS_IP4ADDRLEN; if(!gateway) { LDNS_FREE(gateway_data); @@ -995,17 +1103,22 @@ ldns_rdf2buffer_str_ipseckey(ldns_buffer *output, const ldns_rdf *rdf) gateway_data = LDNS_XMALLOC(uint8_t, LDNS_IP6ADDRLEN); if(!gateway_data) return LDNS_STATUS_MEM_ERR; + if (ldns_rdf_size(rdf) < offset + LDNS_IP6ADDRLEN) { + return LDNS_STATUS_ERR; + } memcpy(gateway_data, &data[offset], LDNS_IP6ADDRLEN); offset += LDNS_IP6ADDRLEN; gateway = - ldns_rdf_new(LDNS_RDF_TYPE_AAAA, LDNS_IP6ADDRLEN, gateway_data); + ldns_rdf_new(LDNS_RDF_TYPE_AAAA, + LDNS_IP6ADDRLEN, gateway_data); if(!gateway) { LDNS_FREE(gateway_data); return LDNS_STATUS_MEM_ERR; } break; case 3: - status = ldns_wire2dname(&gateway, data, ldns_rdf_size(rdf), &offset); + status = ldns_wire2dname(&gateway, data, + ldns_rdf_size(rdf), &offset); if(status != LDNS_STATUS_OK) return status; break; @@ -1014,6 +1127,9 @@ ldns_rdf2buffer_str_ipseckey(ldns_buffer *output, const ldns_rdf *rdf) break; } + if (ldns_rdf_size(rdf) <= offset) { + return LDNS_STATUS_ERR; + } public_key_size = ldns_rdf_size(rdf) - offset; public_key_data = LDNS_XMALLOC(uint8_t, public_key_size); if(!public_key_data) { @@ -1021,7 +1137,8 @@ ldns_rdf2buffer_str_ipseckey(ldns_buffer *output, const ldns_rdf *rdf) return LDNS_STATUS_MEM_ERR; } memcpy(public_key_data, &data[offset], public_key_size); - public_key = ldns_rdf_new(LDNS_RDF_TYPE_B64, public_key_size, public_key_data); + public_key = ldns_rdf_new(LDNS_RDF_TYPE_B64, + public_key_size, public_key_data); if(!public_key) { LDNS_FREE(public_key_data); ldns_rdf_free(gateway); @@ -1029,7 +1146,7 @@ ldns_rdf2buffer_str_ipseckey(ldns_buffer *output, const ldns_rdf *rdf) } ldns_buffer_printf(output, "%u %u %u ", precedence, gateway_type, algorithm); - if (gateway) + if (gateway) (void) ldns_rdf2buffer_str(output, gateway); else ldns_buffer_printf(output, "."); @@ -1043,15 +1160,129 @@ ldns_rdf2buffer_str_ipseckey(ldns_buffer *output, const ldns_rdf *rdf) } ldns_status -ldns_rdf2buffer_str_tsig(ldns_buffer *output, const ldns_rdf *rdf) +ldns_rdf2buffer_str_ilnp64(ldns_buffer *output, const ldns_rdf *rdf) +{ + if (ldns_rdf_size(rdf) != 8) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } + ldns_buffer_printf(output,"%.4x:%.4x:%.4x:%.4x", + ldns_read_uint16(ldns_rdf_data(rdf)), + ldns_read_uint16(ldns_rdf_data(rdf)+2), + ldns_read_uint16(ldns_rdf_data(rdf)+4), + ldns_read_uint16(ldns_rdf_data(rdf)+6)); + return ldns_buffer_status(output); +} + +ldns_status +ldns_rdf2buffer_str_eui48(ldns_buffer *output, const ldns_rdf *rdf) { - /* TSIG RRs have no presentation format, make them #size */ - return ldns_rdf2buffer_str_unknown(output, rdf); + if (ldns_rdf_size(rdf) != 6) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } + ldns_buffer_printf(output,"%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", + ldns_rdf_data(rdf)[0], ldns_rdf_data(rdf)[1], + ldns_rdf_data(rdf)[2], ldns_rdf_data(rdf)[3], + ldns_rdf_data(rdf)[4], ldns_rdf_data(rdf)[5]); + return ldns_buffer_status(output); } +ldns_status +ldns_rdf2buffer_str_eui64(ldns_buffer *output, const ldns_rdf *rdf) +{ + if (ldns_rdf_size(rdf) != 8) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } + ldns_buffer_printf(output,"%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", + ldns_rdf_data(rdf)[0], ldns_rdf_data(rdf)[1], + ldns_rdf_data(rdf)[2], ldns_rdf_data(rdf)[3], + ldns_rdf_data(rdf)[4], ldns_rdf_data(rdf)[5], + ldns_rdf_data(rdf)[6], ldns_rdf_data(rdf)[7]); + return ldns_buffer_status(output); +} ldns_status -ldns_rdf2buffer_str(ldns_buffer *buffer, const ldns_rdf *rdf) +ldns_rdf2buffer_str_tag(ldns_buffer *output, const ldns_rdf *rdf) +{ + size_t nchars; + const uint8_t* chars; + char ch; + if (ldns_rdf_size(rdf) < 2) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } + nchars = ldns_rdf_data(rdf)[0]; + if (nchars >= ldns_rdf_size(rdf) || /* should be rdf_size - 1 */ + nchars < 1) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } + chars = ldns_rdf_data(rdf) + 1; + while (nchars > 0) { + ch = (char)*chars++; + if (! isalnum(ch)) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } + ldns_buffer_printf(output, "%c", ch); + nchars--; + } + return ldns_buffer_status(output); +} + +ldns_status +ldns_rdf2buffer_str_long_str(ldns_buffer *output, const ldns_rdf *rdf) +{ + + ldns_buffer_printf(output, "\""); + ldns_characters2buffer_str(output, + ldns_rdf_size(rdf), ldns_rdf_data(rdf)); + ldns_buffer_printf(output, "\""); + return ldns_buffer_status(output); +} + +ldns_status +ldns_rdf2buffer_str_hip(ldns_buffer *output, const ldns_rdf *rdf) +{ + uint8_t *data = ldns_rdf_data(rdf); + size_t rdf_size = ldns_rdf_size(rdf); + uint8_t hit_size; + uint16_t pk_size; + int written; + + if (rdf_size < 6) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } + if ((hit_size = data[0]) == 0 || + (pk_size = ldns_read_uint16(data + 2)) == 0 || + rdf_size < (size_t) hit_size + pk_size + 4) { + + return LDNS_STATUS_WIRE_RDATA_ERR; + } + + ldns_buffer_printf(output, "%d ", (int) data[1]); + + for (data += 4; hit_size > 0; hit_size--, data++) { + + ldns_buffer_printf(output, "%02x", (int) *data); + } + ldns_buffer_write_u8(output, (uint8_t) ' '); + + if (ldns_buffer_reserve(output, + ldns_b64_ntop_calculate_size(pk_size))) { + + written = ldns_b64_ntop(data, pk_size, + (char *) ldns_buffer_current(output), + ldns_buffer_remaining(output)); + + if (written > 0 && + written < (int) ldns_buffer_remaining(output)) { + + output->_position += written; + } + } + return ldns_buffer_status(output); +} + +ldns_status +ldns_rdf2buffer_str_fmt(ldns_buffer *buffer, + const ldns_output_format* fmt, const ldns_rdf *rdf) { ldns_status res = LDNS_STATUS_OK; @@ -1100,13 +1331,13 @@ ldns_rdf2buffer_str(ldns_buffer *buffer, const ldns_rdf *rdf) res = ldns_rdf2buffer_str_hex(buffer, rdf); break; case LDNS_RDF_TYPE_NSEC: - res = ldns_rdf2buffer_str_nsec(buffer, rdf); + res = ldns_rdf2buffer_str_nsec_fmt(buffer, fmt, rdf); break; case LDNS_RDF_TYPE_NSEC3_SALT: res = ldns_rdf2buffer_str_nsec3_salt(buffer, rdf); break; case LDNS_RDF_TYPE_TYPE: - res = ldns_rdf2buffer_str_type(buffer, rdf); + res = ldns_rdf2buffer_str_type_fmt(buffer, fmt, rdf); break; case LDNS_RDF_TYPE_CLASS: res = ldns_rdf2buffer_str_class(buffer, rdf); @@ -1123,6 +1354,9 @@ ldns_rdf2buffer_str(ldns_buffer *buffer, const ldns_rdf *rdf) case LDNS_RDF_TYPE_TIME: res = ldns_rdf2buffer_str_time(buffer, rdf); break; + case LDNS_RDF_TYPE_HIP: + res = ldns_rdf2buffer_str_hip(buffer, rdf); + break; case LDNS_RDF_TYPE_LOC: res = ldns_rdf2buffer_str_loc(buffer, rdf); break; @@ -1139,15 +1373,27 @@ ldns_rdf2buffer_str(ldns_buffer *buffer, const ldns_rdf *rdf) case LDNS_RDF_TYPE_IPSECKEY: res = ldns_rdf2buffer_str_ipseckey(buffer, rdf); break; - case LDNS_RDF_TYPE_TSIG: - res = ldns_rdf2buffer_str_tsig(buffer, rdf); - break; case LDNS_RDF_TYPE_INT16_DATA: res = ldns_rdf2buffer_str_int16_data(buffer, rdf); break; case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER: res = ldns_rdf2buffer_str_b32_ext(buffer, rdf); break; + case LDNS_RDF_TYPE_ILNP64: + res = ldns_rdf2buffer_str_ilnp64(buffer, rdf); + break; + case LDNS_RDF_TYPE_EUI48: + res = ldns_rdf2buffer_str_eui48(buffer, rdf); + break; + case LDNS_RDF_TYPE_EUI64: + res = ldns_rdf2buffer_str_eui64(buffer, rdf); + break; + case LDNS_RDF_TYPE_TAG: + res = ldns_rdf2buffer_str_tag(buffer, rdf); + break; + case LDNS_RDF_TYPE_LONG_STR: + res = ldns_rdf2buffer_str_long_str(buffer, rdf); + break; } } else { /** This will write mangled RRs */ @@ -1157,7 +1403,13 @@ ldns_rdf2buffer_str(ldns_buffer *buffer, const ldns_rdf *rdf) return res; } -ldns_rdf * +ldns_status +ldns_rdf2buffer_str(ldns_buffer *buffer, const ldns_rdf *rdf) +{ + return ldns_rdf2buffer_str_fmt(buffer,ldns_output_format_default,rdf); +} + +static ldns_rdf * ldns_b32_ext2dname(const ldns_rdf *rdf) { size_t size; @@ -1184,18 +1436,45 @@ ldns_b32_ext2dname(const ldns_rdf *rdf) return NULL; } +static ldns_status +ldns_rr2buffer_str_rfc3597(ldns_buffer *output, const ldns_rr *rr) +{ + size_t total_rdfsize = 0; + size_t i, j; + + ldns_buffer_printf(output, "TYPE%u\t", ldns_rr_get_type(rr)); + for (i = 0; i < ldns_rr_rd_count(rr); i++) { + total_rdfsize += ldns_rdf_size(ldns_rr_rdf(rr, i)); + } + if (total_rdfsize == 0) { + ldns_buffer_printf(output, "\\# 0\n"); + return ldns_buffer_status(output); + } + ldns_buffer_printf(output, "\\# %d ", total_rdfsize); + for (i = 0; i < ldns_rr_rd_count(rr); i++) { + for (j = 0; j < ldns_rdf_size(ldns_rr_rdf(rr, i)); j++) { + ldns_buffer_printf(output, "%.2x", + ldns_rdf_data(ldns_rr_rdf(rr, i))[j]); + } + } + ldns_buffer_printf(output, "\n"); + return ldns_buffer_status(output); +} + ldns_status ldns_rr2buffer_str_fmt(ldns_buffer *output, const ldns_output_format *fmt, const ldns_rr *rr) { uint16_t i, flags; ldns_status status = LDNS_STATUS_OK; + ldns_output_format_storage* fmt_st = (ldns_output_format_storage*)fmt; - if (fmt == NULL) { - fmt = ldns_output_format_default; + if (fmt_st == NULL) { + fmt_st = (ldns_output_format_storage*) + ldns_output_format_default; } if (!rr) { - if (LDNS_COMMENT_NULLS & fmt->flags) { + if (LDNS_COMMENT_NULLS & fmt_st->flags) { ldns_buffer_printf(output, "; (null)\n"); } return ldns_buffer_status(output); @@ -1219,6 +1498,9 @@ ldns_rr2buffer_str_fmt(ldns_buffer *output, } ldns_buffer_printf(output, "\t"); + if (ldns_output_format_covers_type(fmt, ldns_rr_get_type(rr))) { + return ldns_rr2buffer_str_rfc3597(output, rr); + } status = ldns_rr_type2buffer_str(output, ldns_rr_get_type(rr)); if (status != LDNS_STATUS_OK) { return status; @@ -1232,7 +1514,7 @@ ldns_rr2buffer_str_fmt(ldns_buffer *output, for (i = 0; i < ldns_rr_rd_count(rr); i++) { /* ldns_rdf2buffer_str handles NULL input fine! */ - if ((fmt->flags & LDNS_FMT_ZEROIZE_RRSIGS) && + if ((fmt_st->flags & LDNS_FMT_ZEROIZE_RRSIGS) && (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) && ((/* inception */ i == 4 && ldns_rdf_get_type(ldns_rr_rdf(rr, 4)) == @@ -1246,7 +1528,7 @@ ldns_rr2buffer_str_fmt(ldns_buffer *output, ldns_buffer_printf(output, "(null)"); status = ldns_buffer_status(output); - } else if ((fmt->flags & LDNS_FMT_PAD_SOA_SERIAL) && + } else if ((fmt_st->flags & LDNS_FMT_PAD_SOA_SERIAL) && (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) && /* serial */ i == 2 && ldns_rdf_get_type(ldns_rr_rdf(rr, 2)) == @@ -1256,8 +1538,8 @@ ldns_rr2buffer_str_fmt(ldns_buffer *output, ldns_rdf_data(ldns_rr_rdf(rr, 2)))); status = ldns_buffer_status(output); } else { - status = ldns_rdf2buffer_str(output, - ldns_rr_rdf(rr, i)); + status = ldns_rdf2buffer_str_fmt(output, + fmt, ldns_rr_rdf(rr, i)); } if(status != LDNS_STATUS_OK) return status; @@ -1270,137 +1552,126 @@ ldns_rr2buffer_str_fmt(ldns_buffer *output, * getting here */ if (ldns_rr_rd_count(rr) > 0) { switch (ldns_rr_get_type(rr)) { - case LDNS_RR_TYPE_DNSKEY: - /* if ldns_rr_rd_count(rr) > 0 - then ldns_rr_rdf(rr, 0) exists! */ - if (! (fmt->flags & LDNS_COMMENT_KEY)) { - break; - } - flags = ldns_rdf2native_int16( - ldns_rr_rdf(rr, 0)); - ldns_buffer_printf(output, " ;{"); - if (fmt->flags & LDNS_COMMENT_KEY_ID) { - ldns_buffer_printf(output, "id = %u", - (unsigned int) - ldns_calc_keytag(rr)); - } - if ((fmt->flags & LDNS_COMMENT_KEY_TYPE) - && (flags & LDNS_KEY_ZONE_KEY)){ - if (flags & LDNS_KEY_SEP_KEY) { - ldns_buffer_printf( - output, " (ksk)"); - } - else { - ldns_buffer_printf( - output, " (zsk)"); - } - if (fmt->flags & LDNS_COMMENT_KEY_SIZE){ - ldns_buffer_printf( - output, ", "); - } - } else if (fmt->flags - & (LDNS_COMMENT_KEY_ID - |LDNS_COMMENT_KEY_SIZE)) { - ldns_buffer_printf( output, ", "); + case LDNS_RR_TYPE_DNSKEY: + /* if ldns_rr_rd_count(rr) > 0 + then ldns_rr_rdf(rr, 0) exists! */ + if (! (fmt_st->flags & LDNS_COMMENT_KEY)) { + break; + } + flags = ldns_rdf2native_int16(ldns_rr_rdf(rr, 0)); + ldns_buffer_printf(output, " ;{"); + if (fmt_st->flags & LDNS_COMMENT_KEY_ID) { + ldns_buffer_printf(output, "id = %u", + (unsigned int) ldns_calc_keytag(rr)); + } + if ((fmt_st->flags & LDNS_COMMENT_KEY_TYPE) && + (flags & LDNS_KEY_ZONE_KEY)){ + + if (flags & LDNS_KEY_SEP_KEY) { + ldns_buffer_printf(output, " (ksk)"); + } else { + ldns_buffer_printf(output, " (zsk)"); } - if (fmt->flags & LDNS_COMMENT_KEY_SIZE) { - ldns_buffer_printf(output, "size = %db", - ldns_rr_dnskey_key_size(rr)); + if (fmt_st->flags & LDNS_COMMENT_KEY_SIZE){ + ldns_buffer_printf(output, ", "); } - ldns_buffer_printf(output, "}"); - break; - case LDNS_RR_TYPE_RRSIG: - if ((fmt->flags & LDNS_COMMENT_KEY) - && (fmt->flags - & LDNS_COMMENT_RRSIGS) - && ldns_rr_rdf(rr, 6) != NULL) { - ldns_buffer_printf(output - , " ;{id = %d}" - , ldns_rdf2native_int16( + } else if (fmt_st->flags + & (LDNS_COMMENT_KEY_ID + |LDNS_COMMENT_KEY_SIZE)) { + ldns_buffer_printf( output, ", "); + } + if (fmt_st->flags & LDNS_COMMENT_KEY_SIZE) { + ldns_buffer_printf(output, "size = %db", + ldns_rr_dnskey_key_size(rr)); + } + ldns_buffer_printf(output, "}"); + break; + case LDNS_RR_TYPE_RRSIG: + if ((fmt_st->flags & LDNS_COMMENT_KEY) + && (fmt_st->flags& LDNS_COMMENT_RRSIGS) + && ldns_rr_rdf(rr, 6) != NULL) { + ldns_buffer_printf(output, " ;{id = %d}", + ldns_rdf2native_int16( ldns_rr_rdf(rr, 6))); + } + break; + case LDNS_RR_TYPE_DS: + if ((fmt_st->flags & LDNS_COMMENT_BUBBLEBABBLE) && + ldns_rr_rdf(rr, 3) != NULL) { + + uint8_t *data = ldns_rdf_data( + ldns_rr_rdf(rr, 3)); + size_t len = ldns_rdf_size(ldns_rr_rdf(rr, 3)); + char *babble = ldns_bubblebabble(data, len); + if(babble) { + ldns_buffer_printf(output, + " ;{%s}", babble); } + LDNS_FREE(babble); + } + break; + case LDNS_RR_TYPE_NSEC3: + if (! (fmt_st->flags & LDNS_COMMENT_FLAGS) && + ! (fmt_st->flags & LDNS_COMMENT_NSEC3_CHAIN)) { break; - case LDNS_RR_TYPE_DS: - if ((fmt->flags & LDNS_COMMENT_BUBBLEBABBLE) - && ldns_rr_rdf(rr, 3) != NULL) { - uint8_t *data = ldns_rdf_data( - ldns_rr_rdf(rr, 3)); - size_t len = ldns_rdf_size( - ldns_rr_rdf(rr, 3)); - char *babble = ldns_bubblebabble( - data, len); - if(babble) { - ldns_buffer_printf(output - , " ;{%s}", babble); - } - LDNS_FREE(babble); + } + ldns_buffer_printf(output, " ;{"); + if ((fmt_st->flags & LDNS_COMMENT_FLAGS)) { + if (ldns_nsec3_optout(rr)) { + ldns_buffer_printf(output, + " flags: optout"); + } else { + ldns_buffer_printf(output," flags: -"); } - break; - case LDNS_RR_TYPE_NSEC3: - if (! (fmt->flags & LDNS_COMMENT_FLAGS) && - ! (fmt->flags & LDNS_COMMENT_NSEC3_CHAIN)) { - break; + if (fmt_st->flags & LDNS_COMMENT_NSEC3_CHAIN && + fmt_st->hashmap != NULL) { + ldns_buffer_printf(output, ", "); } - ldns_buffer_printf(output, " ;{"); - if ((fmt->flags & LDNS_COMMENT_FLAGS)) { - if (ldns_nsec3_optout(rr)) { - ldns_buffer_printf(output, - " flags: optout"); - } else { + } + if (fmt_st->flags & LDNS_COMMENT_NSEC3_CHAIN && + fmt_st->hashmap != NULL) { + ldns_rbnode_t *node; + ldns_rdf *key = ldns_dname_label( + ldns_rr_owner(rr), 0); + if (key) { + node = ldns_rbtree_search( + fmt_st->hashmap, + (void *) key); + if (node->data) { ldns_buffer_printf(output, - " flags: -"); - } - if (fmt->flags & LDNS_COMMENT_NSEC3_CHAIN - && fmt->data != NULL) { - ldns_buffer_printf(output, ", "); + "from: "); + (void) ldns_rdf2buffer_str( + output, + ldns_dnssec_name_name( + (ldns_dnssec_name*) + node->data + )); } + ldns_rdf_free(key); } - if (fmt->flags & LDNS_COMMENT_NSEC3_CHAIN - && fmt->data != NULL) { - ldns_rbnode_t *node; - ldns_rdf *key = ldns_dname_label( - ldns_rr_owner(rr), 0); - if (key) { - node = ldns_rbtree_search( - (ldns_rbtree_t *) - fmt->data, - (void *) key); - if (node->data) { - ldns_buffer_printf( - output, - "from: "); - (void) - ldns_rdf2buffer_str( - output, - (ldns_rdf *) - node->data); - } - ldns_rdf_free(key); - } - key = ldns_b32_ext2dname( + key = ldns_b32_ext2dname( ldns_nsec3_next_owner(rr)); - if (key) { - node = ldns_rbtree_search( - (ldns_rbtree_t *) - fmt->data, - (void *) key); - if (node->data) { - ldns_buffer_printf( - output, - " to: "); - (void) - ldns_rdf2buffer_str( - output, - (ldns_rdf *) - node->data); - } - ldns_rdf_free(key); + if (key) { + node = ldns_rbtree_search( + fmt_st->hashmap, + (void *) key); + if (node->data) { + ldns_buffer_printf(output, + " to: "); + (void) ldns_rdf2buffer_str( + output, + ldns_dnssec_name_name( + (ldns_dnssec_name*) + node->data + )); } + ldns_rdf_free(key); } - ldns_buffer_printf(output, "}"); - break; - default: - break; + } + ldns_buffer_printf(output, "}"); + break; + default: + break; } } @@ -1724,10 +1995,12 @@ ldns_key2buffer_str(ldns_buffer *output, const ldns_key *k) break; #endif default: +#ifdef STDERR_MSGS fprintf(stderr, "Warning: unknown signature "); fprintf(stderr, "algorithm type %u\n", ldns_key_algorithm(k)); +#endif ldns_buffer_printf(output, "Algorithm: %u (Unknown)\n", ldns_key_algorithm(k)); diff --git a/usr.sbin/unbound/ldns/host2wire.c b/usr.sbin/unbound/ldns/host2wire.c index de1e01e9ba3..8fb5c3a2ba5 100644 --- a/usr.sbin/unbound/ldns/host2wire.c +++ b/usr.sbin/unbound/ldns/host2wire.c @@ -81,6 +81,7 @@ ldns_rr_list2buffer_wire(ldns_buffer *buffer,const ldns_rr_list *rr_list) return ldns_buffer_status(buffer); } + ldns_status ldns_rr2buffer_wire_canonical(ldns_buffer *buffer, const ldns_rr *rr, @@ -136,17 +137,15 @@ ldns_rr2buffer_wire_canonical(ldns_buffer *buffer, rdl_pos = ldns_buffer_position(buffer); ldns_buffer_write_u16(buffer, 0); } - for (i = 0; i < ldns_rr_rd_count(rr); i++) { if (pre_rfc3597) { (void) ldns_rdf2buffer_wire_canonical( - buffer, ldns_rr_rdf(rr, i)); + buffer, ldns_rr_rdf(rr, i)); } else { (void) ldns_rdf2buffer_wire( - buffer, ldns_rr_rdf(rr, i)); + buffer, ldns_rr_rdf(rr, i)); } } - if (rdl_pos != 0) { ldns_buffer_write_u16_at(buffer, rdl_pos, ldns_buffer_position(buffer) @@ -177,13 +176,11 @@ ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section) /* remember pos for later */ rdl_pos = ldns_buffer_position(buffer); ldns_buffer_write_u16(buffer, 0); - } - + } for (i = 0; i < ldns_rr_rd_count(rr); i++) { (void) ldns_rdf2buffer_wire( buffer, ldns_rr_rdf(rr, i)); } - if (rdl_pos != 0) { ldns_buffer_write_u16_at(buffer, rdl_pos, ldns_buffer_position(buffer) @@ -206,7 +203,8 @@ ldns_rrsig2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr) /* Convert all the rdfs, except the actual signature data * rdf number 8 - the last, hence: -1 */ for (i = 0; i < ldns_rr_rd_count(rr) - 1; i++) { - (void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_rdf(rr, i)); + (void) ldns_rdf2buffer_wire_canonical(buffer, + ldns_rr_rdf(rr, i)); } return ldns_buffer_status(buffer); @@ -218,9 +216,8 @@ ldns_rr_rdata2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr) uint16_t i; /* convert all the rdf's */ for (i = 0; i < ldns_rr_rd_count(rr); i++) { - (void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr, i)); + (void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr,i)); } - return ldns_buffer_status(buffer); } @@ -245,7 +242,8 @@ ldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet) flags = ldns_pkt_ra(packet) << 7 /*| ldns_pkt_z(packet) << 6*/ | ldns_pkt_ad(packet) << 5 - | ldns_pkt_cd(packet) << 4 | ldns_pkt_get_rcode(packet); + | ldns_pkt_cd(packet) << 4 + | ldns_pkt_get_rcode(packet); ldns_buffer_write_u8(buffer, flags); ldns_buffer_write_u16(buffer, ldns_pkt_qdcount(packet)); diff --git a/usr.sbin/unbound/ldns/install-sh b/usr.sbin/unbound/ldns/install-sh index a9244eb0786..377bb8687ff 100755 --- a/usr.sbin/unbound/ldns/install-sh +++ b/usr.sbin/unbound/ldns/install-sh @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2011-01-19.21; # UTC +scriptversion=2011-11-20.07; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -35,7 +35,7 @@ scriptversion=2011-01-19.21; # UTC # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent -# `make' implicit rules from creating a file called install from it +# 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written @@ -156,7 +156,7 @@ while test $# -ne 0; do -s) stripcmd=$stripprog;; -t) dst_arg=$2 - # Protect names problematic for `test' and other utilities. + # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac @@ -190,7 +190,7 @@ if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then fi shift # arg dst_arg=$arg - # Protect names problematic for `test' and other utilities. + # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac @@ -202,7 +202,7 @@ if test $# -eq 0; then echo "$0: no input file specified." >&2 exit 1 fi - # It's OK to call `install-sh -d' without argument. + # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi @@ -240,7 +240,7 @@ fi for src do - # Protect names problematic for `test' and other utilities. + # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac @@ -354,7 +354,7 @@ do if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writeable bit of parent directory when it shouldn't. + # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in diff --git a/usr.sbin/unbound/ldns/keys.c b/usr.sbin/unbound/ldns/keys.c index de7c94610d8..46f6a3d0cb6 100644 --- a/usr.sbin/unbound/ldns/keys.c +++ b/usr.sbin/unbound/ldns/keys.c @@ -44,7 +44,7 @@ ldns_lookup_table ldns_signing_algorithms[] = { }; ldns_key_list * -ldns_key_list_new() +ldns_key_list_new(void) { ldns_key_list *key_list = LDNS_MALLOC(ldns_key_list); if (!key_list) { @@ -57,7 +57,7 @@ ldns_key_list_new() } ldns_key * -ldns_key_new() +ldns_key_new(void) { ldns_key *newkey; @@ -368,40 +368,50 @@ ldns_key_new_frm_fp_l(ldns_key **key, FILE *fp, int *line_nr) #ifdef USE_SHA2 alg = LDNS_SIGN_RSASHA256; #else +# ifdef STDERR_MSGS fprintf(stderr, "Warning: SHA256 not compiled into this "); fprintf(stderr, "version of ldns\n"); +# endif #endif } if (strncmp(d, "10 RSASHA512", 3) == 0) { #ifdef USE_SHA2 alg = LDNS_SIGN_RSASHA512; #else +# ifdef STDERR_MSGS fprintf(stderr, "Warning: SHA512 not compiled into this "); fprintf(stderr, "version of ldns\n"); +# endif #endif } if (strncmp(d, "12 ECC-GOST", 3) == 0) { #ifdef USE_GOST alg = LDNS_SIGN_ECC_GOST; #else +# ifdef STDERR_MSGS fprintf(stderr, "Warning: ECC-GOST not compiled into this "); fprintf(stderr, "version of ldns, use --enable-gost\n"); +# endif #endif } if (strncmp(d, "13 ECDSAP256SHA256", 3) == 0) { #ifdef USE_ECDSA alg = LDNS_SIGN_ECDSAP256SHA256; #else +# ifdef STDERR_MSGS fprintf(stderr, "Warning: ECDSA not compiled into this "); fprintf(stderr, "version of ldns, use --enable-ecdsa\n"); +# endif #endif } if (strncmp(d, "14 ECDSAP384SHA384", 3) == 0) { #ifdef USE_ECDSA alg = LDNS_SIGN_ECDSAP384SHA384; #else +# ifdef STDERR_MSGS fprintf(stderr, "Warning: ECDSA not compiled into this "); fprintf(stderr, "version of ldns, use --enable-ecdsa\n"); +# endif #endif } if (strncmp(d, "157 HMAC-MD5", 4) == 0) { @@ -1317,8 +1327,10 @@ ldns_key_dsa2bin(unsigned char *data, DSA *k, uint16_t *size) memcpy(data, &T, 1); if (T > 8) { +#ifdef STDERR_MSGS fprintf(stderr, "DSA key with T > 8 (ie. > 1024 bits)"); fprintf(stderr, " not implemented\n"); +#endif return false; } @@ -1605,7 +1617,9 @@ ldns_read_anchor_file(const char *filename) fp = fopen(filename, "r"); if (!fp) { +#ifdef STDERR_MSGS fprintf(stderr, "Unable to open %s: %s\n", filename, strerror(errno)); +#endif LDNS_FREE(line); return NULL; } @@ -1619,7 +1633,9 @@ ldns_read_anchor_file(const char *filename) fclose(fp); if (i <= 0) { +#ifdef STDERR_MSGS fprintf(stderr, "nothing read from %s", filename); +#endif LDNS_FREE(line); return NULL; } else { @@ -1628,7 +1644,9 @@ ldns_read_anchor_file(const char *filename) LDNS_FREE(line); return r; } else { +#ifdef STDERR_MSGS fprintf(stderr, "Error creating DNSKEY or DS rr from %s: %s\n", filename, ldns_get_errorstr_by_id(status)); +#endif LDNS_FREE(line); return NULL; } diff --git a/usr.sbin/unbound/ldns/ldns/common.h.in b/usr.sbin/unbound/ldns/ldns/common.h.in index aedfc96da7f..8bf9654b4ff 100644 --- a/usr.sbin/unbound/ldns/ldns/common.h.in +++ b/usr.sbin/unbound/ldns/ldns/common.h.in @@ -24,6 +24,9 @@ #define LDNS_BUILD_CONFIG_HAVE_ATTR_FORMAT @ldns_build_config_have_attr_format@ #define LDNS_BUILD_CONFIG_HAVE_ATTR_UNUSED @ldns_build_config_have_attr_unused@ #define LDNS_BUILD_CONFIG_HAVE_SOCKLEN_T @ldns_build_config_have_socklen_t@ +#define LDNS_BUILD_CONFIG_USE_DANE @ldns_build_config_use_dane@ +#define LDNS_BUILD_CONFIG_HAVE_B32_PTON @ldns_build_config_have_b32_pton@ +#define LDNS_BUILD_CONFIG_HAVE_B32_NTOP @ldns_build_config_have_b32_ntop@ /* * HAVE_STDBOOL_H is not available when distributed as a library, but no build diff --git a/usr.sbin/unbound/ldns/ldns/config.h.in b/usr.sbin/unbound/ldns/ldns/config.h.in index 98cf357074b..b41af233c3b 100644 --- a/usr.sbin/unbound/ldns/ldns/config.h.in +++ b/usr.sbin/unbound/ldns/ldns/config.h.in @@ -86,9 +86,6 @@ /* Define to 1 if you have the `inet_pton' function. */ #undef HAVE_INET_PTON -/* Define to 1 if the system has the type `intptr_t'. */ -#undef HAVE_INTPTR_T - /* define if you have inttypes.h */ #undef HAVE_INTTYPES_H @@ -287,15 +284,36 @@ /* Define to the version of this package. */ #undef PACKAGE_VERSION +/* Define this to enable RR type CDS. */ +#undef RRTYPE_CDS + +/* Define this to enable RR type NINFO. */ +#undef RRTYPE_NINFO + +/* Define this to enable RR type RKEY. */ +#undef RRTYPE_RKEY + +/* Define this to enable RR type TA. */ +#undef RRTYPE_TA + +/* Define this to enable RR type URI. */ +#undef RRTYPE_URI + /* The size of `time_t', as computed by sizeof. */ #undef SIZEOF_TIME_T /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS +/* Define this to enable messages to stderr. */ +#undef STDERR_MSGS + /* System configuration dir */ #undef SYSCONFDIR +/* Define this to enable DANE support. */ +#undef USE_DANE + /* Define this to enable ECDSA support. */ #undef USE_ECDSA @@ -382,8 +400,7 @@ /* Define to `char' if does not define. */ #undef int8_t -/* Define to the type of a signed integer type wide enough to hold a pointer, - if such a type exists, and if the system does not define it. */ +/* Define to `size_t' if does not define. */ #undef intptr_t /* Define to rpl_malloc if the replacement function should be used. */ @@ -488,7 +505,6 @@ extern "C" { #endif -#ifndef B64_PTON int ldns_b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize); /** @@ -499,8 +515,6 @@ static inline size_t ldns_b64_ntop_calculate_size(size_t srcsize) { return ((((srcsize + 2) / 3) * 4) + 1); } -#endif /* !B64_PTON */ -#ifndef B64_NTOP int ldns_b64_pton(char const *src, uint8_t *target, size_t targsize); /** * calculates the size needed to store the result of ldns_b64_pton @@ -510,7 +524,12 @@ static inline size_t ldns_b64_pton_calculate_size(size_t srcsize) { return (((((srcsize + 3) / 4) * 3)) + 1); } -#endif /* !B64_NTOP */ + +/** + * Given in dnssec_zone.c, also used in dnssec_sign.c:w + + */ +int ldns_dname_compare_v(const void *a, const void *b); #ifndef HAVE_SLEEP /* use windows sleep, in millisecs, instead */ diff --git a/usr.sbin/unbound/ldns/ldns/dane.h b/usr.sbin/unbound/ldns/ldns/dane.h index c1c4e2d75ca..6adecd575c5 100644 --- a/usr.sbin/unbound/ldns/ldns/dane.h +++ b/usr.sbin/unbound/ldns/ldns/dane.h @@ -22,6 +22,7 @@ #ifndef LDNS_DANE_H #define LDNS_DANE_H +#if LDNS_BUILD_CONFIG_USE_DANE #include #include @@ -240,5 +241,6 @@ ldns_status ldns_dane_verify(ldns_rr_list* tlsas, } #endif +#endif /* LDNS_BUILD_CONFIG_USE_DANE */ #endif /* LDNS_DANE_H */ diff --git a/usr.sbin/unbound/ldns/ldns/dnssec.h b/usr.sbin/unbound/ldns/ldns/dnssec.h index 34f63714c34..f4cdafbe9de 100644 --- a/usr.sbin/unbound/ldns/ldns/dnssec.h +++ b/usr.sbin/unbound/ldns/ldns/dnssec.h @@ -364,12 +364,30 @@ ldns_rdf *ldns_nsec3_bitmap(const ldns_rr *nsec3_rr); ldns_rdf *ldns_nsec3_hash_name_frm_nsec3(const ldns_rr *nsec, ldns_rdf *name); /** - * Checks coverage of NSEC RR type bitmap - * \param[in] nsec_bitmap The NSEC bitmap rdata field to check - * \param[in] type The type to check - * \return true if the NSEC RR covers the type + * Check if RR type t is enumerated and set in the RR type bitmap rdf. + * \param[in] bitmap the RR type bitmap rdf to look in + * \param[in] type the type to check for + * \return true when t is found and set, otherwise return false */ -bool ldns_nsec_bitmap_covers_type(const ldns_rdf *nsec_bitmap, ldns_rr_type type); +bool ldns_nsec_bitmap_covers_type(const ldns_rdf* bitmap, ldns_rr_type type); + +/** + * Checks if RR type t is enumerated in the type bitmap rdf and sets the bit. + * \param[in] bitmap the RR type bitmap rdf to look in + * \param[in] type the type to for which the bit to set + * \return LDNS_STATUS_OK on success. LDNS_STATUS_TYPE_NOT_IN_BITMAP is + * returned when the bitmap does not contain the bit to set. + */ +ldns_status ldns_nsec_bitmap_set_type(ldns_rdf* bitmap, ldns_rr_type type); + +/** + * Checks if RR type t is enumerated in the type bitmap rdf and clears the bit. + * \param[in] bitmap the RR type bitmap rdf to look in + * \param[in] type the type to for which the bit to clear + * \return LDNS_STATUS_OK on success. LDNS_STATUS_TYPE_NOT_IN_BITMAP is + * returned when the bitmap does not contain the bit to clear. + */ +ldns_status ldns_nsec_bitmap_clear_type(ldns_rdf* bitmap, ldns_rr_type type); /** * Checks coverage of NSEC(3) RR name span diff --git a/usr.sbin/unbound/ldns/ldns/dnssec_sign.h b/usr.sbin/unbound/ldns/ldns/dnssec_sign.h index e77cb6959df..f51c7fb3812 100644 --- a/usr.sbin/unbound/ldns/ldns/dnssec_sign.h +++ b/usr.sbin/unbound/ldns/ldns/dnssec_sign.h @@ -87,7 +87,7 @@ ldns_rdf *ldns_sign_public_rsamd5(ldns_buffer *to_sign, RSA *key); * when walking the tree with the ldns_dnssec_name_node_next_nonglue() * function. But watch out! Names that are partially occluded (like glue with * the same name as the delegation) will not be marked and should specifically - * be taken into account seperately. + * be taken into account separately. * * When glue_list is given (not NULL), in the process of marking the names, all * glue resource records will be pushed to that list, even glue at the delegation name. @@ -105,7 +105,7 @@ ldns_dnssec_zone_mark_and_get_glue( * when walking the tree with the ldns_dnssec_name_node_next_nonglue() * function. But watch out! Names that are partially occluded (like glue with * the same name as the delegation) will not be marked and should specifically - * be taken into account seperately. + * be taken into account separately. * * \param[in] zone the zone in which to mark the names * \return LDNS_STATUS_OK on succesful completion diff --git a/usr.sbin/unbound/ldns/ldns/dnssec_verify.h b/usr.sbin/unbound/ldns/ldns/dnssec_verify.h index b6bdeca539b..0c41e8c11b6 100644 --- a/usr.sbin/unbound/ldns/ldns/dnssec_verify.h +++ b/usr.sbin/unbound/ldns/ldns/dnssec_verify.h @@ -32,7 +32,7 @@ struct ldns_dnssec_data_chain_struct * Creates a new dnssec_chain structure * \return ldns_dnssec_data_chain * */ -ldns_dnssec_data_chain *ldns_dnssec_data_chain_new(); +ldns_dnssec_data_chain *ldns_dnssec_data_chain_new(void); /** * Frees a dnssec_data_chain structure @@ -137,7 +137,7 @@ struct ldns_dnssec_trust_tree_struct * * \return ldns_dnssec_trust_tree * */ -ldns_dnssec_trust_tree *ldns_dnssec_trust_tree_new(); +ldns_dnssec_trust_tree *ldns_dnssec_trust_tree_new(void); /** * Frees the dnssec_trust_tree recursively diff --git a/usr.sbin/unbound/ldns/ldns/dnssec_zone.h b/usr.sbin/unbound/ldns/ldns/dnssec_zone.h index 70c81b04793..b794f942f47 100644 --- a/usr.sbin/unbound/ldns/ldns/dnssec_zone.h +++ b/usr.sbin/unbound/ldns/ldns/dnssec_zone.h @@ -93,6 +93,13 @@ struct ldns_struct_dnssec_zone { ldns_dnssec_name *soa; /** tree of ldns_dnssec_names */ ldns_rbtree_t *names; + /** tree of ldns_dnssec_names by nsec3 hashes (when applicible) */ + ldns_rbtree_t *hashed_names; + /** points to the first added NSEC3 rr whose parameters will be + * assumed for all subsequent NSEC3 rr's and which will be used + * to calculate hashed names + */ + ldns_rr *_nsec3params; }; typedef struct ldns_struct_dnssec_zone ldns_dnssec_zone; @@ -100,7 +107,7 @@ typedef struct ldns_struct_dnssec_zone ldns_dnssec_zone; * Creates a new entry for 1 pointer to an rr and 1 pointer to the next rrs * \return the allocated data */ -ldns_dnssec_rrs *ldns_dnssec_rrs_new(); +ldns_dnssec_rrs *ldns_dnssec_rrs_new(void); /** * Frees the list of rrs, but *not* the individual ldns_rr records @@ -119,7 +126,8 @@ void ldns_dnssec_rrs_free(ldns_dnssec_rrs *rrs); void ldns_dnssec_rrs_deep_free(ldns_dnssec_rrs *rrs); /** - * Adds an RR to the list of RRs. The list will remain ordered + * Adds an RR to the list of RRs. The list will remain ordered. + * If an equal RR already exists, this RR will not be added. * * \param[in] rrs the list to add to * \param[in] rr the RR to add @@ -149,7 +157,7 @@ void ldns_dnssec_rrs_print_fmt(FILE *out, * Creates a new list (entry) of RRsets * \return the newly allocated structure */ -ldns_dnssec_rrsets *ldns_dnssec_rrsets_new(); +ldns_dnssec_rrsets *ldns_dnssec_rrsets_new(void); /** * Frees the list of rrsets and their rrs, but *not* the ldns_rr @@ -224,7 +232,7 @@ void ldns_dnssec_rrsets_print_fmt(FILE *out, * Create a new data structure for a dnssec name * \return the allocated structure */ -ldns_dnssec_name *ldns_dnssec_name_new(); +ldns_dnssec_name *ldns_dnssec_name_new(void); /** * Create a new data structure for a dnssec name for the given RR @@ -356,7 +364,7 @@ void ldns_dnssec_name_print_fmt(FILE *out, * Creates a new dnssec_zone structure * \return the allocated structure */ -ldns_dnssec_zone *ldns_dnssec_zone_new(); +ldns_dnssec_zone *ldns_dnssec_zone_new(void); /** * Create a new dnssec zone from a file. diff --git a/usr.sbin/unbound/ldns/ldns/error.h b/usr.sbin/unbound/ldns/ldns/error.h index bac38ff8714..41b99ad146d 100644 --- a/usr.sbin/unbound/ldns/ldns/error.h +++ b/usr.sbin/unbound/ldns/ldns/error.h @@ -117,7 +117,16 @@ enum ldns_enum_status { LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH, LDNS_STATUS_DANE_NON_CA_CERTIFICATE, LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE, - LDNS_STATUS_DANE_PKIX_NO_SELF_SIGNED_TRUST_ANCHOR + LDNS_STATUS_DANE_PKIX_NO_SELF_SIGNED_TRUST_ANCHOR, + LDNS_STATUS_EXISTS_ERR, + LDNS_STATUS_INVALID_ILNP64, + LDNS_STATUS_INVALID_EUI48, + LDNS_STATUS_INVALID_EUI64, + LDNS_STATUS_WIRE_RDATA_ERR, + LDNS_STATUS_INVALID_TAG, + LDNS_STATUS_TYPE_NOT_IN_BITMAP, + LDNS_STATUS_INVALID_RDF_TYPE, + LDNS_STATUS_RDATA_OVERFLOW, }; typedef enum ldns_enum_status ldns_status; diff --git a/usr.sbin/unbound/ldns/ldns/host2str.h b/usr.sbin/unbound/ldns/ldns/host2str.h index bbf932767b3..e69389e90ae 100644 --- a/usr.sbin/unbound/ldns/ldns/host2str.h +++ b/usr.sbin/unbound/ldns/ldns/host2str.h @@ -40,32 +40,38 @@ extern "C" { #define LDNS_APL_NEGATION 0x80 /** - * Represent a NULL pointer (in stead of a pointer to a ldns_rr as "; (null)" + * Represent a NULL pointer (instead of a pointer to a ldns_rr as "; (null)" * as opposed to outputting nothing at all in such a case. */ -#define LDNS_COMMENT_NULLS 0x0001 +/* Flag Name Flag Nr. Has data associated + ---------------------------------------------------------------------*/ +#define LDNS_COMMENT_NULLS (1 << 0) /** Show key id with DNSKEY RR's as comment */ -#define LDNS_COMMENT_KEY_ID 0x0002 +#define LDNS_COMMENT_KEY_ID (1 << 1) /** Show if a DNSKEY is a ZSK or KSK as comment */ -#define LDNS_COMMENT_KEY_TYPE 0x0004 +#define LDNS_COMMENT_KEY_TYPE (1 << 2) /** Show DNSKEY key size as comment */ -#define LDNS_COMMENT_KEY_SIZE 0x0008 -/** Show key id, type and size as comment for DNSKEY RR's */ -#define LDNS_COMMENT_KEY (LDNS_COMMENT_KEY_ID \ - |LDNS_COMMENT_KEY_TYPE\ - |LDNS_COMMENT_KEY_SIZE) +#define LDNS_COMMENT_KEY_SIZE (1 << 3) /** Provide bubblebabble representation for DS RR's as comment */ -#define LDNS_COMMENT_BUBBLEBABBLE 0x0010 +#define LDNS_COMMENT_BUBBLEBABBLE (1 << 4) /** Show when a NSEC3 RR has the optout flag set as comment */ -#define LDNS_COMMENT_FLAGS 0x0020 +#define LDNS_COMMENT_FLAGS (1 << 5) /** Show the unhashed owner and next owner names for NSEC3 RR's as comment */ -#define LDNS_COMMENT_NSEC3_CHAIN 0x0040 +#define LDNS_COMMENT_NSEC3_CHAIN (1 << 6) /* yes */ /** Print mark up */ -#define LDNS_COMMENT_LAYOUT 0x0080 +#define LDNS_COMMENT_LAYOUT (1 << 7) /** Also comment KEY_ID with RRSIGS **/ -#define LDNS_COMMENT_RRSIGS 0x0100 -#define LDNS_FMT_ZEROIZE_RRSIGS 0x0200 -#define LDNS_FMT_PAD_SOA_SERIAL 0x0400 +#define LDNS_COMMENT_RRSIGS (1 << 8) +#define LDNS_FMT_ZEROIZE_RRSIGS (1 << 9) +#define LDNS_FMT_PAD_SOA_SERIAL (1 << 10) +#define LDNS_FMT_RFC3597 (1 << 11) /* yes */ + +#define LDNS_FMT_FLAGS_WITH_DATA 2 + +/** Show key id, type and size as comment for DNSKEY RR's */ +#define LDNS_COMMENT_KEY (LDNS_COMMENT_KEY_ID \ + |LDNS_COMMENT_KEY_TYPE\ + |LDNS_COMMENT_KEY_SIZE) /** * Output format specifier @@ -86,6 +92,18 @@ struct ldns_struct_output_format }; typedef struct ldns_struct_output_format ldns_output_format; +/** + * Output format struct with additional data for flags that use them. + * This struct may not be initialized directly. Use ldns_output_format_init + * to initialize. + */ +struct ldns_struct_output_format_storage +{ int flags; + ldns_rbtree_t* hashmap; /* for LDNS_COMMENT_NSEC3_CHAIN */ + ldns_rdf* bitmap; /* for LDNS_FMT_RFC3597 */ +}; +typedef struct ldns_struct_output_format_storage ldns_output_format_storage; + /** * Standard output format record that disables commenting in the textual * representation of Resource Records completely. @@ -107,6 +125,55 @@ extern const ldns_output_format *ldns_output_format_default; */ extern const ldns_output_format *ldns_output_format_bubblebabble; +/** + * Initialize output format storage to the default value. + * \param[in] fmt A reference to an output_format_ storage struct + * \return The initialized storage struct typecasted to ldns_output_format + */ +INLINE +ldns_output_format* ldns_output_format_init(ldns_output_format_storage* fmt) { + fmt->flags = ldns_output_format_default->flags; + fmt->hashmap = NULL; + fmt->bitmap = NULL; + return (ldns_output_format*)fmt; +} + +/** + * Set an ouput format flag. + */ +INLINE void ldns_output_format_set(ldns_output_format* fmt, int flag) { + fmt->flags |= flag; +} + +/** + * Clear an ouput format flag. + */ +INLINE void ldns_output_format_clear(ldns_output_format* fmt, int flag) { + fmt->flags &= !flag; +} + +/** + * Makes sure the LDNS_FMT_RFC3597 is set in the output format. + * Marks the type to be printed in RFC3597 format. + * /param[in] fmt the output format to update + * /param[in] the type to be printed in RFC3597 format + * /return LDNS_STATUS_OK on success + */ +ldns_status +ldns_output_format_set_type(ldns_output_format* fmt, ldns_rr_type type); + +/** + * Makes sure the LDNS_FMT_RFC3597 is set in the output format. + * Marks the type to not be printed in RFC3597 format. When no other types + * have been marked before, all known types (except the given one) will be + * marked for printing in RFC3597 format. + * /param[in] fmt the output format to update + * /param[in] the type not to be printed in RFC3597 format + * /return LDNS_STATUS_OK on success + */ +ldns_status +ldns_output_format_clear_type(ldns_output_format* fmt, ldns_rr_type type); + /** * Converts an ldns packet opcode value to its mnemonic, and adds that * to the output buffer @@ -399,15 +466,6 @@ ldns_status ldns_rdf2buffer_str_int16_data(ldns_buffer *output, const ldns_rdf * */ ldns_status ldns_rdf2buffer_str_ipseckey(ldns_buffer *output, const ldns_rdf *rdf); -/** - * Converts an LDNS_RDF_TYPE_TSIG rdata element to string format and adds it to the output buffer - * \param[in] *rdf The rdata to convert - * \param[in] *output The buffer to add the data to - * \return LDNS_STATUS_OK on success, and error status on failure - */ -ldns_status ldns_rdf2buffer_str_tsig(ldns_buffer *output, const ldns_rdf *rdf); - - /** * Converts the data in the rdata field to presentation * format (as char *) and appends it to the given buffer @@ -518,6 +576,66 @@ ldns_status ldns_rdf2buffer_str_int32(ldns_buffer *output, const ldns_rdf *rdf); */ ldns_status ldns_rdf2buffer_str_time(ldns_buffer *output, const ldns_rdf *rdf); +/** + * Converts an LDNS_RDF_TYPE_ILNP64 rdata element to 4 hexadecimal numbers + * separated by colons and adds it to the output buffer + * \param[in] *rdf The rdata to convert + * \param[in] *output The buffer to add the data to + * \return LDNS_STATUS_OK on success, and error status on failure + */ +ldns_status ldns_rdf2buffer_str_ilnp64(ldns_buffer *output, + const ldns_rdf *rdf); + +/** + * Converts an LDNS_RDF_TYPE_EUI48 rdata element to 6 hexadecimal numbers + * separated by dashes and adds it to the output buffer + * \param[in] *rdf The rdata to convert + * \param[in] *output The buffer to add the data to + * \return LDNS_STATUS_OK on success, and error status on failure + */ +ldns_status ldns_rdf2buffer_str_eui48(ldns_buffer *output, + const ldns_rdf *rdf); + +/** + * Converts an LDNS_RDF_TYPE_EUI64 rdata element to 8 hexadecimal numbers + * separated by dashes and adds it to the output buffer + * \param[in] *rdf The rdata to convert + * \param[in] *output The buffer to add the data to + * \return LDNS_STATUS_OK on success, and error status on failure + */ +ldns_status ldns_rdf2buffer_str_eui64(ldns_buffer *output, + const ldns_rdf *rdf); + +/** + * Adds the LDNS_RDF_TYPE_TAG rdata to the output buffer, + * provided it contains only alphanumeric characters. + * \param[in] *rdf The rdata to convert + * \param[in] *output The buffer to add the data to + * \return LDNS_STATUS_OK on success, and error status on failure + */ +ldns_status ldns_rdf2buffer_str_tag(ldns_buffer *output, + const ldns_rdf *rdf); + +/** + * Adds the LDNS_RDF_TYPE_LONG_STR rdata to the output buffer, in-between + * double quotes and all non printable characters properly escaped. + * \param[in] *rdf The rdata to convert + * \param[in] *output The buffer to add the data to + * \return LDNS_STATUS_OK on success, and error status on failure + */ +ldns_status ldns_rdf2buffer_str_long_str(ldns_buffer *output, + const ldns_rdf *rdf); + +/** + * Converts an LDNS_RDF_TYPE_HIP rdata element to presentation format for + * the algorithm, HIT and Public Key and adds it the output buffer . + * \param[in] *rdf The rdata to convert + * \param[in] *output The buffer to add the data to + * \return LDNS_STATUS_OK on success, and error status on failure + */ +ldns_status ldns_rdf2buffer_str_hip(ldns_buffer *output, + const ldns_rdf *rdf); + /** * Converts the data in the rdata field to presentation format and * returns that as a char *. diff --git a/usr.sbin/unbound/ldns/ldns/keys.h b/usr.sbin/unbound/ldns/ldns/keys.h index 3e156233ba2..d3b487386fc 100644 --- a/usr.sbin/unbound/ldns/ldns/keys.h +++ b/usr.sbin/unbound/ldns/ldns/keys.h @@ -166,13 +166,13 @@ typedef struct ldns_struct_key_list ldns_key_list; * Creates a new empty key list * \return a new ldns_key_list structure pointer */ -ldns_key_list *ldns_key_list_new(); +ldns_key_list *ldns_key_list_new(void); /** * Creates a new empty key structure * \return a new ldns_key * structure */ -ldns_key *ldns_key_new(); +ldns_key *ldns_key_new(void); /** * Creates a new key based on the algorithm diff --git a/usr.sbin/unbound/ldns/ldns/ldns.h b/usr.sbin/unbound/ldns/ldns/ldns.h index a41e0325d67..60663ef95c7 100644 --- a/usr.sbin/unbound/ldns/ldns/ldns.h +++ b/usr.sbin/unbound/ldns/ldns/ldns.h @@ -26,7 +26,7 @@ faster than Perl. The first main tool to use ldns is Drill, from which part of the library was derived. From version 1.0.0 on, drill is included in the ldns release -and will not be distributed seperately anymore. The library also includes some +and will not be distributed separately anymore. The library also includes some other examples and tools to show how it can be used. These can be found in the examples/ directory in the tarball. @@ -37,9 +37,9 @@ Feature list - TSIG support, - DNSSEC support; signing and verification, - small size, - - online documentation as well as manual pages. + - online documentation as well as manual pages. -If you want to send us patches please use the code from subversion (trunk). +If you want to send us patches please use the code from git. \section using_ldns Using ldns @@ -119,6 +119,7 @@ Or you can just use the menu above to browse through the API docs. #include #include #include +#include #include #include #include diff --git a/usr.sbin/unbound/ldns/ldns/net.h.in b/usr.sbin/unbound/ldns/ldns/net.h.in index cd4cfdec9c6..e6b3618f20f 100644 --- a/usr.sbin/unbound/ldns/ldns/net.h.in +++ b/usr.sbin/unbound/ldns/ldns/net.h.in @@ -50,7 +50,6 @@ ldns_status ldns_udp_send(uint8_t **result, ldns_buffer *qbin, const struct sock * \param[in] timeout *unused*, was the timeout value for the network * \return the socket used */ - int ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout); /** diff --git a/usr.sbin/unbound/ldns/ldns/packet.h b/usr.sbin/unbound/ldns/ldns/packet.h index 687a6a25957..9dca06f5627 100644 --- a/usr.sbin/unbound/ldns/ldns/packet.h +++ b/usr.sbin/unbound/ldns/ldns/packet.h @@ -410,6 +410,17 @@ uint32_t ldns_pkt_querytime(const ldns_pkt *p); */ size_t ldns_pkt_size(const ldns_pkt *p); +/** + * Return the number of RRs in the given section. + * Returns the sum of all RRs when LDNS_SECTION_ANY is given. + * Returns the sum of all non-question RRs when LDNS_SECTION_ANY_NOQUESTION + * is given. + * \param[in] p the packet + * \param[in] s the section + * \return the number of RRs in the given section + */ +uint16_t ldns_pkt_section_count(const ldns_pkt *p, ldns_pkt_section s); + /** * Return the packet's tsig pseudo rr's * \param[in] p the packet @@ -739,7 +750,7 @@ void ldns_pkt_set_edns_data(ldns_pkt *packet, ldns_rdf *data); * allocates and initializes a ldns_pkt structure. * \return pointer to the new packet */ -ldns_pkt *ldns_pkt_new(); +ldns_pkt *ldns_pkt_new(void); /** * frees the packet structure and all data that it contains. @@ -759,6 +770,18 @@ void ldns_pkt_free(ldns_pkt *packet); */ ldns_status ldns_pkt_query_new_frm_str(ldns_pkt **p, const char *rr_name, ldns_rr_type rr_type, ldns_rr_class rr_class , uint16_t flags); +/** + * creates an IXFR request packet for the given name, class. + * adds the SOA record to the authority section. + * \param[out] p the packet to be returned + * \param[in] rr_name the name to query for (as string) + * \param[in] rr_class the class to query for + * \param[in] flags packet flags + * \param[in] soa soa record to be added to the authority section + * \return LDNS_STATUS_OK or a ldns_status mesg with the error + */ +ldns_status ldns_pkt_ixfr_request_new_frm_str(ldns_pkt **p, const char *rr_name, ldns_rr_class rr_class, uint16_t flags, ldns_rr* soa); + /** * creates a packet with a query in it for the given name, type and class. * \param[in] rr_name the name to query for @@ -769,6 +792,17 @@ ldns_status ldns_pkt_query_new_frm_str(ldns_pkt **p, const char *rr_name, ldns_r */ ldns_pkt *ldns_pkt_query_new(ldns_rdf *rr_name, ldns_rr_type rr_type, ldns_rr_class rr_class, uint16_t flags); +/** + * creates an IXFR request packet for the given name, type and class. + * adds the SOA record to the authority section. + * \param[in] rr_name the name to query for + * \param[in] rr_class the class to query for + * \param[in] flags packet flags + * \param[in] soa soa record to be added to the authority section + * \return ldns_pkt* a pointer to the new pkt + */ +ldns_pkt *ldns_pkt_ixfr_request_new(ldns_rdf *rr_name, ldns_rr_class rr_class, uint16_t flags, ldns_rr* soa); + /** * clones the given packet, creating a fully allocated copy * diff --git a/usr.sbin/unbound/ldns/ldns/radix.h b/usr.sbin/unbound/ldns/ldns/radix.h new file mode 100644 index 00000000000..f8833eb2cec --- /dev/null +++ b/usr.sbin/unbound/ldns/ldns/radix.h @@ -0,0 +1,240 @@ +/* + * radix.h -- generic radix tree + * + * Copyright (c) 2012, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS 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 THE REGENTS OR CONTRIBUTORS 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. + * + */ + +/** + * \file + * Radix tree. Implementation taken from NSD 4, adjusted for use in ldns. + * + */ + +#ifndef LDNS_RADIX_H_ +#define LDNS_RADIX_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint16_t radix_strlen_t; +typedef struct ldns_radix_array_t ldns_radix_array_t; +typedef struct ldns_radix_node_t ldns_radix_node_t; +typedef struct ldns_radix_t ldns_radix_t; + +/** Radix node select edge array */ +struct ldns_radix_array_t { + /** Additional string after the selection byte for this edge. */ + uint8_t* str; + /** Length of additional string for this edge. */ + radix_strlen_t len; + /** Node that deals with byte+str. */ + ldns_radix_node_t* edge; +}; + +/** A node in a radix tree */ +struct ldns_radix_node_t { + /** Key corresponding to this node. */ + uint8_t* key; + /** Key length corresponding to this node. */ + radix_strlen_t klen; + /** Data corresponding to this node. */ + void* data; + /** Parent node. */ + ldns_radix_node_t* parent; + /** Index in the the parent node select edge array. */ + uint8_t parent_index; + /** Length of the array. */ + uint16_t len; + /** Offset of the array. */ + uint16_t offset; + /** Capacity of the array. */ + uint16_t capacity; + /** Select edge array. */ + ldns_radix_array_t* array; +}; + +/** An entire radix tree */ +struct ldns_radix_t { + /** Root. */ + ldns_radix_node_t* root; + /** Number of nodes in tree. */ + size_t count; +}; + +/** + * Create a new radix tree. + * @return: new radix tree. + * + */ +ldns_radix_t* ldns_radix_create(void); + +/** + * Initialize radix tree. + * @param tree: uninitialized radix tree. + * + */ +void ldns_radix_init(ldns_radix_t* tree); + +/** + * Free the radix tree. + * @param tree: radix tree. + * + */ +void ldns_radix_free(ldns_radix_t* tree); + +/** + * Insert data into the tree. + * @param tree: tree to insert to. + * @param key: key. + * @param len: length of key. + * @param data: data. + * @return: status. + * + */ +ldns_status ldns_radix_insert(ldns_radix_t* tree, uint8_t* key, + radix_strlen_t len, void* data); + +/** + * Delete data from the tree. + * @param tree: tree to insert to. + * @param key: key. + * @param len: length of key. + * @return: unlinked data or NULL if not present. + * + */ +void* ldns_radix_delete(ldns_radix_t* tree, uint8_t* key, radix_strlen_t len); + +/** + * Search data in the tree. + * @param tree: tree to insert to. + * @param key: key. + * @param len: length of key. + * @return: the radix node or NULL if not found. + * + */ +ldns_radix_node_t* ldns_radix_search(ldns_radix_t* tree, uint8_t* key, + radix_strlen_t len); + +/** + * Search data in the tree, and if not found, find the closest smaller + * element in the tree. + * @param tree: tree to insert to. + * @param key: key. + * @param len: length of key. + * @param result: the radix node with the exact or closest match. NULL if + * the key is smaller than the smallest key in the tree. + * @return 1 if exact match, 0 otherwise. + * + */ +int ldns_radix_find_less_equal(ldns_radix_t* tree, uint8_t* key, + radix_strlen_t len, ldns_radix_node_t** result); + +/** + * Get the first element in the tree. + * @param tree: tree. + * @return: the radix node with the first element. + * + */ +ldns_radix_node_t* ldns_radix_first(ldns_radix_t* tree); + +/** + * Get the last element in the tree. + * @param tree: tree. + * @return: the radix node with the last element. + * + */ +ldns_radix_node_t* ldns_radix_last(ldns_radix_t* tree); + +/** + * Next element. + * @param node: node. + * @return: node with next element. + * + */ +ldns_radix_node_t* ldns_radix_next(ldns_radix_node_t* node); + +/** + * Previous element. + * @param node: node. + * @return: node with previous element. + * + */ +ldns_radix_node_t* ldns_radix_prev(ldns_radix_node_t* node); + +/** + * Split radix tree intwo. + * @param tree1: one tree. + * @param num: number of elements to split off. + * @param tree2: another tree. + * @return: status. + * + */ +ldns_status ldns_radix_split(ldns_radix_t* tree1, size_t num, + ldns_radix_t** tree2); + +/** + * Join two radix trees. + * @param tree1: one tree. + * @param tree2: another tree. + * @return: status. + * + */ +ldns_status ldns_radix_join(ldns_radix_t* tree1, ldns_radix_t* tree2); + +/** + * Call function for all nodes in the tree, such that leaf nodes are + * called before parent nodes. + * @param node: start node. + * @param func: function. + * @param arg: user argument. + * + */ +void ldns_radix_traverse_postorder(ldns_radix_node_t* node, + void (*func)(ldns_radix_node_t*, void*), void* arg); + +/** + * Print radix tree (for debugging purposes). + * @param fd: file descriptor. + * @param tree: tree. + * + */ +void ldns_radix_printf(FILE* fd, ldns_radix_t* tree); + +#ifdef __cplusplus +} +#endif + +#endif /* LDNS_RADIX_H_ */ diff --git a/usr.sbin/unbound/ldns/ldns/rdata.h b/usr.sbin/unbound/ldns/ldns/rdata.h index 229a4d4c5b5..1866e8fc066 100644 --- a/usr.sbin/unbound/ldns/ldns/rdata.h +++ b/usr.sbin/unbound/ldns/ldns/rdata.h @@ -28,12 +28,13 @@ extern "C" { #endif -#define LDNS_MAX_RDFLEN 8192 +#define LDNS_MAX_RDFLEN 65535 #define LDNS_RDF_SIZE_BYTE 1 #define LDNS_RDF_SIZE_WORD 2 #define LDNS_RDF_SIZE_DOUBLEWORD 4 #define LDNS_RDF_SIZE_6BYTES 6 +#define LDNS_RDF_SIZE_8BYTES 8 #define LDNS_RDF_SIZE_16BYTES 16 #define LDNS_NSEC3_VARS_OPTOUT_MASK 0x01 @@ -85,7 +86,10 @@ enum ldns_enum_rdf_type LDNS_RDF_TYPE_PERIOD, /** tsig time 48 bits */ LDNS_RDF_TYPE_TSIGTIME, - LDNS_RDF_TYPE_TSIG, + /** Represents the Public Key Algorithm, HIT and Public Key fields + for the HIP RR types. A HIP specific rdf type is used because of + the unusual layout in wireformat (see RFC 5205 Section 5) */ + LDNS_RDF_TYPE_HIP, /** variable length any type rdata where the length is specified by the first 2 bytes */ LDNS_RDF_TYPE_INT16_DATA, @@ -104,7 +108,31 @@ enum ldns_enum_rdf_type /** nsec3 hash salt */ LDNS_RDF_TYPE_NSEC3_SALT, /** nsec3 base32 string (with length byte on wire */ - LDNS_RDF_TYPE_NSEC3_NEXT_OWNER + LDNS_RDF_TYPE_NSEC3_NEXT_OWNER, + + /** 4 shorts represented as 4 * 16 bit hex numbers + * separated by colons. For NID and L64. + */ + LDNS_RDF_TYPE_ILNP64, + + /** 6 * 8 bit hex numbers separated by dashes. For EUI48. */ + LDNS_RDF_TYPE_EUI48, + /** 8 * 8 bit hex numbers separated by dashes. For EUI64. */ + LDNS_RDF_TYPE_EUI64, + + /** A non-zero sequence of US-ASCII letters and numbers in lower case. + * For CAA. + */ + LDNS_RDF_TYPE_TAG, + + /** A encoding of the value field as specified + * [RFC1035], Section 5.1., encoded as remaining rdata. + * For CAA. + */ + LDNS_RDF_TYPE_LONG_STR, + + /* Aliases */ + LDNS_RDF_TYPE_BITMAP = LDNS_RDF_TYPE_NSEC }; typedef enum ldns_enum_rdf_type ldns_rdf_type; @@ -380,6 +408,34 @@ ldns_rdf *ldns_rdf_clone(const ldns_rdf *rd); */ int ldns_rdf_compare(const ldns_rdf *rd1, const ldns_rdf *rd2); +/** + * Gets the algorithm value, the HIT and Public Key data from the rdf with + * type LDNS_RDF_TYPE_HIP. + * \param[in] rdf the rdf with type LDNS_RDF_TYPE_HIP + * \param[out] alg the algorithm + * \param[out] hit_size the size of the HIT data + * \param[out] hit the hit data + * \param[out] pk_size the size of the Public Key data + * \param[out] pk the Public Key data + * \return LDNS_STATUS_OK on success, and the error otherwise + */ +ldns_status ldns_rdf_hip_get_alg_hit_pk(ldns_rdf *rdf, uint8_t* alg, + uint8_t *hit_size, uint8_t** hit, + uint16_t *pk_size, uint8_t** pk); + +/** + * Creates a new LDNS_RDF_TYPE_HIP rdf from given data. + * \param[out] rdf the newly created LDNS_RDF_TYPE_HIP rdf + * \param[in] alg the algorithm + * \param[in] hit_size the size of the HIT data + * \param[in] hit the hit data + * \param[in] pk_size the size of the Public Key data + * \param[in] pk the Public Key data + * \return LDNS_STATUS_OK on success, and the error otherwise + */ +ldns_status ldns_rdf_hip_new_frm_alg_hit_pk(ldns_rdf** rdf, uint8_t alg, + uint8_t hit_size, uint8_t *hit, uint16_t pk_size, uint8_t *pk); + #ifdef __cplusplus } #endif diff --git a/usr.sbin/unbound/ldns/ldns/resolver.h b/usr.sbin/unbound/ldns/ldns/resolver.h index 7af5d401e65..26d4f480b5f 100644 --- a/usr.sbin/unbound/ldns/ldns/resolver.h +++ b/usr.sbin/unbound/ldns/ldns/resolver.h @@ -138,6 +138,9 @@ struct ldns_struct_resolver char *_tsig_keydata; /** TSIG signing algorithm */ char *_tsig_algorithm; + + /** Source address to query from */ + ldns_rdf *_source; }; typedef struct ldns_struct_resolver ldns_resolver; @@ -151,6 +154,13 @@ typedef struct ldns_struct_resolver ldns_resolver; */ uint16_t ldns_resolver_port(const ldns_resolver *r); +/** + * Get the source address the resolver should use + * \param[in] r the resolver + * \return the source rdf + */ +ldns_rdf *ldns_resolver_source(const ldns_resolver *r); + /** * Is the resolver set to recurse * \param[in] r the resolver @@ -337,6 +347,13 @@ size_t ldns_resolver_searchlist_count(const ldns_resolver *r); */ void ldns_resolver_set_port(ldns_resolver *r, uint16_t p); +/** + * Set the source rdf (address) the resolver should use + * \param[in] r the resolver + * \param[in] s the source address + */ +void ldns_resolver_set_source(ldns_resolver *r, ldns_rdf *s); + /** * Set the resolver recursion * \param[in] r the resolver @@ -464,9 +481,10 @@ void ldns_resolver_set_retrans(ldns_resolver *r, uint8_t re); void ldns_resolver_set_fallback(ldns_resolver *r, bool fallback); /** - * Set the resolver retry interval (in seconds) + * Set the number of times a resolver should retry a nameserver before the + * next one is tried. * \param[in] r the resolver - * \param[in] re the retry interval + * \param[in] re the number of retries */ void ldns_resolver_set_retry(ldns_resolver *r, uint8_t re); @@ -583,6 +601,22 @@ ldns_status ldns_resolver_push_nameserver_rr_list(ldns_resolver *r, ldns_rr_list */ ldns_pkt* ldns_resolver_search(const ldns_resolver *r, const ldns_rdf *rdf, ldns_rr_type t, ldns_rr_class c, uint16_t flags); + +/** + * Send the query for using the resolver and take the search list into account + * The search algorithm is as follows: + * If the name is absolute, try it as-is, otherwise apply the search list + * \param[out] pkt a packet with the reply from the nameserver + * \param[in] *r operate using this resolver + * \param[in] *rdf query for this name + * \param[in] t query for this type (may be 0, defaults to A) + * \param[in] c query for this class (may be 0, default to IN) + * \param[in] flags the query flags + * + * \return ldns_status LDNS_STATUS_OK on success + */ +ldns_status ldns_resolver_search_status(ldns_pkt** pkt, ldns_resolver *r, const ldns_rdf *rdf, ldns_rr_type t, ldns_rr_class c, uint16_t flags); + /** * Form a query packet from a resolver and name/type/class combo * \param[out] **q a pointer to a ldns_pkt pointer (initialized by this function) @@ -619,12 +653,29 @@ ldns_status ldns_resolver_send_pkt(ldns_pkt **answer, ldns_resolver *r, ldns_pkt /** * Send a query to a nameserver + * \param[out] pkt a packet with the reply from the nameserver * \param[in] *r operate using this resolver * \param[in] *name query for this name * \param[in] *t query for this type (may be 0, defaults to A) * \param[in] *c query for this class (may be 0, default to IN) * \param[in] flags the query flags * + * \return ldns_status LDNS_STATUS_OK on success + * if _defnames is true the default domain will be added + */ +ldns_status ldns_resolver_query_status(ldns_pkt** pkt, ldns_resolver *r, const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, uint16_t flags); + + +/** + * Send a query to a nameserver + * \param[in] *r operate using this resolver + * (despite the const in the declaration, + * the struct is altered as a side-effect) + * \param[in] *name query for this name + * \param[in] *t query for this type (may be 0, defaults to A) + * \param[in] *c query for this class (may be 0, default to IN) + * \param[in] flags the query flags + * * \return ldns_pkt* a packet with the reply from the nameserver * if _defnames is true the default domain will be added */ diff --git a/usr.sbin/unbound/ldns/ldns/rr.h b/usr.sbin/unbound/ldns/ldns/rr.h index 0520dcfe102..ff499395c00 100644 --- a/usr.sbin/unbound/ldns/ldns/rr.h +++ b/usr.sbin/unbound/ldns/ldns/rr.h @@ -36,8 +36,8 @@ extern "C" { /** The bytes TTL, CLASS and length use up in an rr */ #define LDNS_RR_OVERHEAD 10 -/* The first fields are 'common' and can be referenced instantly */ -#define LDNS_RDATA_FIELD_DESCRIPTORS_COMMON 53 +/* The first fields are contiguous and can be referenced instantly */ +#define LDNS_RDATA_FIELD_DESCRIPTORS_COMMON 258 @@ -163,7 +163,7 @@ enum ldns_enum_rr_type LDNS_RR_TYPE_OPT = 41, /** RFC3123 */ LDNS_RR_TYPE_APL = 42, - /** draft-ietf-dnsext-delegation */ + /** RFC4034, RFC3658 */ LDNS_RR_TYPE_DS = 43, /** SSH Key Fingerprint */ LDNS_RR_TYPE_SSHFP = 44, /* RFC 4255 */ @@ -179,19 +179,35 @@ enum ldns_enum_rr_type LDNS_RR_TYPE_NSEC3 = 50, /* RFC 5155 */ LDNS_RR_TYPE_NSEC3PARAM = 51, /* RFC 5155 */ LDNS_RR_TYPE_NSEC3PARAMS = 51, - /** draft-ietf-dane-protocol */ - LDNS_RR_TYPE_TLSA = 52, + LDNS_RR_TYPE_TLSA = 52, /* RFC 6698 */ + LDNS_RR_TYPE_HIP = 55, /* RFC 5205 */ + + /** draft-reid-dnsext-zs */ + LDNS_RR_TYPE_NINFO = 56, + /** draft-reid-dnsext-rkey */ + LDNS_RR_TYPE_RKEY = 57, /** draft-ietf-dnsop-trust-history */ LDNS_RR_TYPE_TALINK = 58, + /** draft-barwood-dnsop-ds-publis */ + LDNS_RR_TYPE_CDS = 59, - LDNS_RR_TYPE_SPF = 99, + LDNS_RR_TYPE_SPF = 99, /* RFC 4408 */ LDNS_RR_TYPE_UINFO = 100, LDNS_RR_TYPE_UID = 101, LDNS_RR_TYPE_GID = 102, LDNS_RR_TYPE_UNSPEC = 103, + LDNS_RR_TYPE_NID = 104, /* RFC 6742 */ + LDNS_RR_TYPE_L32 = 105, /* RFC 6742 */ + LDNS_RR_TYPE_L64 = 106, /* RFC 6742 */ + LDNS_RR_TYPE_LP = 107, /* RFC 6742 */ + + LDNS_RR_TYPE_EUI48 = 108, /* RFC 7043 */ + LDNS_RR_TYPE_EUI64 = 109, /* RFC 7043 */ + + LDNS_RR_TYPE_TKEY = 249, /* RFC 2930 */ LDNS_RR_TYPE_TSIG = 250, LDNS_RR_TYPE_IXFR = 251, LDNS_RR_TYPE_AXFR = 252, @@ -201,7 +217,12 @@ enum ldns_enum_rr_type LDNS_RR_TYPE_MAILA = 254, /** any type (wildcard) */ LDNS_RR_TYPE_ANY = 255, + /** draft-faltstrom-uri-06 */ + LDNS_RR_TYPE_URI = 256, + LDNS_RR_TYPE_CAA = 257, /* RFC 6844 */ + /** DNSSEC Trust Authorities */ + LDNS_RR_TYPE_TA = 32768, /* RFC 4431, 5074, DNSSEC Lookaside Validation */ LDNS_RR_TYPE_DLV = 32769, @@ -337,6 +358,23 @@ struct ldns_struct_rr_descriptor }; typedef struct ldns_struct_rr_descriptor ldns_rr_descriptor; + +/** + * Create a rr type bitmap rdf providing enough space to set all + * known (to ldns) rr types. + * \param[out] rdf the constructed rdf + * \return LDNS_STATUS_OK if all went well. + */ +ldns_status ldns_rdf_bitmap_known_rr_types_space(ldns_rdf** rdf); + +/** + * Create a rr type bitmap rdf with at least all known (to ldns) rr types set. + * \param[out] rdf the constructed rdf + * \return LDNS_STATUS_OK if all went well. + */ +ldns_status ldns_rdf_bitmap_known_rr_types(ldns_rdf** rdf); + + /** * creates a new rr structure. * \return ldns_rr * @@ -589,7 +627,7 @@ ldns_rr* ldns_rr_list_rr(const ldns_rr_list *rr_list, size_t nr); * creates a new rr_list structure. * \return a new rr_list structure */ -ldns_rr_list* ldns_rr_list_new(); +ldns_rr_list* ldns_rr_list_new(void); /** * frees an rr_list structure. diff --git a/usr.sbin/unbound/ldns/ldns/str2host.h b/usr.sbin/unbound/ldns/ldns/str2host.h index 09416cd2252..341aa248195 100644 --- a/usr.sbin/unbound/ldns/ldns/str2host.h +++ b/usr.sbin/unbound/ldns/ldns/str2host.h @@ -180,14 +180,6 @@ ldns_status ldns_str2rdf_alg(ldns_rdf **rd, const char *str); */ ldns_status ldns_str2rdf_unknown(ldns_rdf **rd, const char *str); -/** - * convert string with a tsig? RR into wireformat - * \param[in] rd the rdf where to put the data - * \param[in] str the string to be converted - * \return ldns_status - */ -ldns_status ldns_str2rdf_tsig(ldns_rdf **rd, const char *str); - /** * convert string with a protocol service into wireformat * \param[in] rd the rdf where to put the data @@ -244,6 +236,58 @@ ldns_status ldns_str2rdf_ipseckey(ldns_rdf **rd, const char *str); */ ldns_status ldns_str2rdf_dname(ldns_rdf **rd, const char *str); +/** + * convert 4 * 16bit hex separated by colons into wireformat + * \param[in] rd the rdf where to put the data + * \param[in] str the string to be converted + * \return ldns_status + */ +ldns_status ldns_str2rdf_ilnp64(ldns_rdf **rd, const char *str); + +/** + * convert 6 hex bytes separated by dashes into wireformat + * \param[in] rd the rdf where to put the data + * \param[in] str the string to be converted + * \return ldns_status + */ +ldns_status ldns_str2rdf_eui48(ldns_rdf **rd, const char *str); + +/** + * convert 8 hex bytes separated by dashes into wireformat + * \param[in] rd the rdf where to put the data + * \param[in] str the string to be converted + * \return ldns_status + */ +ldns_status ldns_str2rdf_eui64(ldns_rdf **rd, const char *str); + +/** + * Convert a non-zero sequence of US-ASCII letters and numbers into wireformat + * \param[in] rd the rdf where to put the data + * \param[in] str the string to be converted + * \return ldns_status + */ +ldns_status ldns_str2rdf_tag(ldns_rdf **rd, const char *str); + +/** + * Convert a encoding of the value field as specified + * [RFC1035], Section 5.1., encoded as one bug chunk of data. + * \param[in] rd the rdf where to put the data + * \param[in] str the string to be converted + * \return ldns_status + */ +ldns_status ldns_str2rdf_long_str(ldns_rdf **rd, const char *str); + +/** + * Convert a " " encoding of the value field as specified + * in Section 6. of [RFC5205], encoded as wireformat as specified in Section 5. + * of [RFC5205]. + * \param[in] rd the rdf where to put the data + * \param[in] str the string to be converted + * \return ldns_status + */ +ldns_status ldns_str2rdf_hip(ldns_rdf **rd, const char *str); + + #ifdef __cplusplus } #endif diff --git a/usr.sbin/unbound/ldns/ldns/util.h.in b/usr.sbin/unbound/ldns/ldns/util.h.in index fe4ff3720b0..b6c9abe022f 100644 --- a/usr.sbin/unbound/ldns/ldns/util.h.in +++ b/usr.sbin/unbound/ldns/ldns/util.h.in @@ -325,42 +325,66 @@ uint16_t ldns_get_random(void); */ char *ldns_bubblebabble(uint8_t *data, size_t len); -#ifndef B32_NTOP -int ldns_b32_ntop(uint8_t const *src, size_t srclength, - char *target, size_t targsize); -int b32_ntop(uint8_t const *src, size_t srclength, - char *target, size_t targsize); -int ldns_b32_ntop_extended_hex(uint8_t const *src, size_t srclength, - char *target, size_t targsize); -int b32_ntop_extended_hex(uint8_t const *src, size_t srclength, - char *target, size_t targsize); + +INLINE time_t ldns_time(time_t *t) { return time(t); } + + /** * calculates the size needed to store the result of b32_ntop */ /*@unused@*/ -INLINE size_t ldns_b32_ntop_calculate_size(size_t srcsize) +INLINE size_t ldns_b32_ntop_calculate_size(size_t src_data_length) { - size_t result = ((((srcsize / 5) * 8) - 2) + 2); - return result; + return src_data_length == 0 ? 0 : ((src_data_length - 1) / 5 + 1) * 8; +} + +INLINE size_t ldns_b32_ntop_calculate_size_no_padding(size_t src_data_length) +{ + return ((src_data_length + 3) * 8 / 5) - 4; } -#endif /* !B32_NTOP */ -#ifndef B32_PTON -int ldns_b32_pton(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize); -int b32_pton(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize); -int ldns_b32_pton_extended_hex(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize); -int b32_pton_extended_hex(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize); + +int ldns_b32_ntop(const uint8_t* src_data, size_t src_data_length, + char* target_text_buffer, size_t target_text_buffer_size); + +int ldns_b32_ntop_extended_hex(const uint8_t* src_data, size_t src_data_length, + char* target_text_buffer, size_t target_text_buffer_size); + +#if ! LDNS_BUILD_CONFIG_HAVE_B32_NTOP + +int b32_ntop(const uint8_t* src_data, size_t src_data_length, + char* target_text_buffer, size_t target_text_buffer_size); + +int b32_ntop_extended_hex(const uint8_t* src_data, size_t src_data_length, + char* target_text_buffer, size_t target_text_buffer_size); + +#endif /* ! LDNS_BUILD_CONFIG_HAVE_B32_NTOP */ + + /** * calculates the size needed to store the result of b32_pton */ /*@unused@*/ -INLINE size_t ldns_b32_pton_calculate_size(size_t srcsize) +INLINE size_t ldns_b32_pton_calculate_size(size_t src_text_length) { - size_t result = ((((srcsize) / 8) * 5)); - return result; + return src_text_length * 5 / 8; } -#endif /* !B32_PTON */ -INLINE time_t ldns_time(time_t *t) { return time(t); } +int ldns_b32_pton(const char* src_text, size_t src_text_length, + uint8_t* target_data_buffer, size_t target_data_buffer_size); + +int ldns_b32_pton_extended_hex(const char* src_text, size_t src_text_length, + uint8_t* target_data_buffer, size_t target_data_buffer_size); + +#if ! LDNS_BUILD_CONFIG_HAVE_B32_PTON + +int b32_pton(const char* src_text, size_t src_text_length, + uint8_t* target_data_buffer, size_t target_data_buffer_size); + +int b32_pton_extended_hex(const char* src_text, size_t src_text_length, + uint8_t* target_data_buffer, size_t target_data_buffer_size); + +#endif /* ! LDNS_BUILD_CONFIG_HAVE_B32_PTON */ + #ifdef __cplusplus } diff --git a/usr.sbin/unbound/ldns/net.c b/usr.sbin/unbound/ldns/net.c index 6b444da677b..b8a5385e1c2 100644 --- a/usr.sbin/unbound/ldns/net.c +++ b/usr.sbin/unbound/ldns/net.c @@ -56,175 +56,53 @@ ldns_send(ldns_pkt **result_packet, ldns_resolver *r, const ldns_pkt *query_pkt) return result; } -ldns_status -ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac) +/* code from rdata.c */ +static struct sockaddr_storage * +ldns_rdf2native_sockaddr_storage_port( + const ldns_rdf *rd, uint16_t port, size_t *size) { - uint8_t i; - - struct sockaddr_storage *ns; - size_t ns_len; - struct timeval tv_s; - struct timeval tv_e; - - ldns_rdf **ns_array; - size_t *rtt; - ldns_pkt *reply; - bool all_servers_rtt_inf; - uint8_t retries; - - uint8_t *reply_bytes = NULL; - size_t reply_size = 0; - ldns_status status, send_status; - - assert(r != NULL); - - status = LDNS_STATUS_OK; - rtt = ldns_resolver_rtt(r); - ns_array = ldns_resolver_nameservers(r); - reply = NULL; - ns_len = 0; - - all_servers_rtt_inf = true; - - if (ldns_resolver_random(r)) { - ldns_resolver_nameservers_randomize(r); - } - - /* loop through all defined nameservers */ - for (i = 0; i < ldns_resolver_nameserver_count(r); i++) { - if (rtt[i] == LDNS_RESOLV_RTT_INF) { - /* not reachable nameserver! */ - continue; - } - - /* maybe verbosity setting? - printf("Sending to "); - ldns_rdf_print(stdout, ns_array[i]); - printf("\n"); - */ - ns = ldns_rdf2native_sockaddr_storage(ns_array[i], - ldns_resolver_port(r), &ns_len); + struct sockaddr_storage *data; + struct sockaddr_in *data_in; + struct sockaddr_in6 *data_in6; + data = LDNS_MALLOC(struct sockaddr_storage); + if (!data) { + return NULL; + } + /* zero the structure for portability */ + memset(data, 0, sizeof(struct sockaddr_storage)); + switch(ldns_rdf_get_type(rd)) { + case LDNS_RDF_TYPE_A: #ifndef S_SPLINT_S - if ((ns->ss_family == AF_INET) && - (ldns_resolver_ip6(r) == LDNS_RESOLV_INET6)) { - /* not reachable */ - LDNS_FREE(ns); - continue; - } - - if ((ns->ss_family == AF_INET6) && - (ldns_resolver_ip6(r) == LDNS_RESOLV_INET)) { - /* not reachable */ - LDNS_FREE(ns); - continue; - } + data->ss_family = AF_INET; #endif + data_in = (struct sockaddr_in*) data; + data_in->sin_port = (in_port_t)htons(port); + memcpy(&(data_in->sin_addr), ldns_rdf_data(rd), ldns_rdf_size(rd)); + *size = sizeof(struct sockaddr_in); + return data; + case LDNS_RDF_TYPE_AAAA: +#ifndef S_SPLINT_S + data->ss_family = AF_INET6; +#endif + data_in6 = (struct sockaddr_in6*) data; + data_in6->sin6_port = (in_port_t)htons(port); + memcpy(&data_in6->sin6_addr, ldns_rdf_data(rd), ldns_rdf_size(rd)); + *size = sizeof(struct sockaddr_in6); + return data; + default: + LDNS_FREE(data); + return NULL; + } +} - all_servers_rtt_inf = false; - - gettimeofday(&tv_s, NULL); - - send_status = LDNS_STATUS_ERR; - - /* reply_bytes implicitly handles our error */ - if (1 == ldns_resolver_usevc(r)) { - for (retries = ldns_resolver_retry(r); retries > 0; retries--) { - send_status = - ldns_tcp_send(&reply_bytes, qb, ns, - (socklen_t)ns_len, ldns_resolver_timeout(r), - &reply_size); - if (send_status == LDNS_STATUS_OK) { - break; - } - } - } else { - for (retries = ldns_resolver_retry(r); retries > 0; retries--) { - /* ldns_rdf_print(stdout, ns_array[i]); */ - send_status = - ldns_udp_send(&reply_bytes, qb, ns, - (socklen_t)ns_len, ldns_resolver_timeout(r), - &reply_size); - - if (send_status == LDNS_STATUS_OK) { - break; - } - } - } - - if (send_status != LDNS_STATUS_OK) { - ldns_resolver_set_nameserver_rtt(r, i, LDNS_RESOLV_RTT_INF); - status = send_status; - } - - /* obey the fail directive */ - if (!reply_bytes) { - /* the current nameserver seems to have a problem, blacklist it */ - if (ldns_resolver_fail(r)) { - LDNS_FREE(ns); - return LDNS_STATUS_ERR; - } else { - LDNS_FREE(ns); - continue; - } - } - - status = ldns_wire2pkt(&reply, reply_bytes, reply_size); - if (status != LDNS_STATUS_OK) { - LDNS_FREE(reply_bytes); - LDNS_FREE(ns); - return status; - } - - LDNS_FREE(ns); - gettimeofday(&tv_e, NULL); - - if (reply) { - ldns_pkt_set_querytime(reply, (uint32_t) - ((tv_e.tv_sec - tv_s.tv_sec) * 1000) + - (tv_e.tv_usec - tv_s.tv_usec) / 1000); - ldns_pkt_set_answerfrom(reply, - ldns_rdf_clone(ns_array[i])); - ldns_pkt_set_timestamp(reply, tv_s); - ldns_pkt_set_size(reply, reply_size); - break; - } else { - if (ldns_resolver_fail(r)) { - /* if fail is set bail out, after the first - * one */ - break; - } - } - - /* wait retrans seconds... */ - sleep((unsigned int) ldns_resolver_retrans(r)); - } - - if (all_servers_rtt_inf) { - LDNS_FREE(reply_bytes); - return LDNS_STATUS_RES_NO_NS; - } -#ifdef HAVE_SSL - if (tsig_mac && reply && reply_bytes) { - if (!ldns_pkt_tsig_verify(reply, - reply_bytes, - reply_size, - ldns_resolver_tsig_keyname(r), - ldns_resolver_tsig_keydata(r), tsig_mac)) { - status = LDNS_STATUS_CRYPTO_TSIG_BOGUS; - } - } -#else - (void)tsig_mac; -#endif /* HAVE_SSL */ - - LDNS_FREE(reply_bytes); - if (result) { - *result = reply; - } - - return status; +struct sockaddr_storage * +ldns_rdf2native_sockaddr_storage( + const ldns_rdf *rd, uint16_t port, size_t *size) +{ + return ldns_rdf2native_sockaddr_storage_port( + rd, (port == 0 ? (uint16_t)LDNS_PORT : port), size); } /** best effort to set nonblocking */ @@ -290,63 +168,123 @@ ldns_sock_wait(int sockfd, struct timeval timeout, int write) return 1; } -ldns_status -ldns_udp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to, - socklen_t tolen, struct timeval timeout, size_t *answer_size) + +static int +ldns_tcp_connect_from(const struct sockaddr_storage *to, socklen_t tolen, + const struct sockaddr_storage *from, socklen_t fromlen, + struct timeval timeout) { int sockfd; - uint8_t *answer; - - sockfd = ldns_udp_bgsend(qbin, to, tolen, timeout); - if (sockfd == 0) { - return LDNS_STATUS_SOCKET_ERROR; +#ifndef S_SPLINT_S + if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM, + IPPROTO_TCP)) == -1) { + return 0; + } +#endif + if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == -1){ + return 0; } - /* wait for an response*/ - if(!ldns_sock_wait(sockfd, timeout, 0)) { + /* perform nonblocking connect, to be able to wait with select() */ + ldns_sock_nonblock(sockfd); + if (connect(sockfd, (struct sockaddr*)to, tolen) == -1) { #ifndef USE_WINSOCK - close(sockfd); +#ifdef EINPROGRESS + if(errno != EINPROGRESS) { #else - closesocket(sockfd); + if(1) { #endif - return LDNS_STATUS_NETWORK_ERR; + close(sockfd); + return 0; + } +#else /* USE_WINSOCK */ + if(WSAGetLastError() != WSAEINPROGRESS && + WSAGetLastError() != WSAEWOULDBLOCK) { + closesocket(sockfd); + return 0; + } +#endif + /* error was only telling us that it would block */ } - /* set to nonblocking, so if the checksum is bad, it becomes - * an EGAIN error and the ldns_udp_send function does not block, - * but returns a 'NETWORK_ERROR' much like a timeout. */ - ldns_sock_nonblock(sockfd); + /* wait(write) until connected or error */ + while(1) { + int error = 0; + socklen_t len = (socklen_t)sizeof(error); - answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL); + if(!ldns_sock_wait(sockfd, timeout, 1)) { #ifndef USE_WINSOCK - close(sockfd); + close(sockfd); #else - closesocket(sockfd); + closesocket(sockfd); #endif + return 0; + } - if (*answer_size == 0) { - /* oops */ - return LDNS_STATUS_NETWORK_ERR; + /* check if there is a pending error for nonblocking connect */ + if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&error, + &len) < 0) { +#ifndef USE_WINSOCK + error = errno; /* on solaris errno is error */ +#else + error = WSAGetLastError(); +#endif + } +#ifndef USE_WINSOCK +#if defined(EINPROGRESS) && defined(EWOULDBLOCK) + if(error == EINPROGRESS || error == EWOULDBLOCK) + continue; /* try again */ +#endif + else if(error != 0) { + close(sockfd); + /* error in errno for our user */ + errno = error; + return 0; + } +#else /* USE_WINSOCK */ + if(error == WSAEINPROGRESS) + continue; + else if(error == WSAEWOULDBLOCK) + continue; + else if(error != 0) { + closesocket(sockfd); + errno = error; + return 0; + } +#endif /* USE_WINSOCK */ + /* connected */ + break; } - *result = answer; - return LDNS_STATUS_OK; + /* set the socket blocking again */ + ldns_sock_block(sockfd); + + return sockfd; } int -ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, +ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout) { - int sockfd; - - sockfd = ldns_udp_connect(to, timeout); + return ldns_tcp_connect_from(to, tolen, NULL, 0, timeout); +} +static int +ldns_tcp_bgsend_from(ldns_buffer *qbin, + const struct sockaddr_storage *to, socklen_t tolen, + const struct sockaddr_storage *from, socklen_t fromlen, + struct timeval timeout) +{ + int sockfd; + + sockfd = ldns_tcp_connect_from(to, tolen, from, fromlen, timeout); + if (sockfd == 0) { return 0; } - - if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) { + + if (ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) { #ifndef USE_WINSOCK close(sockfd); #else @@ -354,9 +292,67 @@ ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t #endif return 0; } + return sockfd; } +int +ldns_tcp_bgsend(ldns_buffer *qbin, + const struct sockaddr_storage *to, socklen_t tolen, + struct timeval timeout) +{ + return ldns_tcp_bgsend_from(qbin, to, tolen, NULL, 0, timeout); +} + + +/* keep in mind that in DNS tcp messages the first 2 bytes signal the + * amount data to expect + */ +static ldns_status +ldns_tcp_send_from(uint8_t **result, ldns_buffer *qbin, + const struct sockaddr_storage *to, socklen_t tolen, + const struct sockaddr_storage *from, socklen_t fromlen, + struct timeval timeout, size_t *answer_size) +{ + int sockfd; + uint8_t *answer; + + sockfd = ldns_tcp_bgsend_from(qbin, to, tolen, from, fromlen, timeout); + + if (sockfd == 0) { + return LDNS_STATUS_ERR; + } + + answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout); +#ifndef USE_WINSOCK + close(sockfd); +#else + closesocket(sockfd); +#endif + + if (*answer_size == 0) { + /* oops */ + return LDNS_STATUS_NETWORK_ERR; + } + + /* resize accordingly */ + *result = LDNS_XREALLOC(answer, uint8_t, (size_t)*answer_size); + if(!*result) { + LDNS_FREE(answer); + return LDNS_STATUS_MEM_ERR; + } + return LDNS_STATUS_OK; +} + +ldns_status +ldns_tcp_send(uint8_t **result, ldns_buffer *qbin, + const struct sockaddr_storage *to, socklen_t tolen, + struct timeval timeout, size_t *answer_size) +{ + return ldns_tcp_send_from(result, qbin, + to, tolen, NULL, 0, timeout, answer_size); +} + int ldns_udp_connect(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout)) { @@ -372,94 +368,280 @@ ldns_udp_connect(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(t return sockfd; } -int -ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen, +static int +ldns_udp_bgsend_from(ldns_buffer *qbin, + const struct sockaddr_storage *to , socklen_t tolen, + const struct sockaddr_storage *from, socklen_t fromlen, struct timeval timeout) { int sockfd; -#ifndef S_SPLINT_S - if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM, - IPPROTO_TCP)) == -1) { + sockfd = ldns_udp_connect(to, timeout); + + if (sockfd == 0) { + return 0; + } + + if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == -1){ return 0; } + + if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) { +#ifndef USE_WINSOCK + close(sockfd); +#else + closesocket(sockfd); +#endif + return 0; + } + return sockfd; +} + +int +ldns_udp_bgsend(ldns_buffer *qbin, + const struct sockaddr_storage *to , socklen_t tolen, + struct timeval timeout) +{ + return ldns_udp_bgsend_from(qbin, to, tolen, NULL, 0, timeout); +} + +static ldns_status +ldns_udp_send_from(uint8_t **result, ldns_buffer *qbin, + const struct sockaddr_storage *to , socklen_t tolen, + const struct sockaddr_storage *from, socklen_t fromlen, + struct timeval timeout, size_t *answer_size) +{ + int sockfd; + uint8_t *answer; + + sockfd = ldns_udp_bgsend_from(qbin, to, tolen, from, fromlen, timeout); + + if (sockfd == 0) { + return LDNS_STATUS_SOCKET_ERROR; + } + + /* wait for an response*/ + if(!ldns_sock_wait(sockfd, timeout, 0)) { +#ifndef USE_WINSOCK + close(sockfd); +#else + closesocket(sockfd); #endif + return LDNS_STATUS_NETWORK_ERR; + } + + /* set to nonblocking, so if the checksum is bad, it becomes + * an EGAIN error and the ldns_udp_send function does not block, + * but returns a 'NETWORK_ERROR' much like a timeout. */ + ldns_sock_nonblock(sockfd); + + answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL); +#ifndef USE_WINSOCK + close(sockfd); +#else + closesocket(sockfd); +#endif + + if (*answer_size == 0) { + /* oops */ + return LDNS_STATUS_NETWORK_ERR; + } + + *result = answer; + return LDNS_STATUS_OK; +} + +ldns_status +ldns_udp_send(uint8_t **result, ldns_buffer *qbin, + const struct sockaddr_storage *to , socklen_t tolen, + struct timeval timeout, size_t *answer_size) +{ + return ldns_udp_send_from(result, qbin, to, tolen, NULL, 0, + timeout, answer_size); +} + +ldns_status +ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac) +{ + uint8_t i; + + struct sockaddr_storage *src = NULL; + size_t src_len; + struct sockaddr_storage *ns; + size_t ns_len; + struct timeval tv_s; + struct timeval tv_e; + + ldns_rdf **ns_array; + size_t *rtt; + ldns_pkt *reply; + bool all_servers_rtt_inf; + uint8_t retries; + + uint8_t *reply_bytes = NULL; + size_t reply_size = 0; + ldns_status status, send_status; + + assert(r != NULL); + + status = LDNS_STATUS_OK; + rtt = ldns_resolver_rtt(r); + ns_array = ldns_resolver_nameservers(r); + reply = NULL; + ns_len = 0; + + all_servers_rtt_inf = true; + + if (ldns_resolver_random(r)) { + ldns_resolver_nameservers_randomize(r); + } + + if(ldns_resolver_source(r)) { + src = ldns_rdf2native_sockaddr_storage_port( + ldns_resolver_source(r), 0, &src_len); + } + + /* loop through all defined nameservers */ + for (i = 0; i < ldns_resolver_nameserver_count(r); i++) { + if (rtt[i] == LDNS_RESOLV_RTT_INF) { + /* not reachable nameserver! */ + continue; + } + + /* maybe verbosity setting? + printf("Sending to "); + ldns_rdf_print(stdout, ns_array[i]); + printf("\n"); + */ + ns = ldns_rdf2native_sockaddr_storage(ns_array[i], + ldns_resolver_port(r), &ns_len); + - /* perform nonblocking connect, to be able to wait with select() */ - ldns_sock_nonblock(sockfd); - if (connect(sockfd, (struct sockaddr*)to, tolen) == -1) { -#ifndef USE_WINSOCK -#ifdef EINPROGRESS - if(errno != EINPROGRESS) { -#else - if(1) { -#endif - close(sockfd); - return 0; +#ifndef S_SPLINT_S + if ((ns->ss_family == AF_INET) && + (ldns_resolver_ip6(r) == LDNS_RESOLV_INET6)) { + /* not reachable */ + LDNS_FREE(ns); + continue; } -#else /* USE_WINSOCK */ - if(WSAGetLastError() != WSAEINPROGRESS && - WSAGetLastError() != WSAEWOULDBLOCK) { - closesocket(sockfd); - return 0; + + if ((ns->ss_family == AF_INET6) && + (ldns_resolver_ip6(r) == LDNS_RESOLV_INET)) { + /* not reachable */ + LDNS_FREE(ns); + continue; } #endif - /* error was only telling us that it would block */ - } - /* wait(write) until connected or error */ - while(1) { - int error = 0; - socklen_t len = (socklen_t)sizeof(error); + all_servers_rtt_inf = false; - if(!ldns_sock_wait(sockfd, timeout, 1)) { -#ifndef USE_WINSOCK - close(sockfd); -#else - closesocket(sockfd); -#endif - return 0; + gettimeofday(&tv_s, NULL); + + send_status = LDNS_STATUS_ERR; + + /* reply_bytes implicitly handles our error */ + if (ldns_resolver_usevc(r)) { + for (retries = ldns_resolver_retry(r); retries > 0; retries--) { + send_status = + ldns_tcp_send_from(&reply_bytes, qb, + ns, (socklen_t)ns_len, + src, (socklen_t)src_len, + ldns_resolver_timeout(r), + &reply_size); + if (send_status == LDNS_STATUS_OK) { + break; + } + } + } else { + for (retries = ldns_resolver_retry(r); retries > 0; retries--) { + /* ldns_rdf_print(stdout, ns_array[i]); */ + send_status = + ldns_udp_send_from(&reply_bytes, qb, + ns, (socklen_t)ns_len, + src, (socklen_t)src_len, + ldns_resolver_timeout(r), + &reply_size); + if (send_status == LDNS_STATUS_OK) { + break; + } + } } - /* check if there is a pending error for nonblocking connect */ - if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&error, - &len) < 0) { -#ifndef USE_WINSOCK - error = errno; /* on solaris errno is error */ -#else - error = WSAGetLastError(); -#endif + if (send_status != LDNS_STATUS_OK) { + ldns_resolver_set_nameserver_rtt(r, i, LDNS_RESOLV_RTT_INF); + status = send_status; } -#ifndef USE_WINSOCK -#if defined(EINPROGRESS) && defined(EWOULDBLOCK) - if(error == EINPROGRESS || error == EWOULDBLOCK) - continue; /* try again */ -#endif - else if(error != 0) { - close(sockfd); - /* error in errno for our user */ - errno = error; - return 0; + + /* obey the fail directive */ + if (!reply_bytes) { + /* the current nameserver seems to have a problem, blacklist it */ + if (ldns_resolver_fail(r)) { + LDNS_FREE(ns); + return LDNS_STATUS_ERR; + } else { + LDNS_FREE(ns); + continue; + } + } + + status = ldns_wire2pkt(&reply, reply_bytes, reply_size); + if (status != LDNS_STATUS_OK) { + LDNS_FREE(reply_bytes); + LDNS_FREE(ns); + return status; } -#else /* USE_WINSOCK */ - if(error == WSAEINPROGRESS) - continue; - else if(error == WSAEWOULDBLOCK) - continue; - else if(error != 0) { - closesocket(sockfd); - errno = error; - return 0; + + LDNS_FREE(ns); + gettimeofday(&tv_e, NULL); + + if (reply) { + ldns_pkt_set_querytime(reply, (uint32_t) + ((tv_e.tv_sec - tv_s.tv_sec) * 1000) + + (tv_e.tv_usec - tv_s.tv_usec) / 1000); + ldns_pkt_set_answerfrom(reply, + ldns_rdf_clone(ns_array[i])); + ldns_pkt_set_timestamp(reply, tv_s); + ldns_pkt_set_size(reply, reply_size); + break; + } else { + if (ldns_resolver_fail(r)) { + /* if fail is set bail out, after the first + * one */ + break; + } } -#endif /* USE_WINSOCK */ - /* connected */ - break; + + /* wait retrans seconds... */ + sleep((unsigned int) ldns_resolver_retrans(r)); } - /* set the socket blocking again */ - ldns_sock_block(sockfd); + if(src) { + LDNS_FREE(src); + } + if (all_servers_rtt_inf) { + LDNS_FREE(reply_bytes); + return LDNS_STATUS_RES_NO_NS; + } +#ifdef HAVE_SSL + if (tsig_mac && reply && reply_bytes) { + if (!ldns_pkt_tsig_verify(reply, + reply_bytes, + reply_size, + ldns_resolver_tsig_keyname(r), + ldns_resolver_tsig_keydata(r), tsig_mac)) { + status = LDNS_STATUS_CRYPTO_TSIG_BOGUS; + } + } +#else + (void)tsig_mac; +#endif /* HAVE_SSL */ - return sockfd; + LDNS_FREE(reply_bytes); + if (result) { + *result = reply; + } + + return status; } ssize_t @@ -643,110 +825,6 @@ ldns_tcp_read_wire(int sockfd, size_t *size) return wire; } -/* keep in mind that in DNS tcp messages the first 2 bytes signal the - * amount data to expect - */ -ldns_status -ldns_tcp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to, - socklen_t tolen, struct timeval timeout, size_t *answer_size) -{ - int sockfd; - uint8_t *answer; - - sockfd = ldns_tcp_bgsend(qbin, to, tolen, timeout); - - if (sockfd == 0) { - return LDNS_STATUS_ERR; - } - - answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout); -#ifndef USE_WINSOCK - close(sockfd); -#else - closesocket(sockfd); -#endif - - if (*answer_size == 0) { - /* oops */ - return LDNS_STATUS_NETWORK_ERR; - } - - /* resize accordingly */ - *result = LDNS_XREALLOC(answer, uint8_t, (size_t)*answer_size); - if(!*result) { - LDNS_FREE(answer); - return LDNS_STATUS_MEM_ERR; - } - return LDNS_STATUS_OK; -} - -int -ldns_tcp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, - struct timeval timeout) -{ - int sockfd; - - sockfd = ldns_tcp_connect(to, tolen, timeout); - - if (sockfd == 0) { - return 0; - } - - if (ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) { -#ifndef USE_WINSOCK - close(sockfd); -#else - closesocket(sockfd); -#endif - return 0; - } - - return sockfd; -} - -/* code from rdata.c */ -struct sockaddr_storage * -ldns_rdf2native_sockaddr_storage(const ldns_rdf *rd, uint16_t port, size_t *size) -{ - struct sockaddr_storage *data; - struct sockaddr_in *data_in; - struct sockaddr_in6 *data_in6; - - data = LDNS_MALLOC(struct sockaddr_storage); - if (!data) { - return NULL; - } - /* zero the structure for portability */ - memset(data, 0, sizeof(struct sockaddr_storage)); - if (port == 0) { - port = LDNS_PORT; - } - - switch(ldns_rdf_get_type(rd)) { - case LDNS_RDF_TYPE_A: -#ifndef S_SPLINT_S - data->ss_family = AF_INET; -#endif - data_in = (struct sockaddr_in*) data; - data_in->sin_port = (in_port_t)htons(port); - memcpy(&(data_in->sin_addr), ldns_rdf_data(rd), ldns_rdf_size(rd)); - *size = sizeof(struct sockaddr_in); - return data; - case LDNS_RDF_TYPE_AAAA: -#ifndef S_SPLINT_S - data->ss_family = AF_INET6; -#endif - data_in6 = (struct sockaddr_in6*) data; - data_in6->sin6_port = (in_port_t)htons(port); - memcpy(&data_in6->sin6_addr, ldns_rdf_data(rd), ldns_rdf_size(rd)); - *size = sizeof(struct sockaddr_in6); - return data; - default: - LDNS_FREE(data); - return NULL; - } -} - #ifndef S_SPLINT_S ldns_rdf * ldns_sockaddr_storage2rdf(struct sockaddr_storage *sock, uint16_t *port) @@ -789,6 +867,8 @@ ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class) ldns_pkt *query; ldns_buffer *query_wire; + struct sockaddr_storage *src = NULL; + size_t src_len = 0; struct sockaddr_storage *ns = NULL; size_t ns_len = 0; size_t ns_i; @@ -803,6 +883,10 @@ ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class) if (!query) { return LDNS_STATUS_ADDRESS_ERR; } + if(ldns_resolver_source(resolver)) { + src = ldns_rdf2native_sockaddr_storage_port( + ldns_resolver_source(resolver), 0, &src_len); + } /* For AXFR, we have to make the connection ourselves */ /* try all nameservers (which usually would mean v4 fallback if * @hostname is used */ @@ -817,7 +901,9 @@ ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class) resolver->_nameservers[ns_i], ldns_resolver_port(resolver), &ns_len); - resolver->_socket = ldns_tcp_connect(ns, (socklen_t)ns_len, + resolver->_socket = ldns_tcp_connect_from( + ns, (socklen_t)ns_len, + src, (socklen_t)src_len, ldns_resolver_timeout(resolver)); } @@ -834,8 +920,8 @@ ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class) ldns_resolver_tsig_keydata(resolver), 300, ldns_resolver_tsig_algorithm(resolver), NULL); if (status != LDNS_STATUS_OK) { - /* RoRi: to prevent problems on subsequent calls to ldns_axfr_start - we have to close the socket here! */ + /* to prevent problems on subsequent calls to + * ldns_axfr_start we have to close the socket here! */ #ifndef USE_WINSOCK close(resolver->_socket); #else @@ -873,8 +959,8 @@ ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class) ldns_buffer_free(query_wire); LDNS_FREE(ns); - /* RoRi: to prevent problems on subsequent calls to ldns_axfr_start - we have to close the socket here! */ + /* to prevent problems on subsequent calls to ldns_axfr_start + * we have to close the socket here! */ #ifndef USE_WINSOCK close(resolver->_socket); #else @@ -891,8 +977,8 @@ ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class) ldns_buffer_free(query_wire); LDNS_FREE(ns); - /* RoRi: to prevent problems on subsequent calls to ldns_axfr_start - we have to close the socket here! */ + /* to prevent problems on subsequent calls to ldns_axfr_start + * we have to close the socket here! */ #ifndef USE_WINSOCK close(resolver->_socket); diff --git a/usr.sbin/unbound/ldns/packaging/ldns-config.1 b/usr.sbin/unbound/ldns/packaging/ldns-config.1 index c5a00a1eb38..72afc1898eb 100644 --- a/usr.sbin/unbound/ldns/packaging/ldns-config.1 +++ b/usr.sbin/unbound/ldns/packaging/ldns-config.1 @@ -24,7 +24,11 @@ Show the flags to be used to link with ldns .TP \fB--version\fR -Shows the version of the installed ldns library +Shows the ldns version of the installed ldns library + +.TP +\fB--libversion\fR +Shows version of the binary api of the installed ldns library .TP \fB--help\fR diff --git a/usr.sbin/unbound/ldns/packaging/ldns-config.in b/usr.sbin/unbound/ldns/packaging/ldns-config.in index b728ba544e1..d2cf4d43caf 100755 --- a/usr.sbin/unbound/ldns/packaging/ldns-config.in +++ b/usr.sbin/unbound/ldns/packaging/ldns-config.in @@ -9,6 +9,7 @@ LDFLAGS="@LDFLAGS@ @LIBSSL_LDFLAGS@ @PYTHON_LDFLAGS@" LIBS="@LIBS@ @LIBSSL_LIBS@" LIBDIR="@libdir@" INCLUDEDIR="@includedir@" +LIBVERSION="@LIBLDNS_CURRENT@.@LIBLDNS_REVISION@.@LIBLDNS_AGE@" for arg in $@ do @@ -28,4 +29,8 @@ do then echo "${VERSION}" fi + if [ $arg = "--libversion" ] + then + echo "${LIBVERSION}" + fi done diff --git a/usr.sbin/unbound/ldns/packet.c b/usr.sbin/unbound/ldns/packet.c index b44c0add645..0ac64c52fc4 100644 --- a/usr.sbin/unbound/ldns/packet.c +++ b/usr.sbin/unbound/ldns/packet.c @@ -266,7 +266,7 @@ ldns_pkt_rr_list_by_name(ldns_pkt *packet, ret = NULL; for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) { - if (ldns_rdf_compare(ldns_rr_owner( + if (ldns_dname_compare(ldns_rr_owner( ldns_rr_list_rr(rrs, i)), ownername) == 0) { /* owner names match */ @@ -337,7 +337,7 @@ ldns_pkt_rr_list_by_name_and_type(const ldns_pkt *packet, for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) { if (type == ldns_rr_get_type(ldns_rr_list_rr(rrs, i)) && - ldns_rdf_compare(ldns_rr_owner(ldns_rr_list_rr(rrs, i)), + ldns_dname_compare(ldns_rr_owner(ldns_rr_list_rr(rrs, i)), ownername ) == 0 ) { @@ -729,7 +729,7 @@ ldns_pkt_edns(const ldns_pkt *pkt) { /* Create/destroy/convert functions */ ldns_pkt * -ldns_pkt_new() +ldns_pkt_new(void) { ldns_pkt *packet; packet = LDNS_MALLOC(ldns_pkt); @@ -827,8 +827,8 @@ ldns_pkt_set_flags(ldns_pkt *packet, uint16_t flags) } -static ldns_status -ldns_pkt_add_authsoa(ldns_pkt* packet, ldns_rdf* rr_name, ldns_rr_class rr_class) +static ldns_rr* +ldns_pkt_authsoa(ldns_rdf* rr_name, ldns_rr_class rr_class) { ldns_rr* soa_rr = ldns_rr_new(); ldns_rdf *owner_rdf; @@ -841,12 +841,12 @@ ldns_pkt_add_authsoa(ldns_pkt* packet, ldns_rdf* rr_name, ldns_rr_class rr_class ldns_rdf *minimum_rdf; if (!soa_rr) { - return LDNS_STATUS_MEM_ERR; + return NULL; } owner_rdf = ldns_rdf_clone(rr_name); if (!owner_rdf) { ldns_rr_free(soa_rr); - return LDNS_STATUS_MEM_ERR; + return NULL; } ldns_rr_set_owner(soa_rr, owner_rdf); @@ -856,59 +856,59 @@ ldns_pkt_add_authsoa(ldns_pkt* packet, ldns_rdf* rr_name, ldns_rr_class rr_class if (ldns_str2rdf_dname(&mname_rdf, ".") != LDNS_STATUS_OK) { ldns_rr_free(soa_rr); - return LDNS_STATUS_MEM_ERR; + return NULL; } else { ldns_rr_push_rdf(soa_rr, mname_rdf); } if (ldns_str2rdf_dname(&rname_rdf, ".") != LDNS_STATUS_OK) { ldns_rr_free(soa_rr); - return LDNS_STATUS_MEM_ERR; + return NULL; } else { ldns_rr_push_rdf(soa_rr, rname_rdf); } serial_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); if (!serial_rdf) { ldns_rr_free(soa_rr); - return LDNS_STATUS_MEM_ERR; + return NULL; } else { ldns_rr_push_rdf(soa_rr, serial_rdf); } refresh_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); if (!refresh_rdf) { ldns_rr_free(soa_rr); - return LDNS_STATUS_MEM_ERR; + return NULL; } else { ldns_rr_push_rdf(soa_rr, refresh_rdf); } retry_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); if (!retry_rdf) { ldns_rr_free(soa_rr); - return LDNS_STATUS_MEM_ERR; + return NULL; } else { ldns_rr_push_rdf(soa_rr, retry_rdf); } expire_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); if (!expire_rdf) { ldns_rr_free(soa_rr); - return LDNS_STATUS_MEM_ERR; + return NULL; } else { ldns_rr_push_rdf(soa_rr, expire_rdf); } minimum_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); if (!minimum_rdf) { ldns_rr_free(soa_rr); - return LDNS_STATUS_MEM_ERR; + return NULL; } else { ldns_rr_push_rdf(soa_rr, minimum_rdf); } - ldns_pkt_push_rr(packet, LDNS_SECTION_AUTHORITY, soa_rr); - return LDNS_STATUS_OK; + return soa_rr; } -ldns_status -ldns_pkt_query_new_frm_str(ldns_pkt **p, const char *name, ldns_rr_type rr_type, - ldns_rr_class rr_class, uint16_t flags) +static ldns_status +ldns_pkt_query_new_frm_str_internal(ldns_pkt **p, const char *name, + ldns_rr_type rr_type, ldns_rr_class rr_class, uint16_t flags, + ldns_rr* authsoa_rr) { ldns_pkt *packet; ldns_rr *question_rr; @@ -918,11 +918,11 @@ ldns_pkt_query_new_frm_str(ldns_pkt **p, const char *name, ldns_rr_type rr_type, if (!packet) { return LDNS_STATUS_MEM_ERR; } - + if (!ldns_pkt_set_flags(packet, flags)) { return LDNS_STATUS_ERR; } - + question_rr = ldns_rr_new(); if (!question_rr) { return LDNS_STATUS_MEM_ERR; @@ -948,12 +948,8 @@ ldns_pkt_query_new_frm_str(ldns_pkt **p, const char *name, ldns_rr_type rr_type, return LDNS_STATUS_ERR; } - /** IXFR? */ - if (rr_type == LDNS_RR_TYPE_IXFR) { - if (ldns_pkt_add_authsoa(packet, name_rdf, rr_class) != LDNS_STATUS_OK) { - ldns_pkt_free(packet); - return LDNS_STATUS_ERR; - } + if (authsoa_rr) { + ldns_pkt_push_rr(packet, LDNS_SECTION_AUTHORITY, authsoa_rr); } packet->_tsig_rr = NULL; @@ -967,9 +963,33 @@ ldns_pkt_query_new_frm_str(ldns_pkt **p, const char *name, ldns_rr_type rr_type, } } -ldns_pkt * -ldns_pkt_query_new(ldns_rdf *rr_name, ldns_rr_type rr_type, ldns_rr_class rr_class, - uint16_t flags) +ldns_status +ldns_pkt_query_new_frm_str(ldns_pkt **p, const char *name, + ldns_rr_type rr_type, ldns_rr_class rr_class, uint16_t flags) +{ + return ldns_pkt_query_new_frm_str_internal(p, name, rr_type, + rr_class, flags, NULL); +} + +ldns_status +ldns_pkt_ixfr_request_new_frm_str(ldns_pkt **p, const char *name, + ldns_rr_class rr_class, uint16_t flags, ldns_rr *soa) +{ + ldns_rr* authsoa_rr = soa; + if (!authsoa_rr) { + ldns_rdf *name_rdf; + if (ldns_str2rdf_dname(&name_rdf, name) == LDNS_STATUS_OK) { + authsoa_rr = ldns_pkt_authsoa(name_rdf, rr_class); + } + ldns_rdf_free(name_rdf); + } + return ldns_pkt_query_new_frm_str_internal(p, name, LDNS_RR_TYPE_IXFR, + rr_class, flags, authsoa_rr); +} + +static ldns_pkt * +ldns_pkt_query_new_internal(ldns_rdf *rr_name, ldns_rr_type rr_type, + ldns_rr_class rr_class, uint16_t flags, ldns_rr* authsoa_rr) { ldns_pkt *packet; ldns_rr *question_rr; @@ -982,7 +1002,7 @@ ldns_pkt_query_new(ldns_rdf *rr_name, ldns_rr_type rr_type, ldns_rr_class rr_cla if (!ldns_pkt_set_flags(packet, flags)) { return NULL; } - + question_rr = ldns_rr_new(); if (!question_rr) { ldns_pkt_free(packet); @@ -1002,18 +1022,34 @@ ldns_pkt_query_new(ldns_rdf *rr_name, ldns_rr_type rr_type, ldns_rr_class rr_cla ldns_rr_set_question(question_rr, true); ldns_pkt_push_rr(packet, LDNS_SECTION_QUESTION, question_rr); - /** IXFR? */ - if (rr_type == LDNS_RR_TYPE_IXFR) { - if (ldns_pkt_add_authsoa(packet, rr_name, rr_class) != LDNS_STATUS_OK) { - ldns_pkt_free(packet); - return NULL; - } + if (authsoa_rr) { + ldns_pkt_push_rr(packet, LDNS_SECTION_AUTHORITY, authsoa_rr); } packet->_tsig_rr = NULL; return packet; } +ldns_pkt * +ldns_pkt_query_new(ldns_rdf *rr_name, ldns_rr_type rr_type, + ldns_rr_class rr_class, uint16_t flags) +{ + return ldns_pkt_query_new_internal(rr_name, rr_type, + rr_class, flags, NULL); +} + +ldns_pkt * +ldns_pkt_ixfr_request_new(ldns_rdf *rr_name, ldns_rr_class rr_class, + uint16_t flags, ldns_rr* soa) +{ + ldns_rr* authsoa_rr = soa; + if (!authsoa_rr) { + authsoa_rr = ldns_pkt_authsoa(rr_name, rr_class); + } + return ldns_pkt_query_new_internal(rr_name, LDNS_RR_TYPE_IXFR, + rr_class, flags, authsoa_rr); +} + ldns_pkt_type ldns_pkt_reply_type(ldns_pkt *p) { diff --git a/usr.sbin/unbound/ldns/parse.c b/usr.sbin/unbound/ldns/parse.c index ea5ffad026f..710c4e70b84 100644 --- a/usr.sbin/unbound/ldns/parse.c +++ b/usr.sbin/unbound/ldns/parse.c @@ -135,7 +135,7 @@ ldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *li if (c != '\0' && c != '\n') { i++; } - if (limit > 0 && i >= limit) { + if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) { *t = '\0'; return -1; } @@ -308,7 +308,7 @@ ldns_bget_token(ldns_buffer *b, char *token, const char *delim, size_t limit) } i++; - if (limit > 0 && i >= limit) { + if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) { *t = '\0'; return -1; } @@ -340,18 +340,6 @@ tokenread: return (ssize_t)i; } -void -ldns_bskipc(ldns_buffer *buffer, char c) -{ - while (c == (char) ldns_buffer_read_u8_at(buffer, ldns_buffer_position(buffer))) { - if (ldns_buffer_available_at(buffer, - buffer->_position + sizeof(char), sizeof(char))) { - buffer->_position += sizeof(char); - } else { - return; - } - } -} void ldns_bskipcs(ldns_buffer *buffer, const char *s) @@ -376,12 +364,6 @@ ldns_bskipcs(ldns_buffer *buffer, const char *s) } } -void -ldns_fskipc(ATTR_UNUSED(FILE *fp), ATTR_UNUSED(char c)) -{ -} - - void ldns_fskipcs(FILE *fp, const char *s) { diff --git a/usr.sbin/unbound/ldns/radix.c b/usr.sbin/unbound/ldns/radix.c new file mode 100644 index 00000000000..69797567213 --- /dev/null +++ b/usr.sbin/unbound/ldns/radix.c @@ -0,0 +1,1590 @@ +/* + * radix.c -- generic radix tree + * + * Taken from NSD4, modified for ldns + * + * Copyright (c) 2012, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS 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 THE REGENTS OR CONTRIBUTORS 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. + * + */ + +/** + * \file + * Implementation of a radix tree. + */ + +#include +#include +#include +#include + +/** Helper functions */ +static ldns_radix_node_t* ldns_radix_new_node(void* data, uint8_t* key, + radix_strlen_t len); +static int ldns_radix_find_prefix(ldns_radix_t* tree, uint8_t* key, + radix_strlen_t len, ldns_radix_node_t** result, radix_strlen_t* pos); +static int ldns_radix_array_space(ldns_radix_node_t* node, uint8_t byte); +static int ldns_radix_array_grow(ldns_radix_node_t* node, unsigned need); +static int ldns_radix_str_create(ldns_radix_array_t* array, uint8_t* key, + radix_strlen_t pos, radix_strlen_t len); +static int ldns_radix_prefix_remainder(radix_strlen_t prefix_len, + uint8_t* longer_str, radix_strlen_t longer_len, uint8_t** split_str, + radix_strlen_t* split_len); +static int ldns_radix_array_split(ldns_radix_array_t* array, uint8_t* key, + radix_strlen_t pos, radix_strlen_t len, ldns_radix_node_t* add); +static int ldns_radix_str_is_prefix(uint8_t* str1, radix_strlen_t len1, + uint8_t* str2, radix_strlen_t len2); +static radix_strlen_t ldns_radix_str_common(uint8_t* str1, radix_strlen_t len1, + uint8_t* str2, radix_strlen_t len2); +static ldns_radix_node_t* ldns_radix_next_in_subtree(ldns_radix_node_t* node); +static ldns_radix_node_t* ldns_radix_prev_from_index(ldns_radix_node_t* node, + uint8_t index); +static ldns_radix_node_t* ldns_radix_last_in_subtree_incl_self( + ldns_radix_node_t* node); +static ldns_radix_node_t* ldns_radix_last_in_subtree(ldns_radix_node_t* node); +static void ldns_radix_del_fix(ldns_radix_t* tree, ldns_radix_node_t* node); +static void ldns_radix_cleanup_onechild(ldns_radix_node_t* node); +static void ldns_radix_cleanup_leaf(ldns_radix_node_t* node); +static void ldns_radix_node_free(ldns_radix_node_t* node, void* arg); +static void ldns_radix_node_array_free(ldns_radix_node_t* node); +static void ldns_radix_node_array_free_front(ldns_radix_node_t* node); +static void ldns_radix_node_array_free_end(ldns_radix_node_t* node); +static void ldns_radix_array_reduce(ldns_radix_node_t* node); +static void ldns_radix_self_or_prev(ldns_radix_node_t* node, + ldns_radix_node_t** result); + + +/** + * Create a new radix node. + * + */ +static ldns_radix_node_t* +ldns_radix_new_node(void* data, uint8_t* key, radix_strlen_t len) +{ + ldns_radix_node_t* node = LDNS_MALLOC(ldns_radix_node_t); + if (!node) { + return NULL; + } + node->data = data; + node->key = key; + node->klen = len; + node->parent = NULL; + node->parent_index = 0; + node->len = 0; + node->offset = 0; + node->capacity = 0; + node->array = NULL; + return node; +} + + +/** + * Create a new radix tree. + * + */ +ldns_radix_t * +ldns_radix_create(void) +{ + ldns_radix_t* tree; + + /** Allocate memory for it */ + tree = (ldns_radix_t *) LDNS_MALLOC(ldns_radix_t); + if (!tree) { + return NULL; + } + /** Initialize it */ + ldns_radix_init(tree); + return tree; +} + + +/** + * Initialize radix tree. + * + */ +void +ldns_radix_init(ldns_radix_t* tree) +{ + /** Initialize it */ + if (tree) { + tree->root = NULL; + tree->count = 0; + } + return; +} + + +/** + * Free radix tree. + * + */ +void +ldns_radix_free(ldns_radix_t* tree) +{ + if (tree) { + if (tree->root) { + ldns_radix_traverse_postorder(tree->root, + ldns_radix_node_free, NULL); + } + LDNS_FREE(tree); + } + return; +} + + +/** + * Insert data into the tree. + * + */ +ldns_status +ldns_radix_insert(ldns_radix_t* tree, uint8_t* key, radix_strlen_t len, + void* data) +{ + radix_strlen_t pos = 0; + ldns_radix_node_t* add = NULL; + ldns_radix_node_t* prefix = NULL; + + if (!tree || !key || !data) { + return LDNS_STATUS_NULL; + } + add = ldns_radix_new_node(data, key, len); + if (!add) { + return LDNS_STATUS_MEM_ERR; + } + /** Search the trie until we can make no further process. */ + if (!ldns_radix_find_prefix(tree, key, len, &prefix, &pos)) { + /** No prefix found */ + assert(tree->root == NULL); + if (len == 0) { + /** + * Example 1: The root: + * | [0] + **/ + tree->root = add; + } else { + /** Example 2: 'dns': + * | [0] + * --| [d+ns] dns + **/ + prefix = ldns_radix_new_node(NULL, (uint8_t*)"", 0); + if (!prefix) { + LDNS_FREE(add); + return LDNS_STATUS_MEM_ERR; + } + /** Find some space in the array for the first byte */ + if (!ldns_radix_array_space(prefix, key[0])) { + LDNS_FREE(add); + LDNS_FREE(prefix->array); + LDNS_FREE(prefix); + return LDNS_STATUS_MEM_ERR; + } + /** Set relational pointers */ + add->parent = prefix; + add->parent_index = 0; + prefix->array[0].edge = add; + if (len > 1) { + /** Store the remainder of the prefix */ + if (!ldns_radix_prefix_remainder(1, key, + len, &prefix->array[0].str, + &prefix->array[0].len)) { + LDNS_FREE(add); + LDNS_FREE(prefix->array); + LDNS_FREE(prefix); + return LDNS_STATUS_MEM_ERR; + } + } + tree->root = prefix; + } + } else if (pos == len) { + /** Exact match found */ + if (prefix->data) { + /* Element already exists */ + LDNS_FREE(add); + return LDNS_STATUS_EXISTS_ERR; + } + prefix->data = data; + prefix->key = key; + prefix->klen = len; /* redundant */ + } else { + /** Prefix found */ + uint8_t byte = key[pos]; + assert(pos < len); + if (byte < prefix->offset || + (byte - prefix->offset) >= prefix->len) { + /** Find some space in the array for the byte. */ + /** + * Example 3: 'ldns' + * | [0] + * --| [d+ns] dns + * --| [l+dns] ldns + **/ + if (!ldns_radix_array_space(prefix, byte)) { + LDNS_FREE(add); + return LDNS_STATUS_MEM_ERR; + } + assert(byte >= prefix->offset); + assert((byte - prefix->offset) <= prefix->len); + byte -= prefix->offset; + if (pos+1 < len) { + /** Create remainder of the string. */ + if (!ldns_radix_str_create( + &prefix->array[byte], key, pos+1, + len)) { + LDNS_FREE(add); + return LDNS_STATUS_MEM_ERR; + } + } + /** Add new node. */ + add->parent = prefix; + add->parent_index = byte; + prefix->array[byte].edge = add; + } else if (prefix->array[byte-prefix->offset].edge == NULL) { + /** Use existing element. */ + /** + * Example 4: 'edns' + * | [0] + * --| [d+ns] dns + * --| [e+dns] edns + * --| [l+dns] ldns + **/ + byte -= prefix->offset; + if (pos+1 < len) { + /** Create remainder of the string. */ + if (!ldns_radix_str_create( + &prefix->array[byte], key, pos+1, + len)) { + LDNS_FREE(add); + return LDNS_STATUS_MEM_ERR; + } + } + /** Add new node. */ + add->parent = prefix; + add->parent_index = byte; + prefix->array[byte].edge = add; + } else { + /** + * Use existing element, but it has a shared prefix, + * we need a split. + */ + if (!ldns_radix_array_split(&prefix->array[byte-(prefix->offset)], + key, pos+1, len, add)) { + LDNS_FREE(add); + return LDNS_STATUS_MEM_ERR; + } + } + } + + tree->count ++; + return LDNS_STATUS_OK; +} + + +/** + * Delete data from the tree. + * + */ +void* ldns_radix_delete(ldns_radix_t* tree, uint8_t* key, radix_strlen_t len) +{ + ldns_radix_node_t* del = ldns_radix_search(tree, key, len); + void* data = NULL; + if (del) { + tree->count--; + data = del->data; + del->data = NULL; + ldns_radix_del_fix(tree, del); + return data; + } + return NULL; +} + + +/** + * Search data in the tree. + * + */ +ldns_radix_node_t* +ldns_radix_search(ldns_radix_t* tree, uint8_t* key, radix_strlen_t len) +{ + ldns_radix_node_t* node = NULL; + radix_strlen_t pos = 0; + uint8_t byte = 0; + + if (!tree || !key) { + return NULL; + } + node = tree->root; + while (node) { + if (pos == len) { + return node->data?node:NULL; + } + byte = key[pos]; + if (byte < node->offset) { + return NULL; + } + byte -= node->offset; + if (byte >= node->len) { + return NULL; + } + pos++; + if (node->array[byte].len > 0) { + /** Must match additional string. */ + if (pos + node->array[byte].len > len) { + return NULL; + } + if (memcmp(&key[pos], node->array[byte].str, + node->array[byte].len) != 0) { + return NULL; + } + pos += node->array[byte].len; + } + node = node->array[byte].edge; + } + return NULL; +} + + +/** + * Search data in the tree, and if not found, find the closest smaller + * element in the tree. + * + */ +int +ldns_radix_find_less_equal(ldns_radix_t* tree, uint8_t* key, + radix_strlen_t len, ldns_radix_node_t** result) +{ + ldns_radix_node_t* node = NULL; + radix_strlen_t pos = 0; + uint8_t byte; + int memcmp_res = 0; + + if (!tree || !tree->root || !key) { + *result = NULL; + return 0; + } + + node = tree->root; + while (pos < len) { + byte = key[pos]; + if (byte < node->offset) { + /** + * No exact match. The lesser is in this or the + * previous node. + */ + ldns_radix_self_or_prev(node, result); + return 0; + } + byte -= node->offset; + if (byte >= node->len) { + /** + * No exact match. The lesser is in this node or the + * last of this array, or something before this node. + */ + *result = ldns_radix_last_in_subtree_incl_self(node); + if (*result == NULL) { + *result = ldns_radix_prev(node); + } + return 0; + } + pos++; + if (!node->array[byte].edge) { + /** + * No exact match. Find the previous in the array + * from this index. + */ + *result = ldns_radix_prev_from_index(node, byte); + if (*result == NULL) { + ldns_radix_self_or_prev(node, result); + } + return 0; + } + if (node->array[byte].len != 0) { + /** Must match additional string. */ + if (pos + node->array[byte].len > len) { + /** Additional string is longer than key. */ + if (memcmp(&key[pos], node->array[byte].str, + len-pos) <= 0) { + /** Key is before this node. */ + *result = ldns_radix_prev( + node->array[byte].edge); + } else { + /** Key is after additional string. */ + *result = ldns_radix_last_in_subtree_incl_self(node->array[byte].edge); + if (*result == NULL) { + *result = ldns_radix_prev(node->array[byte].edge); + } + } + return 0; + } + memcmp_res = memcmp(&key[pos], node->array[byte].str, + node->array[byte].len); + if (memcmp_res < 0) { + *result = ldns_radix_prev( + node->array[byte].edge); + return 0; + } else if (memcmp_res > 0) { + *result = ldns_radix_last_in_subtree_incl_self(node->array[byte].edge); + if (*result == NULL) { + *result = ldns_radix_prev(node->array[byte].edge); + } + return 0; + } + + pos += node->array[byte].len; + } + node = node->array[byte].edge; + } + if (node->data) { + /** Exact match. */ + *result = node; + return 1; + } + /** There is a node which is an exact match, but has no element. */ + *result = ldns_radix_prev(node); + return 0; +} + + +/** + * Get the first element in the tree. + * + */ +ldns_radix_node_t* +ldns_radix_first(ldns_radix_t* tree) +{ + ldns_radix_node_t* first = NULL; + if (!tree || !tree->root) { + return NULL; + } + first = tree->root; + if (first->data) { + return first; + } + return ldns_radix_next(first); +} + + +/** + * Get the last element in the tree. + * + */ +ldns_radix_node_t* +ldns_radix_last(ldns_radix_t* tree) +{ + if (!tree || !tree->root) { + return NULL; + } + return ldns_radix_last_in_subtree_incl_self(tree->root); +} + + +/** + * Next element. + * + */ +ldns_radix_node_t* +ldns_radix_next(ldns_radix_node_t* node) +{ + if (!node) { + return NULL; + } + if (node->len) { + /** Go down: most-left child is the next. */ + ldns_radix_node_t* next = ldns_radix_next_in_subtree(node); + if (next) { + return next; + } + } + /** No elements in subtree, get to parent and go down next branch. */ + while (node->parent) { + uint8_t index = node->parent_index; + node = node->parent; + index++; + for (; index < node->len; index++) { + if (node->array[index].edge) { + ldns_radix_node_t* next; + /** Node itself. */ + if (node->array[index].edge->data) { + return node->array[index].edge; + } + /** Dive into subtree. */ + next = ldns_radix_next_in_subtree(node); + if (next) { + return next; + } + } + } + } + return NULL; +} + + +/** + * Previous element. + * + */ +ldns_radix_node_t* +ldns_radix_prev(ldns_radix_node_t* node) +{ + if (!node) { + return NULL; + } + + /** Get to parent and go down previous branch. */ + while (node->parent) { + uint8_t index = node->parent_index; + ldns_radix_node_t* prev; + node = node->parent; + assert(node->len > 0); + prev = ldns_radix_prev_from_index(node, index); + if (prev) { + return prev; + } + if (node->data) { + return node; + } + } + return NULL; +} + + +/** + * Print node. + * + */ +static void +ldns_radix_node_print(FILE* fd, ldns_radix_node_t* node, + uint8_t i, uint8_t* str, radix_strlen_t len, unsigned d) +{ + uint8_t j; + if (!node) { + return; + } + for (j = 0; j < d; j++) { + fprintf(fd, "--"); + } + if (str) { + radix_strlen_t l; + fprintf(fd, "| [%u+", (unsigned) i); + for (l=0; l < len; l++) { + fprintf(fd, "%c", (char) str[l]); + } + fprintf(fd, "]%u", (unsigned) len); + } else { + fprintf(fd, "| [%u]", (unsigned) i); + } + + if (node->data) { + fprintf(fd, " %s", (char*) node->data); + } + fprintf(fd, "\n"); + + for (j = 0; j < node->len; j++) { + if (node->array[j].edge) { + ldns_radix_node_print(fd, node->array[j].edge, j, + node->array[j].str, node->array[j].len, d+1); + } + } + return; +} + + +/** + * Print radix tree. + * + */ +void +ldns_radix_printf(FILE* fd, ldns_radix_t* tree) +{ + if (!fd || !tree) { + return; + } + if (!tree->root) { + fprintf(fd, "; empty radix tree\n"); + return; + } + ldns_radix_node_print(fd, tree->root, 0, NULL, 0, 0); + return; +} + + +/** + * Join two radix trees. + * + */ +ldns_status +ldns_radix_join(ldns_radix_t* tree1, ldns_radix_t* tree2) +{ + ldns_radix_node_t* cur_node, *next_node; + ldns_status status; + if (!tree2 || !tree2->root) { + return LDNS_STATUS_OK; + } + /** Add all elements from tree2 into tree1. */ + + cur_node = ldns_radix_first(tree2); + while (cur_node) { + status = LDNS_STATUS_NO_DATA; + /** Insert current node into tree1 */ + if (cur_node->data) { + status = ldns_radix_insert(tree1, cur_node->key, + cur_node->klen, cur_node->data); + /** Exist errors may occur */ + if (status != LDNS_STATUS_OK && + status != LDNS_STATUS_EXISTS_ERR) { + return status; + } + } + next_node = ldns_radix_next(cur_node); + if (status == LDNS_STATUS_OK) { + (void) ldns_radix_delete(tree2, cur_node->key, + cur_node->klen); + } + cur_node = next_node; + } + + return LDNS_STATUS_OK; +} + + +/** + * Split a radix tree intwo. + * + */ +ldns_status +ldns_radix_split(ldns_radix_t* tree1, size_t num, ldns_radix_t** tree2) +{ + size_t count = 0; + ldns_radix_node_t* cur_node; + ldns_status status = LDNS_STATUS_OK; + if (!tree1 || !tree1->root || num == 0) { + return LDNS_STATUS_OK; + } + if (!tree2) { + return LDNS_STATUS_NULL; + } + if (!*tree2) { + *tree2 = ldns_radix_create(); + if (!*tree2) { + return LDNS_STATUS_MEM_ERR; + } + } + cur_node = ldns_radix_first(tree1); + while (count < num && cur_node) { + if (cur_node->data) { + /** Delete current node from tree1. */ + uint8_t* cur_key = cur_node->key; + radix_strlen_t cur_len = cur_node->klen; + void* cur_data = ldns_radix_delete(tree1, cur_key, + cur_len); + /** Insert current node into tree2/ */ + if (!cur_data) { + return LDNS_STATUS_NO_DATA; + } + status = ldns_radix_insert(*tree2, cur_key, cur_len, + cur_data); + if (status != LDNS_STATUS_OK && + status != LDNS_STATUS_EXISTS_ERR) { + return status; + } +/* + if (status == LDNS_STATUS_OK) { + cur_node->key = NULL; + cur_node->klen = 0; + } +*/ + /** Update count; get first element from tree1 again. */ + count++; + cur_node = ldns_radix_first(tree1); + } else { + cur_node = ldns_radix_next(cur_node); + } + } + return LDNS_STATUS_OK; +} + + +/** + * Call function for all nodes in the tree, such that leaf nodes are + * called before parent nodes. + * + */ +void +ldns_radix_traverse_postorder(ldns_radix_node_t* node, + void (*func)(ldns_radix_node_t*, void*), void* arg) +{ + uint8_t i; + if (!node) { + return; + } + for (i=0; i < node->len; i++) { + ldns_radix_traverse_postorder(node->array[i].edge, + func, arg); + } + /** Call user function */ + (*func)(node, arg); + return; +} + + +/** Static helper functions */ + +/** + * Find a prefix of the key. + * @param tree: tree. + * @param key: key. + * @param len: length of key. + * @param result: the longest prefix, the entry itself if *pos==len, + * otherwise an array entry. + * @param pos: position in string where next unmatched byte is. + * If *pos==len, an exact match is found. + * If *pos== 0, a "" match was found. + * @return 0 (false) if no prefix found. + * + */ +static int +ldns_radix_find_prefix(ldns_radix_t* tree, uint8_t* key, + radix_strlen_t len, ldns_radix_node_t** result, radix_strlen_t* respos) +{ + /** Start searching at the root node */ + ldns_radix_node_t* n = tree->root; + radix_strlen_t pos = 0; + uint8_t byte; + *respos = 0; + *result = n; + if (!n) { + /** No root, no prefix found */ + return 0; + } + /** For each node, look if we can make further progress */ + while (n) { + if (pos == len) { + /** Exact match */ + return 1; + } + byte = key[pos]; + if (byte < n->offset) { + /** key < node */ + return 1; + } + byte -= n->offset; + if (byte >= n->len) { + /** key > node */ + return 1; + } + /** So far, the trie matches */ + pos++; + if (n->array[byte].len != 0) { + /** Must match additional string */ + if (pos + n->array[byte].len > len) { + return 1; /* no match at child node */ + } + if (memcmp(&key[pos], n->array[byte].str, + n->array[byte].len) != 0) { + return 1; /* no match at child node */ + } + pos += n->array[byte].len; + } + /** Continue searching prefix at this child node */ + n = n->array[byte].edge; + if (!n) { + return 1; + } + /** Update the prefix node */ + *respos = pos; + *result = n; + } + /** Done */ + return 1; +} + + +/** + * Make space in the node's array for another byte. + * @param node: node. + * @param byte: byte. + * @return 1 if successful, 0 otherwise. + * + */ +static int +ldns_radix_array_space(ldns_radix_node_t* node, uint8_t byte) +{ + /** Is there an array? */ + if (!node->array) { + assert(node->capacity == 0); + /** No array, create new array */ + node->array = LDNS_MALLOC(ldns_radix_array_t); + if (!node->array) { + return 0; + } + memset(&node->array[0], 0, sizeof(ldns_radix_array_t)); + node->len = 1; + node->capacity = 1; + node->offset = byte; + return 1; + } + /** Array exist */ + assert(node->array != NULL); + assert(node->capacity > 0); + + if (node->len == 0) { + /** Unused array */ + node->len = 1; + node->offset = byte; + } else if (byte < node->offset) { + /** Byte is below the offset */ + uint8_t index; + uint16_t need = node->offset - byte; + /** Is there enough capacity? */ + if (node->len + need > node->capacity) { + /** Not enough capacity, grow array */ + if (!ldns_radix_array_grow(node, + (unsigned) (node->len + need))) { + return 0; /* failed to grow array */ + } + } + /** Move items to the end */ + memmove(&node->array[need], &node->array[0], + node->len*sizeof(ldns_radix_array_t)); + /** Fix parent index */ + for (index = 0; index < node->len; index++) { + if (node->array[index+need].edge) { + node->array[index+need].edge->parent_index = + index + need; + } + } + /** Zero the first */ + memset(&node->array[0], 0, need*sizeof(ldns_radix_array_t)); + node->len += need; + node->offset = byte; + } else if (byte - node->offset >= node->len) { + /** Byte does not fit in array */ + uint16_t need = (byte - node->offset) - node->len + 1; + /** Is there enough capacity? */ + if (node->len + need > node->capacity) { + /** Not enough capacity, grow array */ + if (!ldns_radix_array_grow(node, + (unsigned) (node->len + need))) { + return 0; /* failed to grow array */ + } + } + /** Zero the added items */ + memset(&node->array[node->len], 0, + need*sizeof(ldns_radix_array_t)); + node->len += need; + } + return 1; +} + + +/** + * Grow the array. + * @param node: node. + * @param need: number of elements the array at least need to grow. + * Can't be bigger than 256. + * @return: 0 if failed, 1 if was successful. + * + */ +static int +ldns_radix_array_grow(ldns_radix_node_t* node, unsigned need) +{ + unsigned size = ((unsigned)node->capacity)*2; + ldns_radix_array_t* a = NULL; + if (need > size) { + size = need; + } + if (size > 256) { + size = 256; + } + a = LDNS_XMALLOC(ldns_radix_array_t, size); + if (!a) { + return 0; + } + assert(node->len <= node->capacity); + assert(node->capacity < size); + memcpy(&a[0], &node->array[0], node->len*sizeof(ldns_radix_array_t)); + LDNS_FREE(node->array); + node->array = a; + node->capacity = size; + return 1; +} + + +/** + * Create a prefix in the array string. + * @param array: array. + * @param key: key. + * @param pos: start position in key. + * @param len: length of key. + * @return 0 if failed, 1 if was successful. + * + */ +static int +ldns_radix_str_create(ldns_radix_array_t* array, uint8_t* key, + radix_strlen_t pos, radix_strlen_t len) +{ + array->str = LDNS_XMALLOC(uint8_t, (len-pos)); + if (!array->str) { + return 0; + } + memmove(array->str, key+pos, len-pos); + array->len = (len-pos); + return 1; +} + + +/** + * Allocate remainder from prefixes for a split. + * @param prefixlen: length of prefix. + * @param longer_str: the longer string. + * @param longer_len: the longer string length. + * @param split_str: the split string. + * @param split_len: the split string length. + * @return 0 if failed, 1 if successful. + * + */ +static int +ldns_radix_prefix_remainder(radix_strlen_t prefix_len, + uint8_t* longer_str, radix_strlen_t longer_len, + uint8_t** split_str, radix_strlen_t* split_len) +{ + *split_len = longer_len - prefix_len; + *split_str = LDNS_XMALLOC(uint8_t, (*split_len)); + if (!*split_str) { + return 0; + } + memmove(*split_str, longer_str+prefix_len, longer_len-prefix_len); + return 1; +} + + +/** + * Create a split when two nodes have a shared prefix. + * @param array: array. + * @param key: key. + * @param pos: start position in key. + * @param len: length of the key. + * @param add: node to be added. + * @return 0 if failed, 1 if was successful. + * + */ +static int +ldns_radix_array_split(ldns_radix_array_t* array, uint8_t* key, + radix_strlen_t pos, radix_strlen_t len, ldns_radix_node_t* add) +{ + uint8_t* str_to_add = key + pos; + radix_strlen_t strlen_to_add = len - pos; + + if (ldns_radix_str_is_prefix(str_to_add, strlen_to_add, + array->str, array->len)) { + /** The string to add is a prefix of the existing string */ + uint8_t* split_str = NULL, *dup_str = NULL; + radix_strlen_t split_len = 0; + /** + * Example 5: 'ld' + * | [0] + * --| [d+ns] dns + * --| [e+dns] edns + * --| [l+d] ld + * ----| [n+s] ldns + **/ + assert(strlen_to_add < array->len); + /** Store the remainder in the split string */ + if (array->len - strlen_to_add > 1) { + if (!ldns_radix_prefix_remainder(strlen_to_add+1, + array->str, array->len, &split_str, + &split_len)) { + return 0; + } + } + /** Duplicate the string to add */ + if (strlen_to_add != 0) { + dup_str = LDNS_XMALLOC(uint8_t, strlen_to_add); + if (!dup_str) { + LDNS_FREE(split_str); + return 0; + } + memcpy(dup_str, str_to_add, strlen_to_add); + } + /** Make space in array for the new node */ + if (!ldns_radix_array_space(add, + array->str[strlen_to_add])) { + LDNS_FREE(split_str); + LDNS_FREE(dup_str); + return 0; + } + /** + * The added node should go direct under the existing parent. + * The existing node should go under the added node. + */ + add->parent = array->edge->parent; + add->parent_index = array->edge->parent_index; + add->array[0].edge = array->edge; + add->array[0].str = split_str; + add->array[0].len = split_len; + array->edge->parent = add; + array->edge->parent_index = 0; + LDNS_FREE(array->str); + array->edge = add; + array->str = dup_str; + array->len = strlen_to_add; + } else if (ldns_radix_str_is_prefix(array->str, array->len, + str_to_add, strlen_to_add)) { + /** The existing string is a prefix of the string to add */ + /** + * Example 6: 'dns-ng' + * | [0] + * --| [d+ns] dns + * ----| [-+ng] dns-ng + * --| [e+dns] edns + * --| [l+d] ld + * ----| [n+s] ldns + **/ + uint8_t* split_str = NULL; + radix_strlen_t split_len = 0; + assert(array->len < strlen_to_add); + if (strlen_to_add - array->len > 1) { + if (!ldns_radix_prefix_remainder(array->len+1, + str_to_add, strlen_to_add, &split_str, + &split_len)) { + return 0; + } + } + /** Make space in array for the new node */ + if (!ldns_radix_array_space(array->edge, + str_to_add[array->len])) { + LDNS_FREE(split_str); + return 0; + } + /** + * The added node should go direct under the existing node. + */ + add->parent = array->edge; + add->parent_index = str_to_add[array->len] - + array->edge->offset; + array->edge->array[add->parent_index].edge = add; + array->edge->array[add->parent_index].str = split_str; + array->edge->array[add->parent_index].len = split_len; + } else { + /** Create a new split node. */ + /** + * Example 7: 'dndns' + * | [0] + * --| [d+n] + * ----| [d+ns] dndns + * ----| [s] dns + * ------| [-+ng] dns-ng + * --| [e+dns] edns + * --| [l+d] ld + * ----| [n+s] ldns + **/ + ldns_radix_node_t* common = NULL; + uint8_t* common_str = NULL, *s1 = NULL, *s2 = NULL; + radix_strlen_t common_len = 0, l1 = 0, l2 = 0; + common_len = ldns_radix_str_common(array->str, array->len, + str_to_add, strlen_to_add); + assert(common_len < array->len); + assert(common_len < strlen_to_add); + /** Create the new common node. */ + common = ldns_radix_new_node(NULL, (uint8_t*)"", 0); + if (!common) { + return 0; + } + if (array->len - common_len > 1) { + if (!ldns_radix_prefix_remainder(common_len+1, + array->str, array->len, &s1, &l1)) { + return 0; + } + } + if (strlen_to_add - common_len > 1) { + if (!ldns_radix_prefix_remainder(common_len+1, + str_to_add, strlen_to_add, &s2, &l2)) { + return 0; + } + } + /** Create the shared prefix. */ + if (common_len > 0) { + common_str = LDNS_XMALLOC(uint8_t, common_len); + if (!common_str) { + LDNS_FREE(common); + LDNS_FREE(s1); + LDNS_FREE(s2); + return 0; + } + memcpy(common_str, str_to_add, common_len); + } + /** Make space in the common node array. */ + if (!ldns_radix_array_space(common, array->str[common_len]) || + !ldns_radix_array_space(common, str_to_add[common_len])) { + LDNS_FREE(common->array); + LDNS_FREE(common); + LDNS_FREE(common_str); + LDNS_FREE(s1); + LDNS_FREE(s2); + return 0; + } + /** + * The common node should go direct under the parent node. + * The added and existing nodes go under the common node. + */ + common->parent = array->edge->parent; + common->parent_index = array->edge->parent_index; + array->edge->parent = common; + array->edge->parent_index = array->str[common_len] - + common->offset; + add->parent = common; + add->parent_index = str_to_add[common_len] - common->offset; + common->array[array->edge->parent_index].edge = array->edge; + common->array[array->edge->parent_index].str = s1; + common->array[array->edge->parent_index].len = l1; + common->array[add->parent_index].edge = add; + common->array[add->parent_index].str = s2; + common->array[add->parent_index].len = l2; + LDNS_FREE(array->str); + array->edge = common; + array->str = common_str; + array->len = common_len; + } + return 1; +} + + +/** + * Check if one string prefix of other string. + * @param str1: one string. + * @param len1: one string length. + * @param str2: other string. + * @param len2: other string length. + * @return 1 if prefix, 0 otherwise. + * + */ +static int +ldns_radix_str_is_prefix(uint8_t* str1, radix_strlen_t len1, + uint8_t* str2, radix_strlen_t len2) +{ + if (len1 == 0) { + return 1; /* empty prefix is also a prefix */ + } + if (len1 > len2) { + return 0; /* len1 is longer so str1 cannot be a prefix */ + } + return (memcmp(str1, str2, len1) == 0); +} + + +/** + * Return the number of bytes in common for the two strings. + * @param str1: one string. + * @param len1: one string length. + * @param str2: other string. + * @param len2: other string length. + * @return length of substring that the two strings have in common. + * + */ +static radix_strlen_t +ldns_radix_str_common(uint8_t* str1, radix_strlen_t len1, + uint8_t* str2, radix_strlen_t len2) +{ + radix_strlen_t i, max = (len1len; i++) { + if (node->array[i].edge) { + /** Node itself. */ + if (node->array[i].edge->data) { + return node->array[i].edge; + } + /** Dive into subtree. */ + next = ldns_radix_next_in_subtree(node->array[i].edge); + if (next) { + return next; + } + } + } + return NULL; +} + + +/** + * Find the previous element in the array of this node, from index. + * @param node: node. + * @param index: index. + * @return previous node from index. + * + */ +static ldns_radix_node_t* +ldns_radix_prev_from_index(ldns_radix_node_t* node, uint8_t index) +{ + uint8_t i = index; + while (i > 0) { + i--; + if (node->array[i].edge) { + ldns_radix_node_t* prev = + ldns_radix_last_in_subtree_incl_self(node); + if (prev) { + return prev; + } + } + } + return NULL; +} + + +/** + * Find last node in subtree, or this node (if have data). + * @param node: node. + * @return last node in subtree, or this node, or NULL. + * + */ +static ldns_radix_node_t* +ldns_radix_last_in_subtree_incl_self(ldns_radix_node_t* node) +{ + ldns_radix_node_t* last = ldns_radix_last_in_subtree(node); + if (last) { + return last; + } else if (node->data) { + return node; + } + return NULL; +} + + +/** + * Find last node in subtree. + * @param node: node. + * @return last node in subtree. + * + */ +static ldns_radix_node_t* +ldns_radix_last_in_subtree(ldns_radix_node_t* node) +{ + int i; + /** Look for the most right leaf node. */ + for (i=(int)(node->len)-1; i >= 0; i--) { + if (node->array[i].edge) { + /** Keep looking for the most right leaf node. */ + if (node->array[i].edge->len > 0) { + ldns_radix_node_t* last = + ldns_radix_last_in_subtree( + node->array[i].edge); + if (last) { + return last; + } + } + /** Could this be the most right leaf node? */ + if (node->array[i].edge->data) { + return node->array[i].edge; + } + } + } + return NULL; +} + + +/** + * Fix tree after deleting element. + * @param tree: tree. + * @param node: node with deleted element. + * + */ +static void +ldns_radix_del_fix(ldns_radix_t* tree, ldns_radix_node_t* node) +{ + while (node) { + if (node->data) { + /** Thou should not delete nodes with data attached. */ + return; + } else if (node->len == 1 && node->parent) { + /** Node with one child is fold back into. */ + ldns_radix_cleanup_onechild(node); + return; + } else if (node->len == 0) { + /** Leaf node. */ + ldns_radix_node_t* parent = node->parent; + if (!parent) { + /** The root is a leaf node. */ + ldns_radix_node_free(node, NULL); + tree->root = NULL; + return; + } + /** Cleanup leaf node and continue with parent. */ + ldns_radix_cleanup_leaf(node); + node = parent; + } else { + /** + * Node cannot be deleted, because it has edge nodes + * and no parent to fix up to. + */ + return; + } + } + /** Not reached. */ + return; +} + + +/** + * Clean up a node with one child. + * @param node: node with one child. + * + */ +static void +ldns_radix_cleanup_onechild(ldns_radix_node_t* node) +{ + uint8_t* join_str; + radix_strlen_t join_len; + uint8_t parent_index = node->parent_index; + ldns_radix_node_t* child = node->array[0].edge; + ldns_radix_node_t* parent = node->parent; + + /** Node has one child, merge the child node into the parent node. */ + assert(parent_index < parent->len); + join_len = parent->array[parent_index].len + node->array[0].len + 1; + + join_str = LDNS_XMALLOC(uint8_t, join_len); + if (!join_str) { + /** + * Cleanup failed due to out of memory. + * This tree is now inefficient, with the empty node still + * existing, but it is still valid. + */ + return; + } + + memcpy(join_str, parent->array[parent_index].str, + parent->array[parent_index].len); + join_str[parent->array[parent_index].len] = child->parent_index + + node->offset; + memmove(join_str + parent->array[parent_index].len+1, + node->array[0].str, node->array[0].len); + + LDNS_FREE(parent->array[parent_index].str); + parent->array[parent_index].str = join_str; + parent->array[parent_index].len = join_len; + parent->array[parent_index].edge = child; + child->parent = parent; + child->parent_index = parent_index; + ldns_radix_node_free(node, NULL); + return; +} + + +/** + * Clean up a leaf node. + * @param node: leaf node. + * + */ +static void +ldns_radix_cleanup_leaf(ldns_radix_node_t* node) +{ + uint8_t parent_index = node->parent_index; + ldns_radix_node_t* parent = node->parent; + /** Delete lead node and fix parent array. */ + assert(parent_index < parent->len); + ldns_radix_node_free(node, NULL); + LDNS_FREE(parent->array[parent_index].str); + parent->array[parent_index].str = NULL; + parent->array[parent_index].len = 0; + parent->array[parent_index].edge = NULL; + /** Fix array in parent. */ + if (parent->len == 1) { + ldns_radix_node_array_free(parent); + } else if (parent_index == 0) { + ldns_radix_node_array_free_front(parent); + } else { + ldns_radix_node_array_free_end(parent); + } + return; +} + + +/** + * Free a radix node. + * @param node: node. + * @param arg: user argument. + * + */ +static void +ldns_radix_node_free(ldns_radix_node_t* node, void* arg) +{ + uint16_t i; + (void) arg; + if (!node) { + return; + } + for (i=0; i < node->len; i++) { + LDNS_FREE(node->array[i].str); + } + node->key = NULL; + node->klen = 0; + LDNS_FREE(node->array); + LDNS_FREE(node); + return; +} + + +/** + * Free select edge array. + * @param node: node. + * + */ +static void +ldns_radix_node_array_free(ldns_radix_node_t* node) +{ + node->offset = 0; + node->len = 0; + LDNS_FREE(node->array); + node->array = NULL; + node->capacity = 0; + return; +} + + +/** + * Free front of select edge array. + * @param node: node. + * + */ +static void +ldns_radix_node_array_free_front(ldns_radix_node_t* node) +{ + uint16_t i, n = 0; + /** Remove until a non NULL entry. */ + while (n < node->len && node->array[n].edge == NULL) { + n++; + } + if (n == 0) { + return; + } + if (n == node->len) { + ldns_radix_node_array_free(node); + return; + } + assert(n < node->len); + assert((int) n <= (255 - (int) node->offset)); + memmove(&node->array[0], &node->array[n], + (node->len - n)*sizeof(ldns_radix_array_t)); + node->offset += n; + node->len -= n; + for (i=0; i < node->len; i++) { + if (node->array[i].edge) { + node->array[i].edge->parent_index = i; + } + } + ldns_radix_array_reduce(node); + return; +} + + +/** + * Free front of select edge array. + * @param node: node. + * + */ +static void +ldns_radix_node_array_free_end(ldns_radix_node_t* node) +{ + uint16_t n = 0; + /** Shorten array. */ + while (n < node->len && node->array[node->len-1-n].edge == NULL) { + n++; + } + if (n == 0) { + return; + } + if (n == node->len) { + ldns_radix_node_array_free(node); + return; + } + assert(n < node->len); + node->len -= n; + ldns_radix_array_reduce(node); + return; +} + + +/** + * Reduce the capacity of the array if needed. + * @param node: node. + * + */ +static void +ldns_radix_array_reduce(ldns_radix_node_t* node) +{ + if (node->len <= node->capacity/2 && node->len != node->capacity) { + ldns_radix_array_t* a = LDNS_XMALLOC(ldns_radix_array_t, + node->len); + if (!a) { + return; + } + memcpy(a, node->array, sizeof(ldns_radix_array_t)*node->len); + LDNS_FREE(node->array); + node->array = a; + node->capacity = node->len; + } + return; +} + + +/** + * Return this element if it exists, the previous otherwise. + * @param node: from this node. + * @param result: result node. + * + */ +static void +ldns_radix_self_or_prev(ldns_radix_node_t* node, ldns_radix_node_t** result) +{ + if (node->data) { + *result = node; + } else { + *result = ldns_radix_prev(node); + } + return; +} diff --git a/usr.sbin/unbound/ldns/rdata.c b/usr.sbin/unbound/ldns/rdata.c index 8af16a13a1c..6493543f0a2 100644 --- a/usr.sbin/unbound/ldns/rdata.c +++ b/usr.sbin/unbound/ldns/rdata.c @@ -112,14 +112,14 @@ time_t ldns_rdf2native_time_t(const ldns_rdf *rd) { uint32_t data; - - switch(ldns_rdf_get_type(rd)) { - case LDNS_RDF_TYPE_TIME: - memcpy(&data, ldns_rdf_data(rd), sizeof(data)); - return (time_t)ntohl(data); - default: - return 0; + + /* only allow 32 bit rdfs */ + if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_DOUBLEWORD || + ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_TIME) { + return 0; } + memcpy(&data, ldns_rdf_data(rd), sizeof(data)); + return (time_t)ntohl(data); } ldns_rdf * @@ -309,8 +309,8 @@ ldns_rdf_new_frm_str(ldns_rdf_type type, const char *str) case LDNS_RDF_TYPE_PERIOD: status = ldns_str2rdf_period(&rdf, str); break; - case LDNS_RDF_TYPE_TSIG: - status = ldns_str2rdf_tsig(&rdf, str); + case LDNS_RDF_TYPE_HIP: + status = ldns_str2rdf_hip(&rdf, str); break; case LDNS_RDF_TYPE_SERVICE: status = ldns_str2rdf_service(&rdf, str); @@ -336,6 +336,21 @@ ldns_rdf_new_frm_str(ldns_rdf_type type, const char *str) case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER: status = ldns_str2rdf_b32_ext(&rdf, str); break; + case LDNS_RDF_TYPE_ILNP64: + status = ldns_str2rdf_ilnp64(&rdf, str); + break; + case LDNS_RDF_TYPE_EUI48: + status = ldns_str2rdf_eui48(&rdf, str); + break; + case LDNS_RDF_TYPE_EUI64: + status = ldns_str2rdf_eui64(&rdf, str); + break; + case LDNS_RDF_TYPE_TAG: + status = ldns_str2rdf_tag(&rdf, str); + break; + case LDNS_RDF_TYPE_LONG_STR: + status = ldns_str2rdf_long_str(&rdf, str); + break; case LDNS_RDF_TYPE_NONE: default: /* default default ??? */ @@ -503,6 +518,64 @@ ldns_rdf_address_reverse(ldns_rdf *rd) return rev; } +ldns_status +ldns_rdf_hip_get_alg_hit_pk(ldns_rdf *rdf, uint8_t* alg, + uint8_t *hit_size, uint8_t** hit, + uint16_t *pk_size, uint8_t** pk) +{ + uint8_t *data; + size_t rdf_size; + + if (! rdf || ! alg || ! hit || ! hit_size || ! pk || ! pk_size) { + return LDNS_STATUS_INVALID_POINTER; + } else if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_HIP) { + return LDNS_STATUS_INVALID_RDF_TYPE; + } else if ((rdf_size = ldns_rdf_size(rdf)) < 6) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } + data = ldns_rdf_data(rdf); + *hit_size = data[0]; + *alg = data[1]; + *pk_size = ldns_read_uint16(data + 2); + *hit = data + 4; + *pk = data + 4 + *hit_size; + if (*hit_size == 0 || *pk_size == 0 || + rdf_size < (size_t) *hit_size + *pk_size + 4) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } + return LDNS_STATUS_OK; +} + +ldns_status +ldns_rdf_hip_new_frm_alg_hit_pk(ldns_rdf** rdf, uint8_t alg, + uint8_t hit_size, uint8_t *hit, + uint16_t pk_size, uint8_t *pk) +{ + uint8_t *data; + + if (! rdf) { + return LDNS_STATUS_INVALID_POINTER; + } + if (4 + hit_size + pk_size > LDNS_MAX_RDFLEN) { + return LDNS_STATUS_RDATA_OVERFLOW; + } + data = LDNS_XMALLOC(uint8_t, 4 + hit_size + pk_size); + if (data == NULL) { + return LDNS_STATUS_MEM_ERR; + } + data[0] = hit_size; + data[1] = alg; + ldns_write_uint16(data + 2, pk_size); + memcpy(data + 4, hit, hit_size); + memcpy(data + 4 + hit_size, pk, pk_size); + *rdf = ldns_rdf_new(LDNS_RDF_TYPE_HIP, 4 + hit_size + pk_size, data); + if (! *rdf) { + LDNS_FREE(data); + return LDNS_STATUS_MEM_ERR; + } + return LDNS_STATUS_OK; +} + ldns_status ldns_octet(char *word, size_t *length) { diff --git a/usr.sbin/unbound/ldns/resolver.c b/usr.sbin/unbound/ldns/resolver.c index 2cee9fff194..16efc90f1a3 100644 --- a/usr.sbin/unbound/ldns/resolver.c +++ b/usr.sbin/unbound/ldns/resolver.c @@ -26,6 +26,12 @@ ldns_resolver_port(const ldns_resolver *r) return r->_port; } +ldns_rdf * +ldns_resolver_source(const ldns_resolver *r) +{ + return r->_source; +} + uint16_t ldns_resolver_edns_udp_size(const ldns_resolver *r) { @@ -234,6 +240,12 @@ ldns_resolver_set_port(ldns_resolver *r, uint16_t p) r->_port = p; } +void +ldns_resolver_set_source(ldns_resolver *r, ldns_rdf *s) +{ + r->_source = s; +} + ldns_rdf * ldns_resolver_pop_nameserver(ldns_resolver *r) { @@ -436,7 +448,7 @@ ldns_resolver_set_fail(ldns_resolver *r, bool f) r->_fail =f; } -void +static void ldns_resolver_set_searchlist_count(ldns_resolver *r, size_t c) { r->_searchlist_count = c; @@ -625,6 +637,7 @@ ldns_resolver_new(void) ldns_resolver_set_igntc(r, false); ldns_resolver_set_recursive(r, false); ldns_resolver_set_dnsrch(r, true); + ldns_resolver_set_source(r, NULL); /* randomize the nameserver to be queried * when there are multiple @@ -670,8 +683,15 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr) ssize_t gtr, bgtr; ldns_buffer *b; int lnr = 0, oldline; + FILE* myfp = fp; if(!line_nr) line_nr = &lnr; + if(!fp) { + myfp = fopen("/etc/resolv.conf", "r"); + if(!myfp) + return LDNS_STATUS_FILE_ERR; + } + /* do this better * expect = * 0: keyword @@ -691,6 +711,7 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr) r = ldns_resolver_new(); if (!r) { + if(!fp) fclose(myfp); return LDNS_STATUS_MEM_ERR; } @@ -706,9 +727,9 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr) /* skip until end of line */ int c; do { - c = fgetc(fp); + c = fgetc(myfp); } while(c != EOF && c != '\n'); - if(c=='\n' && line_nr) (*line_nr)++; + if(c=='\n') (*line_nr)++; } /* and read next to prepare for further parsing */ oldline = *line_nr; @@ -718,7 +739,7 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr) switch(expect) { case LDNS_RESOLV_KEYWORD: /* keyword */ - gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_NORMAL, 0, line_nr); + gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr); if (gtr != 0) { if(word[0] == '#') continue; for(i = 0; i < LDNS_RESOLV_KEYWORDS; i++) { @@ -735,6 +756,7 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr) /* skip line */ /* ldns_resolver_deep_free(r); + if(!fp) fclose(myfp); return LDNS_STATUS_SYNTAX_KEYWORD_ERR; */ } @@ -742,8 +764,9 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr) break; case LDNS_RESOLV_DEFDOMAIN: /* default domain dname */ - gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_NORMAL, 0, line_nr); + gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr); if (gtr == 0) { + if(!fp) fclose(myfp); return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR; } if(word[0] == '#') { @@ -753,6 +776,7 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr) tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, word); if (!tmp) { ldns_resolver_deep_free(r); + if(!fp) fclose(myfp); return LDNS_STATUS_SYNTAX_DNAME_ERR; } @@ -762,8 +786,9 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr) break; case LDNS_RESOLV_NAMESERVER: /* NS aaaa or a record */ - gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_NORMAL, 0, line_nr); + gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr); if (gtr == 0) { + if(!fp) fclose(myfp); return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR; } if(word[0] == '#') { @@ -783,6 +808,7 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr) /* could not parse it, exit */ if (!tmp) { ldns_resolver_deep_free(r); + if(!fp) fclose(myfp); return LDNS_STATUS_SYNTAX_ERR; } (void)ldns_resolver_push_nameserver(r, tmp); @@ -791,10 +817,11 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr) break; case LDNS_RESOLV_SEARCH: /* search list domain dname */ - gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr); + gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr); b = LDNS_MALLOC(ldns_buffer); if(!b) { ldns_resolver_deep_free(r); + if(!fp) fclose(myfp); return LDNS_STATUS_MEM_ERR; } @@ -802,6 +829,7 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr) if(ldns_buffer_status(b) != LDNS_STATUS_OK) { LDNS_FREE(b); ldns_resolver_deep_free(r); + if(!fp) fclose(myfp); return LDNS_STATUS_MEM_ERR; } bgtr = ldns_bget_token(b, word, LDNS_PARSE_NORMAL, (size_t) gtr + 1); @@ -815,6 +843,7 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr) if (!tmp) { ldns_resolver_deep_free(r); ldns_buffer_free(b); + if(!fp) fclose(myfp); return LDNS_STATUS_SYNTAX_DNAME_ERR; } @@ -831,20 +860,21 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr) } break; case LDNS_RESOLV_SORTLIST: - gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr); + gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr); /* sortlist not implemented atm */ expect = LDNS_RESOLV_KEYWORD; break; case LDNS_RESOLV_OPTIONS: - gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr); + gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr); /* options not implemented atm */ expect = LDNS_RESOLV_KEYWORD; break; case LDNS_RESOLV_ANCHOR: /* a file containing a DNSSEC trust anchor */ - gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_NORMAL, 0, line_nr); + gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr); if (gtr == 0) { ldns_resolver_deep_free(r); + if(!fp) fclose(myfp); return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR; } if(word[0] == '#') { @@ -862,6 +892,9 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr) } } + if(!fp) + fclose(myfp); + if (res) { *res = r; return LDNS_STATUS_OK; @@ -953,86 +986,82 @@ ldns_resolver_deep_free(ldns_resolver *res) } } -ldns_pkt * -ldns_resolver_search(const ldns_resolver *r,const ldns_rdf *name, - ldns_rr_type t, ldns_rr_class c, uint16_t flags) +ldns_status +ldns_resolver_search_status(ldns_pkt** pkt, + ldns_resolver *r, const ldns_rdf *name, + ldns_rr_type t, ldns_rr_class c, uint16_t flags) { - ldns_rdf *new_name; ldns_rdf **search_list; size_t i; - ldns_pkt *p; + ldns_status s = LDNS_STATUS_OK; if (ldns_dname_absolute(name)) { /* query as-is */ - return ldns_resolver_query(r, name, t, c, flags); + return ldns_resolver_query_status(pkt, r, name, t, c, flags); } else if (ldns_resolver_dnsrch(r)) { search_list = ldns_resolver_searchlist(r); for (i = 0; i < ldns_resolver_searchlist_count(r); i++) { new_name = ldns_dname_cat_clone(name, search_list[i]); - p = ldns_resolver_query(r, new_name, t, c, flags); + s = ldns_resolver_query_status(pkt, r, + new_name, t, c, flags); ldns_rdf_free(new_name); - if (p) { - if (ldns_pkt_get_rcode(p) == LDNS_RCODE_NOERROR) { - return p; - } else { - ldns_pkt_free(p); - p = NULL; + if (pkt) { + if (s == LDNS_STATUS_OK && *pkt && + ldns_pkt_get_rcode(*pkt) == + LDNS_RCODE_NOERROR) { + return LDNS_STATUS_OK; } + ldns_pkt_free(*pkt); } } } - return NULL; + return s; } ldns_pkt * -ldns_resolver_query(const ldns_resolver *r, const ldns_rdf *name, +ldns_resolver_search(const ldns_resolver *r,const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, uint16_t flags) +{ + ldns_pkt* pkt = NULL; + if (ldns_resolver_search_status(&pkt, (ldns_resolver *)r, + name, t, c, flags) != LDNS_STATUS_OK) { + ldns_pkt_free(pkt); + } + return pkt; +} + +ldns_status +ldns_resolver_query_status(ldns_pkt** pkt, + ldns_resolver *r, const ldns_rdf *name, + ldns_rr_type t, ldns_rr_class c, uint16_t flags) { ldns_rdf *newname; - ldns_pkt *pkt; ldns_status status; - pkt = NULL; - - if (!ldns_resolver_defnames(r)) { - status = ldns_resolver_send(&pkt, (ldns_resolver *)r, name, - t, c, flags); - if (status == LDNS_STATUS_OK) { - return pkt; - } else { - if (pkt) { - ldns_pkt_free(pkt); - } - return NULL; - } - } - - if (!ldns_resolver_domain(r)) { - /* _defnames is set, but the domain is not....?? */ - status = ldns_resolver_send(&pkt, (ldns_resolver *)r, name, - t, c, flags); - if (status == LDNS_STATUS_OK) { - return pkt; - } else { - if (pkt) { - ldns_pkt_free(pkt); - } - return NULL; - } + if (!ldns_resolver_defnames(r) || !ldns_resolver_domain(r)) { + return ldns_resolver_send(pkt, r, name, t, c, flags); } - newname = ldns_dname_cat_clone((const ldns_rdf*)name, ldns_resolver_domain(r)); + newname = ldns_dname_cat_clone(name, ldns_resolver_domain(r)); if (!newname) { - return NULL; + return LDNS_STATUS_MEM_ERR; } - - (void)ldns_resolver_send(&pkt, (ldns_resolver *)r, newname, t, c, - flags); - + status = ldns_resolver_send(pkt, r, newname, t, c, flags); ldns_rdf_free(newname); + return status; +} +ldns_pkt * +ldns_resolver_query(const ldns_resolver *r, const ldns_rdf *name, + ldns_rr_type t, ldns_rr_class c, uint16_t flags) +{ + ldns_pkt* pkt = NULL; + if (ldns_resolver_query_status(&pkt, (ldns_resolver *)r, + name, t, c, flags) != LDNS_STATUS_OK) { + ldns_pkt_free(pkt); + } return pkt; } @@ -1129,7 +1158,12 @@ ldns_resolver_prepare_query_pkt(ldns_pkt **query_pkt, ldns_resolver *r, /* prepare a question pkt from the parameters * and then send this */ - *query_pkt = ldns_pkt_query_new(ldns_rdf_clone(name), t, c, flags); + if (t == LDNS_RR_TYPE_IXFR) { + *query_pkt = ldns_pkt_ixfr_request_new(ldns_rdf_clone(name), + c, flags, NULL); + } else { + *query_pkt = ldns_pkt_query_new(ldns_rdf_clone(name), t, c, flags); + } if (!*query_pkt) { return LDNS_STATUS_ERR; } @@ -1206,7 +1240,7 @@ ldns_resolver_send(ldns_pkt **answer, ldns_resolver *r, const ldns_rdf *name, /* if tsig values are set, tsign it */ /* TODO: make last 3 arguments optional too? maybe make complete - rr instead of seperate values in resolver (and packet) + rr instead of separate values in resolver (and packet) Jelte should this go in pkt_prepare? */ @@ -1286,9 +1320,11 @@ ldns_axfr_next(ldns_resolver *resolver) resolver->_axfr_i = 0; if (status != LDNS_STATUS_OK) { /* TODO: make status return type of this function (...api change) */ +#ifdef STDERR_MSGS fprintf(stderr, "Error parsing rr during AXFR: %s\n", ldns_get_errorstr_by_id(status)); +#endif - /* RoRi: we must now also close the socket, otherwise subsequent uses of the + /* we must now also close the socket, otherwise subsequent uses of the same resolver structure will fail because the link is still open or in an undefined state */ #ifndef USE_WINSOCK @@ -1301,6 +1337,7 @@ ldns_axfr_next(ldns_resolver *resolver) return NULL; } else if (ldns_pkt_get_rcode(resolver->_cur_axfr_pkt) != 0) { rcode = ldns_lookup_by_id(ldns_rcodes, (int) ldns_pkt_get_rcode(resolver->_cur_axfr_pkt)); +#ifdef STDERR_MSGS if (rcode) { fprintf(stderr, "Error in AXFR: %s\n", rcode->name); @@ -1309,8 +1346,9 @@ ldns_axfr_next(ldns_resolver *resolver) (int) ldns_pkt_get_rcode( resolver->_cur_axfr_pkt)); } +#endif - /* RoRi: we must now also close the socket, otherwise subsequent uses of the + /* we must now also close the socket, otherwise subsequent uses of the same resolver structure will fail because the link is still open or in an undefined state */ #ifndef USE_WINSOCK @@ -1329,6 +1367,26 @@ ldns_axfr_next(ldns_resolver *resolver) } +/* this function is needed to abort a transfer that is in progress; + * without it an aborted transfer will lead to the AXFR code in the + * library staying in an indetermined state because the socket for the + * AXFR is never closed + */ +void +ldns_axfr_abort(ldns_resolver *resolver) +{ + /* Only abort if an actual AXFR is in progress */ + if (resolver->_socket != 0) + { +#ifndef USE_WINSOCK + close(resolver->_socket); +#else + closesocket(resolver->_socket); +#endif + resolver->_socket = 0; + } +} + bool ldns_axfr_complete(const ldns_resolver *res) { diff --git a/usr.sbin/unbound/ldns/rr.c b/usr.sbin/unbound/ldns/rr.c index 72076d40c58..cfee170eb2b 100644 --- a/usr.sbin/unbound/ldns/rr.c +++ b/usr.sbin/unbound/ldns/rr.c @@ -87,6 +87,14 @@ ldns_rr_free(ldns_rr *rr) } } +/* Syntactic sugar for ldns_rr_new_frm_str_internal */ +INLINE bool +ldns_rdf_type_maybe_quoted(ldns_rdf_type rdf_type) +{ + return rdf_type == LDNS_RDF_TYPE_STR || + rdf_type == LDNS_RDF_TYPE_LONG_STR; +} + /* * trailing spaces are allowed * leading spaces are not allowed @@ -119,7 +127,7 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str, char *type = NULL; char *rdata = NULL; char *rd = NULL; - char * b64 = NULL; + char *xtok = NULL; /* For RDF types with spaces (i.e. extra tokens) */ size_t rd_strlen; const char *delimiters; ssize_t c; @@ -138,6 +146,12 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str, uint16_t r_max; size_t pre_data_pos; + uint16_t hex_data_size; + char *hex_data_str = NULL; + uint16_t cur_hex_data_size; + size_t hex_pos = 0; + uint8_t *hex_data = NULL; + new = ldns_rr_new(); owner = LDNS_XMALLOC(char, LDNS_MAX_DOMAINLEN + 1); @@ -147,26 +161,32 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str, rr_buf = LDNS_MALLOC(ldns_buffer); rd_buf = LDNS_MALLOC(ldns_buffer); rd = LDNS_XMALLOC(char, LDNS_MAX_RDFLEN); - b64 = LDNS_XMALLOC(char, LDNS_MAX_RDFLEN); - if (!new || !owner || !ttl || !clas || !rdata || !rr_buf || !rd_buf || !rd || !b64 ) { - status = LDNS_STATUS_MEM_ERR; - LDNS_FREE(rr_buf); - goto ldnserror; + xtok = LDNS_XMALLOC(char, LDNS_MAX_RDFLEN); + if (rr_buf) { + rr_buf->_data = NULL; + } + if (rd_buf) { + rd_buf->_data = NULL; + } + if (!new || !owner || !ttl || !clas || !rdata || + !rr_buf || !rd_buf || !rd || !xtok) { + + goto memerror; } ldns_buffer_new_frm_data(rr_buf, (char*)str, strlen(str)); /* split the rr in its parts -1 signals trouble */ - if (ldns_bget_token(rr_buf, owner, "\t\n ", LDNS_MAX_DOMAINLEN) == -1) { + if (ldns_bget_token(rr_buf, owner, "\t\n ", LDNS_MAX_DOMAINLEN) == -1){ + status = LDNS_STATUS_SYNTAX_ERR; - ldns_buffer_free(rr_buf); - goto ldnserror; + goto error; } if (ldns_bget_token(rr_buf, ttl, "\t\n ", LDNS_TTL_DATALEN) == -1) { + status = LDNS_STATUS_SYNTAX_TTL_ERR; - ldns_buffer_free(rr_buf); - goto ldnserror; + goto error; } ttl_val = (uint32_t) ldns_str2period(ttl, &endptr); @@ -189,18 +209,17 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str, if (clas_val == 0) { clas_val = LDNS_RR_CLASS_IN; type = LDNS_XMALLOC(char, strlen(ttl) + 1); - if(!type) { - status = LDNS_STATUS_MEM_ERR; - ldns_buffer_free(rr_buf); - goto ldnserror; + if (!type) { + goto memerror; } strncpy(type, ttl, strlen(ttl) + 1); } } else { - if (ldns_bget_token(rr_buf, clas, "\t\n ", LDNS_SYNTAX_DATALEN) == -1) { + if (-1 == ldns_bget_token( + rr_buf, clas, "\t\n ", LDNS_SYNTAX_DATALEN)) { + status = LDNS_STATUS_SYNTAX_CLASS_ERR; - ldns_buffer_free(rr_buf); - goto ldnserror; + goto error; } clas_val = ldns_get_rr_class_by_name(clas); /* class can be left out too, assume IN, current @@ -209,10 +228,8 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str, if (clas_val == 0) { clas_val = LDNS_RR_CLASS_IN; type = LDNS_XMALLOC(char, strlen(clas) + 1); - if(!type) { - status = LDNS_STATUS_MEM_ERR; - ldns_buffer_free(rr_buf); - goto ldnserror; + if (!type) { + goto memerror; } strncpy(type, clas, strlen(clas) + 1); } @@ -221,24 +238,22 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str, if (!type) { type = LDNS_XMALLOC(char, LDNS_SYNTAX_DATALEN); - if(!type) { - status = LDNS_STATUS_MEM_ERR; - ldns_buffer_free(rr_buf); - goto ldnserror; + if (!type) { + goto memerror; } - if (ldns_bget_token(rr_buf, type, "\t\n ", LDNS_SYNTAX_DATALEN) == -1) { + if (-1 == ldns_bget_token( + rr_buf, type, "\t\n ", LDNS_SYNTAX_DATALEN)) { + status = LDNS_STATUS_SYNTAX_TYPE_ERR; - ldns_buffer_free(rr_buf); - goto ldnserror; + goto error; } } if (ldns_bget_token(rr_buf, rdata, "\0", LDNS_MAX_PACKETLEN) == -1) { /* apparently we are done, and it's only a question RR * so do not set status and go to ldnserror here - */ + */ } - ldns_buffer_new_frm_data(rd_buf, rdata, strlen(rdata)); if (strlen(owner) <= 1 && strncmp(owner, "@", 1) == 0) { @@ -256,9 +271,7 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str, ldns_rdf_deep_free(*prev); *prev = ldns_rdf_clone(ldns_rr_owner(new)); if (!*prev) { - status = LDNS_STATUS_MEM_ERR; - ldns_buffer_free(rr_buf); - goto ldnserror; + goto memerror; } } } else { @@ -270,57 +283,49 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str, } else if (origin) { ldns_rr_set_owner(new, ldns_rdf_clone(origin)); } else { - ldns_rr_set_owner(new, ldns_dname_new_frm_str(".")); + ldns_rr_set_owner(new, + ldns_dname_new_frm_str(".")); } if(!ldns_rr_owner(new)) { - status = LDNS_STATUS_MEM_ERR; - ldns_buffer_free(rr_buf); - goto ldnserror; + goto memerror; } } else { owner_dname = ldns_dname_new_frm_str(owner); if (!owner_dname) { status = LDNS_STATUS_SYNTAX_ERR; - ldns_buffer_free(rr_buf); - goto ldnserror; + goto error; } ldns_rr_set_owner(new, owner_dname); if (!ldns_dname_str_absolute(owner) && origin) { - if(ldns_dname_cat(ldns_rr_owner(new), - origin) != LDNS_STATUS_OK) { + if(ldns_dname_cat(ldns_rr_owner(new), origin) + != LDNS_STATUS_OK) { + status = LDNS_STATUS_SYNTAX_ERR; - ldns_buffer_free(rr_buf); - goto ldnserror; + goto error; } } if (prev) { ldns_rdf_deep_free(*prev); *prev = ldns_rdf_clone(ldns_rr_owner(new)); - if(!*prev) { - status = LDNS_STATUS_MEM_ERR; - ldns_buffer_free(rr_buf); - goto ldnserror; + if (!*prev) { + goto error; } } } } LDNS_FREE(owner); - owner = NULL; ldns_rr_set_question(new, question); ldns_rr_set_ttl(new, ttl_val); LDNS_FREE(ttl); - ttl = NULL; ldns_rr_set_class(new, clas_val); LDNS_FREE(clas); - clas = NULL; rr_type = ldns_get_rr_type_by_name(type); LDNS_FREE(type); - type = NULL; desc = ldns_rr_descript((uint16_t)rr_type); ldns_rr_set_type(new, rr_type); @@ -333,268 +338,275 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str, r_max = 1; } - /* depending on the rr_type we need to extract - * the rdata differently, e.g. NSEC/NSEC3 */ - switch(rr_type) { - default: - done = false; - - for (r_cnt = 0; !done && r_cnt < r_max; r_cnt++) { - quoted = false; - /* if type = B64, the field may contain spaces */ - if (ldns_rr_descriptor_field_type(desc, - r_cnt) == LDNS_RDF_TYPE_B64 || - ldns_rr_descriptor_field_type(desc, - r_cnt) == LDNS_RDF_TYPE_HEX || - ldns_rr_descriptor_field_type(desc, - r_cnt) == LDNS_RDF_TYPE_LOC || - ldns_rr_descriptor_field_type(desc, - r_cnt) == LDNS_RDF_TYPE_WKS || - ldns_rr_descriptor_field_type(desc, - r_cnt) == LDNS_RDF_TYPE_IPSECKEY || - ldns_rr_descriptor_field_type(desc, - r_cnt) == LDNS_RDF_TYPE_NSEC) { - delimiters = "\n\t"; - } else { - delimiters = "\n\t "; - } + for (done = false, r_cnt = 0; !done && r_cnt < r_max; r_cnt++) { + quoted = false; - if (ldns_rr_descriptor_field_type(desc, - r_cnt) == LDNS_RDF_TYPE_STR && - ldns_buffer_remaining(rd_buf) > 0) { - /* skip spaces */ - while (*(ldns_buffer_current(rd_buf)) == ' ') { - ldns_buffer_skip(rd_buf, 1); - } + switch (ldns_rr_descriptor_field_type(desc, r_cnt)) { + case LDNS_RDF_TYPE_B64 : + case LDNS_RDF_TYPE_HEX : /* These rdf types may con- */ + case LDNS_RDF_TYPE_LOC : /* tain whitespace, only if */ + case LDNS_RDF_TYPE_WKS : /* it is the last rd field. */ + case LDNS_RDF_TYPE_IPSECKEY : + case LDNS_RDF_TYPE_NSEC : if (r_cnt == r_max - 1) { + delimiters = "\n\t"; + break; + } + default : delimiters = "\n\t "; + } - if (*(ldns_buffer_current(rd_buf)) == '\"') { - delimiters = "\"\0"; - ldns_buffer_skip(rd_buf, 1); - quoted = true; - } + if (ldns_rdf_type_maybe_quoted( + ldns_rr_descriptor_field_type( + desc, r_cnt)) && + ldns_buffer_remaining(rd_buf) > 0){ + + /* skip spaces */ + while (*(ldns_buffer_current(rd_buf)) == ' ') { + ldns_buffer_skip(rd_buf, 1); + } + + if (*(ldns_buffer_current(rd_buf)) == '\"') { + delimiters = "\"\0"; + ldns_buffer_skip(rd_buf, 1); + quoted = true; + } + } + + /* because number of fields can be variable, we can't rely on + * _maximum() only + */ + + /* skip spaces */ + while (ldns_buffer_position(rd_buf) < ldns_buffer_limit(rd_buf) + && *(ldns_buffer_current(rd_buf)) == ' ' + && !quoted) { + + ldns_buffer_skip(rd_buf, 1); + } + + pre_data_pos = ldns_buffer_position(rd_buf); + if (-1 == (c = ldns_bget_token( + rd_buf, rd, delimiters, LDNS_MAX_RDFLEN))) { + + done = true; + break; + } + /* hmmz, rfc3597 specifies that any type can be represented + * with \# method, which can contain spaces... + * it does specify size though... + */ + rd_strlen = strlen(rd); + + /* unknown RR data */ + if (strncmp(rd, "\\#", 2) == 0 && !quoted && + (rd_strlen == 2 || rd[2]==' ')) { + + was_unknown_rr_format = 1; + /* go back to before \# + * and skip it while setting delimiters better + */ + ldns_buffer_set_position(rd_buf, pre_data_pos); + delimiters = "\n\t "; + (void)ldns_bget_token(rd_buf, rd, + delimiters, LDNS_MAX_RDFLEN); + /* read rdata octet length */ + c = ldns_bget_token(rd_buf, rd, + delimiters, LDNS_MAX_RDFLEN); + if (c == -1) { + /* something goes very wrong here */ + status = LDNS_STATUS_SYNTAX_RDATA_ERR; + goto error; + } + hex_data_size = (uint16_t) atoi(rd); + /* copy hex chars into hex str (2 chars per byte) */ + hex_data_str = LDNS_XMALLOC(char, 2*hex_data_size + 1); + if (!hex_data_str) { + /* malloc error */ + goto memerror; + } + cur_hex_data_size = 0; + while(cur_hex_data_size < 2 * hex_data_size) { + c = ldns_bget_token(rd_buf, rd, + delimiters, LDNS_MAX_RDFLEN); + if (c != -1) { + rd_strlen = strlen(rd); } + if (c == -1 || + (size_t)cur_hex_data_size + rd_strlen > + 2 * (size_t)hex_data_size) { - /* because number of fields can be variable, we can't - rely on _maximum() only */ - /* skip spaces */ - while (ldns_buffer_position(rd_buf) < ldns_buffer_limit(rd_buf) && - *(ldns_buffer_current(rd_buf)) == ' ' && !quoted - ) { - ldns_buffer_skip(rd_buf, 1); + status = LDNS_STATUS_SYNTAX_RDATA_ERR; + goto error; } + strncpy(hex_data_str + cur_hex_data_size, rd, + rd_strlen); - pre_data_pos = ldns_buffer_position(rd_buf); - if ((c = ldns_bget_token(rd_buf, rd, delimiters, - LDNS_MAX_RDFLEN)) != -1) { - /* hmmz, rfc3597 specifies that any type can be represented with - * \# method, which can contain spaces... - * it does specify size though... - */ - rd_strlen = strlen(rd); + cur_hex_data_size += rd_strlen; + } + hex_data_str[cur_hex_data_size] = '\0'; - /* unknown RR data */ - if (strncmp(rd, "\\#", 2) == 0 && !quoted && (rd_strlen == 2 || rd[2]==' ')) { - uint16_t hex_data_size; - char *hex_data_str; - uint16_t cur_hex_data_size; - - was_unknown_rr_format = 1; - /* go back to before \# and skip it while setting delimiters better */ - ldns_buffer_set_position(rd_buf, pre_data_pos); - delimiters = "\n\t "; - (void)ldns_bget_token(rd_buf, rd, delimiters, LDNS_MAX_RDFLEN); - /* read rdata octet length */ - c = ldns_bget_token(rd_buf, rd, delimiters, LDNS_MAX_RDFLEN); - if (c == -1) { - /* something goes very wrong here */ - LDNS_FREE(rd); - LDNS_FREE(b64); - ldns_buffer_free(rd_buf); - ldns_buffer_free(rr_buf); - LDNS_FREE(rdata); - ldns_rr_free(new); - return LDNS_STATUS_SYNTAX_RDATA_ERR; - } - hex_data_size = (uint16_t) atoi(rd); - /* copy the hex chars into hex str (which is 2 chars per byte) */ - hex_data_str = LDNS_XMALLOC(char, 2 * hex_data_size + 1); - if (!hex_data_str) { - /* malloc error */ - LDNS_FREE(rd); - LDNS_FREE(b64); - ldns_buffer_free(rd_buf); - ldns_buffer_free(rr_buf); - LDNS_FREE(rdata); - ldns_rr_free(new); - return LDNS_STATUS_SYNTAX_RDATA_ERR; - } - cur_hex_data_size = 0; - while(cur_hex_data_size < 2 * hex_data_size) { - c = ldns_bget_token(rd_buf, rd, delimiters, LDNS_MAX_RDFLEN); - if (c != -1) { - rd_strlen = strlen(rd); - } - if (c == -1 || (size_t)cur_hex_data_size + rd_strlen > 2 * (size_t)hex_data_size) { - LDNS_FREE(hex_data_str); - LDNS_FREE(rd); - LDNS_FREE(b64); - ldns_buffer_free(rd_buf); - ldns_buffer_free(rr_buf); - LDNS_FREE(rdata); - ldns_rr_free(new); - return LDNS_STATUS_SYNTAX_RDATA_ERR; - } - strncpy(hex_data_str + cur_hex_data_size, rd, rd_strlen); - cur_hex_data_size += rd_strlen; - } - hex_data_str[cur_hex_data_size] = '\0'; - - /* correct the rdf type */ - /* if *we* know the type, interpret it as wireformat */ - if (desc) { - size_t hex_pos = 0; - uint8_t *hex_data = LDNS_XMALLOC(uint8_t, hex_data_size + 2); - ldns_status s; - if(!hex_data) { - LDNS_FREE(hex_data_str); - LDNS_FREE(rd); - LDNS_FREE(b64); - ldns_buffer_free(rd_buf); - ldns_buffer_free(rr_buf); - LDNS_FREE(rdata); - ldns_rr_free(new); - return LDNS_STATUS_MEM_ERR; - } - ldns_write_uint16(hex_data, hex_data_size); - ldns_hexstring_to_data(hex_data + 2, hex_data_str); - s = ldns_wire2rdf(new, hex_data, - hex_data_size+2, &hex_pos); - if(s != LDNS_STATUS_OK) { - LDNS_FREE(hex_data_str); - LDNS_FREE(rd); - LDNS_FREE(b64); - ldns_buffer_free(rd_buf); - ldns_buffer_free(rr_buf); - LDNS_FREE(rdata); - ldns_rr_free(new); - LDNS_FREE(hex_data); - return s; - } - LDNS_FREE(hex_data); - } else { - r = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_HEX, hex_data_str); - if(!r) { - LDNS_FREE(hex_data_str); - LDNS_FREE(rd); - LDNS_FREE(b64); - ldns_buffer_free(rd_buf); - ldns_buffer_free(rr_buf); - LDNS_FREE(rdata); - ldns_rr_free(new); - return LDNS_STATUS_MEM_ERR; - } - ldns_rdf_set_type(r, LDNS_RDF_TYPE_UNKNOWN); - if(!ldns_rr_push_rdf(new, r)) { - LDNS_FREE(hex_data_str); - LDNS_FREE(rd); - LDNS_FREE(b64); - ldns_buffer_free(rd_buf); - ldns_buffer_free(rr_buf); - LDNS_FREE(rdata); - ldns_rr_free(new); - return LDNS_STATUS_MEM_ERR; - } - } - LDNS_FREE(hex_data_str); - } else { - /* Normal RR */ - switch(ldns_rr_descriptor_field_type(desc, r_cnt)) { - case LDNS_RDF_TYPE_HEX: - case LDNS_RDF_TYPE_B64: - /* can have spaces, and will always be the last - * record of the rrdata. Read in the rest */ - if ((c = ldns_bget_token(rd_buf, - b64, - "\n", - LDNS_MAX_RDFLEN)) - != -1) { - rd = strncat(rd, - b64, - LDNS_MAX_RDFLEN - - strlen(rd) - 1); - } - r = ldns_rdf_new_frm_str( - ldns_rr_descriptor_field_type(desc, r_cnt), - rd); - break; - case LDNS_RDF_TYPE_DNAME: - r = ldns_rdf_new_frm_str( - ldns_rr_descriptor_field_type(desc, r_cnt), - rd); - - /* check if the origin should be used or concatenated */ - if (r && ldns_rdf_size(r) > 1 && ldns_rdf_data(r)[0] == 1 - && ldns_rdf_data(r)[1] == '@') { - ldns_rdf_deep_free(r); - if (origin) { - r = ldns_rdf_clone(origin); - } else { - /* if this is the SOA, use its own owner name */ - if (rr_type == LDNS_RR_TYPE_SOA) { - r = ldns_rdf_clone(ldns_rr_owner(new)); - } else { - r = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, "."); - } - } - } else if (r && rd_strlen >= 1 && !ldns_dname_str_absolute(rd) && origin) { - if (ldns_dname_cat(r, origin) != LDNS_STATUS_OK) { - LDNS_FREE(rd); - LDNS_FREE(b64); - ldns_buffer_free(rd_buf); - ldns_buffer_free(rr_buf); - LDNS_FREE(rdata); - ldns_rr_free(new); - return LDNS_STATUS_ERR; - } - } - break; - default: - r = ldns_rdf_new_frm_str( - ldns_rr_descriptor_field_type(desc, r_cnt), - rd); - break; - } - if (r) { - ldns_rr_push_rdf(new, r); - } else { - LDNS_FREE(rd); - LDNS_FREE(b64); - ldns_buffer_free(rd_buf); - ldns_buffer_free(rr_buf); - LDNS_FREE(rdata); - ldns_rr_free(new); - return LDNS_STATUS_SYNTAX_RDATA_ERR; - } + /* correct the rdf type */ + /* if *we* know the type, interpret it as wireformat */ + if (desc) { + hex_pos = 0; + hex_data = + LDNS_XMALLOC(uint8_t, hex_data_size+2); + + if (!hex_data) { + goto memerror; + } + ldns_write_uint16(hex_data, hex_data_size); + ldns_hexstring_to_data( + hex_data + 2, hex_data_str); + status = ldns_wire2rdf(new, hex_data, + hex_data_size + 2, &hex_pos); + if (status != LDNS_STATUS_OK) { + goto error; + } + LDNS_FREE(hex_data); + } else { + r = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_HEX, + hex_data_str); + if (!r) { + goto memerror; + } + ldns_rdf_set_type(r, LDNS_RDF_TYPE_UNKNOWN); + if (!ldns_rr_push_rdf(new, r)) { + goto memerror; + } + } + LDNS_FREE(hex_data_str); + + } else { + /* Normal RR */ + switch(ldns_rr_descriptor_field_type(desc, r_cnt)) { + + case LDNS_RDF_TYPE_HEX: + case LDNS_RDF_TYPE_B64: + /* When this is the last rdata field, then the + * rest should be read in (cause then these + * rdf types may contain spaces). + */ + if (r_cnt == r_max - 1) { + c = ldns_bget_token(rd_buf, xtok, + "\n", LDNS_MAX_RDFLEN); + if (c != -1) { + (void) strncat(rd, xtok, + LDNS_MAX_RDFLEN - + strlen(rd) - 1); } - if (quoted) { - if (ldns_buffer_available(rd_buf, 1)) { - ldns_buffer_skip(rd_buf, 1); - } else { - done = true; - } + } + r = ldns_rdf_new_frm_str( + ldns_rr_descriptor_field_type( + desc, r_cnt), rd); + break; + + case LDNS_RDF_TYPE_HIP: + /* + * In presentation format this RDATA type has + * three tokens: An algorithm byte, then a + * variable length HIT (in hexbytes) and then + * a variable length Public Key (in base64). + * + * We have just read the algorithm, so we need + * two more tokens: HIT and Public Key. + */ + do { + /* Read and append HIT */ + if (ldns_bget_token(rd_buf, + xtok, delimiters, + LDNS_MAX_RDFLEN) == -1) + break; + + (void) strncat(rd, " ", + LDNS_MAX_RDFLEN - + strlen(rd) - 1); + (void) strncat(rd, xtok, + LDNS_MAX_RDFLEN - + strlen(rd) - 1); + + /* Read and append Public Key*/ + if (ldns_bget_token(rd_buf, + xtok, delimiters, + LDNS_MAX_RDFLEN) == -1) + break; + + (void) strncat(rd, " ", + LDNS_MAX_RDFLEN - + strlen(rd) - 1); + (void) strncat(rd, xtok, + LDNS_MAX_RDFLEN - + strlen(rd) - 1); + } while (false); + + r = ldns_rdf_new_frm_str( + ldns_rr_descriptor_field_type( + desc, r_cnt), rd); + break; + + case LDNS_RDF_TYPE_DNAME: + r = ldns_rdf_new_frm_str( + ldns_rr_descriptor_field_type( + desc, r_cnt), rd); + + /* check if the origin should be used + * or concatenated + */ + if (r && ldns_rdf_size(r) > 1 && + ldns_rdf_data(r)[0] == 1 && + ldns_rdf_data(r)[1] == '@') { + + ldns_rdf_deep_free(r); + + r = origin ? ldns_rdf_clone(origin) + + : ( rr_type == LDNS_RR_TYPE_SOA ? + + ldns_rdf_clone( + ldns_rr_owner(new)) + + : ldns_rdf_new_frm_str( + LDNS_RDF_TYPE_DNAME, ".") + ); + + } else if (r && rd_strlen >= 1 && origin && + !ldns_dname_str_absolute(rd)) { + + status = ldns_dname_cat(r, origin); + if (status != LDNS_STATUS_OK) { + goto error; } - } else { - done = true; } + break; + default: + r = ldns_rdf_new_frm_str( + ldns_rr_descriptor_field_type( + desc, r_cnt), rd); + break; } - } + if (!r) { + status = LDNS_STATUS_SYNTAX_RDATA_ERR; + goto error; + } + ldns_rr_push_rdf(new, r); + } + if (quoted) { + if (ldns_buffer_available(rd_buf, 1)) { + ldns_buffer_skip(rd_buf, 1); + } else { + done = true; + } + } + + } /* for (done = false, r_cnt = 0; !done && r_cnt < r_max; r_cnt++) */ LDNS_FREE(rd); - LDNS_FREE(b64); + LDNS_FREE(xtok); ldns_buffer_free(rd_buf); ldns_buffer_free(rr_buf); LDNS_FREE(rdata); - if (!question && desc && !was_unknown_rr_format && ldns_rr_rd_count(new) < r_min) { + if (!question && desc && !was_unknown_rr_format && + ldns_rr_rd_count(new) < r_min) { + ldns_rr_free(new); return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR; } @@ -607,17 +619,30 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str, } return LDNS_STATUS_OK; -ldnserror: +memerror: + status = LDNS_STATUS_MEM_ERR; +error: + if (rd_buf && rd_buf->_data) { + ldns_buffer_free(rd_buf); + } else { + LDNS_FREE(rd_buf); + } + if (rr_buf && rr_buf->_data) { + ldns_buffer_free(rr_buf); + } else { + LDNS_FREE(rr_buf); + } LDNS_FREE(type); LDNS_FREE(owner); LDNS_FREE(ttl); LDNS_FREE(clas); - LDNS_FREE(rdata); + LDNS_FREE(hex_data); + LDNS_FREE(hex_data_str); + LDNS_FREE(xtok); LDNS_FREE(rd); - LDNS_FREE(rd_buf); - LDNS_FREE(b64); + LDNS_FREE(rdata); ldns_rr_free(new); - return status; + return status; } ldns_status @@ -936,7 +961,7 @@ ldns_rr_list_rr(const ldns_rr_list *rr_list, size_t nr) } ldns_rr_list * -ldns_rr_list_new() +ldns_rr_list_new(void) { ldns_rr_list *rr_list = LDNS_MALLOC(ldns_rr_list); if(!rr_list) return NULL; @@ -1395,25 +1420,7 @@ ldns_rr_list_clone(const ldns_rr_list *rrlist) } -int -qsort_rr_compare(const void *a, const void *b) -{ - const ldns_rr *rr1 = * (const ldns_rr **) a; - const ldns_rr *rr2 = * (const ldns_rr **) b; - - if (rr1 == NULL && rr2 == NULL) { - return 0; - } - if (rr1 == NULL) { - return -1; - } - if (rr2 == NULL) { - return 1; - } - return ldns_rr_compare(rr1, rr2); -} - -int +static int qsort_schwartz_rr_compare(const void *a, const void *b) { int result = 0; @@ -1863,9 +1870,7 @@ static const ldns_rdf_type type_px_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME }; static const ldns_rdf_type type_gpos_wireformat[] = { - LDNS_RDF_TYPE_STR, - LDNS_RDF_TYPE_STR, - LDNS_RDF_TYPE_STR + LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR }; static const ldns_rdf_type type_aaaa_wireformat[] = { LDNS_RDF_TYPE_AAAA }; static const ldns_rdf_type type_loc_wireformat[] = { LDNS_RDF_TYPE_LOC }; @@ -1943,6 +1948,15 @@ static const ldns_rdf_type type_dnskey_wireformat[] = { LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_B64 }; +static const ldns_rdf_type type_tkey_wireformat[] = { + LDNS_RDF_TYPE_DNAME, + LDNS_RDF_TYPE_TIME, + LDNS_RDF_TYPE_TIME, + LDNS_RDF_TYPE_INT16, + LDNS_RDF_TYPE_INT16, + LDNS_RDF_TYPE_INT16_DATA, + LDNS_RDF_TYPE_INT16_DATA, +}; static const ldns_rdf_type type_tsig_wireformat[] = { LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_TSIGTIME, @@ -1958,6 +1972,43 @@ static const ldns_rdf_type type_tlsa_wireformat[] = { LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_HEX }; +static const ldns_rdf_type type_hip_wireformat[] = { + LDNS_RDF_TYPE_HIP +}; +static const ldns_rdf_type type_nid_wireformat[] = { + LDNS_RDF_TYPE_INT16, + LDNS_RDF_TYPE_ILNP64 +}; +static const ldns_rdf_type type_l32_wireformat[] = { + LDNS_RDF_TYPE_INT16, + LDNS_RDF_TYPE_A +}; +static const ldns_rdf_type type_l64_wireformat[] = { + LDNS_RDF_TYPE_INT16, + LDNS_RDF_TYPE_ILNP64 +}; +static const ldns_rdf_type type_lp_wireformat[] = { + LDNS_RDF_TYPE_INT16, + LDNS_RDF_TYPE_DNAME +}; +static const ldns_rdf_type type_eui48_wireformat[] = { + LDNS_RDF_TYPE_EUI48 +}; +static const ldns_rdf_type type_eui64_wireformat[] = { + LDNS_RDF_TYPE_EUI64 +}; +#ifdef RRTYPE_URI +static const ldns_rdf_type type_uri_wireformat[] = { + LDNS_RDF_TYPE_INT16, + LDNS_RDF_TYPE_INT16, + LDNS_RDF_TYPE_LONG_STR +}; +#endif +static const ldns_rdf_type type_caa_wireformat[] = { + LDNS_RDF_TYPE_INT8, + LDNS_RDF_TYPE_TAG, + LDNS_RDF_TYPE_LONG_STR +}; /** \endcond */ /** \cond */ @@ -2021,7 +2072,7 @@ static ldns_rr_descriptor rdata_field_descriptors[] = { /* 26 */ {LDNS_RR_TYPE_PX, "PX", 3, 3, type_px_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 2 }, /* 27 */ - {LDNS_RR_TYPE_GPOS, "GPOS", 1, 1, type_gpos_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + {LDNS_RR_TYPE_GPOS, "GPOS", 3, 3, type_gpos_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 28 */ {LDNS_RR_TYPE_AAAA, "AAAA", 1, 1, type_aaaa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 29 */ @@ -2061,7 +2112,7 @@ static ldns_rr_descriptor rdata_field_descriptors[] = { /* 46 */ {LDNS_RR_TYPE_RRSIG, "RRSIG", 9, 9, type_rrsig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, /* 47 */ - {LDNS_RR_TYPE_NSEC, "NSEC", 1, 2, type_nsec_wireformat, LDNS_RDF_TYPE_NSEC, LDNS_RR_NO_COMPRESS, 1 }, + {LDNS_RR_TYPE_NSEC, "NSEC", 1, 2, type_nsec_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, /* 48 */ {LDNS_RR_TYPE_DNSKEY, "DNSKEY", 4, 4, type_dnskey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, /* 49 */ @@ -2075,12 +2126,36 @@ static ldns_rr_descriptor rdata_field_descriptors[] = { {LDNS_RR_TYPE_NULL, "TYPE53", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE54", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, -{LDNS_RR_TYPE_NULL, "TYPE55", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + + /* 55 + * Hip ends with 0 or more Rendezvous Servers represented as dname's. + * Hence the LDNS_RDF_TYPE_DNAME _variable field and the _maximum field + * set to 0. + */ + {LDNS_RR_TYPE_HIP, "HIP", 1, 1, type_hip_wireformat, LDNS_RDF_TYPE_DNAME, LDNS_RR_NO_COMPRESS, 0 }, + +#ifdef RRTYPE_NINFO + /* 56 */ + {LDNS_RR_TYPE_NINFO, "NINFO", 1, 0, NULL, LDNS_RDF_TYPE_STR, LDNS_RR_NO_COMPRESS, 0 }, +#else {LDNS_RR_TYPE_NULL, "TYPE56", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, +#endif +#ifdef RRTYPE_RKEY + /* 57 */ + {LDNS_RR_TYPE_RKEY, "RKEY", 4, 4, type_key_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, +#else {LDNS_RR_TYPE_NULL, "TYPE57", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, +#endif /* 58 */ -{LDNS_RR_TYPE_TALINK, "TALINK", 2, 2, type_talink_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 2 }, + {LDNS_RR_TYPE_TALINK, "TALINK", 2, 2, type_talink_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 2 }, + +#ifdef RRTYPE_CDS + /* 59 */ + {LDNS_RR_TYPE_CDS, "CDS", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, +#else {LDNS_RR_TYPE_NULL, "TYPE59", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, +#endif + {LDNS_RR_TYPE_NULL, "TYPE60", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE61", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE62", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, @@ -2120,17 +2195,32 @@ static ldns_rr_descriptor rdata_field_descriptors[] = { {LDNS_RR_TYPE_NULL, "TYPE96", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE97", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE98", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, -{LDNS_RR_TYPE_SPF, "SPF", 1, 0, NULL, LDNS_RDF_TYPE_STR, LDNS_RR_NO_COMPRESS, 0 }, + + /* 99 */ + {LDNS_RR_TYPE_SPF, "SPF", 1, 0, NULL, LDNS_RDF_TYPE_STR, LDNS_RR_NO_COMPRESS, 0 }, + + /* UINFO [IANA-Reserved] */ {LDNS_RR_TYPE_NULL, "TYPE100", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + /* UID [IANA-Reserved] */ {LDNS_RR_TYPE_NULL, "TYPE101", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + /* GID [IANA-Reserved] */ {LDNS_RR_TYPE_NULL, "TYPE102", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + /* UNSPEC [IANA-Reserved] */ {LDNS_RR_TYPE_NULL, "TYPE103", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, -{LDNS_RR_TYPE_NULL, "TYPE104", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, -{LDNS_RR_TYPE_NULL, "TYPE105", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, -{LDNS_RR_TYPE_NULL, "TYPE106", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, -{LDNS_RR_TYPE_NULL, "TYPE107", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, -{LDNS_RR_TYPE_NULL, "TYPE108", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, -{LDNS_RR_TYPE_NULL, "TYPE109", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + + /* 104 */ + {LDNS_RR_TYPE_NID, "NID", 2, 2, type_nid_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + /* 105 */ + {LDNS_RR_TYPE_L32, "L32", 2, 2, type_l32_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + /* 106 */ + {LDNS_RR_TYPE_L64, "L64", 2, 2, type_l64_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + /* 107 */ + {LDNS_RR_TYPE_LP, "LP", 2, 2, type_lp_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, + /* 108 */ + {LDNS_RR_TYPE_EUI48, "EUI48", 1, 1, type_eui48_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + /* 109 */ + {LDNS_RR_TYPE_EUI64, "EUI64", 1, 1, type_eui64_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + {LDNS_RR_TYPE_NULL, "TYPE110", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE111", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE112", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, @@ -2270,14 +2360,48 @@ static ldns_rr_descriptor rdata_field_descriptors[] = { {LDNS_RR_TYPE_NULL, "TYPE246", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE247", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE248", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, -{LDNS_RR_TYPE_NULL, "TYPE249", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, -/* LDNS_RDF_TYPE_INT16_DATA essentially takes two fields (length and data) and - * makes them into one. So, while in rfc 2845 is specified that a TSIG may have - * 8 or 9 rdata fields, by this implementation, the min/max are 7 each. - */ -{LDNS_RR_TYPE_TSIG, "TSIG", 7, 7, type_tsig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + + /* LDNS_RDF_TYPE_INT16_DATA takes two fields (length and data) as one. + * So, unlike RFC 2930 spec, we have 7 min/max rdf's i.s.o. 8/9. + */ + /* 249 */ + {LDNS_RR_TYPE_TKEY, "TKEY", 7, 7, type_tkey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, + /* LDNS_RDF_TYPE_INT16_DATA takes two fields (length and data) as one. + * So, unlike RFC 2930 spec, we have 7 min/max rdf's i.s.o. 8/9. + */ + /* 250 */ + {LDNS_RR_TYPE_TSIG, "TSIG", 7, 7, type_tsig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }, + + /* IXFR: A request for a transfer of an incremental zone transfer */ +{LDNS_RR_TYPE_NULL, "TYPE251", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + /* AXFR: A request for a transfer of an entire zone */ +{LDNS_RR_TYPE_NULL, "TYPE252", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + /* MAILB: A request for mailbox-related records (MB, MG or MR) */ +{LDNS_RR_TYPE_NULL, "TYPE253", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + /* MAILA: A request for mail agent RRs (Obsolete - see MX) */ +{LDNS_RR_TYPE_NULL, "TYPE254", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + /* ANY: A request for all (available) records */ +{LDNS_RR_TYPE_NULL, "TYPE255", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + +#ifdef RRTYPE_URI + /* 256 */ + {LDNS_RR_TYPE_URI, "URI", 3, 3, type_uri_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, +#else +{LDNS_RR_TYPE_NULL, "TYPE256", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, +#endif + /* 257 */ + {LDNS_RR_TYPE_CAA, "CAA", 3, 3, type_caa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + /* split in array, no longer contiguous */ -{LDNS_RR_TYPE_DLV, "DLV", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 } + +#ifdef RRTYPE_TA + /* 32768 */ + {LDNS_RR_TYPE_TA, "TA", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, +#else +{LDNS_RR_TYPE_NULL, "TYPE32768", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, +#endif + /* 32769 */ + {LDNS_RR_TYPE_DLV, "DLV", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 } }; /** \endcond */ @@ -2288,11 +2412,130 @@ static ldns_rr_descriptor rdata_field_descriptors[] = { #define LDNS_RDATA_FIELD_DESCRIPTORS_COUNT \ (sizeof(rdata_field_descriptors)/sizeof(rdata_field_descriptors[0])) + +/*---------------------------------------------------------------------------* + * The functions below return an bitmap RDF with the space required to set + * or unset all known RR types. Arguably these functions are better situated + * in rdata.c, however for the space calculation it is necesarry to walk + * through rdata_field_descriptors which is not easily possible from anywhere + * other than rr.c where it is declared static. + * + * Alternatively rr.c could have provided an iterator for rr_type or + * rdf_descriptors, but this seemed overkill for internal use only. + */ +static ldns_rr_descriptor* rdata_field_descriptors_end = + &rdata_field_descriptors[LDNS_RDATA_FIELD_DESCRIPTORS_COUNT]; + +/* From RFC3845: + * + * 2.1.2. The List of Type Bit Map(s) Field + * + * The RR type space is split into 256 window blocks, each representing + * the low-order 8 bits of the 16-bit RR type space. Each block that + * has at least one active RR type is encoded using a single octet + * window number (from 0 to 255), a single octet bitmap length (from 1 + * to 32) indicating the number of octets used for the window block's + * bitmap, and up to 32 octets (256 bits) of bitmap. + * + * Window blocks are present in the NSEC RR RDATA in increasing + * numerical order. + * + * "|" denotes concatenation + * + * Type Bit Map(s) Field = ( Window Block # | Bitmap Length | Bitmap ) + + * + * + * + * Blocks with no types present MUST NOT be included. Trailing zero + * octets in the bitmap MUST be omitted. The length of each block's + * bitmap is determined by the type code with the largest numerical + * value within that block, among the set of RR types present at the + * NSEC RR's owner name. Trailing zero octets not specified MUST be + * interpreted as zero octets. + */ +static ldns_status +ldns_rdf_bitmap_known_rr_types_set(ldns_rdf** rdf, int value) +{ + uint8_t window; /* most significant octet of type */ + uint8_t subtype; /* least significant octet of type */ + uint16_t windows[256] /* Max subtype per window */ +#ifndef S_SPLINT_S + = { 0 } +#endif + ; + ldns_rr_descriptor* d; /* used to traverse rdata_field_descriptors */ + size_t i; /* used to traverse windows array */ + + size_t sz; /* size needed for type bitmap rdf */ + uint8_t* data = NULL; /* rdf data */ + uint8_t* dptr; /* used to itraverse rdf data */ + + assert(rdf != NULL); + + /* Which windows need to be in the bitmap rdf? + */ + for (d=rdata_field_descriptors; d < rdata_field_descriptors_end; d++) { + window = d->_type >> 8; + subtype = d->_type & 0xff; + if (windows[window] < subtype) { + windows[window] = subtype; + } + } + + /* How much space do we need in the rdf for those windows? + */ + sz = 0; + for (i = 0; i < 256; i++) { + if (windows[i]) { + sz += windows[i] / 8 + 3; + } + } + if (sz > 0) { + /* Format rdf data according RFC3845 Section 2.1.2 (see above) + */ + dptr = data = LDNS_XMALLOC(uint8_t, sz); + memset(data, value, sz); + if (!data) { + return LDNS_STATUS_MEM_ERR; + } + for (i = 0; i < 256; i++) { + if (windows[i]) { + *dptr++ = (uint8_t)i; + *dptr++ = (uint8_t)(windows[i] / 8 + 1); + dptr += dptr[-1]; + } + } + } + /* Allocate and return rdf structure for the data + */ + *rdf = ldns_rdf_new(LDNS_RDF_TYPE_BITMAP, sz, data); + if (!*rdf) { + LDNS_FREE(data); + return LDNS_STATUS_MEM_ERR; + } + return LDNS_STATUS_OK; +} + +ldns_status +ldns_rdf_bitmap_known_rr_types_space(ldns_rdf** rdf) +{ + return ldns_rdf_bitmap_known_rr_types_set(rdf, 0); +} + +ldns_status +ldns_rdf_bitmap_known_rr_types(ldns_rdf** rdf) +{ + return ldns_rdf_bitmap_known_rr_types_set(rdf, 255); +} +/* End of RDF bitmap functions + *---------------------------------------------------------------------------*/ + + const ldns_rr_descriptor * ldns_rr_descript(uint16_t type) { size_t i; - if (type <= LDNS_RDATA_FIELD_DESCRIPTORS_COMMON) { + if (type < LDNS_RDATA_FIELD_DESCRIPTORS_COMMON) { return &rdata_field_descriptors[type]; } else { /* because not all array index equals type code */ diff --git a/usr.sbin/unbound/ldns/sha1.c b/usr.sbin/unbound/ldns/sha1.c index 5dec680a1b7..18a4dd28f34 100644 --- a/usr.sbin/unbound/ldns/sha1.c +++ b/usr.sbin/unbound/ldns/sha1.c @@ -15,12 +15,12 @@ */ /* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ -/* #define SHA1HANDSOFF * Copies data before messing with it. */ #include #include #include +#define SHA1HANDSOFF 1 /* Copies data before messing with it. */ #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /* blk0() and blk() perform the initial expand. */ diff --git a/usr.sbin/unbound/ldns/sha2.c b/usr.sbin/unbound/ldns/sha2.c index b25858c26bb..a808325c2fb 100644 --- a/usr.sbin/unbound/ldns/sha2.c +++ b/usr.sbin/unbound/ldns/sha2.c @@ -37,7 +37,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: sha2.c,v 1.1.1.1 2012/03/26 18:08:22 sthen Exp $ + * $Id: sha2.c,v 1.1.1.2 2014/02/04 03:48:15 brad Exp $ */ #include @@ -546,9 +546,15 @@ void ldns_sha256_update(ldns_sha256_CTX* context, const sha2_byte *data, size_t usedspace = freespace = 0; } +typedef union _ldns_sha2_buffer_union { + uint8_t* theChars; + uint64_t* theLongs; +} ldns_sha2_buffer_union; + void ldns_sha256_final(sha2_byte digest[], ldns_sha256_CTX* context) { sha2_word32 *d = (sha2_word32*)digest; size_t usedspace; + ldns_sha2_buffer_union cast_var; /* Sanity check: */ assert(context != (ldns_sha256_CTX*)0); @@ -585,7 +591,8 @@ void ldns_sha256_final(sha2_byte digest[], ldns_sha256_CTX* context) { *context->buffer = 0x80; } /* Set the bit count: */ - *(sha2_word64*)&context->buffer[ldns_sha256_SHORT_BLOCK_LENGTH] = context->bitcount; + cast_var.theChars = context->buffer; + cast_var.theLongs[ldns_sha256_SHORT_BLOCK_LENGTH / 8] = context->bitcount; /* final transform: */ ldns_sha256_Transform(context, (sha2_word32*)context->buffer); @@ -850,6 +857,7 @@ void ldns_sha512_update(ldns_sha512_CTX* context, const sha2_byte *data, size_t static void ldns_sha512_Last(ldns_sha512_CTX* context) { size_t usedspace; + ldns_sha2_buffer_union cast_var; usedspace = (context->bitcount[0] >> 3) % LDNS_SHA512_BLOCK_LENGTH; #if BYTE_ORDER == LITTLE_ENDIAN @@ -882,8 +890,9 @@ static void ldns_sha512_Last(ldns_sha512_CTX* context) { *context->buffer = 0x80; } /* Store the length of input data (in bits): */ - *(sha2_word64*)&context->buffer[ldns_sha512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; - *(sha2_word64*)&context->buffer[ldns_sha512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; + cast_var.theChars = context->buffer; + cast_var.theLongs[ldns_sha512_SHORT_BLOCK_LENGTH / 8] = context->bitcount[1]; + cast_var.theLongs[ldns_sha512_SHORT_BLOCK_LENGTH / 8 + 1] = context->bitcount[0]; /* final transform: */ ldns_sha512_Transform(context, (sha2_word64*)context->buffer); diff --git a/usr.sbin/unbound/ldns/str2host.c b/usr.sbin/unbound/ldns/str2host.c index 51357cc3176..26cef3d036e 100644 --- a/usr.sbin/unbound/ldns/str2host.c +++ b/usr.sbin/unbound/ldns/str2host.c @@ -257,33 +257,48 @@ ldns_str2rdf_int8(ldns_rdf **rd, const char *bytestr) * Returns the number of bytes read from the escaped string, or * 0 on error */ -static int -parse_escape(uint8_t *s, uint8_t *q) { +INLINE bool +parse_escape(uint8_t *ch_p, const char** str_p) +{ uint16_t val; - if (strlen((char *)s) > 3 && - isdigit((int) s[1]) && - isdigit((int) s[2]) && - isdigit((int) s[3])) { - /* cast this so it fits */ - val = (uint16_t) ldns_hexdigit_to_int((char) s[1]) * 100 + - ldns_hexdigit_to_int((char) s[2]) * 10 + - ldns_hexdigit_to_int((char) s[3]); + + if ((*str_p)[0] && isdigit((*str_p)[0]) && + (*str_p)[1] && isdigit((*str_p)[1]) && + (*str_p)[2] && isdigit((*str_p)[2])) { + + val = (uint16_t)(((*str_p)[0] - '0') * 100 + + ((*str_p)[1] - '0') * 10 + + ((*str_p)[2] - '0')); + if (val > 255) { - /* outside range */ - return 0; - } - *q = (uint8_t) val; - return 3; - } else { - s++; - if (*s == '\0' || isdigit((int) *s)) { - /* apparently the string terminator - * or a digit has been escaped... - */ - return 0; + goto error; } - *q = *s; - return 1; + *ch_p = (uint8_t)val; + *str_p += 3; + return true; + + } else if ((*str_p)[0] && !isdigit((*str_p)[0])) { + + *ch_p = (uint8_t)*(*str_p)++; + return true; + } +error: + *str_p = NULL; + return false; /* LDNS_STATUS_SYNTAX_BAD_ESCAPE */ +} + +INLINE bool +parse_char(uint8_t *ch_p, const char** str_p) +{ + switch (**str_p) { + + case '\0': return false; + + case '\\': *str_p += 1; + return parse_escape(ch_p, str_p); + + default: *ch_p = (uint8_t)*(*str_p)++; + return true; } } @@ -297,8 +312,8 @@ ldns_str2rdf_dname(ldns_rdf **d, const char *str) { size_t len; - int esc; - uint8_t *s, *q, *pq, label_len; + const char *s; + uint8_t *q, *pq, label_len; uint8_t buf[LDNS_MAX_DOMAINLEN + 1]; *d = NULL; @@ -328,7 +343,7 @@ ldns_str2rdf_dname(ldns_rdf **d, const char *str) q = buf+1; pq = buf; label_len = 0; - for (s = (uint8_t *)str; *s; s++, q++) { + for (s = str; *s; s++, q++) { if (q > buf + LDNS_MAX_DOMAINLEN) { return LDNS_STATUS_DOMAINNAME_OVERFLOW; } @@ -348,16 +363,15 @@ ldns_str2rdf_dname(ldns_rdf **d, const char *str) break; case '\\': /* octet value or literal char */ - esc = parse_escape(s, q); - if (esc > 0) { - s += esc; - label_len++; - } else { + s += 1; + if (! parse_escape(q, &s)) { return LDNS_STATUS_SYNTAX_BAD_ESCAPE; } + s -= 1; + label_len++; break; default: - *q = *s; + *q = (uint8_t)*s; label_len++; } } @@ -413,36 +427,44 @@ ldns_str2rdf_aaaa(ldns_rdf **rd, const char *str) ldns_status ldns_str2rdf_str(ldns_rdf **rd, const char *str) { - uint8_t *data; - size_t i, str_i, esc_i; + uint8_t *data, *dp, ch = 0; + size_t length; - if (strlen(str) > 255) { - return LDNS_STATUS_INVALID_STR; + /* Worst case space requirement. We'll realloc to actual size later. */ + dp = data = LDNS_XMALLOC(uint8_t, strlen(str) > 255 ? 256 : (strlen(str) + 1)); + if (! data) { + return LDNS_STATUS_MEM_ERR; } - data = LDNS_XMALLOC(uint8_t, strlen(str) + 1); - if(!data) return LDNS_STATUS_MEM_ERR; - i = 1; - - for (str_i = 0; str_i < strlen(str); str_i++) { - if (str[str_i] == '\\') { - /* octet value or literal char */ - esc_i = (size_t) parse_escape((uint8_t*) &str[str_i], (uint8_t*) &data[i]); - if (esc_i == 0) { - LDNS_FREE(data); - return LDNS_STATUS_SYNTAX_BAD_ESCAPE; - } - str_i += esc_i; - } else { - data[i] = (uint8_t) str[str_i]; + /* Fill data (up to 255 characters) */ + while (parse_char(&ch, &str)) { + if (dp - data >= 255) { + LDNS_FREE(data); + return LDNS_STATUS_INVALID_STR; } - i++; + *++dp = ch; + } + if (! str) { + return LDNS_STATUS_SYNTAX_BAD_ESCAPE; } - data[0] = i - 1; - *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_STR, i, data); + length = (size_t)(dp - data); + /* Fix last length byte */ + data[0] = (uint8_t)length; - LDNS_FREE(data); - return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; + /* Lose the overmeasure */ + data = LDNS_XREALLOC(dp = data, uint8_t, length + 1); + if (! data) { + LDNS_FREE(dp); + return LDNS_STATUS_MEM_ERR; + } + + /* Create rdf */ + *rd = ldns_rdf_new(LDNS_RDF_TYPE_STR, length + 1, data); + if (! *rd) { + LDNS_FREE(data); + return LDNS_STATUS_MEM_ERR; + } + return LDNS_STATUS_OK; } ldns_status @@ -790,15 +812,6 @@ ldns_str2rdf_unknown( ATTR_UNUSED(ldns_rdf **rd) return LDNS_STATUS_NOT_IMPL; } -ldns_status -ldns_str2rdf_tsig( ATTR_UNUSED(ldns_rdf **rd) - , ATTR_UNUSED(const char *str) - ) -{ - /* there is no string representation for TSIG rrs */ - return LDNS_STATUS_NOT_IMPL; -} - ldns_status ldns_str2rdf_service( ATTR_UNUSED(ldns_rdf **rd) , ATTR_UNUSED(const char *str) @@ -1317,3 +1330,240 @@ ldns_str2rdf_ipseckey(ldns_rdf **rd, const char *str) if(!*rd) return LDNS_STATUS_MEM_ERR; return LDNS_STATUS_OK; } + +ldns_status +ldns_str2rdf_ilnp64(ldns_rdf **rd, const char *str) +{ + unsigned int a, b, c, d; + uint16_t shorts[4]; + int l; + + if (sscanf(str, "%4x:%4x:%4x:%4x%n", &a, &b, &c, &d, &l) != 4 || + l != (int)strlen(str) || /* more data to read */ + strpbrk(str, "+-") /* signed hexes */ + ) { + return LDNS_STATUS_INVALID_ILNP64; + } else { + shorts[0] = htons(a); + shorts[1] = htons(b); + shorts[2] = htons(c); + shorts[3] = htons(d); + *rd = ldns_rdf_new_frm_data( + LDNS_RDF_TYPE_ILNP64, 4 * sizeof(uint16_t), &shorts); + } + return *rd ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR; +} + +ldns_status +ldns_str2rdf_eui48(ldns_rdf **rd, const char *str) +{ + unsigned int a, b, c, d, e, f; + uint8_t bytes[6]; + int l; + + if (sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x%n", + &a, &b, &c, &d, &e, &f, &l) != 6 || + l != (int)strlen(str) || /* more data to read */ + strpbrk(str, "+-") /* signed hexes */ + ) { + return LDNS_STATUS_INVALID_EUI48; + } else { + bytes[0] = a; + bytes[1] = b; + bytes[2] = c; + bytes[3] = d; + bytes[4] = e; + bytes[5] = f; + *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_EUI48, 6, &bytes); + } + return *rd ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR; +} + +ldns_status +ldns_str2rdf_eui64(ldns_rdf **rd, const char *str) +{ + unsigned int a, b, c, d, e, f, g, h; + uint8_t bytes[8]; + int l; + + if (sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x-%2x-%2x%n", + &a, &b, &c, &d, &e, &f, &g, &h, &l) != 8 || + l != (int)strlen(str) || /* more data to read */ + strpbrk(str, "+-") /* signed hexes */ + ) { + return LDNS_STATUS_INVALID_EUI64; + } else { + bytes[0] = a; + bytes[1] = b; + bytes[2] = c; + bytes[3] = d; + bytes[4] = e; + bytes[5] = f; + bytes[6] = g; + bytes[7] = h; + *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_EUI64, 8, &bytes); + } + return *rd ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR; +} + +ldns_status +ldns_str2rdf_tag(ldns_rdf **rd, const char *str) +{ + uint8_t *data; + const char* ptr; + + if (strlen(str) > 255) { + return LDNS_STATUS_INVALID_TAG; + } + for (ptr = str; *ptr; ptr++) { + if (! isalnum(*ptr)) { + return LDNS_STATUS_INVALID_TAG; + } + } + data = LDNS_XMALLOC(uint8_t, strlen(str) + 1); + if (!data) { + return LDNS_STATUS_MEM_ERR; + } + data[0] = strlen(str); + memcpy(data + 1, str, strlen(str)); + + *rd = ldns_rdf_new(LDNS_RDF_TYPE_TAG, strlen(str) + 1, data); + if (!*rd) { + LDNS_FREE(data); + return LDNS_STATUS_MEM_ERR; + } + return LDNS_STATUS_OK; +} + +ldns_status +ldns_str2rdf_long_str(ldns_rdf **rd, const char *str) +{ + uint8_t *data, *dp, ch = 0; + size_t length; + + /* Worst case space requirement. We'll realloc to actual size later. */ + dp = data = LDNS_XMALLOC(uint8_t, strlen(str)); + if (! data) { + return LDNS_STATUS_MEM_ERR; + } + + /* Fill data with parsed bytes */ + while (parse_char(&ch, &str)) { + *dp++ = ch; + if (dp - data > LDNS_MAX_RDFLEN) { + LDNS_FREE(data); + return LDNS_STATUS_INVALID_STR; + } + } + if (! str) { + return LDNS_STATUS_SYNTAX_BAD_ESCAPE; + } + length = (size_t)(dp - data); + + /* Lose the overmeasure */ + data = LDNS_XREALLOC(dp = data, uint8_t, length); + if (! data) { + LDNS_FREE(dp); + return LDNS_STATUS_MEM_ERR; + } + + /* Create rdf */ + *rd = ldns_rdf_new(LDNS_RDF_TYPE_LONG_STR, length, data); + if (! *rd) { + LDNS_FREE(data); + return LDNS_STATUS_MEM_ERR; + } + return LDNS_STATUS_OK; +} + +ldns_status +ldns_str2rdf_hip(ldns_rdf **rd, const char *str) +{ + const char *hit = strchr(str, ' ') + 1; + const char *pk = hit == NULL ? NULL : strchr(hit, ' ') + 1; + size_t hit_size = hit == NULL ? 0 + : pk == NULL ? strlen(hit) : (size_t) (pk - hit) - 1; + size_t pk_size = pk == NULL ? 0 : strlen(pk); + size_t hit_wire_size = (hit_size + 1) / 2; + size_t pk_wire_size = ldns_b64_pton_calculate_size(pk_size); + size_t rdf_size = 4 + hit_wire_size + pk_wire_size; + + char *endptr; /* utility var for strtol usage */ + int algorithm = strtol(str, &endptr, 10); + + uint8_t *data, *dp; + int hi, lo, written; + + if (hit_size == 0 || pk_size == 0 || (hit_size + 1) / 2 > 255 + || rdf_size > LDNS_MAX_RDFLEN + || algorithm < 0 || algorithm > 255 + || (errno != 0 && algorithm == 0) /* out of range */ + || endptr == str /* no digits */) { + + return LDNS_STATUS_SYNTAX_ERR; + } + if ((data = LDNS_XMALLOC(uint8_t, rdf_size)) == NULL) { + + return LDNS_STATUS_MEM_ERR; + } + /* From RFC 5205 section 5. HIP RR Storage Format: + ************************************************* + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | HIT length | PK algorithm | PK length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + ~ HIT ~ + | | + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | + +-+-+-+-+-+-+-+-+-+-+-+ + + | Public Key | + ~ ~ + | | + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + | | + ~ Rendezvous Servers ~ + | | + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + +-+-+-+-+-+-+-+ */ + + data[0] = (uint8_t) hit_wire_size; + data[1] = (uint8_t) algorithm; + + for (dp = data + 4; *hit && *hit != ' '; dp++) { + + if ((hi = ldns_hexdigit_to_int(*hit++)) == -1 || + (lo = ldns_hexdigit_to_int(*hit++)) == -1) { + + LDNS_FREE(data); + return LDNS_STATUS_INVALID_HEX; + } + *dp = (uint8_t) hi << 4 | lo; + } + if ((written = ldns_b64_pton(pk, dp, pk_wire_size)) <= 0) { + + LDNS_FREE(data); + return LDNS_STATUS_INVALID_B64; + } + + /* Because ldns_b64_pton_calculate_size isn't always correct: + * (we have to fix it at some point) + */ + pk_wire_size = (uint16_t) written; + ldns_write_uint16(data + 2, pk_wire_size); + rdf_size = 4 + hit_wire_size + pk_wire_size; + + /* Create rdf */ + if (! (*rd = ldns_rdf_new(LDNS_RDF_TYPE_HIP, rdf_size, data))) { + + LDNS_FREE(data); + return LDNS_STATUS_MEM_ERR; + } + return LDNS_STATUS_OK; +} diff --git a/usr.sbin/unbound/ldns/tsig.c b/usr.sbin/unbound/ldns/tsig.c index 41693463df3..53aa85ecb46 100644 --- a/usr.sbin/unbound/ldns/tsig.c +++ b/usr.sbin/unbound/ldns/tsig.c @@ -51,7 +51,7 @@ ldns_tsig_keydata_clone(ldns_tsig_credentials *tc) /* * Makes an exact copy of the wire, but with the tsig rr removed */ -uint8_t * +static uint8_t * ldns_tsig_prepare_pkt_wire(uint8_t *wire, size_t wire_len, size_t *result_len) { uint8_t *wire2 = NULL; @@ -134,19 +134,15 @@ ldns_digest_function(char *name) { /* these are the mandatory algorithms from RFC4635 */ /* The optional algorithms are not yet implemented */ - if (strlen(name) == 12 - && strncasecmp(name, "hmac-sha256.", 11) == 0) { + if (strcasecmp(name, "hmac-sha256.") == 0) { #ifdef HAVE_EVP_SHA256 return EVP_sha256(); #else return NULL; #endif - } else if (strlen(name) == 10 - && strncasecmp(name, "hmac-sha1.", 9) == 0) { + } else if (strcasecmp(name, "hmac-sha1.") == 0) { return EVP_sha1(); - } else if (strlen(name) == 25 - && strncasecmp(name, "hmac-md5.sig-alg.reg.int.", 25) - == 0) { + } else if (strcasecmp(name, "hmac-md5.sig-alg.reg.int.") == 0) { return EVP_md5(); } else { return NULL; diff --git a/usr.sbin/unbound/ldns/util.c b/usr.sbin/unbound/ldns/util.c index f5462c4b08f..33060d9637b 100644 --- a/usr.sbin/unbound/ldns/util.c +++ b/usr.sbin/unbound/ldns/util.c @@ -20,48 +20,12 @@ #include #include #include +#include #ifdef HAVE_SSL #include #endif -/* put this here tmp. for debugging */ -void -xprintf_rdf(ldns_rdf *rd) -{ - /* assume printable string */ - fprintf(stderr, "size\t:%u\n", (unsigned int)ldns_rdf_size(rd)); - fprintf(stderr, "type\t:%u\n", (unsigned int)ldns_rdf_get_type(rd)); - fprintf(stderr, "data\t:[%.*s]\n", (int)ldns_rdf_size(rd), - (char*)ldns_rdf_data(rd)); -} - -void -xprintf_rr(ldns_rr *rr) -{ - /* assume printable string */ - uint16_t count, i; - - count = ldns_rr_rd_count(rr); - - for(i = 0; i < count; i++) { - fprintf(stderr, "print rd %u\n", (unsigned int) i); - xprintf_rdf(rr->_rdata_fields[i]); - } -} - -void xprintf_hex(uint8_t *data, size_t len) -{ - size_t i; - for (i = 0; i < len; i++) { - if (i > 0 && i % 20 == 0) { - printf("\t; %u - %u\n", (unsigned int) i - 19, (unsigned int) i); - } - printf("%02x ", (unsigned int) data[i]); - } - printf("\n"); -} - ldns_lookup_table * ldns_lookup_by_name(ldns_lookup_table *table, const char *name) { @@ -497,3 +461,313 @@ ldns_bubblebabble(uint8_t *data, size_t len) retval[j++] = '\0'; return retval; } + +/* + * For backwards compatibility, because we have always exported this symbol. + */ +#ifdef HAVE_B64_NTOP +int ldns_b64_ntop(const uint8_t* src, size_t srclength, + char *target, size_t targsize); +{ + return b64_ntop(src, srclength, target, targsize); +} +#endif + +/* + * For backwards compatibility, because we have always exported this symbol. + */ +#ifdef HAVE_B64_PTON +int ldns_b64_pton(const char* src, uint8_t *target, size_t targsize) +{ + return b64_pton(src, target, targsize); +} +#endif + + +static int +ldns_b32_ntop_base(const uint8_t* src, size_t src_sz, + char* dst, size_t dst_sz, + bool extended_hex, bool add_padding) +{ + size_t ret_sz; + const char* b32 = extended_hex ? "0123456789abcdefghijklmnopqrstuv" + : "abcdefghijklmnopqrstuvwxyz234567"; + + size_t c = 0; /* c is used to carry partial base32 character over + * byte boundaries for sizes with a remainder. + * (i.e. src_sz % 5 != 0) + */ + + ret_sz = add_padding ? ldns_b32_ntop_calculate_size(src_sz) + : ldns_b32_ntop_calculate_size_no_padding(src_sz); + + /* Do we have enough space? */ + if (dst_sz < ret_sz + 1) + return -1; + + /* We know the size; terminate the string */ + dst[ret_sz] = '\0'; + + /* First process all chunks of five */ + while (src_sz >= 5) { + /* 00000... ........ ........ ........ ........ */ + dst[0] = b32[(src[0] ) >> 3]; + + /* .....111 11...... ........ ........ ........ */ + dst[1] = b32[(src[0] & 0x07) << 2 | src[1] >> 6]; + + /* ........ ..22222. ........ ........ ........ */ + dst[2] = b32[(src[1] & 0x3e) >> 1]; + + /* ........ .......3 3333.... ........ ........ */ + dst[3] = b32[(src[1] & 0x01) << 4 | src[2] >> 4]; + + /* ........ ........ ....4444 4....... ........ */ + dst[4] = b32[(src[2] & 0x0f) << 1 | src[3] >> 7]; + + /* ........ ........ ........ .55555.. ........ */ + dst[5] = b32[(src[3] & 0x7c) >> 2]; + + /* ........ ........ ........ ......66 666..... */ + dst[6] = b32[(src[3] & 0x03) << 3 | src[4] >> 5]; + + /* ........ ........ ........ ........ ...77777 */ + dst[7] = b32[(src[4] & 0x1f) ]; + + src_sz -= 5; + src += 5; + dst += 8; + } + /* Process what remains */ + switch (src_sz) { + case 4: /* ........ ........ ........ ......66 666..... */ + dst[6] = b32[(src[3] & 0x03) << 3]; + + /* ........ ........ ........ .55555.. ........ */ + dst[5] = b32[(src[3] & 0x7c) >> 2]; + + /* ........ ........ ....4444 4....... ........ */ + c = src[3] >> 7 ; + case 3: dst[4] = b32[(src[2] & 0x0f) << 1 | c]; + + /* ........ .......3 3333.... ........ ........ */ + c = src[2] >> 4 ; + case 2: dst[3] = b32[(src[1] & 0x01) << 4 | c]; + + /* ........ ..22222. ........ ........ ........ */ + dst[2] = b32[(src[1] & 0x3e) >> 1]; + + /* .....111 11...... ........ ........ ........ */ + c = src[1] >> 6 ; + case 1: dst[1] = b32[(src[0] & 0x07) << 2 | c]; + + /* 00000... ........ ........ ........ ........ */ + dst[0] = b32[ src[0] >> 3]; + } + /* Add padding */ + if (add_padding) { + switch (src_sz) { + case 1: dst[2] = '='; + dst[3] = '='; + case 2: dst[4] = '='; + case 3: dst[5] = '='; + dst[6] = '='; + case 4: dst[7] = '='; + } + } + return (int)ret_sz; +} + +int +ldns_b32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz) +{ + return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, false, true); +} + +int +ldns_b32_ntop_extended_hex(const uint8_t* src, size_t src_sz, + char* dst, size_t dst_sz) +{ + return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, true, true); +} + +#ifndef HAVE_B32_NTOP + +int +b32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz) +{ + return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, false, true); +} + +int +b32_ntop_extended_hex(const uint8_t* src, size_t src_sz, + char* dst, size_t dst_sz) +{ + return ldns_b32_ntop_base(src, src_sz, dst, dst_sz, true, true); +} + +#endif /* ! HAVE_B32_NTOP */ + +static int +ldns_b32_pton_base(const char* src, size_t src_sz, + uint8_t* dst, size_t dst_sz, + bool extended_hex, bool check_padding) +{ + size_t i = 0; + char ch = '\0'; + uint8_t buf[8]; + uint8_t* start = dst; + + while (src_sz) { + /* Collect 8 characters in buf (if possible) */ + for (i = 0; i < 8; i++) { + + do { + ch = *src++; + --src_sz; + + } while (isspace(ch) && src_sz > 0); + + if (ch == '=' || ch == '\0') + break; + + else if (extended_hex) + + if (ch >= '0' && ch <= '9') + buf[i] = (uint8_t)ch - '0'; + else if (ch >= 'a' && ch <= 'v') + buf[i] = (uint8_t)ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'V') + buf[i] = (uint8_t)ch - 'A' + 10; + else + return -1; + + else if (ch >= 'a' && ch <= 'z') + buf[i] = (uint8_t)ch - 'a'; + else if (ch >= 'A' && ch <= 'Z') + buf[i] = (uint8_t)ch - 'A'; + else if (ch >= '2' && ch <= '7') + buf[i] = (uint8_t)ch - '2' + 26; + else + return -1; + } + /* Less that 8 characters. We're done. */ + if (i < 8) + break; + + /* Enough space available at the destination? */ + if (dst_sz < 5) + return -1; + + /* 00000... ........ ........ ........ ........ */ + /* .....111 11...... ........ ........ ........ */ + dst[0] = buf[0] << 3 | buf[1] >> 2; + + /* .....111 11...... ........ ........ ........ */ + /* ........ ..22222. ........ ........ ........ */ + /* ........ .......3 3333.... ........ ........ */ + dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4; + + /* ........ .......3 3333.... ........ ........ */ + /* ........ ........ ....4444 4....... ........ */ + dst[2] = buf[3] << 4 | buf[4] >> 1; + + /* ........ ........ ....4444 4....... ........ */ + /* ........ ........ ........ .55555.. ........ */ + /* ........ ........ ........ ......66 666..... */ + dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3; + + /* ........ ........ ........ ......66 666..... */ + /* ........ ........ ........ ........ ...77777 */ + dst[4] = buf[6] << 5 | buf[7]; + + dst += 5; + dst_sz -= 5; + } + /* Not ending on a eight byte boundary? */ + if (i > 0 && i < 8) { + + /* Enough space available at the destination? */ + if (dst_sz < (i + 1) / 2) + return -1; + + switch (i) { + case 7: /* ........ ........ ........ ......66 666..... */ + /* ........ ........ ........ .55555.. ........ */ + /* ........ ........ ....4444 4....... ........ */ + dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3; + + case 5: /* ........ ........ ....4444 4....... ........ */ + /* ........ .......3 3333.... ........ ........ */ + dst[2] = buf[3] << 4 | buf[4] >> 1; + + case 4: /* ........ .......3 3333.... ........ ........ */ + /* ........ ..22222. ........ ........ ........ */ + /* .....111 11...... ........ ........ ........ */ + dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4; + + case 2: /* .....111 11...... ........ ........ ........ */ + /* 00000... ........ ........ ........ ........ */ + dst[0] = buf[0] << 3 | buf[1] >> 2; + + break; + + default: + return -1; + } + dst += (i + 1) / 2; + + if (check_padding) { + /* Check remaining padding characters */ + if (ch != '=') + return -1; + + /* One down, 8 - i - 1 more to come... */ + for (i = 8 - i - 1; i > 0; i--) { + + do { + if (src_sz == 0) + return -1; + ch = *src++; + src_sz--; + + } while (isspace(ch)); + + if (ch != '=') + return -1; + } + } + } + return dst - start; +} + +int +ldns_b32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz) +{ + return ldns_b32_pton_base(src, src_sz, dst, dst_sz, false, true); +} + +int +ldns_b32_pton_extended_hex(const char* src, size_t src_sz, + uint8_t* dst, size_t dst_sz) +{ + return ldns_b32_pton_base(src, src_sz, dst, dst_sz, true, true); +} + +#ifndef HAVE_B32_PTON + +int +b32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz) +{ + return ldns_b32_pton_base(src, src_sz, dst, dst_sz, false, true); +} + +int +b32_pton_extended_hex(const char* src, size_t src_sz, + uint8_t* dst, size_t dst_sz) +{ + return ldns_b32_pton_base(src, src_sz, dst, dst_sz, true, true); +} + +#endif /* ! HAVE_B32_PTON */ + diff --git a/usr.sbin/unbound/ldns/wire2host.c b/usr.sbin/unbound/ldns/wire2host.c index e87fcdf5df6..f305808c285 100644 --- a/usr.sbin/unbound/ldns/wire2host.c +++ b/usr.sbin/unbound/ldns/wire2host.c @@ -64,10 +64,12 @@ ldns_wire2dname(ldns_rdf **dname, const uint8_t *wire, size_t max, size_t *pos) uint8_t tmp_dname[LDNS_MAX_DOMAINLEN]; unsigned int pointer_count = 0; + if (pos == NULL) { + return LDNS_STATUS_WIRE_RDATA_ERR; + } if (*pos >= max) { return LDNS_STATUS_PACKET_OVERFLOW; } - label_size = wire[*pos]; while (label_size > 0) { /* compression */ @@ -162,9 +164,13 @@ ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos) uint16_t rd_length; ldns_rdf *cur_rdf = NULL; ldns_rdf_type cur_rdf_type; - const ldns_rr_descriptor *descriptor = ldns_rr_descript(ldns_rr_get_type(rr)); + const ldns_rr_descriptor *descriptor; ldns_status status; + assert(rr != NULL); + + descriptor = ldns_rr_descript(ldns_rr_get_type(rr)); + if (*pos + 2 > max) { return LDNS_STATUS_PACKET_OVERFLOW; } @@ -178,14 +184,15 @@ ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos) end = *pos + (size_t) rd_length; - for (rdf_index = 0; - rdf_index < ldns_rr_descriptor_maximum(descriptor); rdf_index++) { - if (*pos >= end) { - break; - } + rdf_index = 0; + while (*pos < end && + rdf_index < ldns_rr_descriptor_maximum(descriptor)) { + cur_rdf_length = 0; - cur_rdf_type = ldns_rr_descriptor_field_type(descriptor, rdf_index); + cur_rdf_type = ldns_rr_descriptor_field_type( + descriptor, rdf_index); + /* handle special cases immediately, set length for fixed length rdata and do them below */ switch (cur_rdf_type) { @@ -210,21 +217,40 @@ ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos) cur_rdf_length = LDNS_RDF_SIZE_DOUBLEWORD; break; case LDNS_RDF_TYPE_TSIGTIME: + case LDNS_RDF_TYPE_EUI48: cur_rdf_length = LDNS_RDF_SIZE_6BYTES; break; + case LDNS_RDF_TYPE_ILNP64: + case LDNS_RDF_TYPE_EUI64: + cur_rdf_length = LDNS_RDF_SIZE_8BYTES; + break; case LDNS_RDF_TYPE_AAAA: cur_rdf_length = LDNS_RDF_SIZE_16BYTES; break; case LDNS_RDF_TYPE_STR: case LDNS_RDF_TYPE_NSEC3_SALT: + case LDNS_RDF_TYPE_TAG: /* len is stored in first byte * it should be in the rdf too, so just * copy len+1 from this position */ cur_rdf_length = ((size_t) wire[*pos]) + 1; break; + case LDNS_RDF_TYPE_INT16_DATA: - cur_rdf_length = (size_t) ldns_read_uint16(&wire[*pos]) + 2; + if (*pos + 2 > end) { + return LDNS_STATUS_PACKET_OVERFLOW; + } + cur_rdf_length = + (size_t) ldns_read_uint16(&wire[*pos]) + 2; + break; + case LDNS_RDF_TYPE_HIP: + if (*pos + 4 > end) { + return LDNS_STATUS_PACKET_OVERFLOW; + } + cur_rdf_length = + (size_t) wire[*pos] + + (size_t) ldns_read_uint16(&wire[*pos + 2]) + 4; break; case LDNS_RDF_TYPE_B32_EXT: case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER: @@ -242,7 +268,7 @@ ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos) case LDNS_RDF_TYPE_NSAP: case LDNS_RDF_TYPE_ATMA: case LDNS_RDF_TYPE_IPSECKEY: - case LDNS_RDF_TYPE_TSIG: + case LDNS_RDF_TYPE_LONG_STR: case LDNS_RDF_TYPE_NONE: /* * Read to end of rr rdata @@ -262,7 +288,8 @@ ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos) } memcpy(data, &wire[*pos], cur_rdf_length); - cur_rdf = ldns_rdf_new(cur_rdf_type, cur_rdf_length, data); + cur_rdf = ldns_rdf_new(cur_rdf_type, + cur_rdf_length, data); *pos = *pos + cur_rdf_length; } @@ -270,7 +297,11 @@ ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos) ldns_rr_push_rdf(rr, cur_rdf); cur_rdf = NULL; } - } + + rdf_index++; + + } /* while (rdf_index < ldns_rr_descriptor_maximum(descriptor)) */ + return LDNS_STATUS_OK; } diff --git a/usr.sbin/unbound/ldns/zone.c b/usr.sbin/unbound/ldns/zone.c index 0616a141b55..d97a81ec3a4 100644 --- a/usr.sbin/unbound/ldns/zone.c +++ b/usr.sbin/unbound/ldns/zone.c @@ -56,103 +56,6 @@ ldns_zone_push_rr(ldns_zone *z, ldns_rr *rr) return ldns_rr_list_push_rr( ldns_zone_rrs(z), rr); } -/* return a clone of the given rr list, without the glue records - * rr list should be the complete zone - * if present, stripped records are added to the list *glue_records - */ -ldns_rr_list * -ldns_zone_strip_glue_rrs(const ldns_rdf *zone_name, const ldns_rr_list *rrs, ldns_rr_list *glue_rrs) -{ - ldns_rr_list *new_list; - - /* when do we find glue? It means we find an IP address - * (AAAA/A) for a nameserver listed in the zone - * - * Alg used here: - * first find all the zonecuts (NS records) - * find all the AAAA or A records (can be done it the - * above loop). - * - * Check if the aaaa/a list are subdomains under the - * NS domains. - * If yes -> glue, if no -> not glue - */ - - ldns_rr_list *zone_cuts; - ldns_rr_list *addr; - ldns_rr *r, *ns, *a; - ldns_rdf *dname_a, *ns_owner; - uint16_t i,j; - - new_list = NULL; - zone_cuts = NULL; - addr = NULL; - - new_list = ldns_rr_list_new(); - if (!new_list) goto memory_error; - zone_cuts = ldns_rr_list_new(); - if (!zone_cuts) goto memory_error; - addr = ldns_rr_list_new(); - if (!addr) goto memory_error; - - for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) { - r = ldns_rr_list_rr(rrs, i); - if (ldns_rr_get_type(r) == LDNS_RR_TYPE_A || - ldns_rr_get_type(r) == LDNS_RR_TYPE_AAAA) { - /* possibly glue */ - if (!ldns_rr_list_push_rr(addr, r)) goto memory_error; - continue; - } - if (ldns_rr_get_type(r) == LDNS_RR_TYPE_NS) { - /* multiple zones will end up here - - * for now; not a problem - */ - /* don't add NS records for the current zone itself */ - if (ldns_rdf_compare(ldns_rr_owner(r), - zone_name) != 0) { - if (!ldns_rr_list_push_rr(zone_cuts, r)) goto memory_error; - } - continue; - } - } - - /* will sorting make it quicker ?? */ - for(i = 0; i < ldns_rr_list_rr_count(zone_cuts); i++) { - ns = ldns_rr_list_rr(zone_cuts, i); - ns_owner = ldns_rr_owner(ns); - for(j = 0; j < ldns_rr_list_rr_count(addr); j++) { - a = ldns_rr_list_rr(addr, j); - dname_a = ldns_rr_owner(a); - - if (ldns_dname_is_subdomain(dname_a, ns_owner)) { - /* GLUE! */ - if (glue_rrs) { - if (!ldns_rr_list_push_rr(glue_rrs, a)) goto memory_error; - } - break; - } else { - if (!ldns_rr_list_push_rr(new_list, a)) goto memory_error; - } - } - } - - ldns_rr_list_free(addr); - ldns_rr_list_free(zone_cuts); - - return new_list; - -memory_error: - if (new_list) { - ldns_rr_list_free(new_list); - } - if (zone_cuts) { - ldns_rr_list_free(zone_cuts); - } - if (addr) { - ldns_rr_list_free(addr); - } - return NULL; -} /* * Get the list of glue records in a zone @@ -399,22 +302,6 @@ ldns_zone_sort(ldns_zone *zone) ldns_rr_list_sort(zrr); } -#if 0 -/** - * ixfr function. Work on a ldns_zone and remove and add - * the rrs from the rrlist - * \param[in] z the zone to work on - * \param[in] del rr_list to remove from the zone - * \param[in] add rr_list to add to the zone - * \return Tja, wat zouden we eens returnen TODO - */ -void -ldns_zone_ixfr_del_add(ldns_zone *z, ldns_rr_list *del, ldns_rr_list *add) -{ - -} -#endif - void ldns_zone_free(ldns_zone *zone) { -- cgit v1.2.3